Imported Upstream version 1.8.3
[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 = NULL;
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]",
308                 (int)state->ruid, (int)state->euid, (int)state->suid,
309                 -1, ROOT_UID, -1);
310             goto bad;
311         }
312     }
313     if (setresuid(OID(ruid), OID(euid), OID(suid))) {
314         warning("setresuid() [%d, %d, %d] -> [%d, %d, %d]",
315             (int)state->ruid, (int)state->euid, (int)state->suid,
316             (int)OID(ruid), (int)OID(euid), (int)OID(suid));
317         goto bad;
318     }
319     if (setresgid(OID(rgid), OID(egid), OID(sgid))) {
320         warning("setresgid() [%d, %d, %d] -> [%d, %d, %d]",
321             (int)state->rgid, (int)state->egid, (int)state->sgid,
322             (int)OID(rgid), (int)OID(egid), (int)OID(sgid));
323         goto bad;
324     }
325     if (state->grlist != ostate->grlist) {
326         if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
327             warning("setgroups()");
328             goto bad;
329         }
330     }
331     grlist_delref(state->grlist);
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 != PERM_INITIAL) {
365         if (perm_stack_depth == 0) {
366             errstr = _("perm stack underflow");
367             errno = EINVAL;
368             goto bad;
369         }
370         ostate = &perm_stack[perm_stack_depth - 1];
371         if (memcmp(state, ostate, sizeof(*state)) == 0)
372             goto done;
373     }
374
375     switch (perm) {
376     case PERM_INITIAL:
377         /* Stash initial state */
378         state->ruid = getuid();
379         state->euid = geteuid();
380         state->rgid = getgid();
381         state->egid = getegid();
382         state->grlist = user_group_list;
383         grlist_addref(state->grlist);
384         break;
385
386     case PERM_ROOT:
387         /*
388          * setreuid(0, 0) may fail on some systems
389          * when the euid is not already 0.
390          */
391         if (setreuid(-1, ROOT_UID)) {
392             errstr = "setreuid(-1, ROOT_UID)";
393             goto bad;
394         }
395         if (setuid(ROOT_UID)) {
396             errstr = "setuid(ROOT_UID)";
397             goto bad;
398         }
399         state->ruid = ROOT_UID;
400         state->euid = ROOT_UID;
401         state->rgid = -1;
402         state->egid = -1;
403         state->grlist = ostate->grlist;
404         grlist_addref(state->grlist);
405         break;
406
407     case PERM_USER:
408         state->rgid = -1;
409         state->egid = user_gid;
410         if (setregid(-1, ID(egid))) {
411             errstr = "setregid(-1, user_gid)";
412             goto bad;
413         }
414         state->grlist = user_group_list;
415         grlist_addref(state->grlist);
416         if (state->grlist != ostate->grlist) {
417             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
418                 errstr = "setgroups()";
419                 goto bad;
420             }
421         }
422         state->ruid = ROOT_UID;
423         state->euid = user_uid;
424         if (setreuid(ID(ruid), ID(euid))) {
425             errstr = "setreuid(ROOT_UID, user_uid)";
426             goto bad;
427         }
428         break;
429
430     case PERM_FULL_USER:
431         /* headed for exec() */
432         state->rgid = user_gid;
433         state->egid = user_gid;
434         if (setregid(ID(rgid), ID(egid))) {
435             errstr = "setregid(user_gid, user_gid)";
436             goto bad;
437         }
438         state->grlist = user_group_list;
439         grlist_addref(state->grlist);
440         if (state->grlist != ostate->grlist) {
441             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
442                 errstr = "setgroups()";
443                 goto bad;
444             }
445         }
446         state->ruid = user_uid;
447         state->euid = user_uid;
448         if (setreuid(ID(ruid), ID(euid))) {
449             errstr = "setreuid(user_uid, user_uid)";
450             goto bad;
451         }
452         break;
453
454     case PERM_RUNAS:
455         state->rgid = -1;
456         state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
457         if (setregid(ID(rgid), ID(egid))) {
458             errstr = _("unable to change to runas gid");
459             goto bad;
460         }
461         state->grlist = runas_setgroups();
462         state->ruid = ROOT_UID;
463         state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
464         if (setreuid(ID(ruid), ID(euid))) {
465             errstr = _("unable to change to runas uid");
466             goto bad;
467         }
468         break;
469
470     case PERM_SUDOERS:
471         state->grlist = ostate->grlist;
472         grlist_addref(state->grlist);
473
474         /* assume euid == ROOT_UID, ruid == user */
475         state->rgid = -1;
476         state->egid = sudoers_gid;
477         if (setregid(-1, ID(egid)))
478             error(1, _("unable to change to sudoers gid"));
479
480         state->ruid = ROOT_UID;
481         /*
482          * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
483          * we use a non-zero uid in order to avoid NFS lossage.
484          * Using uid 1 is a bit bogus but should work on all OS's.
485          */
486         if (sudoers_uid == ROOT_UID && (sudoers_mode & 040))
487             state->euid = 1;
488         else
489             state->euid = sudoers_uid;
490         if (setreuid(ID(ruid), ID(euid))) {
491             errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
492             goto bad;
493         }
494         break;
495
496     case PERM_TIMESTAMP:
497         state->grlist = ostate->grlist;
498         grlist_addref(state->grlist);
499         state->rgid = -1;
500         state->egid = -1;
501         state->ruid = ROOT_UID;
502         state->euid = timestamp_uid;
503         if (setreuid(ID(ruid), ID(euid))) {
504             errstr = "setreuid(ROOT_UID, timestamp_uid)";
505             goto bad;
506         }
507         break;
508     }
509
510 done:
511     perm_stack_depth++;
512     return 1;
513 bad:
514     /* XXX - better warnings inline */
515     warningx("%s: %s", errstr,
516         errno == EAGAIN ? _("too many processes") : strerror(errno));
517     if (noexit)
518         return 0;
519     exit(1);
520 }
521
522 void
523 restore_perms(void)
524 {
525     struct perm_state *state, *ostate;
526
527     if (perm_stack_depth < 2)
528         return;
529
530     state = &perm_stack[perm_stack_depth - 1];
531     ostate = &perm_stack[perm_stack_depth - 2];
532     perm_stack_depth--;
533
534     /*
535      * When changing euid to ROOT_UID, setreuid() may fail even if
536      * the ruid is ROOT_UID so call setuid() first.
537      */
538     if (OID(euid) == ROOT_UID) {
539         /* setuid() may not set the saved ID unless the euid is ROOT_UID */
540         if (ID(euid) != ROOT_UID)
541             (void)setreuid(-1, ROOT_UID);
542         if (setuid(ROOT_UID)) {
543             warning("setuid() [%d, %d] -> %d)", (int)state->ruid,
544                 (int)state->euid, ROOT_UID);
545             goto bad;
546         }
547     }
548     if (setreuid(OID(ruid), OID(euid))) {
549         warning("setreuid() [%d, %d] -> [%d, %d]", (int)state->ruid,
550             (int)state->euid, (int)OID(ruid), (int)OID(euid));
551         goto bad;
552     }
553     if (setregid(OID(rgid), OID(egid))) {
554         warning("setregid() [%d, %d] -> [%d, %d]", (int)state->rgid,
555             (int)state->egid, (int)OID(rgid), (int)OID(egid));
556         goto bad;
557     }
558     if (state->grlist != ostate->grlist) {
559         if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
560             warning("setgroups()");
561             goto bad;
562         }
563     }
564     grlist_delref(state->grlist);
565     return;
566
567 bad:
568     exit(1);
569 }
570
571 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
572 # ifdef HAVE_SETEUID
573
574 /*
575  * Set real and effective uids and gids based on perm.
576  * We always retain a real or effective uid of ROOT_UID unless
577  * we are headed for an exec().
578  * This version of set_perms() works fine with the "stay_setuid" option.
579  */
580 int
581 set_perms(int perm)
582 {
583     struct perm_state *state, *ostate = NULL;
584     const char *errstr;
585     int noexit;
586
587     noexit = ISSET(perm, PERM_NOEXIT);
588     CLR(perm, PERM_MASK);
589
590     if (perm_stack_depth == PERM_STACK_MAX) {
591         errstr = _("perm stack overflow");
592         errno = EINVAL;
593         goto bad;
594     }
595
596     state = &perm_stack[perm_stack_depth];
597     if (perm != PERM_INITIAL) {
598         if (perm_stack_depth == 0) {
599             errstr = _("perm stack underflow");
600             errno = EINVAL;
601             goto bad;
602         }
603         ostate = &perm_stack[perm_stack_depth - 1];
604         if (memcmp(state, ostate, sizeof(*state)) == 0)
605             goto done;
606     }
607
608     /*
609      * Since we only have setuid() and seteuid() and semantics
610      * for these calls differ on various systems, we set
611      * real and effective uids to ROOT_UID initially to be safe.
612      */
613     if (perm != PERM_INITIAL) {
614         if (seteuid(ROOT_UID)) {
615             errstr = "seteuid(ROOT_UID)";
616             goto bad;
617         }
618         if (setuid(ROOT_UID)) {
619             errstr = "setuid(ROOT_UID)";
620             goto bad;
621         }
622     }
623
624     switch (perm) {
625     case PERM_INITIAL:
626         /* Stash initial state */
627         state->ruid = getuid();
628         state->euid = geteuid();
629         state->rgid = getgid();
630         state->egid = getegid();
631         state->grlist = user_group_list;
632         grlist_addref(state->grlist);
633         break;
634
635     case PERM_ROOT:
636         /* We already set ruid/euid above. */
637         state->ruid = ROOT_UID;
638         state->euid = ROOT_UID;
639         state->rgid = -1;
640         state->egid = -1;
641         state->grlist = ostate->grlist;
642         grlist_addref(state->grlist);
643         break;
644
645     case PERM_USER:
646         state->egid = user_gid;
647         if (setegid(ID(egid))) {
648             errstr = "setegid(user_gid)";
649             goto bad;
650         }
651         state->grlist = user_group_list;
652         grlist_addref(state->grlist);
653         if (state->grlist != ostate->grlist) {
654             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
655                 errstr = "setgroups()";
656                 goto bad;
657             }
658         }
659         state->rgid = -1;
660         state->ruid = ROOT_UID;
661         state->euid = user_uid;
662         if (seteuid(ID(euid))) {
663             errstr = "seteuid(user_uid)";
664             goto bad;
665         }
666         break;
667
668     case PERM_FULL_USER:
669         /* headed for exec() */
670         state->rgid = user_gid;
671         state->egid = user_gid;
672         if (setgid(user_gid)) {
673             errstr = "setgid(user_gid)";
674             goto bad;
675         }
676         state->grlist = user_group_list;
677         grlist_addref(state->grlist);
678         if (state->grlist != ostate->grlist) {
679             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
680                 errstr = "setgroups()";
681                 goto bad;
682             }
683         }
684         state->ruid = user_uid;
685         state->euid = user_uid;
686         if (setuid(user_uid)) {
687             errstr = "setuid(user_uid)";
688             goto bad;
689         }
690         break;
691
692     case PERM_RUNAS:
693         state->rgid = -1;
694         state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
695         if (setegid(ID(egid))) {
696             errstr = _("unable to change to runas gid");
697             goto bad;
698         }
699         state->grlist = runas_setgroups();
700         state->ruid = -1;
701         state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
702         if (seteuid(ID(euid))) {
703             errstr = _("unable to change to runas uid");
704             goto bad;
705         }
706         break;
707
708     case PERM_SUDOERS:
709         state->grlist = ostate->grlist;
710         grlist_addref(state->grlist);
711
712         /* assume euid == ROOT_UID, ruid == user */
713         state->rgid = -1;
714         state->egid = sudoers_gid;
715         if (setegid(ID(egid)))
716             error(1, _("unable to change to sudoers gid"));
717
718         state->ruid = ROOT_UID;
719         /*
720          * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
721          * we use a non-zero uid in order to avoid NFS lossage.
722          * Using uid 1 is a bit bogus but should work on all OS's.
723          */
724         if (sudoers_uid == ROOT_UID && (sudoers_mode & 040))
725             state->euid = 1;
726         else
727             state->euid = sudoers_uid;
728         if (seteuid(ID(euid))) {
729             errstr = "seteuid(SUDOERS_UID)";
730             goto bad;
731         }
732         break;
733
734     case PERM_TIMESTAMP:
735         state->grlist = ostate->grlist;
736         grlist_addref(state->grlist);
737         state->rgid = -1;
738         state->egid = -1;
739         state->ruid = ROOT_UID;
740         state->euid = timestamp_uid;
741         if (seteuid(ID(euid))) {
742             errstr = "seteuid(timestamp_uid)";
743             goto bad;
744         }
745         break;
746     }
747
748 done:
749     perm_stack_depth++;
750     return 1;
751 bad:
752     /* XXX - better warnings inline */
753     warningx("%s: %s", errstr,
754         errno == EAGAIN ? _("too many processes") : strerror(errno));
755     if (noexit)
756         return 0;
757     exit(1);
758 }
759
760 void
761 restore_perms(void)
762 {
763     struct perm_state *state, *ostate;
764
765     if (perm_stack_depth < 2)
766         return;
767
768     state = &perm_stack[perm_stack_depth - 1];
769     ostate = &perm_stack[perm_stack_depth - 2];
770     perm_stack_depth--;
771
772     /*
773      * Since we only have setuid() and seteuid() and semantics
774      * for these calls differ on various systems, we set
775      * real and effective uids to ROOT_UID initially to be safe.
776      */
777     if (seteuid(ROOT_UID)) {
778         errstr = "seteuid(ROOT_UID)";
779         goto bad;
780     }
781     if (setuid(ROOT_UID)) {
782         errstr = "setuid(ROOT_UID)";
783         goto bad;
784     }
785
786     if (setegid(OID(egid))) {
787         warning("setegid(%d)", (int)OID(egid));
788         goto bad;
789     }
790     if (state->grlist != ostate->grlist) {
791         if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
792             warning("setgroups()");
793             goto bad;
794         }
795     }
796     if (seteuid(OID(euid))) {
797         warning("seteuid(%d)", (int)OID(euid));
798         goto bad;
799     }
800     grlist_delref(state->grlist);
801     return;
802
803 bad:
804     exit(1);
805 }
806
807 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
808
809 /*
810  * Set uids and gids based on perm via setuid() and setgid().
811  * NOTE: does not support the "stay_setuid" or timestampowner options.
812  *       Also, sudoers_uid and sudoers_gid are not used.
813  */
814 int
815 set_perms(int perm)
816 {
817     struct perm_state *state, *ostate = NULL;
818     const char *errstr;
819     int noexit;
820
821     noexit = ISSET(perm, PERM_NOEXIT);
822     CLR(perm, PERM_MASK);
823
824     if (perm_stack_depth == PERM_STACK_MAX) {
825         errstr = _("perm stack overflow");
826         errno = EINVAL;
827         goto bad;
828     }
829
830     state = &perm_stack[perm_stack_depth];
831     if (perm != PERM_INITIAL) {
832         if (perm_stack_depth == 0) {
833             errstr = _("perm stack underflow");
834             errno = EINVAL;
835             goto bad;
836         }
837         ostate = &perm_stack[perm_stack_depth - 1];
838         if (memcmp(state, ostate, sizeof(*state)) == 0)
839             goto done;
840     }
841
842     switch (perm) {
843     case PERM_INITIAL:
844         /* Stash initial state */
845         state->ruid = getuid();
846         state->rgid = getgid();
847         state->grlist = user_group_list;
848         grlist_addref(state->grlist);
849         break;
850
851     case PERM_ROOT:
852         state->ruid = ROOT_UID;
853         state->rgid = -1;
854         state->grlist = ostate->grlist;
855         grlist_addref(state->grlist);
856         if (setuid(ROOT_UID)) {
857             errstr = "setuid(ROOT_UID)";
858             goto bad;
859         }
860         break;
861
862     case PERM_FULL_USER:
863         state->rgid = user_gid;
864         (void) setgid(user_gid);
865         state->grlist = user_group_list;
866         grlist_addref(state->grlist);
867         if (state->grlist != ostate->grlist) {
868             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
869                 errstr = "setgroups()";
870                 goto bad;
871             }
872         }
873         state->ruid = user_uid;
874         if (setuid(user_uid)) {
875             errstr = "setuid(user_uid)";
876             goto bad;
877         }
878         break;
879
880     case PERM_USER:
881     case PERM_SUDOERS:
882     case PERM_RUNAS:
883     case PERM_TIMESTAMP:
884         /* Unsupported since we can't set euid. */
885         break;
886     }
887
888 done:
889     perm_stack_depth++;
890     return 1;
891 bad:
892     /* XXX - better warnings inline */
893     warningx("%s: %s", errstr,
894         errno == EAGAIN ? _("too many processes") : strerror(errno));
895     if (noexit)
896         return 0;
897     exit(1);
898 }
899
900 void
901 restore_perms(void)
902 {
903     struct perm_state *state, *ostate;
904
905     if (perm_stack_depth < 2)
906         return;
907
908     state = &perm_stack[perm_stack_depth - 1];
909     ostate = &perm_stack[perm_stack_depth - 2];
910     perm_stack_depth--;
911
912     if (OID(rgid) != -1 && setgid(ostate->rgid)) {
913         warning("setgid(%d)", (int)ostate->rgid);
914         goto bad;
915     }
916     if (state->grlist != ostate->grlist) {
917         if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
918             warning("setgroups()");
919             goto bad;
920         }
921     }
922     grlist_delref(state->grlist);
923     if (OID(ruid) != -1 && setuid(ostate->ruid)) {
924         warning("setuid(%d)", (int)ostate->ruid);
925         goto bad;
926     }
927     return;
928
929 bad:
930     exit(1);
931 }
932 #  endif /* HAVE_SETEUID */
933 # endif /* HAVE_SETREUID */
934 #endif /* HAVE_SETRESUID */
935
936 static struct group_list *
937 runas_setgroups(void)
938 {
939     struct passwd *pw;
940     struct group_list *grlist;
941
942     if (def_preserve_groups) {
943         grlist_addref(user_group_list);
944         return user_group_list;
945     }
946
947     pw = runas_pw ? runas_pw : sudo_user.pw;
948 #ifdef HAVE_SETAUTHDB
949     aix_setauthdb(pw->pw_name);
950 #endif
951     grlist = get_group_list(pw);
952 #ifdef HAVE_SETAUTHDB
953     aix_restoreauthdb();
954 #endif
955     if (sudo_setgroups(grlist->ngids, grlist->gids) < 0)
956         log_error(USE_ERRNO|MSG_ONLY, _("unable to set runas group vector"));
957     return grlist;
958 }