2 * Copyright (c) 1994-1996,1998-2009 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 */
38 # ifdef HAVE_STRINGS_H
41 #endif /* HAVE_STRING_H */
44 #endif /* HAVE_UNISTD_H */
48 #ifdef HAVE_LOGIN_CAP_H
49 # include <login_cap.h>
55 __unused static const char rcsid[] = "$Sudo: set_perms.c,v 1.49 2009/06/25 12:44:33 millert Exp $";
59 # define ROOT_UID 65535
67 static void runas_setup __P((void));
68 static void runas_setgroups __P((void));
69 static void restore_groups __P((void));
71 static int current_perm = -1;
75 * Set real and effective and saved uids and gids based on perm.
76 * We always retain a saved uid of 0 unless we are headed for an exec().
77 * We only flip the effective gid since it only changes for PERM_SUDOERS.
78 * This version of set_perms() works fine with the "stay_setuid" option.
87 noexit = ISSET(perm, PERM_NOEXIT);
90 if (perm == current_perm)
95 if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) {
96 errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
99 (void) setresgid(-1, user_gid, -1);
100 if (current_perm == PERM_RUNAS)
105 (void) setresgid(-1, user_gid, -1);
106 if (setresuid(user_uid, user_uid, ROOT_UID)) {
107 errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
113 /* headed for exec() */
114 (void) setgid(user_gid);
115 if (setresuid(user_uid, user_uid, user_uid)) {
116 errstr = "setresuid(user_uid, user_uid, user_uid)";
123 (void) setresgid(-1, runas_gr ?
124 runas_gr->gr_gid : runas_pw->pw_gid, -1);
125 if (setresuid(-1, runas_pw ? runas_pw->pw_uid :
127 errstr = "unable to change to runas uid";
132 case PERM_FULL_RUNAS:
133 /* headed for exec(), assume euid == ROOT_UID */
135 if (setresuid(def_stay_setuid ?
136 user_uid : runas_pw->pw_uid,
137 runas_pw->pw_uid, runas_pw->pw_uid)) {
138 errstr = "unable to change to runas uid";
144 /* assume euid == ROOT_UID, ruid == user */
145 if (setresgid(-1, SUDOERS_GID, -1))
146 error(1, "unable to change to sudoers gid");
149 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
150 * is group readable we use a non-zero
151 * uid in order to avoid NFS lossage.
152 * Using uid 1 is a bit bogus but should
155 if (SUDOERS_UID == ROOT_UID) {
156 if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID)) {
157 errstr = "setresuid(ROOT_UID, 1, ROOT_UID)";
161 if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) {
162 errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
168 if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) {
169 errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
178 warningx("%s: %s", errstr,
179 errno == EAGAIN ? "too many processes" : strerror(errno));
186 # ifdef HAVE_SETREUID
189 * Set real and effective uids and gids based on perm.
190 * We always retain a real or effective uid of ROOT_UID unless
191 * we are headed for an exec().
192 * This version of set_perms() works fine with the "stay_setuid" option.
201 noexit = ISSET(perm, PERM_NOEXIT);
202 CLR(perm, PERM_MASK);
204 if (perm == current_perm)
209 if (setreuid(-1, ROOT_UID)) {
210 errstr = "setreuid(-1, ROOT_UID)";
213 if (setuid(ROOT_UID)) {
214 errstr = "setuid(ROOT_UID)";
217 (void) setregid(-1, user_gid);
218 if (current_perm == PERM_RUNAS)
223 (void) setregid(-1, user_gid);
224 if (setreuid(ROOT_UID, user_uid)) {
225 errstr = "setreuid(ROOT_UID, user_uid)";
231 /* headed for exec() */
232 (void) setgid(user_gid);
233 if (setreuid(user_uid, user_uid)) {
234 errstr = "setreuid(user_uid, user_uid)";
241 (void) setregid(-1, runas_gr ?
242 runas_gr->gr_gid : runas_pw->pw_gid);
244 runas_pw ? runas_pw->pw_uid : user_uid)) {
245 errstr = "unable to change to runas uid";
250 case PERM_FULL_RUNAS:
251 /* headed for exec(), assume euid == ROOT_UID */
253 if (setreuid(def_stay_setuid ? user_uid :
254 runas_pw->pw_uid, runas_pw->pw_uid)) {
255 errstr = "unable to change to runas uid";
261 /* assume euid == ROOT_UID, ruid == user */
262 if (setregid(-1, SUDOERS_GID))
263 error(1, "unable to change to sudoers gid");
266 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
267 * is group readable we use a non-zero
268 * uid in order to avoid NFS lossage.
269 * Using uid 1 is a bit bogus but should
272 if (SUDOERS_UID == ROOT_UID) {
273 if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) {
274 errstr = "setreuid(ROOT_UID, 1)";
278 if (setreuid(ROOT_UID, SUDOERS_UID)) {
279 errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
285 if (setreuid(ROOT_UID, timestamp_uid)) {
286 errstr = "setreuid(ROOT_UID, timestamp_uid)";
295 warningx("%s: %s", errstr,
296 errno == EAGAIN ? "too many processes" : strerror(errno));
302 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
306 * Set real and effective uids and gids based on perm.
307 * NOTE: does not support the "stay_setuid" option.
316 noexit = ISSET(perm, PERM_NOEXIT);
317 CLR(perm, PERM_MASK);
319 if (perm == current_perm)
323 * Since we only have setuid() and seteuid() and semantics
324 * for these calls differ on various systems, we set
325 * real and effective uids to ROOT_UID initially to be safe.
327 if (seteuid(ROOT_UID)) {
328 errstr = "seteuid(ROOT_UID)";
331 if (setuid(ROOT_UID)) {
332 errstr = "setuid(ROOT_UID)";
339 (void) setegid(user_gid);
340 if (current_perm == PERM_RUNAS)
345 (void) setegid(user_gid);
346 if (seteuid(user_uid)) {
347 errstr = "seteuid(user_uid)";
353 /* headed for exec() */
354 (void) setgid(user_gid);
355 if (setuid(user_uid)) {
356 errstr = "setuid(user_uid)";
363 (void) setegid(runas_gr ?
364 runas_gr->gr_gid : runas_pw->pw_gid);
365 if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) {
366 errstr = "unable to change to runas uid";
371 case PERM_FULL_RUNAS:
372 /* headed for exec() */
374 if (setuid(runas_pw->pw_uid)) {
375 errstr = "unable to change to runas uid";
381 if (setegid(SUDOERS_GID))
382 error(1, "unable to change to sudoers gid");
385 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
386 * is group readable we use a non-zero
387 * uid in order to avoid NFS lossage.
388 * Using uid 1 is a bit bogus but should
391 if (SUDOERS_UID == ROOT_UID) {
392 if ((SUDOERS_MODE & 040) && seteuid(1)) {
393 errstr = "seteuid(1)";
397 if (seteuid(SUDOERS_UID)) {
398 errstr = "seteuid(SUDOERS_UID)";
404 if (seteuid(timestamp_uid)) {
405 errstr = "seteuid(timestamp_uid)";
414 warningx("%s: %s", errstr,
415 errno == EAGAIN ? "too many processes" : strerror(errno));
421 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
424 * Set uids and gids based on perm via setuid() and setgid().
425 * NOTE: does not support the "stay_setuid" or timestampowner options.
426 * Also, SUDOERS_UID and SUDOERS_GID are not used.
435 noexit = ISSET(perm, PERM_NOEXIT);
436 CLR(perm, PERM_MASK);
438 if (perm == current_perm)
443 if (setuid(ROOT_UID)) {
444 errstr = "setuid(ROOT_UID)";
447 if (current_perm == PERM_RUNAS)
452 (void) setgid(user_gid);
453 if (setuid(user_uid)) {
454 errstr = "setuid(user_uid)";
459 case PERM_FULL_RUNAS:
461 if (setuid(runas_pw->pw_uid)) {
462 errstr = "unable to change to runas uid";
471 /* Unsupported since we can't set euid. */
478 warningx("%s: %s", errstr,
479 errno == EAGAIN ? "too many processes" : strerror(errno));
484 # endif /* HAVE_SETEUID */
485 # endif /* HAVE_SETREUID */
486 #endif /* HAVE_SETRESUID */
488 #ifdef HAVE_INITGROUPS
492 static int ngroups = -1;
493 #ifdef HAVE_GETGROUPS
494 static GETGROUPS_T *groups;
498 if (def_preserve_groups)
502 * Use stashed copy of runas groups if available, else initgroups and stash.
505 pw = runas_pw ? runas_pw : sudo_user.pw;
506 if (initgroups(pw->pw_name, pw->pw_gid) < 0)
507 log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
508 #ifdef HAVE_GETGROUPS
509 if ((ngroups = getgroups(0, NULL)) > 0) {
510 groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
511 if (getgroups(ngroups, groups) < 0)
512 log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
515 if (setgroups(ngroups, groups) < 0)
516 log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
517 #endif /* HAVE_GETGROUPS */
524 if (setgroups(user_ngroups, user_groups) < 0)
525 log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
542 #endif /* HAVE_INITGROUPS */
548 #ifdef HAVE_LOGIN_CAP_H
550 extern login_cap_t *lc;
553 if (runas_pw->pw_name != NULL) {
554 gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
555 #ifdef HAVE_GETUSERATTR
556 aix_setlimits(runas_pw->pw_name);
559 pam_prep_user(runas_pw);
560 #endif /* HAVE_PAM */
562 #ifdef HAVE_LOGIN_CAP_H
563 if (def_use_loginclass) {
565 * We only use setusercontext() to set the nice value and rlimits.
567 flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
568 if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
569 if (runas_pw->pw_uid != ROOT_UID)
570 error(1, "unable to set user context");
572 warning("unable to set user context");
575 #endif /* HAVE_LOGIN_CAP_H */
577 * Initialize group vector
582 warning("cannot set egid to runas gid");
585 warning("cannot set gid to runas gid");