2 * Copyright (c) 1994-1996,1998-2010 Todd C. Miller <Todd.Miller@courtesan.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 * Sponsored in part by the Defense Advanced Research Projects
17 * Agency (DARPA) and Air Force Research Laboratory, Air Force
18 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
23 #include <sys/types.h>
24 #include <sys/param.h>
34 #endif /* STDC_HEADERS */
37 #endif /* HAVE_STRING_H */
40 #endif /* HAVE_STRINGS_H */
43 #endif /* HAVE_UNISTD_H */
47 #ifdef HAVE_LOGIN_CAP_H
48 # include <login_cap.h>
52 # include <sys/task.h>
58 # define ROOT_UID 65535
66 static void runas_setup __P((void));
67 static void runas_setgroups __P((void));
68 static void restore_groups __P((void));
70 static int current_perm = -1;
74 * Set real and effective and saved uids and gids based on perm.
75 * We always retain a saved uid of 0 unless we are headed for an exec().
76 * We only flip the effective gid since it only changes for PERM_SUDOERS.
77 * This version of set_perms() works fine with the "stay_setuid" option.
86 noexit = ISSET(perm, PERM_NOEXIT);
89 if (perm == current_perm)
94 if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) {
95 errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
98 (void) setresgid(-1, user_gid, -1);
99 if (current_perm == PERM_RUNAS)
104 (void) setresgid(-1, user_gid, -1);
105 if (setresuid(user_uid, user_uid, ROOT_UID)) {
106 errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
112 /* headed for exec() */
113 (void) setgid(user_gid);
114 if (setresuid(user_uid, user_uid, user_uid)) {
115 errstr = "setresuid(user_uid, user_uid, user_uid)";
122 (void) setresgid(-1, runas_gr ?
123 runas_gr->gr_gid : runas_pw->pw_gid, -1);
124 if (setresuid(-1, runas_pw ? runas_pw->pw_uid :
126 errstr = "unable to change to runas uid";
131 case PERM_FULL_RUNAS:
132 /* headed for exec(), assume euid == ROOT_UID */
134 if (setresuid(def_stay_setuid ?
135 user_uid : runas_pw->pw_uid,
136 runas_pw->pw_uid, runas_pw->pw_uid)) {
137 errstr = "unable to change to runas uid";
143 /* assume euid == ROOT_UID, ruid == user */
144 if (setresgid(-1, SUDOERS_GID, -1))
145 error(1, "unable to change to sudoers gid");
148 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
149 * is group readable we use a non-zero
150 * uid in order to avoid NFS lossage.
151 * Using uid 1 is a bit bogus but should
154 if (SUDOERS_UID == ROOT_UID) {
155 if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID)) {
156 errstr = "setresuid(ROOT_UID, 1, ROOT_UID)";
160 if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) {
161 errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
167 if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) {
168 errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
177 warningx("%s: %s", errstr,
178 errno == EAGAIN ? "too many processes" : strerror(errno));
185 # ifdef HAVE_SETREUID
188 * Set real and effective uids and gids based on perm.
189 * We always retain a real or effective uid of ROOT_UID unless
190 * we are headed for an exec().
191 * This version of set_perms() works fine with the "stay_setuid" option.
200 noexit = ISSET(perm, PERM_NOEXIT);
201 CLR(perm, PERM_MASK);
203 if (perm == current_perm)
208 if (setreuid(-1, ROOT_UID)) {
209 errstr = "setreuid(-1, ROOT_UID)";
212 if (setuid(ROOT_UID)) {
213 errstr = "setuid(ROOT_UID)";
216 (void) setregid(-1, user_gid);
217 if (current_perm == PERM_RUNAS)
222 (void) setregid(-1, user_gid);
223 if (setreuid(ROOT_UID, user_uid)) {
224 errstr = "setreuid(ROOT_UID, user_uid)";
230 /* headed for exec() */
231 (void) setgid(user_gid);
232 if (setreuid(user_uid, user_uid)) {
233 errstr = "setreuid(user_uid, user_uid)";
240 (void) setregid(-1, runas_gr ?
241 runas_gr->gr_gid : runas_pw->pw_gid);
243 runas_pw ? runas_pw->pw_uid : user_uid)) {
244 errstr = "unable to change to runas uid";
249 case PERM_FULL_RUNAS:
250 /* headed for exec(), assume euid == ROOT_UID */
252 if (setreuid(def_stay_setuid ? user_uid :
253 runas_pw->pw_uid, runas_pw->pw_uid)) {
254 errstr = "unable to change to runas uid";
260 /* assume euid == ROOT_UID, ruid == user */
261 if (setregid(-1, SUDOERS_GID))
262 error(1, "unable to change to sudoers gid");
265 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
266 * is group readable we use a non-zero
267 * uid in order to avoid NFS lossage.
268 * Using uid 1 is a bit bogus but should
271 if (SUDOERS_UID == ROOT_UID) {
272 if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) {
273 errstr = "setreuid(ROOT_UID, 1)";
277 if (setreuid(ROOT_UID, SUDOERS_UID)) {
278 errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
284 if (setreuid(ROOT_UID, timestamp_uid)) {
285 errstr = "setreuid(ROOT_UID, timestamp_uid)";
294 warningx("%s: %s", errstr,
295 errno == EAGAIN ? "too many processes" : strerror(errno));
301 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
305 * Set real and effective uids and gids based on perm.
306 * NOTE: does not support the "stay_setuid" option.
315 noexit = ISSET(perm, PERM_NOEXIT);
316 CLR(perm, PERM_MASK);
318 if (perm == current_perm)
322 * Since we only have setuid() and seteuid() and semantics
323 * for these calls differ on various systems, we set
324 * real and effective uids to ROOT_UID initially to be safe.
326 if (seteuid(ROOT_UID)) {
327 errstr = "seteuid(ROOT_UID)";
330 if (setuid(ROOT_UID)) {
331 errstr = "setuid(ROOT_UID)";
338 (void) setegid(user_gid);
339 if (current_perm == PERM_RUNAS)
344 (void) setegid(user_gid);
345 if (seteuid(user_uid)) {
346 errstr = "seteuid(user_uid)";
352 /* headed for exec() */
353 (void) setgid(user_gid);
354 if (setuid(user_uid)) {
355 errstr = "setuid(user_uid)";
362 (void) setegid(runas_gr ?
363 runas_gr->gr_gid : runas_pw->pw_gid);
364 if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) {
365 errstr = "unable to change to runas uid";
370 case PERM_FULL_RUNAS:
371 /* headed for exec() */
373 if (setuid(runas_pw->pw_uid)) {
374 errstr = "unable to change to runas uid";
380 if (setegid(SUDOERS_GID))
381 error(1, "unable to change to sudoers gid");
384 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
385 * is group readable we use a non-zero
386 * uid in order to avoid NFS lossage.
387 * Using uid 1 is a bit bogus but should
390 if (SUDOERS_UID == ROOT_UID) {
391 if ((SUDOERS_MODE & 040) && seteuid(1)) {
392 errstr = "seteuid(1)";
396 if (seteuid(SUDOERS_UID)) {
397 errstr = "seteuid(SUDOERS_UID)";
403 if (seteuid(timestamp_uid)) {
404 errstr = "seteuid(timestamp_uid)";
413 warningx("%s: %s", errstr,
414 errno == EAGAIN ? "too many processes" : strerror(errno));
420 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
423 * Set uids and gids based on perm via setuid() and setgid().
424 * NOTE: does not support the "stay_setuid" or timestampowner options.
425 * Also, SUDOERS_UID and SUDOERS_GID are not used.
434 noexit = ISSET(perm, PERM_NOEXIT);
435 CLR(perm, PERM_MASK);
437 if (perm == current_perm)
442 if (setuid(ROOT_UID)) {
443 errstr = "setuid(ROOT_UID)";
446 if (current_perm == PERM_RUNAS)
451 (void) setgid(user_gid);
452 if (setuid(user_uid)) {
453 errstr = "setuid(user_uid)";
458 case PERM_FULL_RUNAS:
460 if (setuid(runas_pw->pw_uid)) {
461 errstr = "unable to change to runas uid";
470 /* Unsupported since we can't set euid. */
477 warningx("%s: %s", errstr,
478 errno == EAGAIN ? "too many processes" : strerror(errno));
483 # endif /* HAVE_SETEUID */
484 # endif /* HAVE_SETREUID */
485 #endif /* HAVE_SETRESUID */
487 #ifdef HAVE_INITGROUPS
491 static int ngroups = -1;
492 # ifdef HAVE_GETGROUPS
493 static GETGROUPS_T *groups;
495 static struct passwd *pw;
496 struct passwd *opw = pw;
498 if (def_preserve_groups)
502 * Use stashed copy of runas groups if available, else initgroups and stash.
504 pw = runas_pw ? runas_pw : sudo_user.pw;
506 # ifdef HAVE_SETAUTHDB
507 aix_setauthdb(pw->pw_name);
509 if (initgroups(pw->pw_name, pw->pw_gid) < 0)
510 log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
511 # ifdef HAVE_GETGROUPS
516 if ((ngroups = getgroups(0, NULL)) > 0) {
517 groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
518 if (getgroups(ngroups, groups) < 0)
519 log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
521 # ifdef HAVE_SETAUTHDB
525 if (setgroups(ngroups, groups) < 0)
526 log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
527 # endif /* HAVE_GETGROUPS */
534 if (user_ngroups >= 0 && setgroups(user_ngroups, user_groups) < 0)
535 log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
552 #endif /* HAVE_INITGROUPS */
554 #ifdef HAVE_PROJECT_H
560 char buf[PROJECT_BUFSZ];
564 * Collect the default project for the user and settaskid
567 if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) {
568 errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL);
572 case SETPROJ_ERR_TASK:
575 warningx("resource control limit has been reached");
578 warningx("user \"%s\" is not a member of project \"%s\"",
579 pw->pw_name, proj.pj_name);
582 warningx("the invoking task is final");
585 warningx("could not join project \"%s\"", proj.pj_name);
587 case SETPROJ_ERR_POOL:
590 warningx("no resource pool accepting default bindings "
591 "exists for project \"%s\"", proj.pj_name);
594 warningx("specified resource pool does not exist for "
595 "project \"%s\"", proj.pj_name);
598 warningx("could not bind to default resource pool for "
599 "project \"%s\"", proj.pj_name);
604 warningx("setproject failed for project \"%s\"", proj.pj_name);
606 warningx("warning, resource control assignment failed for "
607 "project \"%s\"", proj.pj_name);
611 warning("getdefaultproj");
615 #endif /* HAVE_PROJECT_H */
621 #ifdef HAVE_LOGIN_CAP_H
623 extern login_cap_t *lc;
626 if (runas_pw->pw_name != NULL) {
627 gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
628 #ifdef HAVE_PROJECT_H
629 set_project(runas_pw);
631 #ifdef HAVE_GETUSERATTR
632 aix_prep_user(runas_pw->pw_name, user_ttypath);
635 pam_begin_session(runas_pw);
636 #endif /* HAVE_PAM */
638 #ifdef HAVE_LOGIN_CAP_H
639 if (def_use_loginclass) {
641 * We only use setusercontext() to set the nice value and rlimits.
643 flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
644 if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
645 if (runas_pw->pw_uid != ROOT_UID)
646 error(1, "unable to set user context");
648 warning("unable to set user context");
651 #endif /* HAVE_LOGIN_CAP_H */
653 * Initialize group vector
658 warning("cannot set egid to runas gid");
661 warning("cannot set gid to runas gid");