Annotation of src/usr.bin/sudo/set_perms.c, Revision 1.12
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.12 ! millert 60: __unused static const char rcsid[] = "$Sudo: set_perms.c,v 1.30.2.7 2007/11/27 23:41:23 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));
1.12 ! millert 73: static void runas_setgroups __P((void));
! 74: static void restore_groups __P((void));
! 75:
! 76: static int current_perm = -1;
1.1 millert 77:
1.7 millert 78: #ifdef HAVE_SETRESUID
79: /*
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.
84: */
85: void
1.11 millert 86: set_perms(perm)
1.7 millert 87: int perm;
88: {
1.12 ! millert 89: if (perm == current_perm)
! 90: return;
! 91:
1.7 millert 92: switch (perm) {
93: case PERM_ROOT:
1.10 millert 94: if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID))
1.11 millert 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);
1.12 ! millert 97: if (current_perm == PERM_RUNAS)
! 98: restore_groups();
1.7 millert 99: break;
100:
101: case PERM_USER:
102: (void) setresgid(-1, user_gid, -1);
1.10 millert 103: if (setresuid(user_uid, user_uid, ROOT_UID))
1.11 millert 104: err(1, "setresuid(user_uid, user_uid, ROOT_UID)");
1.7 millert 105: break;
106:
107: case PERM_FULL_USER:
108: /* headed for exec() */
109: (void) setgid(user_gid);
110: if (setresuid(user_uid, user_uid, user_uid))
1.11 millert 111: err(1, "setresuid(user_uid, user_uid, user_uid)");
1.7 millert 112: break;
113:
114: case PERM_RUNAS:
1.12 ! millert 115: runas_setgroups();
1.11 millert 116: (void) setresgid(-1, runas_pw->pw_gid, -1);
1.10 millert 117: if (setresuid(-1, runas_pw->pw_uid, -1))
1.11 millert 118: err(1, "unable to change to runas uid");
1.10 millert 119: break;
120:
121: case PERM_FULL_RUNAS:
122: /* headed for exec(), assume euid == ROOT_UID */
1.7 millert 123: runas_setup();
1.11 millert 124: if (setresuid(def_stay_setuid ?
1.7 millert 125: user_uid : runas_pw->pw_uid,
1.11 millert 126: runas_pw->pw_uid, runas_pw->pw_uid))
127: err(1, "unable to change to runas uid");
1.7 millert 128: break;
129:
130: case PERM_SUDOERS:
1.10 millert 131: /* assume euid == ROOT_UID, ruid == user */
1.7 millert 132: if (setresgid(-1, SUDOERS_GID, -1))
1.11 millert 133: err(1, "unable to change to sudoers gid");
1.7 millert 134:
135: /*
1.10 millert 136: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.7 millert 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
140: * work on all OS's.
141: */
1.10 millert 142: if (SUDOERS_UID == ROOT_UID) {
143: if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID))
1.11 millert 144: err(1, "setresuid(ROOT_UID, 1, ROOT_UID)");
1.7 millert 145: } else {
1.10 millert 146: if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID))
1.11 millert 147: err(1, "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)");
1.7 millert 148: }
149: break;
150: case PERM_TIMESTAMP:
1.10 millert 151: if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID))
1.11 millert 152: err(1, "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)");
1.7 millert 153: break;
154: }
1.12 ! millert 155:
! 156: current_perm = perm;
1.7 millert 157: }
158:
159: #else
160: # ifdef HAVE_SETREUID
161:
1.1 millert 162: /*
163: * Set real and effective uids and gids based on perm.
1.10 millert 164: * We always retain a real or effective uid of ROOT_UID unless
1.1 millert 165: * we are headed for an exec().
1.7 millert 166: * This version of set_perms() works fine with the "stay_setuid" option.
1.1 millert 167: */
168: void
1.11 millert 169: set_perms(perm)
1.1 millert 170: int perm;
171: {
1.12 ! millert 172: if (perm == current_perm)
! 173: return;
! 174:
1.1 millert 175: switch (perm) {
176: case PERM_ROOT:
1.10 millert 177: if (setreuid(-1, ROOT_UID))
1.11 millert 178: 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 179: if (setuid(ROOT_UID))
1.11 millert 180: err(1, "setuid(ROOT_UID)");
181: (void) setregid(-1, user_gid);
1.12 ! millert 182: if (current_perm == PERM_RUNAS)
! 183: restore_groups();
1.1 millert 184: break;
1.2 millert 185:
1.1 millert 186: case PERM_USER:
1.7 millert 187: (void) setregid(-1, user_gid);
1.10 millert 188: if (setreuid(ROOT_UID, user_uid))
1.11 millert 189: err(1, "setreuid(ROOT_UID, user_uid)");
1.1 millert 190: break;
191:
1.4 millert 192: case PERM_FULL_USER:
193: /* headed for exec() */
194: (void) setgid(user_gid);
1.7 millert 195: if (setreuid(user_uid, user_uid))
1.11 millert 196: err(1, "setreuid(user_uid, user_uid)");
1.4 millert 197: break;
198:
1.1 millert 199: case PERM_RUNAS:
1.12 ! millert 200: runas_setgroups();
1.11 millert 201: (void) setregid(-1, runas_pw->pw_gid);
1.10 millert 202: if (setreuid(-1, runas_pw->pw_uid))
1.11 millert 203: err(1, "unable to change to runas uid");
1.10 millert 204: break;
205:
206: case PERM_FULL_RUNAS:
207: /* headed for exec(), assume euid == ROOT_UID */
1.1 millert 208: runas_setup();
1.11 millert 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");
1.1 millert 212: break;
213:
214: case PERM_SUDOERS:
1.10 millert 215: /* assume euid == ROOT_UID, ruid == user */
1.7 millert 216: if (setregid(-1, SUDOERS_GID))
1.11 millert 217: err(1, "unable to change to sudoers gid");
1.1 millert 218:
219: /*
1.10 millert 220: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.1 millert 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
224: * work on all OS's.
225: */
1.10 millert 226: if (SUDOERS_UID == ROOT_UID) {
227: if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1))
1.11 millert 228: err(1, "setreuid(ROOT_UID, 1)");
1.1 millert 229: } else {
1.10 millert 230: if (setreuid(ROOT_UID, SUDOERS_UID))
1.11 millert 231: err(1, "setreuid(ROOT_UID, SUDOERS_UID)");
1.1 millert 232: }
233: break;
1.7 millert 234: case PERM_TIMESTAMP:
1.10 millert 235: if (setreuid(ROOT_UID, timestamp_uid))
1.11 millert 236: err(1, "setreuid(ROOT_UID, timestamp_uid)");
1.7 millert 237: break;
1.1 millert 238: }
1.12 ! millert 239:
! 240: current_perm = perm;
1.1 millert 241: }
242:
1.11 millert 243: # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
244: # ifdef HAVE_SETEUID
1.1 millert 245:
246: /*
247: * Set real and effective uids and gids based on perm.
248: * NOTE: does not support the "stay_setuid" option.
249: */
250: void
1.11 millert 251: set_perms(perm)
1.1 millert 252: int perm;
253: {
1.12 ! millert 254: if (perm == current_perm)
! 255: return;
! 256:
1.1 millert 257: /*
1.11 millert 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.
1.1 millert 261: */
1.11 millert 262: if (seteuid(ROOT_UID))
263: err(1, "seteuid(ROOT_UID)");
1.10 millert 264: if (setuid(ROOT_UID))
1.11 millert 265: err(1, "setuid(ROOT_UID)");
1.1 millert 266:
267: switch (perm) {
1.11 millert 268: case PERM_ROOT:
269: /* uid set above */
270: (void) setegid(user_gid);
1.12 ! millert 271: if (current_perm == PERM_RUNAS)
! 272: restore_groups();
1.11 millert 273: break;
274:
1.1 millert 275: case PERM_USER:
276: (void) setegid(user_gid);
277: if (seteuid(user_uid))
1.11 millert 278: err(1, "seteuid(user_uid)");
1.4 millert 279: break;
280:
281: case PERM_FULL_USER:
282: /* headed for exec() */
283: (void) setgid(user_gid);
284: if (setuid(user_uid))
1.11 millert 285: err(1, "setuid(user_uid)");
1.1 millert 286: break;
287:
288: case PERM_RUNAS:
1.12 ! millert 289: runas_setgroups();
1.11 millert 290: (void) setegid(runas_pw->pw_gid);
1.10 millert 291: if (seteuid(runas_pw->pw_uid))
1.11 millert 292: err(1, "unable to change to runas uid");
1.10 millert 293: break;
294:
295: case PERM_FULL_RUNAS:
1.11 millert 296: /* headed for exec() */
1.1 millert 297: runas_setup();
298: if (setuid(runas_pw->pw_uid))
1.11 millert 299: err(1, "unable to change to runas uid");
1.1 millert 300: break;
301:
302: case PERM_SUDOERS:
303: if (setegid(SUDOERS_GID))
1.11 millert 304: err(1, "unable to change to sudoers gid");
1.1 millert 305:
306: /*
1.10 millert 307: * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
1.1 millert 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
311: * work on all OS's.
312: */
1.10 millert 313: if (SUDOERS_UID == ROOT_UID) {
1.1 millert 314: if ((SUDOERS_MODE & 040) && seteuid(1))
1.11 millert 315: err(1, "seteuid(1)");
1.1 millert 316: } else {
317: if (seteuid(SUDOERS_UID))
1.11 millert 318: err(1, "seteuid(SUDOERS_UID)");
1.1 millert 319: }
320: break;
1.7 millert 321: case PERM_TIMESTAMP:
322: if (seteuid(timestamp_uid))
1.11 millert 323: err(1, "seteuid(timestamp_uid)");
1.7 millert 324: break;
1.1 millert 325: }
1.12 ! millert 326:
! 327: current_perm = perm;
1.1 millert 328: }
1.10 millert 329:
1.11 millert 330: # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
1.10 millert 331:
332: /*
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.
336: */
337: void
1.11 millert 338: set_perms(perm)
1.10 millert 339: int perm;
340: {
1.12 ! millert 341: if (perm == current_perm)
! 342: return;
1.10 millert 343:
344: switch (perm) {
345: case PERM_ROOT:
346: if (setuid(ROOT_UID))
1.11 millert 347: err(1, "setuid(ROOT_UID)");
1.12 ! millert 348: if (current_perm == PERM_RUNAS)
! 349: restore_groups();
1.10 millert 350: break;
351:
352: case PERM_FULL_USER:
353: (void) setgid(user_gid);
354: if (setuid(user_uid))
1.11 millert 355: err(1, "setuid(user_uid)");
1.10 millert 356: break;
357:
358: case PERM_FULL_RUNAS:
359: runas_setup();
360: if (setuid(runas_pw->pw_uid))
1.11 millert 361: err(1, "unable to change to runas uid");
1.10 millert 362: break;
363:
364: case PERM_USER:
365: case PERM_SUDOERS:
366: case PERM_RUNAS:
367: case PERM_TIMESTAMP:
368: /* Unsupported since we can't set euid. */
369: break;
370: }
1.12 ! millert 371:
! 372: current_perm = perm;
1.10 millert 373: }
374: # endif /* HAVE_SETEUID */
1.7 millert 375: # endif /* HAVE_SETREUID */
376: #endif /* HAVE_SETRESUID */
1.1 millert 377:
1.12 ! millert 378: #ifdef HAVE_INITGROUPS
! 379: static void
! 380: runas_setgroups()
! 381: {
! 382: static int ngroups = -1;
! 383: static GETGROUPS_T *groups;
! 384: struct passwd *pw;
! 385:
! 386: if (def_preserve_groups)
! 387: return;
! 388:
! 389: /*
! 390: * Use stashed copy of runas groups if available, else initgroups and stash.
! 391: */
! 392: if (ngroups == -1) {
! 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");
! 401: } else {
! 402: if (setgroups(ngroups, groups) < 0)
! 403: log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
! 404: }
! 405: }
! 406:
! 407: static void
! 408: restore_groups()
! 409: {
! 410: if (setgroups(user_ngroups, user_groups) < 0)
! 411: log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
! 412: }
! 413:
! 414: #else
! 415:
! 416: static void
! 417: runas_setgroups()
! 418: {
! 419: /* STUB */
! 420: }
! 421:
! 422: static void
! 423: restore_groups()
! 424: {
! 425: /* STUB */
! 426: }
! 427:
! 428: #endif /* HAVE_INITGROUPS */
! 429:
1.1 millert 430: static void
431: runas_setup()
432: {
433: #ifdef HAVE_LOGIN_CAP_H
1.11 millert 434: int flags;
1.1 millert 435: extern login_cap_t *lc;
436: #endif
437:
438: if (runas_pw->pw_name != NULL) {
439: #ifdef HAVE_PAM
440: pam_prep_user(runas_pw);
441: #endif /* HAVE_PAM */
442:
443: #ifdef HAVE_LOGIN_CAP_H
1.10 millert 444: if (def_use_loginclass) {
1.1 millert 445: /*
1.12 ! millert 446: * We only use setusercontext() set the nice value and rlimits.
1.1 millert 447: */
448: flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
1.10 millert 449: if (!def_preserve_groups)
450: SET(flags, LOGIN_SETGROUP);
1.1 millert 451: else if (setgid(runas_pw->pw_gid))
1.11 millert 452: warn("cannot set gid to runas gid");
453: if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
1.10 millert 454: if (runas_pw->pw_uid != ROOT_UID)
1.11 millert 455: err(1, "unable to set user context");
1.7 millert 456: else
1.11 millert 457: warn("unable to set user context");
1.7 millert 458: }
1.12 ! millert 459: }
1.1 millert 460: #endif /* HAVE_LOGIN_CAP_H */
1.12 ! millert 461: if (setgid(runas_pw->pw_gid))
! 462: warn("cannot set gid to runas gid");
! 463: /*
! 464: * Initialize group vector unless asked not to.
! 465: */
! 466: runas_setgroups();
1.1 millert 467: }
468: }