From 37c594c1bd8515fe5d4d517597acda4b0553ffa0 Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Sat, 3 Apr 2021 01:40:59 +0200 Subject: [PATCH] implemented shell wrapper commands are now run in a subshell, this is often needed for chains of commands where it is not the main command to need the privilege but a subcommand does, for example us echo 30 > /sys/class/backlight/*/brightness it is not echo that needs the elevated privilege but the redirection '>' does. --- us.c | 109 ++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 34 deletions(-) diff --git a/us.c b/us.c index fbae2ab..53d5af8 100644 --- a/us.c +++ b/us.c @@ -33,8 +33,10 @@ static void usage (void); static int perm_set (const char *, const char *); +static int authenticate (const char *); -// FIXME: misc_conv is a separate library, should stick to plain PAM +// FIXME: misc_conv is a separate library, should stick to plain PAM or make +// our own pam module static struct pam_conv conv = {misc_conv, NULL}; int main (int argc, char *argv[]) @@ -66,14 +68,16 @@ int main (int argc, char *argv[]) } } - // Copy argv and argc - int c_argc = argc - optind; +/* + int c_argc = argc - optind + 2; char **c_argv = malloc((c_argc + 1) * sizeof(char *)); if (!c_argv) { fprintf(stderr, "malloc: %s\n", strerror(errno)); goto fail_end; } - for (int i = 0; optind < argc; i++, optind++) { + c_argv[0] = shell; + c_argv[1] = "-c"; + for (int i = 2; optind < argc; i++, optind++) { c_argv[i] = strdup(argv[optind]); if (!c_argv[i]) { fprintf(stderr, "getpwid: %s\n", strerror(errno)); @@ -81,45 +85,50 @@ int main (int argc, char *argv[]) } } c_argc[c_argv] = NULL; +*/ - if (c_argc == 0) { - usage(); - exit(EINVAL); + /* Set argc and argv */ + // TODO: get the right shell for the user (it is in the passwd struct) + char *shell = "/bin/sh"; + char *command, **c_argv; + int size, popind = optind; + int c_argc = 3; // /bin/sh -c command + + c_argv = malloc((c_argc + 1) * sizeof(char *)); + if (!c_argv) { + fprintf(stderr, "malloc: %s\n", strerror(errno)); + exit(errno); } + for (size = 0; optind < argc; optind++) + size += strlen(argv[optind]) + 1; + command = malloc(sizeof(char) * size); + if (!command) { + fprintf(stderr, "malloc: %s\n", strerror(errno)); + exit(errno); + } + for (optind = popind; optind < argc; optind++) { + strcat(command, argv[optind]); + strcat(command, " "); + } + + c_argv[0] = shell; + // FIXME: this should be optional if size is zero: we want just a shell + c_argv[1] = "-c"; + c_argv[2] = command; + c_argv[c_argc] = NULL; + + /* Authenticate */ uid_t ruid = getuid(); struct passwd *pw = getpwuid(ruid); if (!pw) { fprintf(stderr, "getpwid: %s\n", strerror(errno)); - exit(errno); + return errno; } const char *uname = pw->pw_name; + if (authenticate(uname) != PAM_SUCCESS) + exit(EXIT_FAILURE); - pam_handle_t *pamh; - int pam_err, count = 0; - pam_err = pam_start("User Switcher", uname, &conv, &pamh); - if (pam_err != PAM_SUCCESS) { - fprintf(stderr, "pam_start: %s\n", pam_strerror(pamh, pam_err)); - exit(pam_err); - } - - do { - pam_err = pam_authenticate(pamh, 0); - if (pam_err != PAM_SUCCESS) - printf("Auth failed: %s\n", pam_strerror(pamh, pam_err)); - count++; - } while (pam_err != PAM_SUCCESS && count < 4); - if (pam_err != PAM_SUCCESS) { - fprintf(stderr, "better luck next time\n"); - pam_end(pamh, pam_err); - exit(pam_err); - } - // FIXME: check again for the validity of the login for more security - // as in: https://docs.oracle.com/cd/E19120-01/open.solaris/819-2145/pam-20/index.html - // FIXME: ^C [SIGINT] will interrupt this call possibly causing a - // vulnerability - - pam_end(pamh, pam_err); // TODO: clean up env errno = 0; @@ -130,7 +139,7 @@ int main (int argc, char *argv[]) } /* Execute the command */ - if (execvp(*c_argv, c_argv) == -1) // execvp searches in path + if (execv(*c_argv, c_argv) == -1) // execvp searches in path fprintf(stderr, "execv: %s\n", strerror(errno)); /* Cleanup and return */ @@ -231,3 +240,35 @@ static int perm_set (const char *user, const char *group) return 0; } + +static int authenticate (const char *uname) +{ + pam_handle_t *pamh; + int pam_err, count = 0; + pam_err = pam_start("User Switcher", uname, &conv, &pamh); + if (pam_err != PAM_SUCCESS) { + fprintf(stderr, "pam_start: %s\n", pam_strerror(pamh, pam_err)); + return pam_err; + } + + do { + pam_err = pam_authenticate(pamh, 0); + if (pam_err != PAM_SUCCESS) + printf("Auth failed: %s\n", pam_strerror(pamh, pam_err)); + // FIXME: count gets ignored because authentication service has + // a set amount of retries giving an error: + // Have exhausted maximum number of retries for service + count++; + } while (pam_err != PAM_SUCCESS && count < 4); + if (pam_err != PAM_SUCCESS) { + fprintf(stderr, "better luck next time\n"); + pam_end(pamh, pam_err); + return pam_err; + } + // FIXME: check again for the validity of the login for more security + // as in: https://docs.oracle.com/cd/E19120-01/open.solaris/819-2145/pam-20/index.html + // FIXME: ^C [SIGINT] will interrupt this call possibly causing a + // vulnerability + + return pam_end(pamh, pam_err); +}