/* $OpenBSD: doas.c,v 1.4 2019/10/21 03:14:53 tedu Exp $ */ /* * Copyright (c) 2015 Ted Unangst * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include static void __dead usage(void) { fprintf(stderr, "usage: doas [-u user] command [args]\n"); exit(1); } static int parseuid(const char *s, uid_t *uid) { struct passwd *pw; const char *errstr; if ((pw = getpwnam(s)) != NULL) { *uid = pw->pw_uid; if (*uid == UID_MAX) return -1; return 0; } *uid = strtonum(s, 0, UID_MAX - 1, &errstr); if (errstr) return -1; return 0; } int main(int argc, char **argv) { const char *cmd; struct passwd *pw; uid_t uid; uid_t target = 0; gid_t groups[1]; int ch; setprogname("doas"); closefrom(STDERR_FILENO + 1); uid = getuid(); if (uid != 0) errc(1, EPERM, "root only"); while ((ch = getopt(argc, argv, "u:")) != -1) { switch (ch) { case 'u': if (parseuid(optarg, &target) != 0) errx(1, "unknown user"); break; default: usage(); break; } } argv += optind; argc -= optind; if (!argc) usage(); cmd = argv[0]; pw = getpwuid(target); if (!pw) errx(1, "no passwd entry for target"); groups[0] = pw->pw_gid; if (setgroups(1, groups) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) err(1, "failed to change user"); execvp(cmd, argv); if (errno == ENOENT) errx(1, "%s: command not found", cmd); err(1, "%s", cmd); }