[pacman-dev] [PATCH] Adding support for sudo when user is not root and root privileges are required

Lorenzo Mureu mureulor at gmail.com
Sun Mar 22 01:44:03 UTC 2015


This patch adds support for sudo in pacman.
Now, when you run some unharmful (informative) command with pacman all
is fine, but if you try some potentially harmful command (like
installing or removing packages, or syncing) it stops telling you that
you must be root.

While this behaviour is perfectly fine, and that can be what most users
want, I'd prefere that when root previleges are needed pacman acquired
them directly with sudo.

This is accomplished this way:
1) A new configuration file option is provided: UseSudo.
   If it is not set pacman will behave normally, as always (i.e. prints
   an error)
   It is set than it will use sudo if needed

2) As a direct consequence of 1) the configuration structure defined in
   config.h and config.c has a new field: usesudo.
   == 1 means "use sudo"
   == 0 means "never use sudo"
   Its value is set according to the configuration file.
   That is: if user set UseSudo in pacman.conf then usesudo=1 else
   usesudo=0

3) In pacman.c I created a copy of argv (because getopt re-arranges the
   array) and extended it so that, when passed as a parameter to execvp,
   it will run as if it was ` exec sudo pacman "$@" ` in bash
   There ARE some problems, but I could eventually fix them, if needed,
   if the patch was to be accepted.

   1) sargv, the "sudo"-execvp-copy of argv is always created and populated.
      It wouldn't be necessary if getopt didn't re-order argv's elements
      I could put its allocation and initialization inside an if that
      checks usesudo, but I don't know if that is OK with pacman's
      main() flow.

Anyway, I hope this patch isn't too ugly (this is the first I cooperate
to a big program). If it is, please tell me and I'll fix it.

Greetings,
Lorenzo Mureu.

Signed-off-by: Lorenzo Mureu <mureulor at gmail.com>
---
 src/pacman/conf.c   |  7 +++++++
 src/pacman/conf.h   |  3 +++
 src/pacman/pacman.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index ccf8183..52941b9 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -119,6 +119,8 @@ config_t *config_new(void)
 	newconfig->colstr.warn    = "";
 	newconfig->colstr.err     = "";
 	newconfig->colstr.nocolor = "";
+	newconfig->usesudo = 0; 	/* if set to 1: enable using sudo to acquire root privileges
+					   if set to 0: default behaviour */
 
 	return newconfig;
 }
@@ -496,6 +498,11 @@ static int _parse_options(const char *key, char *value,
 				config->color = isatty(fileno(stdout)) ? PM_COLOR_ON : PM_COLOR_OFF;
 				enable_colors(config->color);
 			}
+		/*
+		 * If the UseSudo is specified in the configuration file enable sudo (see above)
+		 */
+		} else if(strcmp(key, "UseSudo") == 0) {
+			config->usesudo=1;
 		} else {
 			pm_printf(ALPM_LOG_WARNING,
 					_("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
diff --git a/src/pacman/conf.h b/src/pacman/conf.h
index d6feb7a..623c338 100644
--- a/src/pacman/conf.h
+++ b/src/pacman/conf.h
@@ -128,6 +128,9 @@ typedef struct __config_t {
 	colstr_t colstr;
 
 	alpm_list_t *repos;
+
+	unsigned short usesudo; /* controls whether to use sudo to acquire root privileges.
+				   see config.c and pacman.c */
 } config_t;
 
 /* Operations */
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index fce0131..0b568e3 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -1041,6 +1041,43 @@ static void cl_to_log(int argc, char *argv[])
 	free(cl_text);
 }
 
+/*
+ * This function increases argv's size by two elements.
+ * The first element of the "new" argv is "sudo" 
+ * The following elements are copied from argv
+ * The last element of the "new" argv is a NULL pointer
+ *
+ * The "new" argv can be passed to execvp to re-run pacman
+ * via sudo, with the same arguments.
+ */
+void sudo_argv(int argc, char ***argv)
+{
+	int i;
+	char **sargv;	/* the "new" argv */
+	
+	sargv = calloc(2 + argc, sizeof(char*)); /* Allocate a bigger array */
+	sargv[0] = calloc(5, sizeof(char));	 /* Allocate space for the string "sudo" */
+	strcpy(sargv[0], "sudo");
+	
+	for (i = 1; i < 1 + argc; i++) {
+		sargv[i]=(*argv)[i-1]; /* Copy elements from argv to sargv */
+	}
+	sargv[argc+1] = NULL;    /* The last element is a NULL pointer */
+	*argv=sargv;  /* sargv then replaces argv */
+}
+
+/*
+ * copy argv (whose size is argc) to nargv (whose space is already allocated)
+ */
+void array_copy(int argc, char **argv, char **nargv)
+{
+	int i;
+	for (i = 0; i < argc; i++) {
+		nargv[i] = calloc(1 + strlen(argv[i]), sizeof(char));
+		strcpy(nargv[i], argv[i]);
+	}
+}
+
 /** Main function.
  * @param argc
  * @param argv
@@ -1053,13 +1090,23 @@ int main(int argc, char *argv[])
 	struct sigaction new_action, old_action;
 	const int signals[] = { SIGHUP, SIGINT, SIGTERM, SIGSEGV, SIGWINCH };
 	uid_t myuid = getuid();
+	
+	/* 
+	 * an array which can be used with execvp to re-run pacman with the same options, with sudo (if the user configured so)
+	 * it must be initialized and populated here (even if it won't be used) because getopt reorders argv, so argv can't be used
+	 */
+	char **sargv; 
+	sargv=calloc(argc, sizeof(char*));
+	array_copy(argc, argv, sargv);  /* create a copy of argv */
+	sudo_argv(argc, &sargv);	/* increase argv's size by 2. First element is sudo, followed by argv's content, then a null pointer, as required by execvp */
 
 	/* Set signal handlers */
 	/* Set up the structure to specify the new action. */
 	new_action.sa_handler = handler;
 	sigemptyset(&new_action.sa_mask);
 	new_action.sa_flags = SA_RESTART;
-
+	
+	
 	/* assign our handler to any signals we care about */
 	for(i = 0; i < sizeof(signals) / sizeof(signals[0]); i++) {
 		int signal = signals[i];
@@ -1185,6 +1232,10 @@ int main(int argc, char *argv[])
 
 	/* check if we have sufficient permission for the requested operation */
 	if(myuid > 0 && needs_root()) {
+		/* if UseSudo option is set, re-exec with sudo */
+		if (config->usesudo == 1 ) {
+			execvp("sudo", sargv);
+		}
 		pm_printf(ALPM_LOG_ERROR, _("you cannot perform this operation unless you are root.\n"));
 		cleanup(EXIT_FAILURE);
 	}
-- 
2.3.3


More information about the pacman-dev mailing list