Annotation of src/usr.bin/sudo/set_perms.c, Revision 1.6
1.1 millert 1: /*
2: * Copyright (c) 1994-1996,1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
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.
33: */
34:
35: #include "config.h"
36:
37: #include <sys/types.h>
38: #include <sys/param.h>
39: #include <sys/stat.h>
40: #include <stdio.h>
41: #ifdef STDC_HEADERS
42: # include <stdlib.h>
43: # include <stddef.h>
44: #else
45: # ifdef HAVE_STDLIB_H
46: # include <stdlib.h>
47: # endif
48: #endif /* STDC_HEADERS */
49: #ifdef HAVE_STRING_H
50: # include <string.h>
51: #else
52: # ifdef HAVE_STRINGS_H
53: # include <strings.h>
54: # endif
55: #endif /* HAVE_STRING_H */
56: #ifdef HAVE_UNISTD_H
57: # include <unistd.h>
58: #endif /* HAVE_UNISTD_H */
59: #include <pwd.h>
60: #include <errno.h>
61: #include <grp.h>
62: #ifdef HAVE_LOGIN_CAP_H
63: # include <login_cap.h>
64: #endif
65:
66: #include "sudo.h"
67:
68: #ifndef lint
1.5 millert 69: static const char rcsid[] = "$Sudo: set_perms.c,v 1.12 2002/01/22 02:00:25 millert Exp $";
1.1 millert 70: #endif /* lint */
71:
72: /*
73: * Prototypes
74: */
75: static void runas_setup __P((void));
1.5 millert 76: static void fatal __P((char *, int));
1.1 millert 77:
1.3 millert 78: #if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
1.1 millert 79: /*
80: * Set real and effective uids and gids based on perm.
81: * Since we have POSIX saved IDs we can get away with just
82: * toggling the effective uid/gid unless we are headed for an exec().
83: */
84: void
85: set_perms_posix(perm, sudo_mode)
86: int perm;
87: int sudo_mode;
88: {
89: int error;
90:
91: switch (perm) {
92: case PERM_ROOT:
93: if (seteuid(0))
1.5 millert 94: 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 95: break;
1.2 millert 96:
97: case PERM_FULL_ROOT:
98: /* headed for exec() */
99: (void) seteuid(0);
100: if (setuid(0))
1.5 millert 101: fatal("setuid(0)", 1);
1.2 millert 102: break;
103:
1.1 millert 104: case PERM_USER:
105: (void) setegid(user_gid);
106: if (seteuid(user_uid))
1.5 millert 107: fatal("seteuid(user_uid)", 1);
1.1 millert 108: break;
1.4 millert 109:
110: case PERM_FULL_USER:
111: /* headed for exec() */
112: (void) setgid(user_gid);
113: if (setuid(user_uid))
1.5 millert 114: fatal("setuid(user_uid)", 1);
1.4 millert 115: break;
1.1 millert 116:
117: case PERM_RUNAS:
118: /* headed for exec(), assume euid == 0 */
119: runas_setup();
120: if (def_flag(I_STAY_SETUID))
121: error = seteuid(runas_pw->pw_uid);
122: else
123: error = setuid(runas_pw->pw_uid);
124: if (error)
1.5 millert 125: fatal("unable to change to runas uid", 1);
1.1 millert 126: break;
127:
128: case PERM_SUDOERS:
129: /* assume euid == 0, ruid == user */
130: if (setegid(SUDOERS_GID))
1.5 millert 131: fatal("unable to change to sudoers gid", 1);
1.1 millert 132:
133: /*
134: * If SUDOERS_UID == 0 and SUDOERS_MODE
135: * is group readable we use a non-zero
136: * uid in order to avoid NFS lossage.
137: * Using uid 1 is a bit bogus but should
138: * work on all OS's.
139: */
140: if (SUDOERS_UID == 0) {
141: if ((SUDOERS_MODE & 040) && seteuid(1))
1.5 millert 142: fatal("seteuid(1)", 1);
1.1 millert 143: } else {
144: if (seteuid(SUDOERS_UID))
1.5 millert 145: fatal("seteuid(SUDOERS_UID)", 1);
1.1 millert 146: }
147: break;
148: }
149: }
1.3 millert 150: #endif /* !NO_SAVED_IDS && _SC_SAVED_IDS && _SC_VERSION */
1.1 millert 151:
152: #ifdef HAVE_SETREUID
153: /*
154: * Set real and effective uids and gids based on perm.
155: * We always retain a real or effective uid of 0 unless
156: * we are headed for an exec().
157: */
158: void
159: set_perms_fallback(perm, sudo_mode)
160: int perm;
161: int sudo_mode;
162: {
163: int error;
164:
165: switch (perm) {
1.2 millert 166: case PERM_FULL_ROOT:
1.1 millert 167: case PERM_ROOT:
168: if (setuid(0))
1.5 millert 169: fatal("setuid(0) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-setreuid", 0);
1.1 millert 170: break;
1.2 millert 171:
1.1 millert 172: case PERM_USER:
173: (void) setegid(user_gid);
174: if (setreuid(0, user_uid))
1.5 millert 175: fatal("setreuid(0, user_uid)", 1);
1.1 millert 176: break;
177:
1.4 millert 178: case PERM_FULL_USER:
179: /* headed for exec() */
180: (void) setgid(user_gid);
181: if (setuid(user_uid))
1.5 millert 182: fatal("setuid(user_uid)", 1);
1.4 millert 183: break;
184:
1.1 millert 185: case PERM_RUNAS:
186: /* headed for exec(), assume euid == 0 */
187: runas_setup();
188: if (def_flag(I_STAY_SETUID))
189: error = setreuid(user_uid, runas_pw->pw_uid);
190: else
191: error = setuid(runas_pw->pw_uid);
192: if (error)
1.5 millert 193: fatal("unable to change to runas uid", 1);
1.1 millert 194: break;
195:
196: case PERM_SUDOERS:
197: /* assume euid == 0, ruid == user */
198: if (setegid(SUDOERS_GID))
1.5 millert 199: fatal("unable to change to sudoers gid", 1);
1.1 millert 200:
201: /*
202: * If SUDOERS_UID == 0 and SUDOERS_MODE
203: * is group readable we use a non-zero
204: * uid in order to avoid NFS lossage.
205: * Using uid 1 is a bit bogus but should
206: * work on all OS's.
207: */
208: if (SUDOERS_UID == 0) {
209: if ((SUDOERS_MODE & 040) && setreuid(0, 1))
1.5 millert 210: fatal("setreuid(0, 1)", 1);
1.1 millert 211: } else {
212: if (setreuid(0, SUDOERS_UID))
1.5 millert 213: fatal("setreuid(0, SUDOERS_UID)", 1);
1.1 millert 214: }
215: break;
216: }
217: }
218:
219: #else
220:
221: /*
222: * Set real and effective uids and gids based on perm.
223: * NOTE: does not support the "stay_setuid" option.
224: */
225: void
226: set_perms_fallback(perm, sudo_mode)
227: int perm;
228: int sudo_mode;
229: {
230:
231: /*
232: * Since we only have setuid() and seteuid() we have to set
233: * real and effective uidss to 0 initially.
234: */
235: if (setuid(0))
1.5 millert 236: fatal("setuid(0)", 1);
1.1 millert 237:
238: switch (perm) {
239: case PERM_USER:
240: (void) setegid(user_gid);
241: if (seteuid(user_uid))
1.5 millert 242: fatal("seteuid(user_uid)", 1);
1.4 millert 243: break;
244:
245: case PERM_FULL_USER:
246: /* headed for exec() */
247: (void) setgid(user_gid);
248: if (setuid(user_uid))
1.5 millert 249: fatal("setuid(user_uid)", 1);
1.1 millert 250: break;
251:
252: case PERM_RUNAS:
253: /* headed for exec(), assume euid == 0 */
254: runas_setup();
255: if (setuid(runas_pw->pw_uid))
1.5 millert 256: fatal("unable to change to runas uid", 1);
1.1 millert 257: break;
258:
259: case PERM_SUDOERS:
260: /* assume euid == 0, ruid == user */
261: if (setegid(SUDOERS_GID))
1.5 millert 262: fatal("unable to change to sudoers gid", 1);
1.1 millert 263:
264: /*
265: * If SUDOERS_UID == 0 and SUDOERS_MODE
266: * is group readable we use a non-zero
267: * uid in order to avoid NFS lossage.
268: * Using uid 1 is a bit bogus but should
269: * work on all OS's.
270: */
271: if (SUDOERS_UID == 0) {
272: if ((SUDOERS_MODE & 040) && seteuid(1))
1.5 millert 273: fatal("seteuid(1)", 1);
1.1 millert 274: } else {
275: if (seteuid(SUDOERS_UID))
1.5 millert 276: fatal("seteuid(SUDOERS_UID)", 1);
1.1 millert 277: }
278: break;
279: }
280: }
281: #endif /* HAVE_SETREUID */
282:
283: static void
284: runas_setup()
285: {
286: #ifdef HAVE_LOGIN_CAP_H
287: int error, flags;
288: extern login_cap_t *lc;
289: #endif
290:
291: if (runas_pw->pw_name != NULL) {
292: #ifdef HAVE_PAM
293: pam_prep_user(runas_pw);
294: #endif /* HAVE_PAM */
295:
296: #ifdef HAVE_LOGIN_CAP_H
297: if (def_flag(I_USE_LOGINCLASS)) {
298: /*
299: * We don't have setusercontext() set the user since we
300: * may only want to set the effective uid. Depending on
301: * sudoers and/or command line arguments we may not want
302: * setusercontext() to call initgroups().
303: */
304: flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
305: if (!def_flag(I_PRESERVE_GROUPS))
306: flags |= LOGIN_SETGROUP;
307: else if (setgid(runas_pw->pw_gid))
308: perror("cannot set gid to runas gid");
309: error = setusercontext(lc, runas_pw,
310: runas_pw->pw_uid, flags);
311: if (error)
312: perror("unable to set user context");
313: } else
314: #endif /* HAVE_LOGIN_CAP_H */
315: {
1.6 ! millert 316: if (setgid(runas_pw->pw_gid)) {
! 317: if (runas_pw->pw_gid != 0)
! 318: fatal("unable to set user context", 1);
! 319: else
! 320: perror("cannot set gid to runas gid");
! 321: }
1.1 millert 322: #ifdef HAVE_INITGROUPS
323: /*
324: * Initialize group vector unless asked not to.
325: */
326: if (!def_flag(I_PRESERVE_GROUPS) &&
327: initgroups(*user_runas, runas_pw->pw_gid) < 0)
328: perror("cannot set group vector");
329: #endif /* HAVE_INITGROUPS */
330: }
331: }
332: }
333:
334: static void
1.5 millert 335: fatal(str, printerr)
1.1 millert 336: char *str;
337: {
338:
1.5 millert 339: if (str) {
340: if (printerr)
341: perror(str);
342: else {
343: fputs(str, stderr);
344: fputc('\n', stderr);
345: }
346: }
1.1 millert 347: exit(1);
348: }