1 /*
2  * Copyright (c) 1994-1996,1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
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.
7  *
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.
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.
19  */
20 
21 #include "config.h"
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
55 static const char rcsid[] = "$Sudo: set_perms.c,v 1.30 2004/05/27 23:12:02 millert Exp $";
56 #endif /* lint */
57 
58 #ifdef __TANDEM
59 # define ROOT_UID	65535
60 #else
61 # define ROOT_UID	0
62 #endif
63 
64 /*
65  * Prototypes
66  */
67 static void runas_setup		__P((void));
68 static void fatal		__P((char *, int));
69 
70 #if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \
71     !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
72 /*
73  * Set real and effective uids and gids based on perm.
74  * Since we have POSIX saved IDs we can get away with just
75  * toggling the effective uid/gid unless we are headed for an exec().
76  */
77 void
set_perms_posix(perm)78 set_perms_posix(perm)
79     int perm;
80 {
81     int error;
82 
83     switch (perm) {
84 	case PERM_ROOT:
85 				if (seteuid(ROOT_UID))
86 				    fatal("seteuid(ROOT_UID) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-saved-ids", 0);
87 			      	break;
88 
89 	case PERM_FULL_ROOT:
90 				/* headed for exec() */
91 				(void) seteuid(ROOT_UID);
92 				if (setuid(ROOT_UID))
93 				    fatal("setuid(ROOT_UID)", 1);
94 			      	break;
95 
96 	case PERM_USER:
97     	    	    	        (void) setegid(user_gid);
98 				if (seteuid(user_uid))
99 				    fatal("seteuid(user_uid)", 1);
100 			      	break;
101 
102 	case PERM_FULL_USER:
103 				/* headed for exec() */
104 				(void) setgid(user_gid);
105 				if (setuid(user_uid))
106 				    fatal("setuid(user_uid)", 1);
107 				break;
108 
109 	case PERM_RUNAS:
110 				if (seteuid(runas_pw->pw_uid))
111 				    fatal("unable to change to runas uid", 1);
112 			      	break;
113 
114 	case PERM_FULL_RUNAS:
115 				/* headed for exec(), assume euid == ROOT_UID */
116 				runas_setup();
117 				if (def_stay_setuid)
118 				    error = seteuid(runas_pw->pw_uid);
119 				else
120 				    error = setuid(runas_pw->pw_uid);
121 				if (error)
122 				    fatal("unable to change to runas uid", 1);
123 				break;
124 
125 	case PERM_SUDOERS:
126 				/* assume euid == ROOT_UID, ruid == user */
127 				if (setegid(SUDOERS_GID))
128 				    fatal("unable to change to sudoers gid", 1);
129 
130 				/*
131 				 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
132 				 * is group readable we use a non-zero
133 				 * uid in order to avoid NFS lossage.
134 				 * Using uid 1 is a bit bogus but should
135 				 * work on all OS's.
136 				 */
137 				if (SUDOERS_UID == ROOT_UID) {
138 				    if ((SUDOERS_MODE & 040) && seteuid(1))
139 					fatal("seteuid(1)", 1);
140 				} else {
141 				    if (seteuid(SUDOERS_UID))
142 					fatal("seteuid(SUDOERS_UID)", 1);
143 				}
144 			      	break;
145 	case PERM_TIMESTAMP:
146 				if (seteuid(timestamp_uid))
147 				    fatal("seteuid(timestamp_uid)", 1);
148 			      	break;
149 
150     }
151 }
152 #endif /* !NO_SAVED_IDS && _SC_SAVED_IDS && _SC_VERSION */
153 
154 #ifdef HAVE_SETRESUID
155 /*
156  * Set real and effective and saved uids and gids based on perm.
157  * We always retain a saved uid of 0 unless we are headed for an exec().
158  * We only flip the effective gid since it only changes for PERM_SUDOERS.
159  * This version of set_perms() works fine with the "stay_setuid" option.
160  */
161 void
set_perms_suid(perm)162 set_perms_suid(perm)
163     int perm;
164 {
165     int error;
166 
167     switch (perm) {
168 	case PERM_FULL_ROOT:
169 	case PERM_ROOT:
170 				if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID))
171 				    fatal("setresuid(ROOT_UID, ROOT_UID, ROOT_UID) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid", 0);
172 			      	break;
173 
174 	case PERM_USER:
175     	    	    	        (void) setresgid(-1, user_gid, -1);
176 				if (setresuid(user_uid, user_uid, ROOT_UID))
177 				    fatal("setresuid(user_uid, user_uid, ROOT_UID)", 1);
178 			      	break;
179 
180 	case PERM_FULL_USER:
181 				/* headed for exec() */
182     	    	    	        (void) setgid(user_gid);
183 				if (setresuid(user_uid, user_uid, user_uid))
184 				    fatal("setresuid(user_uid, user_uid, user_uid)", 1);
185 			      	break;
186 
187 	case PERM_RUNAS:
188 				if (setresuid(-1, runas_pw->pw_uid, -1))
189 				    fatal("unable to change to runas uid", 1);
190 			      	break;
191 
192 	case PERM_FULL_RUNAS:
193 				/* headed for exec(), assume euid == ROOT_UID */
194 				runas_setup();
195 				error = setresuid(def_stay_setuid ?
196 				    user_uid : runas_pw->pw_uid,
197 				    runas_pw->pw_uid, runas_pw->pw_uid);
198 				if (error)
199 				    fatal("unable to change to runas uid", 1);
200 				break;
201 
202 	case PERM_SUDOERS:
203 				/* assume euid == ROOT_UID, ruid == user */
204 				if (setresgid(-1, SUDOERS_GID, -1))
205 				    fatal("unable to change to sudoers gid", 1);
206 
207 				/*
208 				 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
209 				 * is group readable we use a non-zero
210 				 * uid in order to avoid NFS lossage.
211 				 * Using uid 1 is a bit bogus but should
212 				 * work on all OS's.
213 				 */
214 				if (SUDOERS_UID == ROOT_UID) {
215 				    if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID))
216 					fatal("setresuid(ROOT_UID, 1, ROOT_UID)", 1);
217 				} else {
218 				    if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID))
219 					fatal("setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)", 1);
220 				}
221 			      	break;
222 	case PERM_TIMESTAMP:
223 				if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID))
224 				    fatal("setresuid(ROOT_UID, timestamp_uid, ROOT_UID)", 1);
225 			      	break;
226     }
227 }
228 
229 #else
230 # ifdef HAVE_SETREUID
231 
232 /*
233  * Set real and effective uids and gids based on perm.
234  * We always retain a real or effective uid of ROOT_UID unless
235  * we are headed for an exec().
236  * This version of set_perms() works fine with the "stay_setuid" option.
237  */
238 void
set_perms_suid(perm)239 set_perms_suid(perm)
240     int perm;
241 {
242     int error;
243 
244     switch (perm) {
245 	case PERM_FULL_ROOT:
246 	case PERM_ROOT:
247 				if (setreuid(-1, ROOT_UID))
248 				    fatal("setreuid(-1, ROOT_UID) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid", 0);
249 				if (setuid(ROOT_UID))
250 				    fatal("setuid(ROOT_UID)", 1);
251 			      	break;
252 
253 	case PERM_USER:
254     	    	    	        (void) setregid(-1, user_gid);
255 				if (setreuid(ROOT_UID, user_uid))
256 				    fatal("setreuid(ROOT_UID, user_uid)", 1);
257 			      	break;
258 
259 	case PERM_FULL_USER:
260 				/* headed for exec() */
261     	    	    	        (void) setgid(user_gid);
262 				if (setreuid(user_uid, user_uid))
263 				    fatal("setreuid(user_uid, user_uid)", 1);
264 			      	break;
265 
266 	case PERM_RUNAS:
267 				if (setreuid(-1, runas_pw->pw_uid))
268 				    fatal("unable to change to runas uid", 1);
269 			      	break;
270 
271 	case PERM_FULL_RUNAS:
272 				/* headed for exec(), assume euid == ROOT_UID */
273 				runas_setup();
274 				error = setreuid(def_stay_setuid ?
275 				    user_uid : runas_pw->pw_uid,
276 				    runas_pw->pw_uid);
277 				if (error)
278 				    fatal("unable to change to runas uid", 1);
279 				break;
280 
281 	case PERM_SUDOERS:
282 				/* assume euid == ROOT_UID, ruid == user */
283 				if (setregid(-1, SUDOERS_GID))
284 				    fatal("unable to change to sudoers gid", 1);
285 
286 				/*
287 				 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
288 				 * is group readable we use a non-zero
289 				 * uid in order to avoid NFS lossage.
290 				 * Using uid 1 is a bit bogus but should
291 				 * work on all OS's.
292 				 */
293 				if (SUDOERS_UID == ROOT_UID) {
294 				    if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1))
295 					fatal("setreuid(ROOT_UID, 1)", 1);
296 				} else {
297 				    if (setreuid(ROOT_UID, SUDOERS_UID))
298 					fatal("setreuid(ROOT_UID, SUDOERS_UID)", 1);
299 				}
300 			      	break;
301 	case PERM_TIMESTAMP:
302 				if (setreuid(ROOT_UID, timestamp_uid))
303 				    fatal("setreuid(ROOT_UID, timestamp_uid)", 1);
304 			      	break;
305     }
306 }
307 
308 # else
309 #  ifdef HAVE_SETREUID
310 
311 /*
312  * Set real and effective uids and gids based on perm.
313  * NOTE: does not support the "stay_setuid" option.
314  */
315 void
set_perms_nosuid(perm)316 set_perms_nosuid(perm)
317     int perm;
318 {
319 
320     /*
321      * Since we only have setuid() and seteuid() we have to set
322      * real and effective uids to ROOT_UID initially.
323      */
324     if (setuid(ROOT_UID))
325 	fatal("setuid(ROOT_UID)", 1);
326 
327     switch (perm) {
328 	case PERM_USER:
329     	    	    	        (void) setegid(user_gid);
330 				if (seteuid(user_uid))
331 				    fatal("seteuid(user_uid)", 1);
332 			      	break;
333 
334 	case PERM_FULL_USER:
335 				/* headed for exec() */
336     	    	    	        (void) setgid(user_gid);
337 				if (setuid(user_uid))
338 				    fatal("setuid(user_uid)", 1);
339 			      	break;
340 
341 	case PERM_RUNAS:
342 				if (seteuid(runas_pw->pw_uid))
343 				    fatal("unable to change to runas uid", 1);
344 			      	break;
345 
346 	case PERM_FULL_RUNAS:
347 				/* headed for exec(), assume euid == ROOT_UID */
348 				runas_setup();
349 				if (setuid(runas_pw->pw_uid))
350 				    fatal("unable to change to runas uid", 1);
351 				break;
352 
353 	case PERM_SUDOERS:
354 				/* assume euid == ROOT_UID, ruid == user */
355 				if (setegid(SUDOERS_GID))
356 				    fatal("unable to change to sudoers gid", 1);
357 
358 				/*
359 				 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
360 				 * is group readable we use a non-zero
361 				 * uid in order to avoid NFS lossage.
362 				 * Using uid 1 is a bit bogus but should
363 				 * work on all OS's.
364 				 */
365 				if (SUDOERS_UID == ROOT_UID) {
366 				    if ((SUDOERS_MODE & 040) && seteuid(1))
367 					fatal("seteuid(1)", 1);
368 				} else {
369 				    if (seteuid(SUDOERS_UID))
370 					fatal("seteuid(SUDOERS_UID)", 1);
371 				}
372 			      	break;
373 	case PERM_TIMESTAMP:
374 				if (seteuid(timestamp_uid))
375 				    fatal("seteuid(timestamp_uid)", 1);
376 			      	break;
377     }
378 }
379 
380 #  else
381 
382 /*
383  * Set uids and gids based on perm via setuid() and setgid().
384  * NOTE: does not support the "stay_setuid" or timestampowner options.
385  *       Also, SUDOERS_UID and SUDOERS_GID are not used.
386  */
387 void
set_perms_nosuid(perm)388 set_perms_nosuid(perm)
389     int perm;
390 {
391 
392     switch (perm) {
393 	case PERM_FULL_ROOT:
394 	case PERM_ROOT:
395 				if (setuid(ROOT_UID))
396 					fatal("setuid(ROOT_UID)", 1);
397 				break;
398 
399 	case PERM_FULL_USER:
400     	    	    	        (void) setgid(user_gid);
401 				if (setuid(user_uid))
402 				    fatal("setuid(user_uid)", 1);
403 			      	break;
404 
405 	case PERM_FULL_RUNAS:
406 				runas_setup();
407 				if (setuid(runas_pw->pw_uid))
408 				    fatal("unable to change to runas uid", 1);
409 				break;
410 
411 	case PERM_USER:
412 	case PERM_SUDOERS:
413 	case PERM_RUNAS:
414 	case PERM_TIMESTAMP:
415 				/* Unsupported since we can't set euid. */
416 				break;
417     }
418 }
419 #  endif /* HAVE_SETEUID */
420 # endif /* HAVE_SETREUID */
421 #endif /* HAVE_SETRESUID */
422 
423 static void
runas_setup()424 runas_setup()
425 {
426 #ifdef HAVE_LOGIN_CAP_H
427     int error, flags;
428     extern login_cap_t *lc;
429 #endif
430 
431     if (runas_pw->pw_name != NULL) {
432 #ifdef HAVE_PAM
433 	pam_prep_user(runas_pw);
434 #endif /* HAVE_PAM */
435 
436 #ifdef HAVE_LOGIN_CAP_H
437 	if (def_use_loginclass) {
438 	    /*
439              * We don't have setusercontext() set the user since we
440              * may only want to set the effective uid.  Depending on
441              * sudoers and/or command line arguments we may not want
442              * setusercontext() to call initgroups().
443 	     */
444 	    flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
445 	    if (!def_preserve_groups)
446 		SET(flags, LOGIN_SETGROUP);
447 	    else if (setgid(runas_pw->pw_gid))
448 		perror("cannot set gid to runas gid");
449 	    error = setusercontext(lc, runas_pw,
450 		runas_pw->pw_uid, flags);
451 	    if (error) {
452 		if (runas_pw->pw_uid != ROOT_UID)
453 		    fatal("unable to set user context", 1);
454 		else
455 		    perror("unable to set user context");
456 	    }
457 	} else
458 #endif /* HAVE_LOGIN_CAP_H */
459 	{
460 	    if (setgid(runas_pw->pw_gid))
461 		perror("cannot set gid to runas gid");
462 #ifdef HAVE_INITGROUPS
463 	    /*
464 	     * Initialize group vector unless asked not to.
465 	     */
466 	    if (!def_preserve_groups &&
467 		initgroups(*user_runas, runas_pw->pw_gid) < 0)
468 		perror("cannot set group vector");
469 #endif /* HAVE_INITGROUPS */
470 	}
471     }
472 }
473 
474 static void
fatal(str,printerr)475 fatal(str, printerr)
476     char *str;
477     int printerr;
478 {
479 
480     if (str) {
481 	if (printerr)
482 	    perror(str);
483 	else {
484 	    fputs(str, stderr);
485 	    fputc('\n', stderr);
486 	}
487     }
488     exit(1);
489 }
490