Annotation of src/usr.bin/sudo/set_perms.c, Revision 1.13
1.1 millert 1: /*
1.13 ! millert 2: * Copyright (c) 1994-1996,1998-2008 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.13 ! millert 55: __unused static const char rcsid[] = "$Sudo: set_perms.c,v 1.44 2008/03/06 17:19:56 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: */
80: void
1.11 millert 81: set_perms(perm)
1.7 millert 82: int perm;
83: {
1.13 ! millert 84: const char *errstr;
! 85:
1.12 millert 86: if (perm == current_perm)
87: return;
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.13 ! millert 172: return;
! 173: bad:
! 174: errorx(1, "%s: %s", errstr,
! 175: errno == EAGAIN ? "too many processes" : strerror(errno));
1.7 millert 176: }
177:
178: #else
179: # ifdef HAVE_SETREUID
180:
1.1 millert 181: /*
182: * Set real and effective uids and gids based on perm.
1.10 millert 183: * We always retain a real or effective uid of ROOT_UID unless
1.1 millert 184: * we are headed for an exec().
1.7 millert 185: * This version of set_perms() works fine with the "stay_setuid" option.
1.1 millert 186: */
187: void
1.11 millert 188: set_perms(perm)
1.1 millert 189: int perm;
190: {
1.13 ! millert 191: const char *errstr;
! 192:
1.12 millert 193: if (perm == current_perm)
194: return;
195:
1.1 millert 196: switch (perm) {
197: case PERM_ROOT:
1.13 ! millert 198: if (setreuid(-1, ROOT_UID)) {
! 199: errstr = "setreuid(-1, ROOT_UID)";
! 200: goto bad;
! 201: }
! 202: if (setuid(ROOT_UID)) {
! 203: errstr = "setuid(ROOT_UID)";
! 204: goto bad;
! 205: }
1.11 millert 206: (void) setregid(-1, user_gid);
1.12 millert 207: if (current_perm == PERM_RUNAS)
208: restore_groups();
1.1 millert 209: break;
1.2 millert 210:
1.1 millert 211: case PERM_USER:
1.7 millert 212: (void) setregid(-1, user_gid);
1.13 ! millert 213: if (setreuid(ROOT_UID, user_uid)) {
! 214: errstr = "setreuid(ROOT_UID, user_uid)";
! 215: goto bad;
! 216: }
1.1 millert 217: break;
218:
1.4 millert 219: case PERM_FULL_USER:
220: /* headed for exec() */
221: (void) setgid(user_gid);
1.13 ! millert 222: if (setreuid(user_uid, user_uid)) {
! 223: errstr = "setreuid(user_uid, user_uid)";
! 224: goto bad;
! 225: }
1.4 millert 226: break;
227:
1.1 millert 228: case PERM_RUNAS:
1.12 millert 229: runas_setgroups();
1.13 ! millert 230: (void) setregid(-1, runas_gr ?
! 231: runas_gr->gr_gid : runas_pw->pw_gid);
! 232: if (setreuid(-1,
! 233: runas_pw ? runas_pw->pw_uid : user_uid)) {
! 234: errstr = "unable to change to runas uid";
! 235: goto bad;
! 236: }
1.10 millert 237: break;
238:
239: case PERM_FULL_RUNAS:
240: /* headed for exec(), assume euid == ROOT_UID */
1.1 millert 241: runas_setup();
1.11 millert 242: if (setreuid(def_stay_setuid ? user_uid :
1.13 ! millert 243: runas_pw->pw_uid, runas_pw->pw_uid)) {
! 244: errstr = "unable to change to runas uid";
! 245: goto bad;
! 246: }
1.1 millert 247: break;
248:
249: case PERM_SUDOERS:
1.10 millert 250: /* assume euid == ROOT_UID, ruid == user */
1.7 millert 251: if (setregid(-1, SUDOERS_GID))
1.13 ! millert 252: error(1, "unable to change to sudoers gid");
1.1 millert 253:
254: /*
1.10 millert 255: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.1 millert 256: * is group readable we use a non-zero
257: * uid in order to avoid NFS lossage.
258: * Using uid 1 is a bit bogus but should
259: * work on all OS's.
260: */
1.10 millert 261: if (SUDOERS_UID == ROOT_UID) {
1.13 ! millert 262: if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) {
! 263: errstr = "setreuid(ROOT_UID, 1)";
! 264: goto bad;
! 265: }
1.1 millert 266: } else {
1.13 ! millert 267: if (setreuid(ROOT_UID, SUDOERS_UID)) {
! 268: errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
! 269: goto bad;
! 270: }
1.1 millert 271: }
272: break;
1.7 millert 273: case PERM_TIMESTAMP:
1.13 ! millert 274: if (setreuid(ROOT_UID, timestamp_uid)) {
! 275: errstr = "setreuid(ROOT_UID, timestamp_uid)";
! 276: goto bad;
! 277: }
1.7 millert 278: break;
1.1 millert 279: }
1.12 millert 280:
281: current_perm = perm;
1.13 ! millert 282: return;
! 283: bad:
! 284: errorx(1, "%s: %s", errstr,
! 285: errno == EAGAIN ? "too many processes" : strerror(errno));
1.1 millert 286: }
287:
1.11 millert 288: # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
289: # ifdef HAVE_SETEUID
1.1 millert 290:
291: /*
292: * Set real and effective uids and gids based on perm.
293: * NOTE: does not support the "stay_setuid" option.
294: */
295: void
1.11 millert 296: set_perms(perm)
1.1 millert 297: int perm;
298: {
1.13 ! millert 299: const char *errstr;
! 300:
1.12 millert 301: if (perm == current_perm)
302: return;
303:
1.1 millert 304: /*
1.11 millert 305: * Since we only have setuid() and seteuid() and semantics
306: * for these calls differ on various systems, we set
307: * real and effective uids to ROOT_UID initially to be safe.
1.1 millert 308: */
1.13 ! millert 309: if (seteuid(ROOT_UID)) {
! 310: errstr = "seteuid(ROOT_UID)";
! 311: goto bad;
! 312: }
! 313: if (setuid(ROOT_UID)) {
! 314: errstr = "setuid(ROOT_UID)";
! 315: goto bad;
! 316: }
1.1 millert 317:
318: switch (perm) {
1.11 millert 319: case PERM_ROOT:
320: /* uid set above */
321: (void) setegid(user_gid);
1.12 millert 322: if (current_perm == PERM_RUNAS)
323: restore_groups();
1.11 millert 324: break;
325:
1.1 millert 326: case PERM_USER:
327: (void) setegid(user_gid);
1.13 ! millert 328: if (seteuid(user_uid)) {
! 329: errstr = "seteuid(user_uid)";
! 330: goto bad;
! 331: }
1.4 millert 332: break;
333:
334: case PERM_FULL_USER:
335: /* headed for exec() */
336: (void) setgid(user_gid);
1.13 ! millert 337: if (setuid(user_uid)) {
! 338: errstr = "setuid(user_uid)";
! 339: goto bad;
! 340: }
1.1 millert 341: break;
342:
343: case PERM_RUNAS:
1.12 millert 344: runas_setgroups();
1.13 ! millert 345: (void) setegid(runas_gr ?
! 346: runas_gr->gr_gid : runas_pw->pw_gid);
! 347: if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) {
! 348: errstr = "unable to change to runas uid";
! 349: goto bad;
! 350: }
1.10 millert 351: break;
352:
353: case PERM_FULL_RUNAS:
1.11 millert 354: /* headed for exec() */
1.1 millert 355: runas_setup();
1.13 ! millert 356: if (setuid(runas_pw->pw_uid)) {
! 357: errstr = "unable to change to runas uid";
! 358: goto bad;
! 359: }
1.1 millert 360: break;
361:
362: case PERM_SUDOERS:
363: if (setegid(SUDOERS_GID))
1.13 ! millert 364: error(1, "unable to change to sudoers gid");
1.1 millert 365:
366: /*
1.10 millert 367: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.1 millert 368: * is group readable we use a non-zero
369: * uid in order to avoid NFS lossage.
370: * Using uid 1 is a bit bogus but should
371: * work on all OS's.
372: */
1.10 millert 373: if (SUDOERS_UID == ROOT_UID) {
1.13 ! millert 374: if ((SUDOERS_MODE & 040) && seteuid(1)) {
! 375: errstr = "seteuid(1)";
! 376: goto bad;
! 377: }
1.1 millert 378: } else {
1.13 ! millert 379: if (seteuid(SUDOERS_UID)) {
! 380: errstr = "seteuid(SUDOERS_UID)";
! 381: goto bad;
! 382: }
1.1 millert 383: }
384: break;
1.7 millert 385: case PERM_TIMESTAMP:
1.13 ! millert 386: if (seteuid(timestamp_uid)) {
! 387: errstr = "seteuid(timestamp_uid)";
! 388: goto bad;
! 389: }
1.7 millert 390: break;
1.1 millert 391: }
1.12 millert 392:
393: current_perm = perm;
1.13 ! millert 394: return;
! 395: bad:
! 396: errorx(1, "%s: %s", errstr,
! 397: errno == EAGAIN ? "too many processes" : strerror(errno));
1.1 millert 398: }
1.10 millert 399:
1.11 millert 400: # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
1.10 millert 401:
402: /*
403: * Set uids and gids based on perm via setuid() and setgid().
404: * NOTE: does not support the "stay_setuid" or timestampowner options.
405: * Also, SUDOERS_UID and SUDOERS_GID are not used.
406: */
407: void
1.11 millert 408: set_perms(perm)
1.10 millert 409: int perm;
410: {
1.13 ! millert 411: const char *errstr;
! 412:
1.12 millert 413: if (perm == current_perm)
414: return;
1.10 millert 415:
416: switch (perm) {
417: case PERM_ROOT:
1.13 ! millert 418: if (setuid(ROOT_UID)) {
! 419: errstr = "setuid(ROOT_UID)";
! 420: goto bad;
! 421: }
1.12 millert 422: if (current_perm == PERM_RUNAS)
423: restore_groups();
1.10 millert 424: break;
425:
426: case PERM_FULL_USER:
427: (void) setgid(user_gid);
1.13 ! millert 428: if (setuid(user_uid)) {
! 429: errstr = "setuid(user_uid)";
! 430: goto bad;
! 431: }
1.10 millert 432: break;
433:
434: case PERM_FULL_RUNAS:
435: runas_setup();
1.13 ! millert 436: if (setuid(runas_pw->pw_uid)) {
! 437: errstr = "unable to change to runas uid";
! 438: goto bad;
! 439: }
1.10 millert 440: break;
441:
442: case PERM_USER:
443: case PERM_SUDOERS:
444: case PERM_RUNAS:
445: case PERM_TIMESTAMP:
446: /* Unsupported since we can't set euid. */
447: break;
448: }
1.12 millert 449:
450: current_perm = perm;
1.13 ! millert 451: return;
! 452: bad:
! 453: errorx(1, "%s: %s", errstr,
! 454: errno == EAGAIN ? "too many processes" : strerror(errno));
1.10 millert 455: }
456: # endif /* HAVE_SETEUID */
1.7 millert 457: # endif /* HAVE_SETREUID */
458: #endif /* HAVE_SETRESUID */
1.1 millert 459:
1.12 millert 460: #ifdef HAVE_INITGROUPS
461: static void
462: runas_setgroups()
463: {
464: static int ngroups = -1;
465: static GETGROUPS_T *groups;
466: struct passwd *pw;
467:
468: if (def_preserve_groups)
469: return;
470:
471: /*
472: * Use stashed copy of runas groups if available, else initgroups and stash.
473: */
474: if (ngroups == -1) {
475: pw = runas_pw ? runas_pw : sudo_user.pw;
476: if (initgroups(pw->pw_name, pw->pw_gid) < 0)
477: log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
478: if ((ngroups = getgroups(0, NULL)) < 0)
479: log_error(USE_ERRNO|MSG_ONLY, "can't get runas ngroups");
480: groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
481: if (getgroups(ngroups, groups) < 0)
482: log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
483: } else {
484: if (setgroups(ngroups, groups) < 0)
485: log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
486: }
487: }
488:
489: static void
490: restore_groups()
491: {
492: if (setgroups(user_ngroups, user_groups) < 0)
493: log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
494: }
495:
496: #else
497:
498: static void
499: runas_setgroups()
500: {
501: /* STUB */
502: }
503:
504: static void
505: restore_groups()
506: {
507: /* STUB */
508: }
509:
510: #endif /* HAVE_INITGROUPS */
511:
1.1 millert 512: static void
513: runas_setup()
514: {
1.13 ! millert 515: gid_t gid;
1.1 millert 516: #ifdef HAVE_LOGIN_CAP_H
1.11 millert 517: int flags;
1.1 millert 518: extern login_cap_t *lc;
519: #endif
520:
521: if (runas_pw->pw_name != NULL) {
1.13 ! millert 522: gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
! 523: #ifdef HAVE_GETUSERATTR
! 524: aix_setlimits(runas_pw->pw_name);
! 525: #endif
1.1 millert 526: #ifdef HAVE_PAM
527: pam_prep_user(runas_pw);
528: #endif /* HAVE_PAM */
529:
530: #ifdef HAVE_LOGIN_CAP_H
1.10 millert 531: if (def_use_loginclass) {
1.1 millert 532: /*
1.12 millert 533: * We only use setusercontext() set the nice value and rlimits.
1.1 millert 534: */
535: flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
1.10 millert 536: if (!def_preserve_groups)
537: SET(flags, LOGIN_SETGROUP);
1.13 ! millert 538: else if (setgid(gid))
! 539: warning("cannot set gid to runas gid");
1.11 millert 540: if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
1.10 millert 541: if (runas_pw->pw_uid != ROOT_UID)
1.13 ! millert 542: error(1, "unable to set user context");
1.7 millert 543: else
1.13 ! millert 544: warning("unable to set user context");
1.7 millert 545: }
1.12 millert 546: }
1.1 millert 547: #endif /* HAVE_LOGIN_CAP_H */
1.13 ! millert 548: if (setgid(gid))
! 549: warning("cannot set gid to runas gid");
1.12 millert 550: /*
1.13 ! millert 551: * Initialize group vector
1.12 millert 552: */
553: runas_setgroups();
1.1 millert 554: }
555: }