1*38599afaStedu /* $OpenBSD: doas.c,v 1.99 2024/02/15 18:57:58 tedu Exp $ */
27bfbda14Stedu /*
37bfbda14Stedu * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
47bfbda14Stedu *
57bfbda14Stedu * Permission to use, copy, modify, and distribute this software for any
67bfbda14Stedu * purpose with or without fee is hereby granted, provided that the above
77bfbda14Stedu * copyright notice and this permission notice appear in all copies.
87bfbda14Stedu *
97bfbda14Stedu * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
107bfbda14Stedu * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
117bfbda14Stedu * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
127bfbda14Stedu * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
137bfbda14Stedu * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
147bfbda14Stedu * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
157bfbda14Stedu * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
167bfbda14Stedu */
1755aa874dSnicm
187bfbda14Stedu #include <sys/types.h>
1955aa874dSnicm #include <sys/stat.h>
200a39d05fStedu #include <sys/ioctl.h>
217bfbda14Stedu
227bfbda14Stedu #include <limits.h>
237bfbda14Stedu #include <login_cap.h>
247bfbda14Stedu #include <bsd_auth.h>
2580d966b4Stedu #include <readpassphrase.h>
267bfbda14Stedu #include <string.h>
277bfbda14Stedu #include <stdio.h>
287bfbda14Stedu #include <stdlib.h>
297bfbda14Stedu #include <err.h>
307bfbda14Stedu #include <unistd.h>
317bfbda14Stedu #include <pwd.h>
327bfbda14Stedu #include <grp.h>
337bfbda14Stedu #include <syslog.h>
341aced516Stedu #include <errno.h>
350a39d05fStedu #include <fcntl.h>
367bfbda14Stedu
377bfbda14Stedu #include "doas.h"
387bfbda14Stedu
397bfbda14Stedu static void __dead
usage(void)407bfbda14Stedu usage(void)
417bfbda14Stedu {
420a39d05fStedu fprintf(stderr, "usage: doas [-Lns] [-a style] [-C config] [-u user]"
43881f6c5fSkn " command [arg ...]\n");
447bfbda14Stedu exit(1);
457bfbda14Stedu }
467bfbda14Stedu
477bfbda14Stedu static int
parseuid(const char * s,uid_t * uid)487bfbda14Stedu parseuid(const char *s, uid_t *uid)
497bfbda14Stedu {
507bfbda14Stedu struct passwd *pw;
517bfbda14Stedu const char *errstr;
527bfbda14Stedu
537bfbda14Stedu if ((pw = getpwnam(s)) != NULL) {
547bfbda14Stedu *uid = pw->pw_uid;
55754f2b84Stedu if (*uid == UID_MAX)
56754f2b84Stedu return -1;
577bfbda14Stedu return 0;
587bfbda14Stedu }
59754f2b84Stedu *uid = strtonum(s, 0, UID_MAX - 1, &errstr);
607bfbda14Stedu if (errstr)
617bfbda14Stedu return -1;
627bfbda14Stedu return 0;
637bfbda14Stedu }
647bfbda14Stedu
657bfbda14Stedu static int
uidcheck(const char * s,uid_t desired)667bfbda14Stedu uidcheck(const char *s, uid_t desired)
677bfbda14Stedu {
687bfbda14Stedu uid_t uid;
697bfbda14Stedu
707bfbda14Stedu if (parseuid(s, &uid) != 0)
717bfbda14Stedu return -1;
727bfbda14Stedu if (uid != desired)
737bfbda14Stedu return -1;
747bfbda14Stedu return 0;
757bfbda14Stedu }
767bfbda14Stedu
77a5e960b5Stedu static int
parsegid(const char * s,gid_t * gid)78a5e960b5Stedu parsegid(const char *s, gid_t *gid)
797bfbda14Stedu {
807bfbda14Stedu struct group *gr;
817bfbda14Stedu const char *errstr;
827bfbda14Stedu
83a5e960b5Stedu if ((gr = getgrnam(s)) != NULL) {
84a5e960b5Stedu *gid = gr->gr_gid;
85754f2b84Stedu if (*gid == GID_MAX)
86754f2b84Stedu return -1;
87a5e960b5Stedu return 0;
88a5e960b5Stedu }
89754f2b84Stedu *gid = strtonum(s, 0, GID_MAX - 1, &errstr);
907bfbda14Stedu if (errstr)
917bfbda14Stedu return -1;
92a5e960b5Stedu return 0;
937bfbda14Stedu }
947bfbda14Stedu
957bfbda14Stedu static int
match(uid_t uid,gid_t * groups,int ngroups,uid_t target,const char * cmd,const char ** cmdargs,struct rule * r)967bfbda14Stedu match(uid_t uid, gid_t *groups, int ngroups, uid_t target, const char *cmd,
97cb7cef4cSzhuk const char **cmdargs, struct rule *r)
987bfbda14Stedu {
997bfbda14Stedu int i;
1007bfbda14Stedu
1017bfbda14Stedu if (r->ident[0] == ':') {
102a5e960b5Stedu gid_t rgid;
103a5e960b5Stedu if (parsegid(r->ident + 1, &rgid) == -1)
1047bfbda14Stedu return 0;
1057bfbda14Stedu for (i = 0; i < ngroups; i++) {
1067bfbda14Stedu if (rgid == groups[i])
1077bfbda14Stedu break;
1087bfbda14Stedu }
1097bfbda14Stedu if (i == ngroups)
1107bfbda14Stedu return 0;
1117bfbda14Stedu } else {
1127bfbda14Stedu if (uidcheck(r->ident, uid) != 0)
1137bfbda14Stedu return 0;
1147bfbda14Stedu }
1157bfbda14Stedu if (r->target && uidcheck(r->target, target) != 0)
1167bfbda14Stedu return 0;
117cb7cef4cSzhuk if (r->cmd) {
118cb7cef4cSzhuk if (strcmp(r->cmd, cmd))
1197bfbda14Stedu return 0;
120cb7cef4cSzhuk if (r->cmdargs) {
121cb7cef4cSzhuk /* if arguments were given, they should match explicitly */
122cb7cef4cSzhuk for (i = 0; r->cmdargs[i]; i++) {
123cb7cef4cSzhuk if (!cmdargs[i])
124cb7cef4cSzhuk return 0;
125cb7cef4cSzhuk if (strcmp(r->cmdargs[i], cmdargs[i]))
126cb7cef4cSzhuk return 0;
127cb7cef4cSzhuk }
128cb7cef4cSzhuk if (cmdargs[i])
129cb7cef4cSzhuk return 0;
130cb7cef4cSzhuk }
131cb7cef4cSzhuk }
1327bfbda14Stedu return 1;
1337bfbda14Stedu }
1347bfbda14Stedu
1357bfbda14Stedu static int
permit(uid_t uid,gid_t * groups,int ngroups,const struct rule ** lastr,uid_t target,const char * cmd,const char ** cmdargs)13694372f51Stedu permit(uid_t uid, gid_t *groups, int ngroups, const struct rule **lastr,
137cb7cef4cSzhuk uid_t target, const char *cmd, const char **cmdargs)
1387bfbda14Stedu {
139618b6875Smillert size_t i;
1407bfbda14Stedu
1417bfbda14Stedu *lastr = NULL;
1427bfbda14Stedu for (i = 0; i < nrules; i++) {
14322ac959bSderaadt if (match(uid, groups, ngroups, target, cmd,
14422ac959bSderaadt cmdargs, rules[i]))
1457bfbda14Stedu *lastr = rules[i];
1467bfbda14Stedu }
1477bfbda14Stedu if (!*lastr)
148*38599afaStedu return -1;
149*38599afaStedu if ((*lastr)->action == PERMIT)
1507bfbda14Stedu return 0;
151*38599afaStedu return -1;
1527bfbda14Stedu }
1537bfbda14Stedu
1547bfbda14Stedu static void
parseconfig(const char * filename,int checkperms)155588a95a3Szhuk parseconfig(const char *filename, int checkperms)
1567bfbda14Stedu {
1577bfbda14Stedu extern FILE *yyfp;
1584a73e7e2Stedu extern int yyparse(void);
15955aa874dSnicm struct stat sb;
1607bfbda14Stedu
1617bfbda14Stedu yyfp = fopen(filename, "r");
162a4ee1cabSespie if (!yyfp)
163a4ee1cabSespie err(1, checkperms ? "doas is not enabled, %s" :
164a4ee1cabSespie "could not open config file %s", filename);
16555aa874dSnicm
166588a95a3Szhuk if (checkperms) {
16755aa874dSnicm if (fstat(fileno(yyfp), &sb) != 0)
16855aa874dSnicm err(1, "fstat(\"%s\")", filename);
16955aa874dSnicm if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0)
17055aa874dSnicm errx(1, "%s is writable by group or other", filename);
17155aa874dSnicm if (sb.st_uid != 0)
17255aa874dSnicm errx(1, "%s is not owned by root", filename);
173588a95a3Szhuk }
17455aa874dSnicm
175ae699b87Stb yyparse();
1767bfbda14Stedu fclose(yyfp);
177cbc92769Stobias if (parse_error)
1787c3b0d20Szhuk exit(1);
1797bfbda14Stedu }
1807bfbda14Stedu
1817bfbda14Stedu static void __dead
checkconfig(const char * confpath,int argc,char ** argv,uid_t uid,gid_t * groups,int ngroups,uid_t target)182588a95a3Szhuk checkconfig(const char *confpath, int argc, char **argv,
183cac2eb3dStedu uid_t uid, gid_t *groups, int ngroups, uid_t target)
184cac2eb3dStedu {
18594372f51Stedu const struct rule *rule;
186*38599afaStedu int rv;
187588a95a3Szhuk
188588a95a3Szhuk setresuid(uid, uid, uid);
1890fe80ecaSkn if (pledge("stdio rpath getpw", NULL) == -1)
1900fe80ecaSkn err(1, "pledge");
191588a95a3Szhuk parseconfig(confpath, 0);
192588a95a3Szhuk if (!argc)
193588a95a3Szhuk exit(0);
194*38599afaStedu rv = permit(uid, groups, ngroups, &rule, target, argv[0],
195*38599afaStedu (const char **)argv + 1);
196*38599afaStedu if (rv == 0) {
197588a95a3Szhuk printf("permit%s\n", (rule->options & NOPASS) ? " nopass" : "");
198cac2eb3dStedu exit(0);
199588a95a3Szhuk } else {
200588a95a3Szhuk printf("deny\n");
201cac2eb3dStedu exit(1);
202588a95a3Szhuk }
203588a95a3Szhuk }
204588a95a3Szhuk
205960755fcSjcs static int
authuser_checkpass(char * myname,char * login_style)2068a9f00d3Smillert authuser_checkpass(char *myname, char *login_style)
207ec7e1211Stedu {
208ec7e1211Stedu char *challenge = NULL, *response, rbuf[1024], cbuf[128];
209ec7e1211Stedu auth_session_t *as;
210ec7e1211Stedu
211ec7e1211Stedu if (!(as = auth_userchallenge(myname, login_style, "auth-doas",
212960755fcSjcs &challenge))) {
213960755fcSjcs warnx("Authentication failed");
214960755fcSjcs return AUTH_FAILED;
215960755fcSjcs }
216ec7e1211Stedu if (!challenge) {
217ec7e1211Stedu char host[HOST_NAME_MAX + 1];
218ce8e0faaSderaadt
219ec7e1211Stedu if (gethostname(host, sizeof(host)))
220ec7e1211Stedu snprintf(host, sizeof(host), "?");
221ec7e1211Stedu snprintf(cbuf, sizeof(cbuf),
222ec7e1211Stedu "\rdoas (%.32s@%.32s) password: ", myname, host);
223ec7e1211Stedu challenge = cbuf;
224ec7e1211Stedu }
225ec7e1211Stedu response = readpassphrase(challenge, rbuf, sizeof(rbuf),
226ec7e1211Stedu RPP_REQUIRE_TTY);
227ec7e1211Stedu if (response == NULL && errno == ENOTTY) {
228ec7e1211Stedu syslog(LOG_AUTHPRIV | LOG_NOTICE,
229ec7e1211Stedu "tty required for %s", myname);
230ec7e1211Stedu errx(1, "a tty is required");
231ec7e1211Stedu }
232ec7e1211Stedu if (!auth_userresponse(as, response, 0)) {
233df2c0958Stedu explicit_bzero(rbuf, sizeof(rbuf));
234ec7e1211Stedu syslog(LOG_AUTHPRIV | LOG_NOTICE,
235ec7e1211Stedu "failed auth for %s", myname);
236960755fcSjcs warnx("Authentication failed");
237960755fcSjcs return AUTH_FAILED;
238ec7e1211Stedu }
239ec7e1211Stedu explicit_bzero(rbuf, sizeof(rbuf));
2408a9f00d3Smillert return AUTH_OK;
2418a9f00d3Smillert }
2428a9f00d3Smillert
2438a9f00d3Smillert static void
authuser(char * myname,char * login_style,int persist)2448a9f00d3Smillert authuser(char *myname, char *login_style, int persist)
2458a9f00d3Smillert {
2468a9f00d3Smillert int i, fd = -1;
2478a9f00d3Smillert
2488a9f00d3Smillert if (persist)
2498a9f00d3Smillert fd = open("/dev/tty", O_RDWR);
2508a9f00d3Smillert if (fd != -1) {
2518a9f00d3Smillert if (ioctl(fd, TIOCCHKVERAUTH) == 0)
2528a9f00d3Smillert goto good;
2538a9f00d3Smillert }
2548a9f00d3Smillert for (i = 0; i < AUTH_RETRIES; i++) {
2558a9f00d3Smillert if (authuser_checkpass(myname, login_style) == AUTH_OK)
2568a9f00d3Smillert goto good;
2578a9f00d3Smillert }
2588a9f00d3Smillert exit(1);
2590a39d05fStedu good:
2600a39d05fStedu if (fd != -1) {
261b2e46a46Stedu int secs = 5 * 60;
2620a39d05fStedu ioctl(fd, TIOCSETVERAUTH, &secs);
2630a39d05fStedu close(fd);
2640a39d05fStedu }
265ec7e1211Stedu }
266ec7e1211Stedu
2677bfbda14Stedu int
unveilcommands(const char * ipath,const char * cmd)2680d5eb34fSderaadt unveilcommands(const char *ipath, const char *cmd)
2690d5eb34fSderaadt {
2700d5eb34fSderaadt char *path = NULL, *p;
2710d5eb34fSderaadt int unveils = 0;
2720d5eb34fSderaadt
2730d5eb34fSderaadt if (strchr(cmd, '/') != NULL) {
2740d5eb34fSderaadt if (unveil(cmd, "x") != -1)
2750d5eb34fSderaadt unveils++;
2760d5eb34fSderaadt goto done;
2770d5eb34fSderaadt }
2780d5eb34fSderaadt
2790d5eb34fSderaadt if (!ipath) {
2800d5eb34fSderaadt errno = ENOENT;
2810d5eb34fSderaadt goto done;
2820d5eb34fSderaadt }
2830d5eb34fSderaadt path = strdup(ipath);
2840d5eb34fSderaadt if (!path) {
2850d5eb34fSderaadt errno = ENOENT;
2860d5eb34fSderaadt goto done;
2870d5eb34fSderaadt }
2880d5eb34fSderaadt for (p = path; p && *p; ) {
2890d5eb34fSderaadt char buf[PATH_MAX];
2900d5eb34fSderaadt char *cp = strsep(&p, ":");
2910d5eb34fSderaadt
2920d5eb34fSderaadt if (cp) {
2930d5eb34fSderaadt int r = snprintf(buf, sizeof buf, "%s/%s", cp, cmd);
294515e489cSderaadt if (r >= 0 && r < sizeof buf) {
2950d5eb34fSderaadt if (unveil(buf, "x") != -1)
2960d5eb34fSderaadt unveils++;
2970d5eb34fSderaadt }
2980d5eb34fSderaadt }
2990d5eb34fSderaadt }
3000d5eb34fSderaadt done:
3010d5eb34fSderaadt free(path);
3020d5eb34fSderaadt return (unveils);
3030d5eb34fSderaadt }
3040d5eb34fSderaadt
3050d5eb34fSderaadt int
main(int argc,char ** argv)30687a59335Smartijn main(int argc, char **argv)
3077bfbda14Stedu {
308dd06eb07Sderaadt const char *safepath = "/bin:/sbin:/usr/bin:/usr/sbin:"
309dd06eb07Sderaadt "/usr/local/bin:/usr/local/sbin";
310588a95a3Szhuk const char *confpath = NULL;
3118e3a9410Snicm char *shargv[] = { NULL, NULL };
3128e3a9410Snicm char *sh;
313b09050b2Stedu const char *p;
31403cee50eStedu const char *cmd;
31503cee50eStedu char cmdline[LINE_MAX];
316f0b8e6a9Stedu char mypwbuf[_PW_BUF_LEN], targpwbuf[_PW_BUF_LEN];
317f0b8e6a9Stedu struct passwd mypwstore, targpwstore;
318f0b8e6a9Stedu struct passwd *mypw, *targpw;
31994372f51Stedu const struct rule *rule;
32003cee50eStedu uid_t uid;
32103cee50eStedu uid_t target = 0;
32203cee50eStedu gid_t groups[NGROUPS_MAX + 1];
32303cee50eStedu int ngroups;
324f0b8e6a9Stedu int i, ch, rv;
32503cee50eStedu int sflag = 0;
32617356784Sespie int nflag = 0;
327add8871aSdoug char cwdpath[PATH_MAX];
328add8871aSdoug const char *cwd;
329a9ed2e03Ssthen char *login_style = NULL;
33087a59335Smartijn char **envp;
3317bfbda14Stedu
3325de5e581Stedu setprogname("doas");
3335de5e581Stedu
334af293d1aStedu closefrom(STDERR_FILENO + 1);
335af293d1aStedu
33617356784Sespie uid = getuid();
337930540c5Stedu
3380a39d05fStedu while ((ch = getopt(argc, argv, "a:C:Lnsu:")) != -1) {
3397bfbda14Stedu switch (ch) {
340a9ed2e03Ssthen case 'a':
341a9ed2e03Ssthen login_style = optarg;
342a9ed2e03Ssthen break;
343d5db240dStedu case 'C':
344588a95a3Szhuk confpath = optarg;
345588a95a3Szhuk break;
3460a39d05fStedu case 'L':
3470a39d05fStedu i = open("/dev/tty", O_RDWR);
3480a39d05fStedu if (i != -1)
3490a39d05fStedu ioctl(i, TIOCCLRVERAUTH);
350910a0be1Stedu exit(i == -1);
3517bfbda14Stedu case 'u':
3527bfbda14Stedu if (parseuid(optarg, &target) != 0)
3537bfbda14Stedu errx(1, "unknown user");
3547bfbda14Stedu break;
35517356784Sespie case 'n':
35617356784Sespie nflag = 1;
35717356784Sespie break;
3588e3a9410Snicm case 's':
3598e3a9410Snicm sflag = 1;
3608e3a9410Snicm break;
3617bfbda14Stedu default:
3627bfbda14Stedu usage();
3637bfbda14Stedu break;
3647bfbda14Stedu }
3657bfbda14Stedu }
3667bfbda14Stedu argv += optind;
3677bfbda14Stedu argc -= optind;
3687bfbda14Stedu
369588a95a3Szhuk if (confpath) {
370588a95a3Szhuk if (sflag)
371588a95a3Szhuk usage();
372588a95a3Szhuk } else if ((!sflag && !argc) || (sflag && argc))
3737bfbda14Stedu usage();
3747bfbda14Stedu
375f0b8e6a9Stedu rv = getpwuid_r(uid, &mypwstore, mypwbuf, sizeof(mypwbuf), &mypw);
376b59c1698Stedu if (rv != 0)
377f0b8e6a9Stedu err(1, "getpwuid_r failed");
378b59c1698Stedu if (mypw == NULL)
379b59c1698Stedu errx(1, "no passwd entry for self");
3807bfbda14Stedu ngroups = getgroups(NGROUPS_MAX, groups);
3817bfbda14Stedu if (ngroups == -1)
3827bfbda14Stedu err(1, "can't get groups");
3837bfbda14Stedu groups[ngroups++] = getgid();
3847bfbda14Stedu
3858e3a9410Snicm if (sflag) {
3868e3a9410Snicm sh = getenv("SHELL");
387ff37429cSzhuk if (sh == NULL || *sh == '\0') {
388b59c1698Stedu shargv[0] = mypw->pw_shell;
389ff37429cSzhuk } else
3908e3a9410Snicm shargv[0] = sh;
3918e3a9410Snicm argv = shargv;
3928e3a9410Snicm argc = 1;
3938e3a9410Snicm }
3948e3a9410Snicm
395cac2eb3dStedu if (confpath) {
3960fe80ecaSkn if (pledge("stdio rpath getpw id", NULL) == -1)
3970fe80ecaSkn err(1, "pledge");
398cac2eb3dStedu checkconfig(confpath, argc, argv, uid, groups, ngroups,
399cac2eb3dStedu target);
400cac2eb3dStedu exit(1); /* fail safe */
401cac2eb3dStedu }
402cac2eb3dStedu
403bc35909dStedu if (geteuid())
404bc35909dStedu errx(1, "not installed setuid");
405bc35909dStedu
406588a95a3Szhuk parseconfig("/etc/doas.conf", 1);
407588a95a3Szhuk
4082626c77eSzhuk /* cmdline is used only for logging, no need to abort on truncate */
409952479b6Szhuk (void)strlcpy(cmdline, argv[0], sizeof(cmdline));
4108e3a9410Snicm for (i = 1; i < argc; i++) {
4118e3a9410Snicm if (strlcat(cmdline, " ", sizeof(cmdline)) >= sizeof(cmdline))
4122626c77eSzhuk break;
4138e3a9410Snicm if (strlcat(cmdline, argv[i], sizeof(cmdline)) >= sizeof(cmdline))
4142626c77eSzhuk break;
4158e3a9410Snicm }
4168e3a9410Snicm
4172626c77eSzhuk cmd = argv[0];
418*38599afaStedu rv = permit(uid, groups, ngroups, &rule, target, cmd,
419*38599afaStedu (const char **)argv + 1);
420*38599afaStedu if (rv != 0) {
421dd06eb07Sderaadt syslog(LOG_AUTHPRIV | LOG_NOTICE,
42291fb18fcSkn "command not permitted for %s: %s", mypw->pw_name, cmdline);
4233f31dad3Stedu errc(1, EPERM, NULL);
4247bfbda14Stedu }
4257bfbda14Stedu
4267bfbda14Stedu if (!(rule->options & NOPASS)) {
42717356784Sespie if (nflag)
4284d7faafbSmartijn errx(1, "Authentication required");
42980d966b4Stedu
4308a9f00d3Smillert authuser(mypw->pw_name, login_style, rule->options & PERSIST);
4317bfbda14Stedu }
4327aef62b2Sderaadt
433b09050b2Stedu if ((p = getenv("PATH")) != NULL)
434b09050b2Stedu formerpath = strdup(p);
435b09050b2Stedu if (formerpath == NULL)
436b09050b2Stedu formerpath = "";
437b09050b2Stedu
438bc5a8259Sbeck if (unveil(_PATH_LOGIN_CONF, "r") == -1)
439bc5a8259Sbeck err(1, "unveil %s", _PATH_LOGIN_CONF);
440bc5a8259Sbeck if (unveil(_PATH_LOGIN_CONF ".db", "r") == -1)
441bc5a8259Sbeck err(1, "unveil %s.db", _PATH_LOGIN_CONF);
4426699d7aaSrobert if (unveil(_PATH_LOGIN_CONF_D, "r") == -1)
4436699d7aaSrobert err(1, "unveil %s", _PATH_LOGIN_CONF_D);
4440d5eb34fSderaadt if (rule->cmd) {
4450d5eb34fSderaadt if (setenv("PATH", safepath, 1) == -1)
4460d5eb34fSderaadt err(1, "failed to set PATH '%s'", safepath);
4470d5eb34fSderaadt }
4480d5eb34fSderaadt if (unveilcommands(getenv("PATH"), cmd) == 0)
4490d5eb34fSderaadt goto fail;
4500d5eb34fSderaadt
4517aef62b2Sderaadt if (pledge("stdio rpath getpw exec id", NULL) == -1)
4527aef62b2Sderaadt err(1, "pledge");
4537aef62b2Sderaadt
454f0b8e6a9Stedu rv = getpwuid_r(target, &targpwstore, targpwbuf, sizeof(targpwbuf), &targpw);
455b59c1698Stedu if (rv != 0)
456b59c1698Stedu err(1, "getpwuid_r failed");
457b59c1698Stedu if (targpw == NULL)
4587bfbda14Stedu errx(1, "no passwd entry for target");
4597aef62b2Sderaadt
460814cff54Stb if (setusercontext(NULL, targpw, target, LOGIN_SETGROUP |
461814cff54Stb LOGIN_SETPATH |
462814cff54Stb LOGIN_SETPRIORITY | LOGIN_SETRESOURCES | LOGIN_SETUMASK |
463814cff54Stb LOGIN_SETUSER | LOGIN_SETENV | LOGIN_SETRTABLE) != 0)
4647bfbda14Stedu errx(1, "failed to set user context for target");
4657bfbda14Stedu
4667aef62b2Sderaadt if (pledge("stdio rpath exec", NULL) == -1)
4677aef62b2Sderaadt err(1, "pledge");
4687aef62b2Sderaadt
469add8871aSdoug if (getcwd(cwdpath, sizeof(cwdpath)) == NULL)
470add8871aSdoug cwd = "(failed)";
471add8871aSdoug else
472add8871aSdoug cwd = cwdpath;
473add8871aSdoug
4747aef62b2Sderaadt if (pledge("stdio exec", NULL) == -1)
4757aef62b2Sderaadt err(1, "pledge");
4767aef62b2Sderaadt
477d4bf2b56Skn if (!(rule->options & NOLOG)) {
478d4bf2b56Skn syslog(LOG_AUTHPRIV | LOG_INFO,
479d4bf2b56Skn "%s ran command %s as %s from %s",
480b59c1698Stedu mypw->pw_name, cmdline, targpw->pw_name, cwd);
481d4bf2b56Skn }
482add8871aSdoug
483e327fa4eStedu envp = prepenv(rule, mypw, targpw);
48492e88ce8Stedu
4854e86a82bStedu /* setusercontext set path for the next process, so reset it for us */
486e327fa4eStedu if (rule->cmd) {
487e327fa4eStedu if (setenv("PATH", safepath, 1) == -1)
488e327fa4eStedu err(1, "failed to set PATH '%s'", safepath);
4894e86a82bStedu } else {
4904e86a82bStedu if (setenv("PATH", formerpath, 1) == -1)
4914e86a82bStedu err(1, "failed to set PATH '%s'", formerpath);
492e327fa4eStedu }
4937bfbda14Stedu execvpe(cmd, argv, envp);
4940d5eb34fSderaadt fail:
4951aced516Stedu if (errno == ENOENT)
4961aced516Stedu errx(1, "%s: command not found", cmd);
4977bfbda14Stedu err(1, "%s", cmd);
4987bfbda14Stedu }
499