Imported Upstream version 1.8.1p2
[debian/sudo] / plugins / sudoers / set_perms.c
1 /*
2  * Copyright (c) 1994-1996,1998-2011 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
48 #include "sudoers.h"
49
50 /*
51  * Prototypes
52  */
53 static void runas_setgroups(void);
54
55 /*
56  * We keep track of the current permisstions and use a stack to restore
57  * the old permissions.  A depth of 16 is overkill.
58  */
59 struct perm_state {
60     uid_t ruid;
61     uid_t euid;
62 #ifdef HAVE_SETRESUID
63     uid_t suid;
64 #endif
65     gid_t rgid;
66     gid_t egid;
67 #ifdef HAVE_SETRESUID
68     gid_t sgid;
69 #endif
70     GETGROUPS_T *groups;
71     int ngroups;
72 };
73
74 #define PERM_STACK_MAX  16
75 static struct perm_state perm_stack[PERM_STACK_MAX];
76 static int perm_stack_depth = 0;
77
78 /* XXX - make a runas_user struct? */
79 int runas_ngroups = -1;
80 #ifdef HAVE_GETGROUPS
81 GETGROUPS_T *runas_groups;
82 #endif
83
84 #undef ID
85 #define ID(x) (state->x == ostate->x ? -1 : state->x)
86 #undef OID
87 #define OID(x) (ostate->x == state->x ? -1 : ostate->x)
88
89 void
90 rewind_perms(void)
91 {
92     while (perm_stack_depth > 1)
93         restore_perms();
94 }
95
96 #ifdef HAVE_SETRESUID
97
98 /*
99  * Set real and effective and saved uids and gids based on perm.
100  * We always retain a saved uid of 0 unless we are headed for an exec().
101  * We only flip the effective gid since it only changes for PERM_SUDOERS.
102  * This version of set_perms() works fine with the "stay_setuid" option.
103  */
104 int
105 set_perms(int perm)
106 {
107     struct perm_state *state, *ostate = NULL;
108     const char *errstr;
109     int noexit;
110
111     noexit = ISSET(perm, PERM_NOEXIT);
112     CLR(perm, PERM_MASK);
113
114     if (perm_stack_depth == PERM_STACK_MAX) {
115         errstr = "perm stack overflow";
116         errno = EINVAL;
117         goto bad;
118     }
119
120     state = &perm_stack[perm_stack_depth];
121     if (perm_stack_depth)
122         ostate = &perm_stack[perm_stack_depth - 1];
123
124     if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
125         goto done;
126
127     switch (perm) {
128     case PERM_INITIAL:
129         /* Stash initial state */
130 #ifdef HAVE_GETRESUID
131         if (getresuid(&state->ruid, &state->euid, &state->suid)) {
132             errstr = "getresuid";
133             goto bad;
134
135         }
136         if (getresgid(&state->rgid, &state->egid, &state->sgid)) {
137             errstr = "getresgid";
138             goto bad;
139         }
140 #else
141         state->ruid = getuid();
142         state->euid = geteuid();
143         state->suid = state->euid; /* in case we are setuid */
144
145         state->rgid = getgid();
146         state->egid = getegid();
147         state->sgid = state->egid; /* in case we are setgid */
148 #endif
149         state->groups = user_groups;
150         state->ngroups = user_ngroups;
151         break;
152
153     case PERM_ROOT:
154         state->ruid = ROOT_UID;
155         state->euid = ROOT_UID;
156         state->suid = ROOT_UID;
157         if (setresuid(ID(ruid), ID(euid), ID(suid))) {
158             errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
159             goto bad;
160         }
161         state->rgid = -1;
162         state->egid = -1;
163         state->sgid = -1;
164         state->groups = NULL;
165         state->ngroups = -1;
166         break;
167
168     case PERM_USER:
169         state->groups = user_groups;
170         state->ngroups = user_ngroups;
171         if (state->ngroups != -1 && state->groups != ostate->groups) {
172             if (setgroups(state->ngroups, state->groups)) {
173                 errstr = "setgroups()";
174                 goto bad;
175             }
176         }
177         state->rgid = -1;
178         state->egid = user_gid;
179         state->sgid = -1;
180         if (setresgid(-1, ID(egid), -1)) {
181             errstr = "setresgid(-1, user_gid, -1)";
182             goto bad;
183         }
184         state->ruid = user_uid;
185         state->euid = user_uid;
186         state->suid = ROOT_UID;
187         if (setresuid(ID(ruid), ID(euid), ID(suid))) {
188             errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
189             goto bad;
190         }
191         break;
192
193     case PERM_FULL_USER:
194         /* headed for exec() */
195         state->groups = user_groups;
196         state->ngroups = user_ngroups;
197         if (state->ngroups != -1 && state->groups != ostate->groups) {
198             if (setgroups(state->ngroups, state->groups)) {
199                 errstr = "setgroups()";
200                 goto bad;
201             }
202         }
203         state->rgid = user_gid;
204         state->egid = user_gid;
205         state->sgid = user_gid;
206         if (setresgid(ID(rgid), ID(egid), ID(sgid))) {
207             errstr = "setresgid(user_gid, user_gid, user_gid)";
208             goto bad;
209         }
210         state->ruid = user_uid;
211         state->euid = user_uid;
212         state->suid = user_uid;
213         if (setresuid(ID(ruid), ID(euid), ID(suid))) {
214             errstr = "setresuid(user_uid, user_uid, user_uid)";
215             goto bad;
216         }
217         break;
218
219     case PERM_RUNAS:
220         runas_setgroups();
221         state->groups = runas_groups;
222         state->ngroups = runas_ngroups;
223
224         state->rgid = -1;
225         state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
226         state->sgid = -1;
227         if (setresgid(-1, ID(egid), -1)) {
228             errstr = "unable to change to runas gid";
229             goto bad;
230         }
231         state->ruid = -1;
232         state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
233         state->suid = -1;
234         if (setresuid(-1, ID(euid), -1)) {
235             errstr = "unable to change to runas uid";
236             goto bad;
237         }
238         break;
239
240     case PERM_SUDOERS:
241         state->groups = NULL;
242         state->ngroups = -1;
243
244         /* assumes euid == ROOT_UID, ruid == user */
245         state->rgid = -1;
246         state->egid = sudoers_gid;
247         state->sgid = -1;
248         if (setresgid(-1, ID(egid), -1))
249             error(1, "unable to change to sudoers gid");
250
251         state->ruid = ROOT_UID;
252         /*
253          * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
254          * we use a non-zero uid in order to avoid NFS lossage.
255          * Using uid 1 is a bit bogus but should work on all OS's.
256          */
257         if (sudoers_uid == ROOT_UID && (sudoers_mode & 040))
258             state->euid = 1;
259         else
260             state->euid = sudoers_uid;
261         state->suid = ROOT_UID;
262         if (setresuid(ID(ruid), ID(euid), ID(suid))) {
263             errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
264             goto bad;
265         }
266         break;
267
268     case PERM_TIMESTAMP:
269         state->groups = NULL;
270         state->ngroups = -1;
271         state->rgid = -1;
272         state->egid = -1;
273         state->sgid = -1;
274         state->ruid = ROOT_UID;
275         state->euid = timestamp_uid;
276         state->suid = ROOT_UID;
277         if (setresuid(ID(ruid), ID(euid), ID(suid))) {
278             errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
279             goto bad;
280         }
281         break;
282     }
283
284 done:
285     perm_stack_depth++;
286     return 1;
287 bad:
288     /* XXX - better warnings inline */
289     warningx("%s: %s", errstr,
290         errno == EAGAIN ? "too many processes" : strerror(errno));
291     if (noexit)
292         return 0;
293     exit(1);
294 }
295
296 void
297 restore_perms(void)
298 {
299     struct perm_state *state, *ostate;
300
301     if (perm_stack_depth < 2)
302         return;
303
304     state = &perm_stack[perm_stack_depth - 1];
305     ostate = &perm_stack[perm_stack_depth - 2];
306     perm_stack_depth--;
307
308     /* XXX - more cases here where euid != ruid */
309     if (OID(euid) == ROOT_UID && state->euid != ROOT_UID) {
310         if (setresuid(-1, ROOT_UID, -1)) {
311             warning("setresuid() [%d, %d, %d] -> [%d, %d, %d]", state->ruid,
312                 state->euid, state->suid, -1, ROOT_UID, -1);
313             goto bad;
314         }
315     }
316     if (setresuid(OID(ruid), OID(euid), OID(suid))) {
317         warning("setresuid() [%d, %d, %d] -> [%d, %d, %d]", state->ruid,
318             state->euid, state->suid, OID(ruid), OID(euid), OID(suid));
319         goto bad;
320     }
321     if (setresgid(OID(rgid), OID(egid), OID(sgid))) {
322         warning("setresgid() [%d, %d, %d] -> [%d, %d, %d]", state->rgid,
323             state->egid, state->sgid, OID(rgid), OID(egid), OID(sgid));
324         goto bad;
325     }
326     if (state->ngroups != -1 && state->groups != ostate->groups) {
327         if (setgroups(ostate->ngroups, ostate->groups)) {
328             warning("setgroups()");
329             goto bad;
330         }
331     }
332     return;
333
334 bad:
335     exit(1);
336 }
337
338 #else
339 # ifdef HAVE_SETREUID
340
341 /*
342  * Set real and effective uids and gids based on perm.
343  * We always retain a real or effective uid of ROOT_UID unless
344  * we are headed for an exec().
345  * This version of set_perms() works fine with the "stay_setuid" option.
346  */
347 int
348 set_perms(int perm)
349 {
350     struct perm_state *state, *ostate = NULL;
351     const char *errstr;
352     int noexit;
353
354     noexit = ISSET(perm, PERM_NOEXIT);
355     CLR(perm, PERM_MASK);
356
357     if (perm_stack_depth == PERM_STACK_MAX) {
358         errstr = "perm stack overflow";
359         errno = EINVAL;
360         goto bad;
361     }
362
363     state = &perm_stack[perm_stack_depth];
364     if (perm_stack_depth)
365         ostate = &perm_stack[perm_stack_depth - 1];
366
367     if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
368         goto done;
369
370     switch (perm) {
371     case PERM_INITIAL:
372         /* Stash initial state */
373         state->ruid = getuid();
374         state->euid = geteuid();
375         state->rgid = getgid();
376         state->egid = getegid();
377         state->groups = user_groups;
378         state->ngroups = user_ngroups;
379         break;
380
381     case PERM_ROOT:
382         /*
383          * setreuid(0, 0) may fail on some systems
384          * when the euid is not already 0.
385          */
386         if (setreuid(-1, ROOT_UID)) {
387             errstr = "setreuid(-1, ROOT_UID)";
388             goto bad;
389         }
390         if (setuid(ROOT_UID)) {
391             errstr = "setuid(ROOT_UID)";
392             goto bad;
393         }
394         state->ruid = ROOT_UID;
395         state->euid = ROOT_UID;
396         state->rgid = -1;
397         state->egid = -1;
398         state->groups = NULL;
399         state->ngroups = -1;
400         break;
401
402     case PERM_USER:
403         state->groups = user_groups;
404         state->ngroups = user_ngroups;
405         if (state->ngroups != -1 && state->groups != ostate->groups) {
406             if (setgroups(state->ngroups, state->groups)) {
407                 errstr = "setgroups()";
408                 goto bad;
409             }
410         }
411         state->rgid = -1;
412         state->egid = user_gid;
413         if (setregid(-1, ID(egid))) {
414             errstr = "setregid(-1, user_gid)";
415             goto bad;
416         }
417         state->ruid = ROOT_UID;
418         state->euid = user_uid;
419         if (setreuid(ID(ruid), ID(euid))) {
420             errstr = "setreuid(ROOT_UID, user_uid)";
421             goto bad;
422         }
423         break;
424
425     case PERM_FULL_USER:
426         /* headed for exec() */
427         state->groups = user_groups;
428         state->ngroups = user_ngroups;
429         if (state->ngroups != -1 && state->groups != ostate->groups) {
430             if (setgroups(state->ngroups, state->groups)) {
431                 errstr = "setgroups()";
432                 goto bad;
433             }
434         }
435         state->rgid = user_gid;
436         state->egid = user_gid;
437         if (setregid(ID(rgid), ID(egid))) {
438             errstr = "setregid(user_gid, user_gid)";
439             goto bad;
440         }
441         state->ruid = user_uid;
442         state->euid = user_uid;
443         if (setreuid(ID(ruid), ID(euid))) {
444             errstr = "setreuid(user_uid, user_uid)";
445             goto bad;
446         }
447         break;
448
449     case PERM_RUNAS:
450         runas_setgroups();
451         state->groups = runas_groups;
452         state->ngroups = runas_ngroups;
453
454         state->rgid = -1;
455         state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
456         if (setregid(ID(rgid), ID(egid))) {
457             errstr = "unable to change to runas gid";
458             goto bad;
459         }
460         state->ruid = ROOT_UID;
461         state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
462         if (setreuid(ID(ruid), ID(euid))) {
463             errstr = "unable to change to runas uid";
464             goto bad;
465         }
466         break;
467
468     case PERM_SUDOERS:
469         state->groups = NULL;
470         state->ngroups = -1;
471
472         /* assume euid == ROOT_UID, ruid == user */
473         state->rgid = -1;
474         state->egid = sudoers_gid;
475         if (setregid(-1, ID(egid)))
476             error(1, "unable to change to sudoers gid");
477
478         state->ruid = ROOT_UID;
479         /*
480          * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
481          * we use a non-zero uid in order to avoid NFS lossage.
482          * Using uid 1 is a bit bogus but should work on all OS's.
483          */
484         if (sudoers_uid == ROOT_UID && (sudoers_mode & 040))
485             state->euid = 1;
486         else
487             state->euid = sudoers_uid;
488         if (setreuid(ID(ruid), ID(euid))) {
489             errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
490             goto bad;
491         }
492         break;
493
494     case PERM_TIMESTAMP:
495         state->groups = NULL;
496         state->ngroups = -1;
497         state->rgid = -1;
498         state->egid = -1;
499         state->ruid = ROOT_UID;
500         state->euid = timestamp_uid;
501         if (setreuid(ID(ruid), ID(euid))) {
502             errstr = "setreuid(ROOT_UID, timestamp_uid)";
503             goto bad;
504         }
505         break;
506     }
507
508 done:
509     perm_stack_depth++;
510     return 1;
511 bad:
512     /* XXX - better warnings inline */
513     warningx("%s: %s", errstr,
514         errno == EAGAIN ? "too many processes" : strerror(errno));
515     if (noexit)
516         return 0;
517     exit(1);
518 }
519
520 void
521 restore_perms(void)
522 {
523     struct perm_state *state, *ostate;
524
525     if (perm_stack_depth < 2)
526         return;
527
528     state = &perm_stack[perm_stack_depth - 1];
529     ostate = &perm_stack[perm_stack_depth - 2];
530     perm_stack_depth--;
531
532     /*
533      * When changing euid to ROOT_UID, setreuid() may fail even if
534      * the ruid is ROOT_UID so call setuid() first.
535      */
536     if (OID(euid) == ROOT_UID) {
537         /* setuid() may not set the saved ID unless the euid is ROOT_UID */
538         if (ID(euid) != ROOT_UID)
539             (void)setreuid(-1, ROOT_UID);
540         if (setuid(ROOT_UID)) {
541             warning("setuid(%d)", ROOT_UID);
542             goto bad;
543         }
544     }
545     if (setreuid(OID(ruid), OID(euid))) {
546         warning("setreuid() [%d, %d] -> [%d, %d]", state->ruid,
547             state->euid, OID(ruid), OID(euid));
548         goto bad;
549     }
550     if (setregid(OID(rgid), OID(egid))) {
551         warning("setregid() [%d, %d] -> [%d, %d]", state->rgid,
552             state->egid, OID(rgid), OID(egid));
553         goto bad;
554     }
555     if (state->ngroups != -1 && state->groups != ostate->groups) {
556         if (setgroups(ostate->ngroups, ostate->groups)) {
557             warning("setgroups()");
558             goto bad;
559         }
560     }
561     return;
562
563 bad:
564     exit(1);
565 }
566
567 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
568 # ifdef HAVE_SETEUID
569
570 /*
571  * Set real and effective uids and gids based on perm.
572  * We always retain a real or effective uid of ROOT_UID unless
573  * we are headed for an exec().
574  * This version of set_perms() works fine with the "stay_setuid" option.
575  */
576 int
577 set_perms(int perm)
578 {
579     struct perm_state *state, *ostate = NULL;
580     const char *errstr;
581     int noexit;
582
583     noexit = ISSET(perm, PERM_NOEXIT);
584     CLR(perm, PERM_MASK);
585
586     if (perm_stack_depth == PERM_STACK_MAX) {
587         errstr = "perm stack overflow";
588         errno = EINVAL;
589         goto bad;
590     }
591
592     state = &perm_stack[perm_stack_depth];
593     if (perm_stack_depth)
594         ostate = &perm_stack[perm_stack_depth - 1];
595
596     if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
597         goto done;
598
599     /*
600      * Since we only have setuid() and seteuid() and semantics
601      * for these calls differ on various systems, we set
602      * real and effective uids to ROOT_UID initially to be safe.
603      */
604     if (perm != PERM_INITIAL) {
605         if (seteuid(ROOT_UID)) {
606             errstr = "seteuid(ROOT_UID)";
607             goto bad;
608         }
609         if (setuid(ROOT_UID)) {
610             errstr = "setuid(ROOT_UID)";
611             goto bad;
612         }
613     }
614
615     switch (perm) {
616     case PERM_INITIAL:
617         /* Stash initial state */
618         state->ruid = getuid();
619         state->euid = geteuid();
620         state->rgid = getgid();
621         state->egid = getegid();
622         state->groups = user_groups;
623         state->ngroups = user_ngroups;
624         break;
625
626     case PERM_ROOT:
627         /* We already set ruid/euid above. */
628         state->ruid = ROOT_UID;
629         state->euid = ROOT_UID;
630         state->rgid = -1;
631         state->egid = -1;
632         state->groups = NULL;
633         state->ngroups = -1;
634         break;
635
636     case PERM_USER:
637         state->groups = user_groups;
638         state->ngroups = user_ngroups;
639         if (state->ngroups != -1 && state->groups != ostate->groups) {
640             if (setgroups(state->ngroups, state->groups)) {
641                 errstr = "setgroups()";
642                 goto bad;
643             }
644         }
645         state->rgid = -1;
646         state->egid = user_gid;
647         if (setegid(ID(egid))) {
648             errstr = "setegid(user_gid)";
649             goto bad;
650         }
651         state->ruid = ROOT_UID;
652         state->euid = user_uid;
653         if (seteuid(ID(euid))) {
654             errstr = "seteuid(user_uid)";
655             goto bad;
656         }
657         break;
658
659     case PERM_FULL_USER:
660         /* headed for exec() */
661         state->groups = user_groups;
662         state->ngroups = user_ngroups;
663         if (state->ngroups != -1 && state->groups != ostate->groups) {
664             if (setgroups(state->ngroups, state->groups)) {
665                 errstr = "setgroups()";
666                 goto bad;
667             }
668         }
669         state->rgid = user_gid;
670         state->egid = user_gid;
671         if (setgid(user_gid)) {
672             errstr = "setgid(user_gid)";
673             goto bad;
674         }
675         state->ruid = user_uid;
676         state->euid = user_uid;
677         if (setuid(user_uid)) {
678             errstr = "setuid(user_uid)";
679             goto bad;
680         }
681         break;
682
683     case PERM_RUNAS:
684         runas_setgroups();
685         state->groups = runas_groups;
686         state->ngroups = runas_ngroups;
687
688         state->rgid = -1;
689         state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
690         if (setegid(ID(egid))) {
691             errstr = "unable to change to runas gid";
692             goto bad;
693         }
694         state->ruid = -1;
695         state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
696         if (seteuid(ID(euid))) {
697             errstr = "unable to change to runas uid";
698             goto bad;
699         }
700         break;
701
702     case PERM_SUDOERS:
703         state->groups = NULL;
704         state->ngroups = -1;
705
706         /* assume euid == ROOT_UID, ruid == user */
707         state->rgid = -1;
708         state->egid = sudoers_gid;
709         if (setegid(ID(egid)))
710             error(1, "unable to change to sudoers gid");
711
712         state->ruid = ROOT_UID;
713         /*
714          * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
715          * we use a non-zero uid in order to avoid NFS lossage.
716          * Using uid 1 is a bit bogus but should work on all OS's.
717          */
718         if (sudoers_uid == ROOT_UID && (sudoers_mode & 040))
719             state->euid = 1;
720         else
721             state->euid = sudoers_uid;
722         if (seteuid(ID(euid))) {
723             errstr = "seteuid(SUDOERS_UID)";
724             goto bad;
725         }
726         break;
727
728     case PERM_TIMESTAMP:
729         state->groups = NULL;
730         state->ngroups = -1;
731         state->rgid = -1;
732         state->egid = -1;
733         state->ruid = ROOT_UID;
734         state->euid = timestamp_uid;
735         if (seteuid(ID(euid))) {
736             errstr = "seteuid(timestamp_uid)";
737             goto bad;
738         }
739         break;
740     }
741
742 done:
743     perm_stack_depth++;
744     return 1;
745 bad:
746     /* XXX - better warnings inline */
747     warningx("%s: %s", errstr,
748         errno == EAGAIN ? "too many processes" : strerror(errno));
749     if (noexit)
750         return 0;
751     exit(1);
752 }
753
754 void
755 restore_perms(void)
756 {
757     struct perm_state *state, *ostate;
758
759     if (perm_stack_depth < 2)
760         return;
761
762     state = &perm_stack[perm_stack_depth - 1];
763     ostate = &perm_stack[perm_stack_depth - 2];
764     perm_stack_depth--;
765
766     /*
767      * Since we only have setuid() and seteuid() and semantics
768      * for these calls differ on various systems, we set
769      * real and effective uids to ROOT_UID initially to be safe.
770      */
771     if (seteuid(ROOT_UID)) {
772         errstr = "seteuid(ROOT_UID)";
773         goto bad;
774     }
775     if (setuid(ROOT_UID)) {
776         errstr = "setuid(ROOT_UID)";
777         goto bad;
778     }
779
780     if (setegid(OID(egid))) {
781         warning("setegid(%d)", OID(egid));
782         goto bad;
783     }
784     if (state->ngroups != -1 && state->groups != ostate->groups) {
785         if (setgroups(ostate->ngroups, ostate->groups)) {
786             warning("setgroups()");
787             goto bad;
788         }
789     }
790     if (seteuid(OID(euid))) {
791         warning("seteuid(%d)", OID(euid));
792         goto bad;
793     }
794     return;
795
796 bad:
797     exit(1);
798 }
799
800 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
801
802 /*
803  * Set uids and gids based on perm via setuid() and setgid().
804  * NOTE: does not support the "stay_setuid" or timestampowner options.
805  *       Also, sudoers_uid and sudoers_gid are not used.
806  */
807 int
808 set_perms(int perm)
809 {
810     struct perm_state *state, *ostate = NULL;
811     const char *errstr;
812     int noexit;
813
814     noexit = ISSET(perm, PERM_NOEXIT);
815     CLR(perm, PERM_MASK);
816
817     if (perm_stack_depth == PERM_STACK_MAX) {
818         errstr = "perm stack overflow";
819         errno = EINVAL;
820         goto bad;
821     }
822
823     state = &perm_stack[perm_stack_depth];
824     if (perm_stack_depth)
825         ostate = &perm_stack[perm_stack_depth - 1];
826
827     if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
828         goto done;
829
830     switch (perm) {
831     case PERM_INITIAL:
832         /* Stash initial state */
833         state->ruid = getuid();
834         state->rgid = getgid();
835         state->groups = user_groups;
836         state->ngroups = user_ngroups;
837         break;
838
839     case PERM_ROOT:
840         state->ruid = ROOT_UID;
841         state->rgid = -1;
842         state->groups = NULL;
843         state->ngroups = -1;
844         if (setuid(ROOT_UID)) {
845             errstr = "setuid(ROOT_UID)";
846             goto bad;
847         }
848         break;
849
850     case PERM_FULL_USER:
851         state->groups = user_groups;
852         state->ngroups = user_ngroups;
853         if (state->ngroups != -1 && state->groups != ostate->groups) {
854             if (setgroups(state->ngroups, state->groups)) {
855                 errstr = "setgroups()";
856                 goto bad;
857             }
858         }
859         state->rgid = user_gid;
860         (void) setgid(user_gid);
861         state->ruid = user_uid;
862         if (setuid(user_uid)) {
863             errstr = "setuid(user_uid)";
864             goto bad;
865         }
866         break;
867
868     case PERM_USER:
869     case PERM_SUDOERS:
870     case PERM_RUNAS:
871     case PERM_TIMESTAMP:
872         /* Unsupported since we can't set euid. */
873         break;
874     }
875
876 done:
877     perm_stack_depth++;
878     return 1;
879 bad:
880     /* XXX - better warnings inline */
881     warningx("%s: %s", errstr,
882         errno == EAGAIN ? "too many processes" : strerror(errno));
883     if (noexit)
884         return 0;
885     exit(1);
886 }
887
888 void
889 restore_perms(void)
890 {
891     struct perm_state *state, *ostate;
892
893     if (perm_stack_depth < 2)
894         return;
895
896     state = &perm_stack[perm_stack_depth - 1];
897     ostate = &perm_stack[perm_stack_depth - 2];
898     perm_stack_depth--;
899
900     if (state->ngroups != -1 && state->groups != ostate->groups) {
901         if (setgroups(ostate->ngroups, ostate->groups)) {
902             warning("setgroups()");
903             goto bad;
904         }
905     }
906     if (OID(rgid) != -1 && setgid(ostate->rgid)) {
907         warning("setgid(%d)", ostate->rgid);
908         goto bad;
909     }
910     if (OID(ruid) != -1 && setuid(ostate->ruid)) {
911         warning("setuid(%d)", ostate->ruid);
912         goto bad;
913     }
914     return;
915
916 bad:
917     exit(1);
918 }
919 #  endif /* HAVE_SETEUID */
920 # endif /* HAVE_SETREUID */
921 #endif /* HAVE_SETRESUID */
922
923 #ifdef HAVE_INITGROUPS
924 static void
925 runas_setgroups()
926 {
927     static struct passwd *pw;
928     struct passwd *opw = pw;
929
930     if (def_preserve_groups)
931         return;
932
933     /*
934      * Use stashed copy of runas groups if available, else initgroups and stash.
935      */
936     pw = runas_pw ? runas_pw : sudo_user.pw;
937     if (pw != opw) {
938         pw = runas_pw ? runas_pw : sudo_user.pw;
939 # ifdef HAVE_SETAUTHDB
940         aix_setauthdb(pw->pw_name);
941 # endif
942         if (initgroups(pw->pw_name, pw->pw_gid) < 0)
943             log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
944 # ifdef HAVE_GETGROUPS
945         if (runas_groups) {
946             efree(runas_groups);
947             runas_groups = NULL;
948         }
949         if ((runas_ngroups = getgroups(0, NULL)) > 0) {
950             runas_groups = emalloc2(runas_ngroups, sizeof(GETGROUPS_T));
951             if (getgroups(runas_ngroups, runas_groups) < 0)
952                 log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
953         }
954 #  ifdef HAVE_SETAUTHDB
955         aix_restoreauthdb();
956 #  endif
957     } else {
958         if (setgroups(runas_ngroups, runas_groups) < 0)
959             log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
960 # endif /* HAVE_GETGROUPS */
961     }
962 }
963
964 #else
965
966 static void
967 runas_setgroups()
968 {
969     /* STUB */
970 }
971
972 #endif /* HAVE_INITGROUPS */