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