1/*
2 * Copyright (c) 1994-1996,1998-2012 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#endif /* HAVE_STRING_H */
38#ifdef HAVE_STRINGS_H
39# include <strings.h>
40#endif /* HAVE_STRINGS_H */
41#ifdef HAVE_UNISTD_H
42# include <unistd.h>
43#endif /* HAVE_UNISTD_H */
44#include <pwd.h>
45#include <errno.h>
46#include <grp.h>
47#ifdef HAVE_LOGIN_CAP_H
48# include <login_cap.h>
49#endif
50#ifdef HAVE_PROJECT_H
51# include <project.h>
52# include <sys/task.h>
53#endif
54
55#include "sudo.h"
56
57/*
58 * Prototypes
59 */
60static void runas_setup		__P((void));
61static void runas_setgroups	__P((void));
62static void restore_groups	__P((void));
63
64static int current_perm = -1;
65
66#ifdef HAVE_SETRESUID
67/*
68 * Set real and effective and saved uids and gids based on perm.
69 * We always retain a saved uid of 0 unless we are headed for an exec().
70 * We only flip the effective gid since it only changes for PERM_SUDOERS.
71 * This version of set_perms() works fine with the "stay_setuid" option.
72 */
73int
74set_perms(perm)
75    int perm;
76{
77    const char *errstr;
78    int noexit;
79
80    noexit = ISSET(perm, PERM_NOEXIT);
81    CLR(perm, PERM_MASK);
82
83    if (perm == current_perm)
84	return 1;
85
86    switch (perm) {
87	case PERM_ROOT:
88				if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) {
89				    errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
90				    goto bad;
91				}
92				(void) setresgid(-1, ROOT_GID, -1);
93				if (current_perm == PERM_RUNAS)
94				    restore_groups();
95			      	break;
96
97	case PERM_USER:
98    	    	    	        (void) setresgid(-1, user_gid, -1);
99				if (setresuid(user_uid, user_uid, ROOT_UID)) {
100				    errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
101				    goto bad;
102				}
103			      	break;
104
105	case PERM_FULL_USER:
106				/* headed for exec() */
107    	    	    	        (void) setgid(user_gid);
108				if (setresuid(user_uid, user_uid, user_uid)) {
109				    errstr = "setresuid(user_uid, user_uid, user_uid)";
110				    goto bad;
111				}
112			      	break;
113
114	case PERM_RUNAS:
115				runas_setgroups();
116				(void) setresgid(-1, runas_gr ?
117				    runas_gr->gr_gid : runas_pw->pw_gid, -1);
118				if (setresuid(-1, runas_pw ? runas_pw->pw_uid :
119				    user_uid, -1)) {
120				    errstr = "unable to change to runas uid";
121				    goto bad;
122				}
123			      	break;
124
125	case PERM_FULL_RUNAS:
126				/* headed for exec(), assume euid == ROOT_UID */
127				runas_setup();
128				if (setresuid(def_stay_setuid ?
129				    user_uid : runas_pw->pw_uid,
130				    runas_pw->pw_uid, runas_pw->pw_uid)) {
131				    errstr = "unable to change to runas uid";
132				    goto bad;
133				}
134				break;
135
136	case PERM_SUDOERS:
137				/* assume euid == ROOT_UID, ruid == user */
138				if (setresgid(-1, SUDOERS_GID, -1)) {
139				    errstr = "unable to change to sudoers gid";
140				    goto bad;
141				}
142
143				/*
144				 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
145				 * is group readable we use a non-zero
146				 * uid in order to avoid NFS lossage.
147				 * Using uid 1 is a bit bogus but should
148				 * work on all OS's.
149				 */
150				if (SUDOERS_UID == ROOT_UID) {
151				    if ((SUDOERS_MODE & S_IRGRP) && setresuid(ROOT_UID, 1, ROOT_UID)) {
152					errstr = "setresuid(ROOT_UID, 1, ROOT_UID)";
153					goto bad;
154				    }
155				} else {
156				    if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) {
157					errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
158					goto bad;
159				    }
160				}
161			      	break;
162	case PERM_TIMESTAMP:
163				if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) {
164				    errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
165				    goto bad;
166				}
167			      	break;
168    }
169
170    current_perm = perm;
171    return 1;
172bad:
173    warningx("%s: %s", errstr,
174	errno == EAGAIN ? "too many processes" : strerror(errno));
175    if (noexit)
176	return 0;
177    exit(1);
178}
179
180#else
181# ifdef HAVE_SETREUID
182
183/*
184 * Set real and effective uids and gids based on perm.
185 * We always retain a real or effective uid of ROOT_UID unless
186 * we are headed for an exec().
187 * This version of set_perms() works fine with the "stay_setuid" option.
188 */
189int
190set_perms(perm)
191    int perm;
192{
193    const char *errstr;
194    int noexit;
195
196    noexit = ISSET(perm, PERM_NOEXIT);
197    CLR(perm, PERM_MASK);
198
199    if (perm == current_perm)
200	return 1;
201
202    switch (perm) {
203	case PERM_ROOT:
204				if (setreuid(-1, ROOT_UID)) {
205				    errstr = "setreuid(-1, ROOT_UID)";
206				    goto bad;
207				}
208				if (setuid(ROOT_UID)) {
209				    errstr = "setuid(ROOT_UID)";
210				    goto bad;
211				}
212				(void) setregid(-1, ROOT_GID);
213				if (current_perm == PERM_RUNAS)
214				    restore_groups();
215			      	break;
216
217	case PERM_USER:
218    	    	    	        (void) setregid(-1, user_gid);
219				if (setreuid(ROOT_UID, user_uid)) {
220				    errstr = "setreuid(ROOT_UID, user_uid)";
221				    goto bad;
222				}
223			      	break;
224
225	case PERM_FULL_USER:
226				/* headed for exec() */
227    	    	    	        (void) setgid(user_gid);
228				if (setreuid(user_uid, user_uid)) {
229				    errstr = "setreuid(user_uid, user_uid)";
230				    goto bad;
231				}
232			      	break;
233
234	case PERM_RUNAS:
235				runas_setgroups();
236				(void) setregid(-1, runas_gr ?
237				    runas_gr->gr_gid : runas_pw->pw_gid);
238				if (setreuid(-1,
239				    runas_pw ? runas_pw->pw_uid : user_uid)) {
240				    errstr = "unable to change to runas uid";
241				    goto bad;
242				}
243			      	break;
244
245	case PERM_FULL_RUNAS:
246				/* headed for exec(), assume euid == ROOT_UID */
247				runas_setup();
248				if (setreuid(def_stay_setuid ? user_uid :
249				    runas_pw->pw_uid, runas_pw->pw_uid)) {
250				    errstr = "unable to change to runas uid";
251				    goto bad;
252				}
253				break;
254
255	case PERM_SUDOERS:
256				/* assume euid == ROOT_UID, ruid == user */
257				if (setregid(-1, SUDOERS_GID)) {
258				    errstr = "unable to change to sudoers gid";
259				    goto bad;
260				}
261
262				/*
263				 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
264				 * is group readable we use a non-zero
265				 * uid in order to avoid NFS lossage.
266				 * Using uid 1 is a bit bogus but should
267				 * work on all OS's.
268				 */
269				if (SUDOERS_UID == ROOT_UID) {
270				    if ((SUDOERS_MODE & S_IRGRP) && setreuid(ROOT_UID, 1)) {
271					errstr = "setreuid(ROOT_UID, 1)";
272					goto bad;
273				    }
274				} else {
275				    if (setreuid(ROOT_UID, SUDOERS_UID)) {
276					errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
277					goto bad;
278				    }
279				}
280			      	break;
281	case PERM_TIMESTAMP:
282				if (setreuid(ROOT_UID, timestamp_uid)) {
283				    errstr = "setreuid(ROOT_UID, timestamp_uid)";
284				    goto bad;
285				}
286			      	break;
287    }
288
289    current_perm = perm;
290    return 1;
291bad:
292    warningx("%s: %s", errstr,
293	errno == EAGAIN ? "too many processes" : strerror(errno));
294    if (noexit)
295	return 0;
296    exit(1);
297}
298
299# else /* !HAVE_SETRESUID && !HAVE_SETREUID */
300# ifdef HAVE_SETEUID
301
302/*
303 * Set real and effective uids and gids based on perm.
304 * NOTE: does not support the "stay_setuid" option.
305 */
306int
307set_perms(perm)
308    int perm;
309{
310    const char *errstr;
311    int noexit;
312
313    noexit = ISSET(perm, PERM_NOEXIT);
314    CLR(perm, PERM_MASK);
315
316    if (perm == current_perm)
317	return 1;
318
319    /*
320     * Since we only have setuid() and seteuid() and semantics
321     * for these calls differ on various systems, we set
322     * real and effective uids to ROOT_UID initially to be safe.
323     */
324    if (seteuid(ROOT_UID)) {
325	errstr = "seteuid(ROOT_UID)";
326	goto bad;
327    }
328    if (setuid(ROOT_UID)) {
329	errstr = "setuid(ROOT_UID)";
330	goto bad;
331    }
332
333    switch (perm) {
334	case PERM_ROOT:
335				/* uid set above */
336				(void) setegid(ROOT_GID);
337				if (current_perm == PERM_RUNAS)
338				    restore_groups();
339			      	break;
340
341	case PERM_USER:
342    	    	    	        (void) setegid(user_gid);
343				if (seteuid(user_uid)) {
344				    errstr = "seteuid(user_uid)";
345				    goto bad;
346				}
347			      	break;
348
349	case PERM_FULL_USER:
350				/* headed for exec() */
351    	    	    	        (void) setgid(user_gid);
352				if (setuid(user_uid)) {
353				    errstr = "setuid(user_uid)";
354				    goto bad;
355				}
356			      	break;
357
358	case PERM_RUNAS:
359				runas_setgroups();
360				(void) setegid(runas_gr ?
361				    runas_gr->gr_gid : runas_pw->pw_gid);
362				if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) {
363				    errstr = "unable to change to runas uid";
364				    goto bad;
365				}
366			      	break;
367
368	case PERM_FULL_RUNAS:
369				/* headed for exec() */
370				runas_setup();
371				if (setuid(runas_pw->pw_uid)) {
372				    errstr = "unable to change to runas uid";
373				    goto bad;
374				}
375				break;
376
377	case PERM_SUDOERS:
378				if (setegid(SUDOERS_GID)) {
379				    errstr = "unable to change to sudoers gid";
380				    goto bad;
381				}
382
383				/*
384				 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
385				 * is group readable we use a non-zero
386				 * uid in order to avoid NFS lossage.
387				 * Using uid 1 is a bit bogus but should
388				 * work on all OS's.
389				 */
390				if (SUDOERS_UID == ROOT_UID) {
391				    if ((SUDOERS_MODE & S_IRGRP) && seteuid(1)) {
392					errstr = "seteuid(1)";
393					goto bad;
394				    }
395				} else {
396				    if (seteuid(SUDOERS_UID)) {
397					errstr = "seteuid(SUDOERS_UID)";
398					goto bad;
399				    }
400				}
401			      	break;
402	case PERM_TIMESTAMP:
403				if (seteuid(timestamp_uid)) {
404				    errstr = "seteuid(timestamp_uid)";
405				    goto bad;
406				}
407			      	break;
408    }
409
410    current_perm = perm;
411    return 1;
412bad:
413    warningx("%s: %s", errstr,
414	errno == EAGAIN ? "too many processes" : strerror(errno));
415    if (noexit)
416	return 0;
417    exit(1);
418}
419
420# else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
421
422/*
423 * Set uids and gids based on perm via setuid() and setgid().
424 * NOTE: does not support the "stay_setuid" or timestampowner options.
425 *       Also, SUDOERS_UID and SUDOERS_GID are not used.
426 */
427int
428set_perms(perm)
429    int perm;
430{
431    const char *errstr;
432    int noexit;
433
434    noexit = ISSET(perm, PERM_NOEXIT);
435    CLR(perm, PERM_MASK);
436
437    if (perm == current_perm)
438	return 1;
439
440    switch (perm) {
441	case PERM_ROOT:
442				if (setuid(ROOT_UID)) {
443				    errstr = "setuid(ROOT_UID)";
444				    goto bad;
445				}
446    	    	    	        (void) setgid(ROOT_GID);
447				if (current_perm == PERM_RUNAS)
448				    restore_groups();
449				break;
450
451	case PERM_FULL_USER:
452    	    	    	        (void) setgid(user_gid);
453				if (setuid(user_uid)) {
454				    errstr = "setuid(user_uid)";
455				    goto bad;
456				}
457			      	break;
458
459	case PERM_FULL_RUNAS:
460				runas_setup();
461				if (setuid(runas_pw->pw_uid)) {
462				    errstr = "unable to change to runas uid";
463				    goto bad;
464				}
465				break;
466
467	case PERM_USER:
468	case PERM_SUDOERS:
469	case PERM_RUNAS:
470	case PERM_TIMESTAMP:
471				/* Unsupported since we can't set euid. */
472				break;
473    }
474
475    current_perm = perm;
476    return 1;
477bad:
478    warningx("%s: %s", errstr,
479	errno == EAGAIN ? "too many processes" : strerror(errno));
480    if (noexit)
481	return 0;
482    exit(1);
483}
484#  endif /* HAVE_SETEUID */
485# endif /* HAVE_SETREUID */
486#endif /* HAVE_SETRESUID */
487
488#ifdef HAVE_INITGROUPS
489static void
490runas_setgroups()
491{
492    static int ngroups = -1;
493# ifdef HAVE_GETGROUPS
494    static GETGROUPS_T *groups;
495# endif
496    static struct passwd *pw;
497    struct passwd *opw = pw;
498
499    if (def_preserve_groups)
500	return;
501
502    /*
503     * Use stashed copy of runas groups if available, else initgroups and stash.
504     */
505    pw = runas_pw ? runas_pw : sudo_user.pw;
506    if (pw != opw) {
507# ifdef HAVE_SETAUTHDB
508	aix_setauthdb(pw->pw_name);
509# endif
510	if (initgroups(pw->pw_name, pw->pw_gid) < 0)
511	    log_fatal(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
512# ifdef HAVE_GETGROUPS
513	if (groups) {
514	    efree(groups);
515	    groups = NULL;
516	}
517	if ((ngroups = getgroups(0, NULL)) > 0) {
518	    groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
519	    if (getgroups(ngroups, groups) < 0)
520		log_fatal(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
521	}
522#  ifdef HAVE_SETAUTHDB
523	aix_restoreauthdb();
524#  endif
525    } else {
526	if (setgroups(ngroups, groups) < 0)
527	    log_fatal(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
528# endif /* HAVE_GETGROUPS */
529    }
530}
531
532static void
533restore_groups()
534{
535    if (user_ngroups >= 0 && setgroups(user_ngroups, user_groups) < 0)
536	log_fatal(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
537}
538
539#else
540
541static void
542runas_setgroups()
543{
544    /* STUB */
545}
546
547static void
548restore_groups()
549{
550    /* STUB */
551}
552
553#endif /* HAVE_INITGROUPS */
554
555#ifdef HAVE_PROJECT_H
556static void
557set_project(pw)
558    struct passwd *pw;
559{
560    struct project proj;
561    char buf[PROJECT_BUFSZ];
562    int errval;
563
564    /*
565     * Collect the default project for the user and settaskid
566     */
567    setprojent();
568    if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) {
569	errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL);
570	switch(errval) {
571	case 0:
572	    break;
573	case SETPROJ_ERR_TASK:
574	    switch (errno) {
575	    case EAGAIN:
576		warningx("resource control limit has been reached");
577		break;
578	    case ESRCH:
579		warningx("user \"%s\" is not a member of project \"%s\"",
580		    pw->pw_name, proj.pj_name);
581		break;
582	    case EACCES:
583		warningx("the invoking task is final");
584		break;
585	    default:
586		warningx("could not join project \"%s\"", proj.pj_name);
587	    }
588	case SETPROJ_ERR_POOL:
589	    switch (errno) {
590	    case EACCES:
591		warningx("no resource pool accepting default bindings "
592		    "exists for project \"%s\"", proj.pj_name);
593		break;
594	    case ESRCH:
595		warningx("specified resource pool does not exist for "
596		    "project \"%s\"", proj.pj_name);
597		break;
598	    default:
599		warningx("could not bind to default resource pool for "
600		    "project \"%s\"", proj.pj_name);
601	    }
602	    break;
603	default:
604	    if (errval <= 0) {
605		warningx("setproject failed for project \"%s\"", proj.pj_name);
606	    } else {
607		warningx("warning, resource control assignment failed for "
608		    "project \"%s\"", proj.pj_name);
609	    }
610	}
611    } else {
612	warning("getdefaultproj");
613    }
614    endprojent();
615}
616#endif /* HAVE_PROJECT_H */
617
618static void
619runas_setup()
620{
621    gid_t gid;
622#ifdef HAVE_LOGIN_CAP_H
623    int flags;
624    extern login_cap_t *lc;
625#endif
626
627    if (runas_pw->pw_name != NULL) {
628	gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
629#ifdef HAVE_PROJECT_H
630	set_project(runas_pw);
631#endif
632#ifdef HAVE_GETUSERATTR
633	aix_prep_user(runas_pw->pw_name, user_ttypath);
634#endif
635#ifdef HAVE_PAM
636	pam_begin_session(runas_pw);
637#endif /* HAVE_PAM */
638
639#ifdef HAVE_LOGIN_CAP_H
640	if (def_use_loginclass) {
641	    /*
642             * We only use setusercontext() to set the nice value and rlimits.
643	     */
644	    flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
645	    if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
646		if (runas_pw->pw_uid != ROOT_UID)
647		    error(1, "unable to set user context");
648		else
649		    warning("unable to set user context");
650	    }
651	}
652#endif /* HAVE_LOGIN_CAP_H */
653	/*
654	 * Initialize group vector
655	 */
656	runas_setgroups();
657#ifdef HAVE_SETEUID
658	if (setegid(gid))
659	    warning("cannot set egid to runas gid");
660#endif
661	if (setgid(gid))
662	    warning("cannot set gid to runas gid");
663    }
664}
665