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