Annotation of src/usr.bin/sudo/set_perms.c, Revision 1.16
1.1 millert 1: /*
1.14 millert 2: * Copyright (c) 1994-1996,1998-2009 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 */
45: #include <pwd.h>
46: #include <errno.h>
47: #include <grp.h>
48: #ifdef HAVE_LOGIN_CAP_H
49: # include <login_cap.h>
50: #endif
51:
52: #include "sudo.h"
53:
1.10 millert 54: #ifdef __TANDEM
55: # define ROOT_UID 65535
56: #else
57: # define ROOT_UID 0
58: #endif
59:
1.1 millert 60: /*
61: * Prototypes
62: */
63: static void runas_setup __P((void));
1.12 millert 64: static void runas_setgroups __P((void));
65: static void restore_groups __P((void));
66:
67: static int current_perm = -1;
1.1 millert 68:
1.7 millert 69: #ifdef HAVE_SETRESUID
70: /*
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.
75: */
1.14 millert 76: int
1.11 millert 77: set_perms(perm)
1.7 millert 78: int perm;
79: {
1.13 millert 80: const char *errstr;
1.14 millert 81: int noexit;
82:
83: noexit = ISSET(perm, PERM_NOEXIT);
84: CLR(perm, PERM_MASK);
1.13 millert 85:
1.12 millert 86: if (perm == current_perm)
1.14 millert 87: return(1);
1.12 millert 88:
1.7 millert 89: switch (perm) {
90: case PERM_ROOT:
1.13 millert 91: if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) {
92: errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
93: goto bad;
94: }
1.11 millert 95: (void) setresgid(-1, user_gid, -1);
1.12 millert 96: if (current_perm == PERM_RUNAS)
97: restore_groups();
1.7 millert 98: break;
99:
100: case PERM_USER:
101: (void) setresgid(-1, user_gid, -1);
1.13 millert 102: if (setresuid(user_uid, user_uid, ROOT_UID)) {
103: errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
104: goto bad;
105: }
1.7 millert 106: break;
107:
108: case PERM_FULL_USER:
109: /* headed for exec() */
110: (void) setgid(user_gid);
1.13 millert 111: if (setresuid(user_uid, user_uid, user_uid)) {
112: errstr = "setresuid(user_uid, user_uid, user_uid)";
113: goto bad;
114: }
1.7 millert 115: break;
116:
117: case PERM_RUNAS:
1.12 millert 118: runas_setgroups();
1.13 millert 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 :
122: user_uid, -1)) {
123: errstr = "unable to change to runas uid";
124: goto bad;
125: }
1.10 millert 126: break;
127:
128: case PERM_FULL_RUNAS:
129: /* headed for exec(), assume euid == ROOT_UID */
1.7 millert 130: runas_setup();
1.11 millert 131: if (setresuid(def_stay_setuid ?
1.7 millert 132: user_uid : runas_pw->pw_uid,
1.13 millert 133: runas_pw->pw_uid, runas_pw->pw_uid)) {
134: errstr = "unable to change to runas uid";
135: goto bad;
136: }
1.7 millert 137: break;
138:
139: case PERM_SUDOERS:
1.10 millert 140: /* assume euid == ROOT_UID, ruid == user */
1.7 millert 141: if (setresgid(-1, SUDOERS_GID, -1))
1.13 millert 142: error(1, "unable to change to sudoers gid");
1.7 millert 143:
144: /*
1.10 millert 145: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.7 millert 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
149: * work on all OS's.
150: */
1.10 millert 151: if (SUDOERS_UID == ROOT_UID) {
1.13 millert 152: if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID)) {
153: errstr = "setresuid(ROOT_UID, 1, ROOT_UID)";
154: goto bad;
155: }
1.7 millert 156: } else {
1.13 millert 157: if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) {
158: errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
159: goto bad;
160: }
1.7 millert 161: }
162: break;
163: case PERM_TIMESTAMP:
1.13 millert 164: if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) {
165: errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
166: goto bad;
167: }
1.7 millert 168: break;
169: }
1.12 millert 170:
171: current_perm = perm;
1.14 millert 172: return(1);
1.13 millert 173: bad:
1.14 millert 174: warningx("%s: %s", errstr,
1.13 millert 175: errno == EAGAIN ? "too many processes" : strerror(errno));
1.14 millert 176: if (noexit)
177: return(0);
178: exit(1);
1.7 millert 179: }
180:
181: #else
182: # ifdef HAVE_SETREUID
183:
1.1 millert 184: /*
185: * Set real and effective uids and gids based on perm.
1.10 millert 186: * We always retain a real or effective uid of ROOT_UID unless
1.1 millert 187: * we are headed for an exec().
1.7 millert 188: * This version of set_perms() works fine with the "stay_setuid" option.
1.1 millert 189: */
1.14 millert 190: int
1.11 millert 191: set_perms(perm)
1.1 millert 192: int perm;
193: {
1.13 millert 194: const char *errstr;
1.14 millert 195: int noexit;
196:
197: noexit = ISSET(perm, PERM_NOEXIT);
198: CLR(perm, PERM_MASK);
1.13 millert 199:
1.12 millert 200: if (perm == current_perm)
1.14 millert 201: return(1);
1.12 millert 202:
1.1 millert 203: switch (perm) {
204: case PERM_ROOT:
1.13 millert 205: if (setreuid(-1, ROOT_UID)) {
206: errstr = "setreuid(-1, ROOT_UID)";
207: goto bad;
208: }
209: if (setuid(ROOT_UID)) {
210: errstr = "setuid(ROOT_UID)";
211: goto bad;
212: }
1.11 millert 213: (void) setregid(-1, user_gid);
1.12 millert 214: if (current_perm == PERM_RUNAS)
215: restore_groups();
1.1 millert 216: break;
1.2 millert 217:
1.1 millert 218: case PERM_USER:
1.7 millert 219: (void) setregid(-1, user_gid);
1.13 millert 220: if (setreuid(ROOT_UID, user_uid)) {
221: errstr = "setreuid(ROOT_UID, user_uid)";
222: goto bad;
223: }
1.1 millert 224: break;
225:
1.4 millert 226: case PERM_FULL_USER:
227: /* headed for exec() */
228: (void) setgid(user_gid);
1.13 millert 229: if (setreuid(user_uid, user_uid)) {
230: errstr = "setreuid(user_uid, user_uid)";
231: goto bad;
232: }
1.4 millert 233: break;
234:
1.1 millert 235: case PERM_RUNAS:
1.12 millert 236: runas_setgroups();
1.13 millert 237: (void) setregid(-1, runas_gr ?
238: runas_gr->gr_gid : runas_pw->pw_gid);
239: if (setreuid(-1,
240: runas_pw ? runas_pw->pw_uid : user_uid)) {
241: errstr = "unable to change to runas uid";
242: goto bad;
243: }
1.10 millert 244: break;
245:
246: case PERM_FULL_RUNAS:
247: /* headed for exec(), assume euid == ROOT_UID */
1.1 millert 248: runas_setup();
1.11 millert 249: if (setreuid(def_stay_setuid ? user_uid :
1.13 millert 250: runas_pw->pw_uid, runas_pw->pw_uid)) {
251: errstr = "unable to change to runas uid";
252: goto bad;
253: }
1.1 millert 254: break;
255:
256: case PERM_SUDOERS:
1.10 millert 257: /* assume euid == ROOT_UID, ruid == user */
1.7 millert 258: if (setregid(-1, SUDOERS_GID))
1.13 millert 259: error(1, "unable to change to sudoers gid");
1.1 millert 260:
261: /*
1.10 millert 262: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.1 millert 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
266: * work on all OS's.
267: */
1.10 millert 268: if (SUDOERS_UID == ROOT_UID) {
1.13 millert 269: if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) {
270: errstr = "setreuid(ROOT_UID, 1)";
271: goto bad;
272: }
1.1 millert 273: } else {
1.13 millert 274: if (setreuid(ROOT_UID, SUDOERS_UID)) {
275: errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
276: goto bad;
277: }
1.1 millert 278: }
279: break;
1.7 millert 280: case PERM_TIMESTAMP:
1.13 millert 281: if (setreuid(ROOT_UID, timestamp_uid)) {
282: errstr = "setreuid(ROOT_UID, timestamp_uid)";
283: goto bad;
284: }
1.7 millert 285: break;
1.1 millert 286: }
1.12 millert 287:
288: current_perm = perm;
1.14 millert 289: return(1);
1.13 millert 290: bad:
1.14 millert 291: warningx("%s: %s", errstr,
1.13 millert 292: errno == EAGAIN ? "too many processes" : strerror(errno));
1.14 millert 293: if (noexit)
294: return(0);
295: exit(1);
1.1 millert 296: }
297:
1.11 millert 298: # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
299: # ifdef HAVE_SETEUID
1.1 millert 300:
301: /*
302: * Set real and effective uids and gids based on perm.
303: * NOTE: does not support the "stay_setuid" option.
304: */
1.14 millert 305: int
1.11 millert 306: set_perms(perm)
1.1 millert 307: int perm;
308: {
1.13 millert 309: const char *errstr;
1.14 millert 310: int noexit;
311:
312: noexit = ISSET(perm, PERM_NOEXIT);
313: CLR(perm, PERM_MASK);
1.13 millert 314:
1.12 millert 315: if (perm == current_perm)
1.14 millert 316: return(1);
1.12 millert 317:
1.1 millert 318: /*
1.11 millert 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.
1.1 millert 322: */
1.13 millert 323: if (seteuid(ROOT_UID)) {
324: errstr = "seteuid(ROOT_UID)";
325: goto bad;
326: }
327: if (setuid(ROOT_UID)) {
328: errstr = "setuid(ROOT_UID)";
329: goto bad;
330: }
1.1 millert 331:
332: switch (perm) {
1.11 millert 333: case PERM_ROOT:
334: /* uid set above */
335: (void) setegid(user_gid);
1.12 millert 336: if (current_perm == PERM_RUNAS)
337: restore_groups();
1.11 millert 338: break;
339:
1.1 millert 340: case PERM_USER:
341: (void) setegid(user_gid);
1.13 millert 342: if (seteuid(user_uid)) {
343: errstr = "seteuid(user_uid)";
344: goto bad;
345: }
1.4 millert 346: break;
347:
348: case PERM_FULL_USER:
349: /* headed for exec() */
350: (void) setgid(user_gid);
1.13 millert 351: if (setuid(user_uid)) {
352: errstr = "setuid(user_uid)";
353: goto bad;
354: }
1.1 millert 355: break;
356:
357: case PERM_RUNAS:
1.12 millert 358: runas_setgroups();
1.13 millert 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";
363: goto bad;
364: }
1.10 millert 365: break;
366:
367: case PERM_FULL_RUNAS:
1.11 millert 368: /* headed for exec() */
1.1 millert 369: runas_setup();
1.13 millert 370: if (setuid(runas_pw->pw_uid)) {
371: errstr = "unable to change to runas uid";
372: goto bad;
373: }
1.1 millert 374: break;
375:
376: case PERM_SUDOERS:
377: if (setegid(SUDOERS_GID))
1.13 millert 378: error(1, "unable to change to sudoers gid");
1.1 millert 379:
380: /*
1.10 millert 381: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.1 millert 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
385: * work on all OS's.
386: */
1.10 millert 387: if (SUDOERS_UID == ROOT_UID) {
1.13 millert 388: if ((SUDOERS_MODE & 040) && seteuid(1)) {
389: errstr = "seteuid(1)";
390: goto bad;
391: }
1.1 millert 392: } else {
1.13 millert 393: if (seteuid(SUDOERS_UID)) {
394: errstr = "seteuid(SUDOERS_UID)";
395: goto bad;
396: }
1.1 millert 397: }
398: break;
1.7 millert 399: case PERM_TIMESTAMP:
1.13 millert 400: if (seteuid(timestamp_uid)) {
401: errstr = "seteuid(timestamp_uid)";
402: goto bad;
403: }
1.7 millert 404: break;
1.1 millert 405: }
1.12 millert 406:
407: current_perm = perm;
1.14 millert 408: return(1);
1.13 millert 409: bad:
1.14 millert 410: warningx("%s: %s", errstr,
1.13 millert 411: errno == EAGAIN ? "too many processes" : strerror(errno));
1.14 millert 412: if (noexit)
413: return(0);
414: exit(1);
1.1 millert 415: }
1.10 millert 416:
1.11 millert 417: # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
1.10 millert 418:
419: /*
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.
423: */
1.14 millert 424: int
1.11 millert 425: set_perms(perm)
1.10 millert 426: int perm;
427: {
1.13 millert 428: const char *errstr;
1.14 millert 429: int noexit;
430:
431: noexit = ISSET(perm, PERM_NOEXIT);
432: CLR(perm, PERM_MASK);
1.13 millert 433:
1.12 millert 434: if (perm == current_perm)
1.14 millert 435: return(1);
1.10 millert 436:
437: switch (perm) {
438: case PERM_ROOT:
1.13 millert 439: if (setuid(ROOT_UID)) {
440: errstr = "setuid(ROOT_UID)";
441: goto bad;
442: }
1.12 millert 443: if (current_perm == PERM_RUNAS)
444: restore_groups();
1.10 millert 445: break;
446:
447: case PERM_FULL_USER:
448: (void) setgid(user_gid);
1.13 millert 449: if (setuid(user_uid)) {
450: errstr = "setuid(user_uid)";
451: goto bad;
452: }
1.10 millert 453: break;
454:
455: case PERM_FULL_RUNAS:
456: runas_setup();
1.13 millert 457: if (setuid(runas_pw->pw_uid)) {
458: errstr = "unable to change to runas uid";
459: goto bad;
460: }
1.10 millert 461: break;
462:
463: case PERM_USER:
464: case PERM_SUDOERS:
465: case PERM_RUNAS:
466: case PERM_TIMESTAMP:
467: /* Unsupported since we can't set euid. */
468: break;
469: }
1.12 millert 470:
471: current_perm = perm;
1.14 millert 472: return(1);
1.13 millert 473: bad:
1.14 millert 474: warningx("%s: %s", errstr,
1.13 millert 475: errno == EAGAIN ? "too many processes" : strerror(errno));
1.14 millert 476: if (noexit)
477: return(0);
478: exit(1);
1.10 millert 479: }
480: # endif /* HAVE_SETEUID */
1.7 millert 481: # endif /* HAVE_SETREUID */
482: #endif /* HAVE_SETRESUID */
1.1 millert 483:
1.12 millert 484: #ifdef HAVE_INITGROUPS
485: static void
486: runas_setgroups()
487: {
488: static int ngroups = -1;
1.14 millert 489: #ifdef HAVE_GETGROUPS
1.12 millert 490: static GETGROUPS_T *groups;
1.14 millert 491: #endif
1.12 millert 492: struct passwd *pw;
493:
494: if (def_preserve_groups)
495: return;
496:
497: /*
498: * Use stashed copy of runas groups if available, else initgroups and stash.
499: */
500: if (ngroups == -1) {
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");
1.14 millert 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");
509: }
1.12 millert 510: } else {
511: if (setgroups(ngroups, groups) < 0)
512: log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
1.14 millert 513: #endif /* HAVE_GETGROUPS */
1.12 millert 514: }
515: }
516:
517: static void
518: restore_groups()
519: {
520: if (setgroups(user_ngroups, user_groups) < 0)
521: log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
522: }
523:
524: #else
525:
526: static void
527: runas_setgroups()
528: {
529: /* STUB */
530: }
531:
532: static void
533: restore_groups()
534: {
535: /* STUB */
536: }
537:
538: #endif /* HAVE_INITGROUPS */
539:
1.1 millert 540: static void
541: runas_setup()
542: {
1.13 millert 543: gid_t gid;
1.1 millert 544: #ifdef HAVE_LOGIN_CAP_H
1.11 millert 545: int flags;
1.1 millert 546: extern login_cap_t *lc;
547: #endif
548:
549: if (runas_pw->pw_name != NULL) {
1.13 millert 550: gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
551: #ifdef HAVE_GETUSERATTR
552: aix_setlimits(runas_pw->pw_name);
553: #endif
1.1 millert 554: #ifdef HAVE_PAM
555: pam_prep_user(runas_pw);
556: #endif /* HAVE_PAM */
557:
558: #ifdef HAVE_LOGIN_CAP_H
1.10 millert 559: if (def_use_loginclass) {
1.1 millert 560: /*
1.14 millert 561: * We only use setusercontext() to set the nice value and rlimits.
1.1 millert 562: */
563: flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
1.11 millert 564: if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
1.10 millert 565: if (runas_pw->pw_uid != ROOT_UID)
1.13 millert 566: error(1, "unable to set user context");
1.7 millert 567: else
1.13 millert 568: warning("unable to set user context");
1.7 millert 569: }
1.12 millert 570: }
1.1 millert 571: #endif /* HAVE_LOGIN_CAP_H */
1.12 millert 572: /*
1.13 millert 573: * Initialize group vector
1.12 millert 574: */
575: runas_setgroups();
1.15 millert 576: #ifdef HAVE_SETEUID
577: if (setegid(gid))
578: warning("cannot set egid to runas gid");
579: #endif
580: if (setgid(gid))
1.14 millert 581: warning("cannot set gid to runas gid");
1.1 millert 582: }
583: }