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 # define ROOT_UID 65535
63 static void runas_setup __P((void));
64 static void runas_setgroups __P((void));
65 static void restore_groups __P((void));
67 static int current_perm = -1;
71 * Set real and effective and saved uids and gids based on perm.
72 * We always retain a saved uid of 0 unless we are headed for an exec().
73 * We only flip the effective gid since it only changes for PERM_SUDOERS.
74 * This version of set_perms() works fine with the "stay_setuid" option.
83 noexit = ISSET(perm, PERM_NOEXIT);
86 if (perm == current_perm)
91 if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) {
92 errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
95 (void) setresgid(-1, user_gid, -1);
96 if (current_perm == PERM_RUNAS)
101 (void) setresgid(-1, user_gid, -1);
102 if (setresuid(user_uid, user_uid, ROOT_UID)) {
103 errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
109 /* headed for exec() */
110 (void) setgid(user_gid);
111 if (setresuid(user_uid, user_uid, user_uid)) {
112 errstr = "setresuid(user_uid, user_uid, user_uid)";
119 (void) setresgid(-1, runas_gr ?
120 runas_gr->gr_gid : runas_pw->pw_gid, -1);
121 if (setresuid(-1, runas_pw ? runas_pw->pw_uid :
123 errstr = "unable to change to runas uid";
128 case PERM_FULL_RUNAS:
129 /* headed for exec(), assume euid == ROOT_UID */
131 if (setresuid(def_stay_setuid ?
132 user_uid : runas_pw->pw_uid,
133 runas_pw->pw_uid, runas_pw->pw_uid)) {
134 errstr = "unable to change to runas uid";
140 /* assume euid == ROOT_UID, ruid == user */
141 if (setresgid(-1, SUDOERS_GID, -1))
142 error(1, "unable to change to sudoers gid");
145 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
146 * is group readable we use a non-zero
147 * uid in order to avoid NFS lossage.
148 * Using uid 1 is a bit bogus but should
151 if (SUDOERS_UID == ROOT_UID) {
152 if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID)) {
153 errstr = "setresuid(ROOT_UID, 1, ROOT_UID)";
157 if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) {
158 errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
164 if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) {
165 errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
174 warningx("%s: %s", errstr,
175 errno == EAGAIN ? "too many processes" : strerror(errno));
182 # ifdef HAVE_SETREUID
185 * Set real and effective uids and gids based on perm.
186 * We always retain a real or effective uid of ROOT_UID unless
187 * we are headed for an exec().
188 * This version of set_perms() works fine with the "stay_setuid" option.
197 noexit = ISSET(perm, PERM_NOEXIT);
198 CLR(perm, PERM_MASK);
200 if (perm == current_perm)
205 if (setreuid(-1, ROOT_UID)) {
206 errstr = "setreuid(-1, ROOT_UID)";
209 if (setuid(ROOT_UID)) {
210 errstr = "setuid(ROOT_UID)";
213 (void) setregid(-1, user_gid);
214 if (current_perm == PERM_RUNAS)
219 (void) setregid(-1, user_gid);
220 if (setreuid(ROOT_UID, user_uid)) {
221 errstr = "setreuid(ROOT_UID, user_uid)";
227 /* headed for exec() */
228 (void) setgid(user_gid);
229 if (setreuid(user_uid, user_uid)) {
230 errstr = "setreuid(user_uid, user_uid)";
237 (void) setregid(-1, runas_gr ?
238 runas_gr->gr_gid : runas_pw->pw_gid);
240 runas_pw ? runas_pw->pw_uid : user_uid)) {
241 errstr = "unable to change to runas uid";
246 case PERM_FULL_RUNAS:
247 /* headed for exec(), assume euid == ROOT_UID */
249 if (setreuid(def_stay_setuid ? user_uid :
250 runas_pw->pw_uid, runas_pw->pw_uid)) {
251 errstr = "unable to change to runas uid";
257 /* assume euid == ROOT_UID, ruid == user */
258 if (setregid(-1, SUDOERS_GID))
259 error(1, "unable to change to sudoers gid");
262 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
263 * is group readable we use a non-zero
264 * uid in order to avoid NFS lossage.
265 * Using uid 1 is a bit bogus but should
268 if (SUDOERS_UID == ROOT_UID) {
269 if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) {
270 errstr = "setreuid(ROOT_UID, 1)";
274 if (setreuid(ROOT_UID, SUDOERS_UID)) {
275 errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
281 if (setreuid(ROOT_UID, timestamp_uid)) {
282 errstr = "setreuid(ROOT_UID, timestamp_uid)";
291 warningx("%s: %s", errstr,
292 errno == EAGAIN ? "too many processes" : strerror(errno));
298 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
302 * Set real and effective uids and gids based on perm.
303 * NOTE: does not support the "stay_setuid" option.
312 noexit = ISSET(perm, PERM_NOEXIT);
313 CLR(perm, PERM_MASK);
315 if (perm == current_perm)
319 * Since we only have setuid() and seteuid() and semantics
320 * for these calls differ on various systems, we set
321 * real and effective uids to ROOT_UID initially to be safe.
323 if (seteuid(ROOT_UID)) {
324 errstr = "seteuid(ROOT_UID)";
327 if (setuid(ROOT_UID)) {
328 errstr = "setuid(ROOT_UID)";
335 (void) setegid(user_gid);
336 if (current_perm == PERM_RUNAS)
341 (void) setegid(user_gid);
342 if (seteuid(user_uid)) {
343 errstr = "seteuid(user_uid)";
349 /* headed for exec() */
350 (void) setgid(user_gid);
351 if (setuid(user_uid)) {
352 errstr = "setuid(user_uid)";
359 (void) setegid(runas_gr ?
360 runas_gr->gr_gid : runas_pw->pw_gid);
361 if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) {
362 errstr = "unable to change to runas uid";
367 case PERM_FULL_RUNAS:
368 /* headed for exec() */
370 if (setuid(runas_pw->pw_uid)) {
371 errstr = "unable to change to runas uid";
377 if (setegid(SUDOERS_GID))
378 error(1, "unable to change to sudoers gid");
381 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
382 * is group readable we use a non-zero
383 * uid in order to avoid NFS lossage.
384 * Using uid 1 is a bit bogus but should
387 if (SUDOERS_UID == ROOT_UID) {
388 if ((SUDOERS_MODE & 040) && seteuid(1)) {
389 errstr = "seteuid(1)";
393 if (seteuid(SUDOERS_UID)) {
394 errstr = "seteuid(SUDOERS_UID)";
400 if (seteuid(timestamp_uid)) {
401 errstr = "seteuid(timestamp_uid)";
410 warningx("%s: %s", errstr,
411 errno == EAGAIN ? "too many processes" : strerror(errno));
417 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
420 * Set uids and gids based on perm via setuid() and setgid().
421 * NOTE: does not support the "stay_setuid" or timestampowner options.
422 * Also, SUDOERS_UID and SUDOERS_GID are not used.
431 noexit = ISSET(perm, PERM_NOEXIT);
432 CLR(perm, PERM_MASK);
434 if (perm == current_perm)
439 if (setuid(ROOT_UID)) {
440 errstr = "setuid(ROOT_UID)";
443 if (current_perm == PERM_RUNAS)
448 (void) setgid(user_gid);
449 if (setuid(user_uid)) {
450 errstr = "setuid(user_uid)";
455 case PERM_FULL_RUNAS:
457 if (setuid(runas_pw->pw_uid)) {
458 errstr = "unable to change to runas uid";
467 /* Unsupported since we can't set euid. */
474 warningx("%s: %s", errstr,
475 errno == EAGAIN ? "too many processes" : strerror(errno));
480 # endif /* HAVE_SETEUID */
481 # endif /* HAVE_SETREUID */
482 #endif /* HAVE_SETRESUID */
484 #ifdef HAVE_INITGROUPS
488 static int ngroups = -1;
489 #ifdef HAVE_GETGROUPS
490 static GETGROUPS_T *groups;
494 if (def_preserve_groups)
498 * Use stashed copy of runas groups if available, else initgroups and stash.
501 pw = runas_pw ? runas_pw : sudo_user.pw;
502 if (initgroups(pw->pw_name, pw->pw_gid) < 0)
503 log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
504 #ifdef HAVE_GETGROUPS
505 if ((ngroups = getgroups(0, NULL)) > 0) {
506 groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
507 if (getgroups(ngroups, groups) < 0)
508 log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
511 if (setgroups(ngroups, groups) < 0)
512 log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
513 #endif /* HAVE_GETGROUPS */
520 if (setgroups(user_ngroups, user_groups) < 0)
521 log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
538 #endif /* HAVE_INITGROUPS */
544 #ifdef HAVE_LOGIN_CAP_H
546 extern login_cap_t *lc;
549 if (runas_pw->pw_name != NULL) {
550 gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
551 #ifdef HAVE_GETUSERATTR
552 aix_setlimits(runas_pw->pw_name);
555 pam_prep_user(runas_pw);
556 #endif /* HAVE_PAM */
558 #ifdef HAVE_LOGIN_CAP_H
559 if (def_use_loginclass) {
561 * We only use setusercontext() to set the nice value and rlimits.
563 flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
564 if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
565 if (runas_pw->pw_uid != ROOT_UID)
566 error(1, "unable to set user context");
568 warning("unable to set user context");
571 #endif /* HAVE_LOGIN_CAP_H */
573 * Initialize group vector
578 warning("cannot set egid to runas gid");
581 warning("cannot set gid to runas gid");