1*ebe08b20Stedu /* $OpenBSD: doas.c,v 1.4 2019/10/21 03:14:53 tedu Exp $ */
2ca42b2f9Stedu /*
3ca42b2f9Stedu * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
4ca42b2f9Stedu *
5ca42b2f9Stedu * Permission to use, copy, modify, and distribute this software for any
6ca42b2f9Stedu * purpose with or without fee is hereby granted, provided that the above
7ca42b2f9Stedu * copyright notice and this permission notice appear in all copies.
8ca42b2f9Stedu *
9ca42b2f9Stedu * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10ca42b2f9Stedu * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11ca42b2f9Stedu * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12ca42b2f9Stedu * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13ca42b2f9Stedu * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ca42b2f9Stedu * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15ca42b2f9Stedu * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16ca42b2f9Stedu */
17ca42b2f9Stedu
18ca42b2f9Stedu #include <sys/types.h>
19ca42b2f9Stedu #include <sys/stat.h>
20ca42b2f9Stedu
21ca42b2f9Stedu #include <limits.h>
22ca42b2f9Stedu #include <string.h>
23ca42b2f9Stedu #include <stdio.h>
24ca42b2f9Stedu #include <stdlib.h>
25ca42b2f9Stedu #include <err.h>
26ca42b2f9Stedu #include <unistd.h>
27ca42b2f9Stedu #include <pwd.h>
28ca42b2f9Stedu #include <grp.h>
29ca42b2f9Stedu #include <syslog.h>
30ca42b2f9Stedu #include <errno.h>
31ca42b2f9Stedu
32ca42b2f9Stedu static void __dead
usage(void)33ca42b2f9Stedu usage(void)
34ca42b2f9Stedu {
35ca42b2f9Stedu fprintf(stderr, "usage: doas [-u user] command [args]\n");
36ca42b2f9Stedu exit(1);
37ca42b2f9Stedu }
38ca42b2f9Stedu
39ca42b2f9Stedu static int
parseuid(const char * s,uid_t * uid)40ca42b2f9Stedu parseuid(const char *s, uid_t *uid)
41ca42b2f9Stedu {
42ca42b2f9Stedu struct passwd *pw;
43ca42b2f9Stedu const char *errstr;
44ca42b2f9Stedu
45ca42b2f9Stedu if ((pw = getpwnam(s)) != NULL) {
46ca42b2f9Stedu *uid = pw->pw_uid;
47*ebe08b20Stedu if (*uid == UID_MAX)
48*ebe08b20Stedu return -1;
49ca42b2f9Stedu return 0;
50ca42b2f9Stedu }
51*ebe08b20Stedu *uid = strtonum(s, 0, UID_MAX - 1, &errstr);
52ca42b2f9Stedu if (errstr)
53ca42b2f9Stedu return -1;
54ca42b2f9Stedu return 0;
55ca42b2f9Stedu }
56ca42b2f9Stedu
57ca42b2f9Stedu int
main(int argc,char ** argv)58ca42b2f9Stedu main(int argc, char **argv)
59ca42b2f9Stedu {
60ca42b2f9Stedu const char *cmd;
61ca42b2f9Stedu struct passwd *pw;
62ca42b2f9Stedu uid_t uid;
63ca42b2f9Stedu uid_t target = 0;
64ca42b2f9Stedu gid_t groups[1];
657afc52ddSkrw int ch;
66ca42b2f9Stedu
67ca42b2f9Stedu setprogname("doas");
68ca42b2f9Stedu
69ca42b2f9Stedu closefrom(STDERR_FILENO + 1);
70ca42b2f9Stedu
71ca42b2f9Stedu uid = getuid();
72ca42b2f9Stedu if (uid != 0)
73ca42b2f9Stedu errc(1, EPERM, "root only");
74ca42b2f9Stedu
75ca42b2f9Stedu while ((ch = getopt(argc, argv, "u:")) != -1) {
76ca42b2f9Stedu switch (ch) {
77ca42b2f9Stedu case 'u':
78ca42b2f9Stedu if (parseuid(optarg, &target) != 0)
79ca42b2f9Stedu errx(1, "unknown user");
80ca42b2f9Stedu break;
81ca42b2f9Stedu default:
82ca42b2f9Stedu usage();
83ca42b2f9Stedu break;
84ca42b2f9Stedu }
85ca42b2f9Stedu }
86ca42b2f9Stedu argv += optind;
87ca42b2f9Stedu argc -= optind;
88ca42b2f9Stedu
89ca42b2f9Stedu if (!argc)
90ca42b2f9Stedu usage();
91ca42b2f9Stedu
92ca42b2f9Stedu cmd = argv[0];
93ca42b2f9Stedu
94ca42b2f9Stedu pw = getpwuid(target);
95ca42b2f9Stedu if (!pw)
96ca42b2f9Stedu errx(1, "no passwd entry for target");
97ca42b2f9Stedu groups[0] = pw->pw_gid;
98ca42b2f9Stedu
99ca42b2f9Stedu if (setgroups(1, groups) ||
100ca42b2f9Stedu setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
101ca42b2f9Stedu setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
102ca42b2f9Stedu err(1, "failed to change user");
103ca42b2f9Stedu
104ca42b2f9Stedu execvp(cmd, argv);
105ca42b2f9Stedu if (errno == ENOENT)
106ca42b2f9Stedu errx(1, "%s: command not found", cmd);
107ca42b2f9Stedu err(1, "%s", cmd);
108ca42b2f9Stedu }
109