On 2023/05/18 09:11:59 -0600, Todd C. Miller <mill...@openbsd.org> wrote:
> The way user(8) runs commands via system(3) is fragile.  It does
> not correctly handle paths with whitespace or shell metacharacters.
> Rather than try to quote everything (which is also fragile) I think
> it is safest to just exec the commands directly.

when I saw that the previous change was to remove the only "cd xyz &&
cmd" I hoped that the follow up was to use exec instead of system :)

> OK?

verified that it works as intended.  -v is actually nicer now, since
it logs the commands it executes (which is expected as per man page
but not as per previous behaviour.)

for what is worth ok op@ (with or without nits below)

>  - todd
> 
> Index: usr.sbin/user/user.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/user/user.c,v
> retrieving revision 1.130
> diff -u -p -u -r1.130 user.c
> --- usr.sbin/user/user.c      16 May 2023 21:28:46 -0000      1.130
> +++ usr.sbin/user/user.c      18 May 2023 15:10:52 -0000
> @@ -31,6 +31,7 @@
>  
>  #include <sys/types.h>
>  #include <sys/stat.h>
> +#include <sys/wait.h>
>  
>  #include <ctype.h>
>  #include <dirent.h>
> @@ -42,7 +43,7 @@
>  #include <login_cap.h>
>  #include <paths.h>
>  #include <pwd.h>
> -#include <stdarg.h>
> +#include <stdbool.h>

existing code just used 0 and 1 (e.g. creategid.)  lone zeros as
arguments are not really readable, but still I can't make myself
liking stdbool.  not that my tastes matters, but it seems to be used
very sparsingly in usr.sbin

>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
> @@ -103,6 +104,10 @@ enum {
>       F_ACCTUNLOCK    = 0x10000
>  };
>  
> +/* bit flags for runas() */
> +#define RUNAS_DUP_DEVNULL    0x01
> +#define RUNAS_IGNORE_EXITVAL 0x02

another nit: the other flags are defined within an enums.

> [...]
> -/* a replacement for system(3) */
> +/* run the given command with optional arguments as the specified uid */
>  static int
> -asystem(const char *fmt, ...)
> +runas(const char *path, const char *const argv[], uid_t uid, int flags)
>  {
> [...]
> +     default:
> +             while (waitpid(child, &status, 0) == -1) {
> +                     if (errno != EINTR)
> +                             err(EXIT_FAILURE, "waitpid");
> +             }
> +             if (WIFSIGNALED(status)) {
> +                     ret = WTERMSIG(status);
> +                     warnx("[Warning] `%s' killed by signal %d", buf, ret);
> +                     ret |= 128;
> +             } else {
> +                     if (!(flags & RUNAS_IGNORE_EXITVAL))
> +                             ret = WEXITSTATUS(status);
> +                     if (ret != 0)
> +                             warnx("[Warning] unable to run `%s'", buf);

more than "unable to run" I'd say "failed to run" or "command
failed" / "exited with nonzero status".

"unable to run" makes me think that it failed to exec the
program, rather than it failed at runtime.

> +             }
> +             return ret;
>       }
> -     return ret;
> +}
> +
> +/* run the given command with optional arguments */
> +static int
> +run(const char *path, const char *const argv[])
> +{
> +     return runas(path, argv, -1, false);
>  }


Reply via email to