Annotation of src/usr.bin/sudo/set_perms.c, Revision 1.8
1.1 millert 1: /*
1.7 millert 2: * Copyright (c) 1994-1996,1998-2003 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: *
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: *
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * 3. The name of the author may not be used to endorse or promote products
17: * derived from this software without specific prior written permission.
18: *
19: * 4. Products derived from this software may not be called "Sudo" nor
20: * may "Sudo" appear in their names without specific prior written
21: * permission from the author.
22: *
23: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
26: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.8 ! millert 33: *
! 34: * Sponsored in part by the Defense Advanced Research Projects
! 35: * Agency (DARPA) and Air Force Research Laboratory, Air Force
! 36: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
1.1 millert 37: */
38:
39: #include "config.h"
40:
41: #include <sys/types.h>
42: #include <sys/param.h>
43: #include <sys/stat.h>
44: #include <stdio.h>
45: #ifdef STDC_HEADERS
46: # include <stdlib.h>
47: # include <stddef.h>
48: #else
49: # ifdef HAVE_STDLIB_H
50: # include <stdlib.h>
51: # endif
52: #endif /* STDC_HEADERS */
53: #ifdef HAVE_STRING_H
54: # include <string.h>
55: #else
56: # ifdef HAVE_STRINGS_H
57: # include <strings.h>
58: # endif
59: #endif /* HAVE_STRING_H */
60: #ifdef HAVE_UNISTD_H
61: # include <unistd.h>
62: #endif /* HAVE_UNISTD_H */
63: #include <pwd.h>
64: #include <errno.h>
65: #include <grp.h>
66: #ifdef HAVE_LOGIN_CAP_H
67: # include <login_cap.h>
68: #endif
69:
70: #include "sudo.h"
71:
72: #ifndef lint
1.8 ! millert 73: static const char rcsid[] = "$Sudo: set_perms.c,v 1.21 2003/04/16 00:42:10 millert Exp $";
1.1 millert 74: #endif /* lint */
75:
76: /*
77: * Prototypes
78: */
79: static void runas_setup __P((void));
1.5 millert 80: static void fatal __P((char *, int));
1.1 millert 81:
1.7 millert 82: #if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \
83: !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
1.1 millert 84: /*
85: * Set real and effective uids and gids based on perm.
86: * Since we have POSIX saved IDs we can get away with just
87: * toggling the effective uid/gid unless we are headed for an exec().
88: */
89: void
1.7 millert 90: set_perms_posix(perm)
1.1 millert 91: int perm;
92: {
93: int error;
94:
95: switch (perm) {
96: case PERM_ROOT:
97: if (seteuid(0))
1.5 millert 98: fatal("seteuid(0) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-saved-ids", 0);
1.1 millert 99: break;
1.2 millert 100:
101: case PERM_FULL_ROOT:
102: /* headed for exec() */
103: (void) seteuid(0);
104: if (setuid(0))
1.5 millert 105: fatal("setuid(0)", 1);
1.2 millert 106: break;
107:
1.1 millert 108: case PERM_USER:
109: (void) setegid(user_gid);
110: if (seteuid(user_uid))
1.5 millert 111: fatal("seteuid(user_uid)", 1);
1.1 millert 112: break;
1.4 millert 113:
114: case PERM_FULL_USER:
115: /* headed for exec() */
116: (void) setgid(user_gid);
117: if (setuid(user_uid))
1.5 millert 118: fatal("setuid(user_uid)", 1);
1.4 millert 119: break;
1.1 millert 120:
121: case PERM_RUNAS:
122: /* headed for exec(), assume euid == 0 */
123: runas_setup();
124: if (def_flag(I_STAY_SETUID))
125: error = seteuid(runas_pw->pw_uid);
126: else
127: error = setuid(runas_pw->pw_uid);
128: if (error)
1.5 millert 129: fatal("unable to change to runas uid", 1);
1.1 millert 130: break;
131:
132: case PERM_SUDOERS:
133: /* assume euid == 0, ruid == user */
134: if (setegid(SUDOERS_GID))
1.5 millert 135: fatal("unable to change to sudoers gid", 1);
1.1 millert 136:
137: /*
138: * If SUDOERS_UID == 0 and SUDOERS_MODE
139: * is group readable we use a non-zero
140: * uid in order to avoid NFS lossage.
141: * Using uid 1 is a bit bogus but should
142: * work on all OS's.
143: */
144: if (SUDOERS_UID == 0) {
145: if ((SUDOERS_MODE & 040) && seteuid(1))
1.5 millert 146: fatal("seteuid(1)", 1);
1.1 millert 147: } else {
148: if (seteuid(SUDOERS_UID))
1.5 millert 149: fatal("seteuid(SUDOERS_UID)", 1);
1.1 millert 150: }
151: break;
1.7 millert 152: case PERM_TIMESTAMP:
153: if (seteuid(timestamp_uid))
154: fatal("seteuid(timestamp_uid)", 1);
155: break;
156:
1.1 millert 157: }
158: }
1.3 millert 159: #endif /* !NO_SAVED_IDS && _SC_SAVED_IDS && _SC_VERSION */
1.1 millert 160:
1.7 millert 161: #ifdef HAVE_SETRESUID
162: /*
163: * Set real and effective and saved uids and gids based on perm.
164: * We always retain a saved uid of 0 unless we are headed for an exec().
165: * We only flip the effective gid since it only changes for PERM_SUDOERS.
166: * This version of set_perms() works fine with the "stay_setuid" option.
167: */
168: void
169: set_perms_suid(perm)
170: int perm;
171: {
172: int error;
173:
174: switch (perm) {
175: case PERM_FULL_ROOT:
176: case PERM_ROOT:
177: if (setresuid(0, 0, 0))
178: fatal("setresuid(0, 0, 0) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid", 0);
179: break;
180:
181: case PERM_USER:
182: (void) setresgid(-1, user_gid, -1);
183: if (setresuid(user_uid, user_uid, 0))
184: fatal("setresuid(user_uid, user_uid, 0)", 1);
185: break;
186:
187: case PERM_FULL_USER:
188: /* headed for exec() */
189: (void) setgid(user_gid);
190: if (setresuid(user_uid, user_uid, user_uid))
191: fatal("setresuid(user_uid, user_uid, user_uid)", 1);
192: break;
193:
194: case PERM_RUNAS:
195: /* headed for exec(), assume euid == 0 */
196: runas_setup();
197: error = setresuid(def_flag(I_STAY_SETUID) ?
198: user_uid : runas_pw->pw_uid,
199: runas_pw->pw_uid, runas_pw->pw_uid);
200: if (error)
201: fatal("unable to change to runas uid", 1);
202: break;
203:
204: case PERM_SUDOERS:
205: /* assume euid == 0, ruid == user */
206: if (setresgid(-1, SUDOERS_GID, -1))
207: fatal("unable to change to sudoers gid", 1);
208:
209: /*
210: * If SUDOERS_UID == 0 and SUDOERS_MODE
211: * is group readable we use a non-zero
212: * uid in order to avoid NFS lossage.
213: * Using uid 1 is a bit bogus but should
214: * work on all OS's.
215: */
216: if (SUDOERS_UID == 0) {
217: if ((SUDOERS_MODE & 040) && setresuid(0, 1, 0))
218: fatal("setresuid(0, 1, 0)", 1);
219: } else {
220: if (setresuid(0, SUDOERS_UID, 0))
221: fatal("setresuid(0, SUDOERS_UID, 0)", 1);
222: }
223: break;
224: case PERM_TIMESTAMP:
225: if (setresuid(0, timestamp_uid, 0))
226: fatal("setresuid(0, timestamp_uid, 0)", 1);
227: break;
228: }
229: }
230:
231: #else
232: # ifdef HAVE_SETREUID
233:
1.1 millert 234: /*
235: * Set real and effective uids and gids based on perm.
236: * We always retain a real or effective uid of 0 unless
237: * we are headed for an exec().
1.7 millert 238: * This version of set_perms() works fine with the "stay_setuid" option.
1.1 millert 239: */
240: void
1.7 millert 241: set_perms_suid(perm)
1.1 millert 242: int perm;
243: {
244: int error;
245:
246: switch (perm) {
1.2 millert 247: case PERM_FULL_ROOT:
1.1 millert 248: case PERM_ROOT:
1.7 millert 249: if (setreuid(0, 0))
250: fatal("setreuid(0, 0) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid", 0);
1.1 millert 251: break;
1.2 millert 252:
1.1 millert 253: case PERM_USER:
1.7 millert 254: (void) setregid(-1, user_gid);
1.1 millert 255: if (setreuid(0, user_uid))
1.5 millert 256: fatal("setreuid(0, user_uid)", 1);
1.1 millert 257: break;
258:
1.4 millert 259: case PERM_FULL_USER:
260: /* headed for exec() */
261: (void) setgid(user_gid);
1.7 millert 262: if (setreuid(user_uid, user_uid))
263: fatal("setreuid(user_uid, user_uid)", 1);
1.4 millert 264: break;
265:
1.1 millert 266: case PERM_RUNAS:
267: /* headed for exec(), assume euid == 0 */
268: runas_setup();
1.7 millert 269: error = setreuid(def_flag(I_STAY_SETUID) ?
270: user_uid : runas_pw->pw_uid,
271: runas_pw->pw_uid);
1.1 millert 272: if (error)
1.5 millert 273: fatal("unable to change to runas uid", 1);
1.1 millert 274: break;
275:
276: case PERM_SUDOERS:
277: /* assume euid == 0, ruid == user */
1.7 millert 278: if (setregid(-1, SUDOERS_GID))
1.5 millert 279: fatal("unable to change to sudoers gid", 1);
1.1 millert 280:
281: /*
282: * If SUDOERS_UID == 0 and SUDOERS_MODE
283: * is group readable we use a non-zero
284: * uid in order to avoid NFS lossage.
285: * Using uid 1 is a bit bogus but should
286: * work on all OS's.
287: */
288: if (SUDOERS_UID == 0) {
289: if ((SUDOERS_MODE & 040) && setreuid(0, 1))
1.5 millert 290: fatal("setreuid(0, 1)", 1);
1.1 millert 291: } else {
292: if (setreuid(0, SUDOERS_UID))
1.5 millert 293: fatal("setreuid(0, SUDOERS_UID)", 1);
1.1 millert 294: }
295: break;
1.7 millert 296: case PERM_TIMESTAMP:
297: if (setreuid(0, timestamp_uid))
298: fatal("setreuid(0, timestamp_uid)", 1);
299: break;
1.1 millert 300: }
301: }
302:
1.7 millert 303: # else
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: */
309: void
1.7 millert 310: set_perms_nosuid(perm)
1.1 millert 311: int perm;
312: {
313:
314: /*
315: * Since we only have setuid() and seteuid() we have to set
1.7 millert 316: * real and effective uids to 0 initially.
1.1 millert 317: */
318: if (setuid(0))
1.5 millert 319: fatal("setuid(0)", 1);
1.1 millert 320:
321: switch (perm) {
322: case PERM_USER:
323: (void) setegid(user_gid);
324: if (seteuid(user_uid))
1.5 millert 325: fatal("seteuid(user_uid)", 1);
1.4 millert 326: break;
327:
328: case PERM_FULL_USER:
329: /* headed for exec() */
330: (void) setgid(user_gid);
331: if (setuid(user_uid))
1.5 millert 332: fatal("setuid(user_uid)", 1);
1.1 millert 333: break;
334:
335: case PERM_RUNAS:
336: /* headed for exec(), assume euid == 0 */
337: runas_setup();
338: if (setuid(runas_pw->pw_uid))
1.5 millert 339: fatal("unable to change to runas uid", 1);
1.1 millert 340: break;
341:
342: case PERM_SUDOERS:
343: /* assume euid == 0, ruid == user */
344: if (setegid(SUDOERS_GID))
1.5 millert 345: fatal("unable to change to sudoers gid", 1);
1.1 millert 346:
347: /*
348: * If SUDOERS_UID == 0 and SUDOERS_MODE
349: * is group readable we use a non-zero
350: * uid in order to avoid NFS lossage.
351: * Using uid 1 is a bit bogus but should
352: * work on all OS's.
353: */
354: if (SUDOERS_UID == 0) {
355: if ((SUDOERS_MODE & 040) && seteuid(1))
1.5 millert 356: fatal("seteuid(1)", 1);
1.1 millert 357: } else {
358: if (seteuid(SUDOERS_UID))
1.5 millert 359: fatal("seteuid(SUDOERS_UID)", 1);
1.1 millert 360: }
361: break;
1.7 millert 362: case PERM_TIMESTAMP:
363: if (seteuid(timestamp_uid))
364: fatal("seteuid(timestamp_uid)", 1);
365: break;
1.1 millert 366: }
367: }
1.7 millert 368: # endif /* HAVE_SETREUID */
369: #endif /* HAVE_SETRESUID */
1.1 millert 370:
371: static void
372: runas_setup()
373: {
374: #ifdef HAVE_LOGIN_CAP_H
375: int error, flags;
376: extern login_cap_t *lc;
377: #endif
378:
379: if (runas_pw->pw_name != NULL) {
380: #ifdef HAVE_PAM
381: pam_prep_user(runas_pw);
382: #endif /* HAVE_PAM */
383:
384: #ifdef HAVE_LOGIN_CAP_H
385: if (def_flag(I_USE_LOGINCLASS)) {
386: /*
387: * We don't have setusercontext() set the user since we
388: * may only want to set the effective uid. Depending on
389: * sudoers and/or command line arguments we may not want
390: * setusercontext() to call initgroups().
391: */
392: flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
393: if (!def_flag(I_PRESERVE_GROUPS))
394: flags |= LOGIN_SETGROUP;
395: else if (setgid(runas_pw->pw_gid))
396: perror("cannot set gid to runas gid");
397: error = setusercontext(lc, runas_pw,
398: runas_pw->pw_uid, flags);
1.7 millert 399: if (error) {
400: if (runas_pw->pw_uid != 0)
401: fatal("unable to set user context", 1);
402: else
403: perror("unable to set user context");
404: }
1.1 millert 405: } else
406: #endif /* HAVE_LOGIN_CAP_H */
407: {
1.7 millert 408: if (setgid(runas_pw->pw_gid))
409: perror("cannot set gid to runas gid");
1.1 millert 410: #ifdef HAVE_INITGROUPS
411: /*
412: * Initialize group vector unless asked not to.
413: */
414: if (!def_flag(I_PRESERVE_GROUPS) &&
415: initgroups(*user_runas, runas_pw->pw_gid) < 0)
416: perror("cannot set group vector");
417: #endif /* HAVE_INITGROUPS */
418: }
419: }
420: }
421:
422: static void
1.5 millert 423: fatal(str, printerr)
1.1 millert 424: char *str;
425: {
426:
1.5 millert 427: if (str) {
428: if (printerr)
429: perror(str);
430: else {
431: fputs(str, stderr);
432: fputc('\n', stderr);
433: }
434: }
1.1 millert 435: exit(1);
436: }