]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
su.c: implement --exec
authorVito Caputo <vcaputo@pengaru.com>
Sun, 10 May 2020 01:01:22 +0000 (18:01 -0700)
committerSerge Hallyn <shallyn@cisco.com>
Fri, 28 Aug 2020 04:43:32 +0000 (23:43 -0500)
It's now possible to run commands as other users without shell
interpolation by using "--exec":

Read /etc/shadow as root without specifying user:
```
su --exec /bin/cat -- /etc/shadow
```

Or specify user:
```
su --exec /bin/cat root -- /etc/shadow
```

src/su.c

index 578361a760fdf7c7944949bc606c7517100b4dd7..08a28861bb1bfa8784ead26f2767468300313743 100644 (file)
--- a/src/su.c
+++ b/src/su.c
@@ -94,6 +94,7 @@ static bool do_interactive_shell = false;
 static bool fakelogin = false;
 static /*@observer@*/const char *shellstr;
 static /*@null@*/char *command = NULL;
+static /*@null@*/char *exec_command = NULL;
 static int optidx;
 
 
@@ -440,12 +441,14 @@ static void usage (int status)
                 "\n"
                 "Options:\n"
                 "  -c, --command COMMAND         pass COMMAND to the invoked shell\n"
+                "  -e, --exec PATH               run PATH without shell, follow -- with args\n"
                 "  -h, --help                    display this help message and exit\n"
                 "  -, -l, --login                make the shell a login shell\n"
                 "  -m, -p,\n"
                 "  --preserve-environment        do not reset environment variables, and\n"
                 "                                keep the same shell\n"
                 "  -s, --shell SHELL             use SHELL instead of the default in passwd\n"
+                "  --                            pass all subsequent arguments on as-is\n"
                 "\n"
                 "If no username is given, assume root.\n"), (E_SUCCESS != status) ? stderr : stdout);
        exit (status);
@@ -820,6 +823,12 @@ static void process_flags (int argc, char **argv)
                        }
 
                        command = argv[++optidx];
+               } else if (flags_match (arg, "--exec", "-e", NULL)) {
+                       if (optidx == argc - 1) {
+                               flag_arg_required (arg);
+                       }
+
+                       exec_command = argv[++optidx];
                } else if (flags_match (arg, "--help", "-h", NULL)) {
                        usage (E_SUCCESS);
                } else if (flags_match (arg, "--login", "-l", "-")) {
@@ -843,6 +852,17 @@ static void process_flags (int argc, char **argv)
                }
        }
 
+       if (NULL != exec_command && NULL != command) {
+               fprintf (stderr,
+                        _("%s: COMMAND and PATH are mutually exclusive\n"),
+                        argv[0]);
+               usage (E_USAGE);
+       }
+
+       if (NULL != exec_command) {
+               command = exec_command;
+       }
+
        /* if next arg is not "--", treat as USER */
        if (optidx < argc && strcmp (argv[optidx], "--")) {
                STRFCPY (name, argv[optidx++]); /* use this login id */
@@ -1226,10 +1246,18 @@ int main (int argc, char **argv)
                 * with the rest of the command line included.
                 */
                argv[-1] = cp;
-               execve_shell (shellstr, &argv[-1], environ);
-               err = errno;
-               (void) fprintf (stderr,
-                               _("Cannot execute %s\n"), shellstr);
+
+               if (NULL != exec_command) {
+                       (void) execve (command, &argv[1], environ);
+                       err = errno;
+                       (void) fprintf (stderr,
+                                       _("Cannot execute \'%s\'\n"), command);
+               } else {
+                       execve_shell (shellstr, &argv[-1], environ);
+                       err = errno;
+                       (void) fprintf (stderr,
+                                       _("Cannot execute \'%s\'\n"), shellstr);
+               }
                errno = err;
        } else {
                (void) shell (shellstr, cp, environ);