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>
54 # define ROOT_UID 65535
62 static void runas_setup __P((void));
63 static void runas_setgroups __P((void));
64 static void restore_groups __P((void));
66 static int current_perm = -1;
70 * Set real and effective and saved uids and gids based on perm.
71 * We always retain a saved uid of 0 unless we are headed for an exec().
72 * We only flip the effective gid since it only changes for PERM_SUDOERS.
73 * This version of set_perms() works fine with the "stay_setuid" option.
82 noexit = ISSET(perm, PERM_NOEXIT);
85 if (perm == current_perm)
90 if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) {
91 errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
94 (void) setresgid(-1, user_gid, -1);
95 if (current_perm == PERM_RUNAS)
100 (void) setresgid(-1, user_gid, -1);
101 if (setresuid(user_uid, user_uid, ROOT_UID)) {
102 errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
108 /* headed for exec() */
109 (void) setgid(user_gid);
110 if (setresuid(user_uid, user_uid, user_uid)) {
111 errstr = "setresuid(user_uid, user_uid, user_uid)";
118 (void) setresgid(-1, runas_gr ?
119 runas_gr->gr_gid : runas_pw->pw_gid, -1);
120 if (setresuid(-1, runas_pw ? runas_pw->pw_uid :
122 errstr = "unable to change to runas uid";
127 case PERM_FULL_RUNAS:
128 /* headed for exec(), assume euid == ROOT_UID */
130 if (setresuid(def_stay_setuid ?
131 user_uid : runas_pw->pw_uid,
132 runas_pw->pw_uid, runas_pw->pw_uid)) {
133 errstr = "unable to change to runas uid";
139 /* assume euid == ROOT_UID, ruid == user */
140 if (setresgid(-1, SUDOERS_GID, -1))
141 error(1, "unable to change to sudoers gid");
144 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
145 * is group readable we use a non-zero
146 * uid in order to avoid NFS lossage.
147 * Using uid 1 is a bit bogus but should
150 if (SUDOERS_UID == ROOT_UID) {
151 if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID)) {
152 errstr = "setresuid(ROOT_UID, 1, ROOT_UID)";
156 if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) {
157 errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
163 if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) {
164 errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
173 warningx("%s: %s", errstr,
174 errno == EAGAIN ? "too many processes" : strerror(errno));
181 # ifdef HAVE_SETREUID
184 * Set real and effective uids and gids based on perm.
185 * We always retain a real or effective uid of ROOT_UID unless
186 * we are headed for an exec().
187 * This version of set_perms() works fine with the "stay_setuid" option.
196 noexit = ISSET(perm, PERM_NOEXIT);
197 CLR(perm, PERM_MASK);
199 if (perm == current_perm)
204 if (setreuid(-1, ROOT_UID)) {
205 errstr = "setreuid(-1, ROOT_UID)";
208 if (setuid(ROOT_UID)) {
209 errstr = "setuid(ROOT_UID)";
212 (void) setregid(-1, user_gid);
213 if (current_perm == PERM_RUNAS)
218 (void) setregid(-1, user_gid);
219 if (setreuid(ROOT_UID, user_uid)) {
220 errstr = "setreuid(ROOT_UID, user_uid)";
226 /* headed for exec() */
227 (void) setgid(user_gid);
228 if (setreuid(user_uid, user_uid)) {
229 errstr = "setreuid(user_uid, user_uid)";
236 (void) setregid(-1, runas_gr ?
237 runas_gr->gr_gid : runas_pw->pw_gid);
239 runas_pw ? runas_pw->pw_uid : user_uid)) {
240 errstr = "unable to change to runas uid";
245 case PERM_FULL_RUNAS:
246 /* headed for exec(), assume euid == ROOT_UID */
248 if (setreuid(def_stay_setuid ? user_uid :
249 runas_pw->pw_uid, runas_pw->pw_uid)) {
250 errstr = "unable to change to runas uid";
256 /* assume euid == ROOT_UID, ruid == user */
257 if (setregid(-1, SUDOERS_GID))
258 error(1, "unable to change to sudoers gid");
261 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
262 * is group readable we use a non-zero
263 * uid in order to avoid NFS lossage.
264 * Using uid 1 is a bit bogus but should
267 if (SUDOERS_UID == ROOT_UID) {
268 if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) {
269 errstr = "setreuid(ROOT_UID, 1)";
273 if (setreuid(ROOT_UID, SUDOERS_UID)) {
274 errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
280 if (setreuid(ROOT_UID, timestamp_uid)) {
281 errstr = "setreuid(ROOT_UID, timestamp_uid)";
290 warningx("%s: %s", errstr,
291 errno == EAGAIN ? "too many processes" : strerror(errno));
297 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
301 * Set real and effective uids and gids based on perm.
302 * NOTE: does not support the "stay_setuid" option.
311 noexit = ISSET(perm, PERM_NOEXIT);
312 CLR(perm, PERM_MASK);
314 if (perm == current_perm)
318 * Since we only have setuid() and seteuid() and semantics
319 * for these calls differ on various systems, we set
320 * real and effective uids to ROOT_UID initially to be safe.
322 if (seteuid(ROOT_UID)) {
323 errstr = "seteuid(ROOT_UID)";
326 if (setuid(ROOT_UID)) {
327 errstr = "setuid(ROOT_UID)";
334 (void) setegid(user_gid);
335 if (current_perm == PERM_RUNAS)
340 (void) setegid(user_gid);
341 if (seteuid(user_uid)) {
342 errstr = "seteuid(user_uid)";
348 /* headed for exec() */
349 (void) setgid(user_gid);
350 if (setuid(user_uid)) {
351 errstr = "setuid(user_uid)";
358 (void) setegid(runas_gr ?
359 runas_gr->gr_gid : runas_pw->pw_gid);
360 if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) {
361 errstr = "unable to change to runas uid";
366 case PERM_FULL_RUNAS:
367 /* headed for exec() */
369 if (setuid(runas_pw->pw_uid)) {
370 errstr = "unable to change to runas uid";
376 if (setegid(SUDOERS_GID))
377 error(1, "unable to change to sudoers gid");
380 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
381 * is group readable we use a non-zero
382 * uid in order to avoid NFS lossage.
383 * Using uid 1 is a bit bogus but should
386 if (SUDOERS_UID == ROOT_UID) {
387 if ((SUDOERS_MODE & 040) && seteuid(1)) {
388 errstr = "seteuid(1)";
392 if (seteuid(SUDOERS_UID)) {
393 errstr = "seteuid(SUDOERS_UID)";
399 if (seteuid(timestamp_uid)) {
400 errstr = "seteuid(timestamp_uid)";
409 warningx("%s: %s", errstr,
410 errno == EAGAIN ? "too many processes" : strerror(errno));
416 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
419 * Set uids and gids based on perm via setuid() and setgid().
420 * NOTE: does not support the "stay_setuid" or timestampowner options.
421 * Also, SUDOERS_UID and SUDOERS_GID are not used.
430 noexit = ISSET(perm, PERM_NOEXIT);
431 CLR(perm, PERM_MASK);
433 if (perm == current_perm)
438 if (setuid(ROOT_UID)) {
439 errstr = "setuid(ROOT_UID)";
442 if (current_perm == PERM_RUNAS)
447 (void) setgid(user_gid);
448 if (setuid(user_uid)) {
449 errstr = "setuid(user_uid)";
454 case PERM_FULL_RUNAS:
456 if (setuid(runas_pw->pw_uid)) {
457 errstr = "unable to change to runas uid";
466 /* Unsupported since we can't set euid. */
473 warningx("%s: %s", errstr,
474 errno == EAGAIN ? "too many processes" : strerror(errno));
479 # endif /* HAVE_SETEUID */
480 # endif /* HAVE_SETREUID */
481 #endif /* HAVE_SETRESUID */
483 #ifdef HAVE_INITGROUPS
487 static int ngroups = -1;
488 # ifdef HAVE_GETGROUPS
489 static GETGROUPS_T *groups;
491 static struct passwd *pw;
492 struct passwd *opw = pw;
494 if (def_preserve_groups)
498 * Use stashed copy of runas groups if available, else initgroups and stash.
500 pw = runas_pw ? runas_pw : sudo_user.pw;
502 # ifdef HAVE_SETAUTHDB
503 aix_setauthdb(pw->pw_name);
505 if (initgroups(pw->pw_name, pw->pw_gid) < 0)
506 log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
507 # ifdef HAVE_GETGROUPS
512 if ((ngroups = getgroups(0, NULL)) > 0) {
513 groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
514 if (getgroups(ngroups, groups) < 0)
515 log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
517 # ifdef HAVE_SETAUTHDB
521 if (setgroups(ngroups, groups) < 0)
522 log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
523 # endif /* HAVE_GETGROUPS */
530 if (user_ngroups >= 0 && setgroups(user_ngroups, user_groups) < 0)
531 log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
548 #endif /* HAVE_INITGROUPS */
554 #ifdef HAVE_LOGIN_CAP_H
556 extern login_cap_t *lc;
559 if (runas_pw->pw_name != NULL) {
560 gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
561 #ifdef HAVE_GETUSERATTR
562 aix_prep_user(runas_pw->pw_name, user_ttypath);
565 pam_begin_session(runas_pw);
566 #endif /* HAVE_PAM */
568 #ifdef HAVE_LOGIN_CAP_H
569 if (def_use_loginclass) {
571 * We only use setusercontext() to set the nice value and rlimits.
573 flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
574 if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
575 if (runas_pw->pw_uid != ROOT_UID)
576 error(1, "unable to set user context");
578 warning("unable to set user context");
581 #endif /* HAVE_LOGIN_CAP_H */
583 * Initialize group vector
588 warning("cannot set egid to runas gid");
591 warning("cannot set gid to runas gid");