2 * Copyright (c) 1994-1996,1998-2006 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 # include "emul/err.h"
49 #endif /* HAVE_ERR_H */
53 #ifdef HAVE_LOGIN_CAP_H
54 # include <login_cap.h>
60 __unused static const char rcsid[] = "$Sudo: set_perms.c,v 1.30.2.7 2007/11/27 23:41:23 millert Exp $";
64 # define ROOT_UID 65535
72 static void runas_setup __P((void));
73 static void runas_setgroups __P((void));
74 static void restore_groups __P((void));
76 static int current_perm = -1;
80 * Set real and effective and saved uids and gids based on perm.
81 * We always retain a saved uid of 0 unless we are headed for an exec().
82 * We only flip the effective gid since it only changes for PERM_SUDOERS.
83 * This version of set_perms() works fine with the "stay_setuid" option.
89 if (perm == current_perm)
94 if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID))
95 errx(1, "setresuid(ROOT_UID, ROOT_UID, ROOT_UID) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid");
96 (void) setresgid(-1, user_gid, -1);
97 if (current_perm == PERM_RUNAS)
102 (void) setresgid(-1, user_gid, -1);
103 if (setresuid(user_uid, user_uid, ROOT_UID))
104 err(1, "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 err(1, "setresuid(user_uid, user_uid, user_uid)");
116 (void) setresgid(-1, runas_pw->pw_gid, -1);
117 if (setresuid(-1, runas_pw->pw_uid, -1))
118 err(1, "unable to change to runas uid");
121 case PERM_FULL_RUNAS:
122 /* headed for exec(), assume euid == ROOT_UID */
124 if (setresuid(def_stay_setuid ?
125 user_uid : runas_pw->pw_uid,
126 runas_pw->pw_uid, runas_pw->pw_uid))
127 err(1, "unable to change to runas uid");
131 /* assume euid == ROOT_UID, ruid == user */
132 if (setresgid(-1, SUDOERS_GID, -1))
133 err(1, "unable to change to sudoers gid");
136 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
137 * is group readable we use a non-zero
138 * uid in order to avoid NFS lossage.
139 * Using uid 1 is a bit bogus but should
142 if (SUDOERS_UID == ROOT_UID) {
143 if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID))
144 err(1, "setresuid(ROOT_UID, 1, ROOT_UID)");
146 if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID))
147 err(1, "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)");
151 if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID))
152 err(1, "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)");
160 # ifdef HAVE_SETREUID
163 * Set real and effective uids and gids based on perm.
164 * We always retain a real or effective uid of ROOT_UID unless
165 * we are headed for an exec().
166 * This version of set_perms() works fine with the "stay_setuid" option.
172 if (perm == current_perm)
177 if (setreuid(-1, ROOT_UID))
178 errx(1, "setreuid(-1, ROOT_UID) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid");
179 if (setuid(ROOT_UID))
180 err(1, "setuid(ROOT_UID)");
181 (void) setregid(-1, user_gid);
182 if (current_perm == PERM_RUNAS)
187 (void) setregid(-1, user_gid);
188 if (setreuid(ROOT_UID, user_uid))
189 err(1, "setreuid(ROOT_UID, user_uid)");
193 /* headed for exec() */
194 (void) setgid(user_gid);
195 if (setreuid(user_uid, user_uid))
196 err(1, "setreuid(user_uid, user_uid)");
201 (void) setregid(-1, runas_pw->pw_gid);
202 if (setreuid(-1, runas_pw->pw_uid))
203 err(1, "unable to change to runas uid");
206 case PERM_FULL_RUNAS:
207 /* headed for exec(), assume euid == ROOT_UID */
209 if (setreuid(def_stay_setuid ? user_uid :
210 runas_pw->pw_uid, runas_pw->pw_uid))
211 err(1, "unable to change to runas uid");
215 /* assume euid == ROOT_UID, ruid == user */
216 if (setregid(-1, SUDOERS_GID))
217 err(1, "unable to change to sudoers gid");
220 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
221 * is group readable we use a non-zero
222 * uid in order to avoid NFS lossage.
223 * Using uid 1 is a bit bogus but should
226 if (SUDOERS_UID == ROOT_UID) {
227 if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1))
228 err(1, "setreuid(ROOT_UID, 1)");
230 if (setreuid(ROOT_UID, SUDOERS_UID))
231 err(1, "setreuid(ROOT_UID, SUDOERS_UID)");
235 if (setreuid(ROOT_UID, timestamp_uid))
236 err(1, "setreuid(ROOT_UID, timestamp_uid)");
243 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
247 * Set real and effective uids and gids based on perm.
248 * NOTE: does not support the "stay_setuid" option.
254 if (perm == current_perm)
258 * Since we only have setuid() and seteuid() and semantics
259 * for these calls differ on various systems, we set
260 * real and effective uids to ROOT_UID initially to be safe.
262 if (seteuid(ROOT_UID))
263 err(1, "seteuid(ROOT_UID)");
264 if (setuid(ROOT_UID))
265 err(1, "setuid(ROOT_UID)");
270 (void) setegid(user_gid);
271 if (current_perm == PERM_RUNAS)
276 (void) setegid(user_gid);
277 if (seteuid(user_uid))
278 err(1, "seteuid(user_uid)");
282 /* headed for exec() */
283 (void) setgid(user_gid);
284 if (setuid(user_uid))
285 err(1, "setuid(user_uid)");
290 (void) setegid(runas_pw->pw_gid);
291 if (seteuid(runas_pw->pw_uid))
292 err(1, "unable to change to runas uid");
295 case PERM_FULL_RUNAS:
296 /* headed for exec() */
298 if (setuid(runas_pw->pw_uid))
299 err(1, "unable to change to runas uid");
303 if (setegid(SUDOERS_GID))
304 err(1, "unable to change to sudoers gid");
307 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
308 * is group readable we use a non-zero
309 * uid in order to avoid NFS lossage.
310 * Using uid 1 is a bit bogus but should
313 if (SUDOERS_UID == ROOT_UID) {
314 if ((SUDOERS_MODE & 040) && seteuid(1))
315 err(1, "seteuid(1)");
317 if (seteuid(SUDOERS_UID))
318 err(1, "seteuid(SUDOERS_UID)");
322 if (seteuid(timestamp_uid))
323 err(1, "seteuid(timestamp_uid)");
330 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
333 * Set uids and gids based on perm via setuid() and setgid().
334 * NOTE: does not support the "stay_setuid" or timestampowner options.
335 * Also, SUDOERS_UID and SUDOERS_GID are not used.
341 if (perm == current_perm)
346 if (setuid(ROOT_UID))
347 err(1, "setuid(ROOT_UID)");
348 if (current_perm == PERM_RUNAS)
353 (void) setgid(user_gid);
354 if (setuid(user_uid))
355 err(1, "setuid(user_uid)");
358 case PERM_FULL_RUNAS:
360 if (setuid(runas_pw->pw_uid))
361 err(1, "unable to change to runas uid");
368 /* Unsupported since we can't set euid. */
374 # endif /* HAVE_SETEUID */
375 # endif /* HAVE_SETREUID */
376 #endif /* HAVE_SETRESUID */
378 #ifdef HAVE_INITGROUPS
382 static int ngroups = -1;
383 static GETGROUPS_T *groups;
386 if (def_preserve_groups)
390 * Use stashed copy of runas groups if available, else initgroups and stash.
393 pw = runas_pw ? runas_pw : sudo_user.pw;
394 if (initgroups(pw->pw_name, pw->pw_gid) < 0)
395 log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
396 if ((ngroups = getgroups(0, NULL)) < 0)
397 log_error(USE_ERRNO|MSG_ONLY, "can't get runas ngroups");
398 groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
399 if (getgroups(ngroups, groups) < 0)
400 log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
402 if (setgroups(ngroups, groups) < 0)
403 log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
410 if (setgroups(user_ngroups, user_groups) < 0)
411 log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
428 #endif /* HAVE_INITGROUPS */
433 #ifdef HAVE_LOGIN_CAP_H
435 extern login_cap_t *lc;
438 if (runas_pw->pw_name != NULL) {
440 pam_prep_user(runas_pw);
441 #endif /* HAVE_PAM */
443 #ifdef HAVE_LOGIN_CAP_H
444 if (def_use_loginclass) {
446 * We only use setusercontext() set the nice value and rlimits.
448 flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
449 if (!def_preserve_groups)
450 SET(flags, LOGIN_SETGROUP);
451 else if (setgid(runas_pw->pw_gid))
452 warn("cannot set gid to runas gid");
453 if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
454 if (runas_pw->pw_uid != ROOT_UID)
455 err(1, "unable to set user context");
457 warn("unable to set user context");
460 #endif /* HAVE_LOGIN_CAP_H */
461 if (setgid(runas_pw->pw_gid))
462 warn("cannot set gid to runas gid");
464 * Initialize group vector unless asked not to.