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