Annotation of src/usr.bin/sudo/set_perms.c, Revision 1.11
1.1 millert 1: /*
1.11 ! millert 2: * Copyright (c) 1994-1996,1998-2006 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 3: *
1.10 millert 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.
1.1 millert 7: *
1.10 millert 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.
1.8 millert 15: *
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.
1.1 millert 19: */
20:
1.11 ! millert 21: #include <config.h>
1.1 millert 22:
23: #include <sys/types.h>
24: #include <sys/param.h>
25: #include <sys/stat.h>
26: #include <stdio.h>
27: #ifdef STDC_HEADERS
28: # include <stdlib.h>
29: # include <stddef.h>
30: #else
31: # ifdef HAVE_STDLIB_H
32: # include <stdlib.h>
33: # endif
34: #endif /* STDC_HEADERS */
35: #ifdef HAVE_STRING_H
36: # include <string.h>
37: #else
38: # ifdef HAVE_STRINGS_H
39: # include <strings.h>
40: # endif
41: #endif /* HAVE_STRING_H */
42: #ifdef HAVE_UNISTD_H
43: # include <unistd.h>
44: #endif /* HAVE_UNISTD_H */
1.11 ! millert 45: #ifdef HAVE_ERR_H
! 46: # include <err.h>
! 47: #else
! 48: # include "emul/err.h"
! 49: #endif /* HAVE_ERR_H */
1.1 millert 50: #include <pwd.h>
51: #include <errno.h>
52: #include <grp.h>
53: #ifdef HAVE_LOGIN_CAP_H
54: # include <login_cap.h>
55: #endif
56:
57: #include "sudo.h"
58:
59: #ifndef lint
1.11 ! millert 60: __unused static const char rcsid[] = "$Sudo: set_perms.c,v 1.30.2.4 2007/07/06 14:16:22 millert Exp $";
1.1 millert 61: #endif /* lint */
62:
1.10 millert 63: #ifdef __TANDEM
64: # define ROOT_UID 65535
65: #else
66: # define ROOT_UID 0
67: #endif
68:
1.1 millert 69: /*
70: * Prototypes
71: */
72: static void runas_setup __P((void));
73:
1.7 millert 74: #ifdef HAVE_SETRESUID
75: /*
76: * Set real and effective and saved uids and gids based on perm.
77: * We always retain a saved uid of 0 unless we are headed for an exec().
78: * We only flip the effective gid since it only changes for PERM_SUDOERS.
79: * This version of set_perms() works fine with the "stay_setuid" option.
80: */
81: void
1.11 ! millert 82: set_perms(perm)
1.7 millert 83: int perm;
84: {
85: switch (perm) {
86: case PERM_ROOT:
1.10 millert 87: if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID))
1.11 ! millert 88: 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");
! 89: (void) setresgid(-1, user_gid, -1);
1.7 millert 90: break;
91:
92: case PERM_USER:
93: (void) setresgid(-1, user_gid, -1);
1.10 millert 94: if (setresuid(user_uid, user_uid, ROOT_UID))
1.11 ! millert 95: err(1, "setresuid(user_uid, user_uid, ROOT_UID)");
1.7 millert 96: break;
97:
98: case PERM_FULL_USER:
99: /* headed for exec() */
100: (void) setgid(user_gid);
101: if (setresuid(user_uid, user_uid, user_uid))
1.11 ! millert 102: err(1, "setresuid(user_uid, user_uid, user_uid)");
1.7 millert 103: break;
104:
105: case PERM_RUNAS:
1.11 ! millert 106: (void) setresgid(-1, runas_pw->pw_gid, -1);
1.10 millert 107: if (setresuid(-1, runas_pw->pw_uid, -1))
1.11 ! millert 108: err(1, "unable to change to runas uid");
1.10 millert 109: break;
110:
111: case PERM_FULL_RUNAS:
112: /* headed for exec(), assume euid == ROOT_UID */
1.7 millert 113: runas_setup();
1.11 ! millert 114: if (setresuid(def_stay_setuid ?
1.7 millert 115: user_uid : runas_pw->pw_uid,
1.11 ! millert 116: runas_pw->pw_uid, runas_pw->pw_uid))
! 117: err(1, "unable to change to runas uid");
1.7 millert 118: break;
119:
120: case PERM_SUDOERS:
1.10 millert 121: /* assume euid == ROOT_UID, ruid == user */
1.7 millert 122: if (setresgid(-1, SUDOERS_GID, -1))
1.11 ! millert 123: err(1, "unable to change to sudoers gid");
1.7 millert 124:
125: /*
1.10 millert 126: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.7 millert 127: * is group readable we use a non-zero
128: * uid in order to avoid NFS lossage.
129: * Using uid 1 is a bit bogus but should
130: * work on all OS's.
131: */
1.10 millert 132: if (SUDOERS_UID == ROOT_UID) {
133: if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID))
1.11 ! millert 134: err(1, "setresuid(ROOT_UID, 1, ROOT_UID)");
1.7 millert 135: } else {
1.10 millert 136: if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID))
1.11 ! millert 137: err(1, "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)");
1.7 millert 138: }
139: break;
140: case PERM_TIMESTAMP:
1.10 millert 141: if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID))
1.11 ! millert 142: err(1, "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)");
1.7 millert 143: break;
144: }
145: }
146:
147: #else
148: # ifdef HAVE_SETREUID
149:
1.1 millert 150: /*
151: * Set real and effective uids and gids based on perm.
1.10 millert 152: * We always retain a real or effective uid of ROOT_UID unless
1.1 millert 153: * we are headed for an exec().
1.7 millert 154: * This version of set_perms() works fine with the "stay_setuid" option.
1.1 millert 155: */
156: void
1.11 ! millert 157: set_perms(perm)
1.1 millert 158: int perm;
159: {
160: switch (perm) {
161: case PERM_ROOT:
1.10 millert 162: if (setreuid(-1, ROOT_UID))
1.11 ! millert 163: errx(1, "setreuid(-1, ROOT_UID) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid");
1.10 millert 164: if (setuid(ROOT_UID))
1.11 ! millert 165: err(1, "setuid(ROOT_UID)");
! 166: (void) setregid(-1, user_gid);
1.1 millert 167: break;
1.2 millert 168:
1.1 millert 169: case PERM_USER:
1.7 millert 170: (void) setregid(-1, user_gid);
1.10 millert 171: if (setreuid(ROOT_UID, user_uid))
1.11 ! millert 172: err(1, "setreuid(ROOT_UID, user_uid)");
1.1 millert 173: break;
174:
1.4 millert 175: case PERM_FULL_USER:
176: /* headed for exec() */
177: (void) setgid(user_gid);
1.7 millert 178: if (setreuid(user_uid, user_uid))
1.11 ! millert 179: err(1, "setreuid(user_uid, user_uid)");
1.4 millert 180: break;
181:
1.1 millert 182: case PERM_RUNAS:
1.11 ! millert 183: (void) setregid(-1, runas_pw->pw_gid);
1.10 millert 184: if (setreuid(-1, runas_pw->pw_uid))
1.11 ! millert 185: err(1, "unable to change to runas uid");
1.10 millert 186: break;
187:
188: case PERM_FULL_RUNAS:
189: /* headed for exec(), assume euid == ROOT_UID */
1.1 millert 190: runas_setup();
1.11 ! millert 191: if (setreuid(def_stay_setuid ? user_uid :
! 192: runas_pw->pw_uid, runas_pw->pw_uid))
! 193: err(1, "unable to change to runas uid");
1.1 millert 194: break;
195:
196: case PERM_SUDOERS:
1.10 millert 197: /* assume euid == ROOT_UID, ruid == user */
1.7 millert 198: if (setregid(-1, SUDOERS_GID))
1.11 ! millert 199: err(1, "unable to change to sudoers gid");
1.1 millert 200:
201: /*
1.10 millert 202: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.1 millert 203: * is group readable we use a non-zero
204: * uid in order to avoid NFS lossage.
205: * Using uid 1 is a bit bogus but should
206: * work on all OS's.
207: */
1.10 millert 208: if (SUDOERS_UID == ROOT_UID) {
209: if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1))
1.11 ! millert 210: err(1, "setreuid(ROOT_UID, 1)");
1.1 millert 211: } else {
1.10 millert 212: if (setreuid(ROOT_UID, SUDOERS_UID))
1.11 ! millert 213: err(1, "setreuid(ROOT_UID, SUDOERS_UID)");
1.1 millert 214: }
215: break;
1.7 millert 216: case PERM_TIMESTAMP:
1.10 millert 217: if (setreuid(ROOT_UID, timestamp_uid))
1.11 ! millert 218: err(1, "setreuid(ROOT_UID, timestamp_uid)");
1.7 millert 219: break;
1.1 millert 220: }
221: }
222:
1.11 ! millert 223: # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
! 224: # ifdef HAVE_SETEUID
1.1 millert 225:
226: /*
227: * Set real and effective uids and gids based on perm.
228: * NOTE: does not support the "stay_setuid" option.
229: */
230: void
1.11 ! millert 231: set_perms(perm)
1.1 millert 232: int perm;
233: {
234: /*
1.11 ! millert 235: * Since we only have setuid() and seteuid() and semantics
! 236: * for these calls differ on various systems, we set
! 237: * real and effective uids to ROOT_UID initially to be safe.
1.1 millert 238: */
1.11 ! millert 239: if (seteuid(ROOT_UID))
! 240: err(1, "seteuid(ROOT_UID)");
1.10 millert 241: if (setuid(ROOT_UID))
1.11 ! millert 242: err(1, "setuid(ROOT_UID)");
1.1 millert 243:
244: switch (perm) {
1.11 ! millert 245: case PERM_ROOT:
! 246: /* uid set above */
! 247: (void) setegid(user_gid);
! 248: break;
! 249:
1.1 millert 250: case PERM_USER:
251: (void) setegid(user_gid);
252: if (seteuid(user_uid))
1.11 ! millert 253: err(1, "seteuid(user_uid)");
1.4 millert 254: break;
255:
256: case PERM_FULL_USER:
257: /* headed for exec() */
258: (void) setgid(user_gid);
259: if (setuid(user_uid))
1.11 ! millert 260: err(1, "setuid(user_uid)");
1.1 millert 261: break;
262:
263: case PERM_RUNAS:
1.11 ! millert 264: (void) setegid(runas_pw->pw_gid);
1.10 millert 265: if (seteuid(runas_pw->pw_uid))
1.11 ! millert 266: err(1, "unable to change to runas uid");
1.10 millert 267: break;
268:
269: case PERM_FULL_RUNAS:
1.11 ! millert 270: /* headed for exec() */
1.1 millert 271: runas_setup();
272: if (setuid(runas_pw->pw_uid))
1.11 ! millert 273: err(1, "unable to change to runas uid");
1.1 millert 274: break;
275:
276: case PERM_SUDOERS:
277: if (setegid(SUDOERS_GID))
1.11 ! millert 278: err(1, "unable to change to sudoers gid");
1.1 millert 279:
280: /*
1.10 millert 281: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.1 millert 282: * is group readable we use a non-zero
283: * uid in order to avoid NFS lossage.
284: * Using uid 1 is a bit bogus but should
285: * work on all OS's.
286: */
1.10 millert 287: if (SUDOERS_UID == ROOT_UID) {
1.1 millert 288: if ((SUDOERS_MODE & 040) && seteuid(1))
1.11 ! millert 289: err(1, "seteuid(1)");
1.1 millert 290: } else {
291: if (seteuid(SUDOERS_UID))
1.11 ! millert 292: err(1, "seteuid(SUDOERS_UID)");
1.1 millert 293: }
294: break;
1.7 millert 295: case PERM_TIMESTAMP:
296: if (seteuid(timestamp_uid))
1.11 ! millert 297: err(1, "seteuid(timestamp_uid)");
1.7 millert 298: break;
1.1 millert 299: }
300: }
1.10 millert 301:
1.11 ! millert 302: # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
1.10 millert 303:
304: /*
305: * Set uids and gids based on perm via setuid() and setgid().
306: * NOTE: does not support the "stay_setuid" or timestampowner options.
307: * Also, SUDOERS_UID and SUDOERS_GID are not used.
308: */
309: void
1.11 ! millert 310: set_perms(perm)
1.10 millert 311: int perm;
312: {
313:
314: switch (perm) {
315: case PERM_ROOT:
316: if (setuid(ROOT_UID))
1.11 ! millert 317: err(1, "setuid(ROOT_UID)");
1.10 millert 318: break;
319:
320: case PERM_FULL_USER:
321: (void) setgid(user_gid);
322: if (setuid(user_uid))
1.11 ! millert 323: err(1, "setuid(user_uid)");
1.10 millert 324: break;
325:
326: case PERM_FULL_RUNAS:
327: runas_setup();
328: if (setuid(runas_pw->pw_uid))
1.11 ! millert 329: err(1, "unable to change to runas uid");
1.10 millert 330: break;
331:
332: case PERM_USER:
333: case PERM_SUDOERS:
334: case PERM_RUNAS:
335: case PERM_TIMESTAMP:
336: /* Unsupported since we can't set euid. */
337: break;
338: }
339: }
340: # endif /* HAVE_SETEUID */
1.7 millert 341: # endif /* HAVE_SETREUID */
342: #endif /* HAVE_SETRESUID */
1.1 millert 343:
344: static void
345: runas_setup()
346: {
347: #ifdef HAVE_LOGIN_CAP_H
1.11 ! millert 348: int flags;
1.1 millert 349: extern login_cap_t *lc;
350: #endif
351:
352: if (runas_pw->pw_name != NULL) {
353: #ifdef HAVE_PAM
354: pam_prep_user(runas_pw);
355: #endif /* HAVE_PAM */
356:
357: #ifdef HAVE_LOGIN_CAP_H
1.10 millert 358: if (def_use_loginclass) {
1.1 millert 359: /*
360: * We don't have setusercontext() set the user since we
361: * may only want to set the effective uid. Depending on
362: * sudoers and/or command line arguments we may not want
363: * setusercontext() to call initgroups().
364: */
365: flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
1.10 millert 366: if (!def_preserve_groups)
367: SET(flags, LOGIN_SETGROUP);
1.1 millert 368: else if (setgid(runas_pw->pw_gid))
1.11 ! millert 369: warn("cannot set gid to runas gid");
! 370: if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
1.10 millert 371: if (runas_pw->pw_uid != ROOT_UID)
1.11 ! millert 372: err(1, "unable to set user context");
1.7 millert 373: else
1.11 ! millert 374: warn("unable to set user context");
1.7 millert 375: }
1.1 millert 376: } else
377: #endif /* HAVE_LOGIN_CAP_H */
378: {
1.7 millert 379: if (setgid(runas_pw->pw_gid))
1.11 ! millert 380: warn("cannot set gid to runas gid");
1.1 millert 381: #ifdef HAVE_INITGROUPS
382: /*
383: * Initialize group vector unless asked not to.
384: */
1.10 millert 385: if (!def_preserve_groups &&
1.1 millert 386: initgroups(*user_runas, runas_pw->pw_gid) < 0)
1.11 ! millert 387: warn("cannot set group vector");
1.1 millert 388: #endif /* HAVE_INITGROUPS */
389: }
390: }
391: }