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.
noproxy
Alessandro Mauri 4 years ago
parent 704914f4cb
commit 37c594c1bd
  1. 109
      us.c

109
us.c

@ -33,8 +33,10 @@
static void usage (void); static void usage (void);
static int perm_set (const char *, const char *); 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}; static struct pam_conv conv = {misc_conv, NULL};
int main (int argc, char *argv[]) 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 *)); char **c_argv = malloc((c_argc + 1) * sizeof(char *));
if (!c_argv) { if (!c_argv) {
fprintf(stderr, "malloc: %s\n", strerror(errno)); fprintf(stderr, "malloc: %s\n", strerror(errno));
goto fail_end; 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]); c_argv[i] = strdup(argv[optind]);
if (!c_argv[i]) { if (!c_argv[i]) {
fprintf(stderr, "getpwid: %s\n", strerror(errno)); fprintf(stderr, "getpwid: %s\n", strerror(errno));
@ -81,45 +85,50 @@ int main (int argc, char *argv[])
} }
} }
c_argc[c_argv] = NULL; c_argc[c_argv] = NULL;
*/
if (c_argc == 0) { /* Set argc and argv */
usage(); // TODO: get the right shell for the user (it is in the passwd struct)
exit(EINVAL); 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(); uid_t ruid = getuid();
struct passwd *pw = getpwuid(ruid); struct passwd *pw = getpwuid(ruid);
if (!pw) { if (!pw) {
fprintf(stderr, "getpwid: %s\n", strerror(errno)); fprintf(stderr, "getpwid: %s\n", strerror(errno));
exit(errno); return errno;
} }
const char *uname = pw->pw_name; 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 // TODO: clean up env
errno = 0; errno = 0;
@ -130,7 +139,7 @@ int main (int argc, char *argv[])
} }
/* Execute the command */ /* 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)); fprintf(stderr, "execv: %s\n", strerror(errno));
/* Cleanup and return */ /* Cleanup and return */
@ -231,3 +240,35 @@ static int perm_set (const char *user, const char *group)
return 0; 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);
}

Loading…
Cancel
Save