be665dae326791cafc4aa45858d1b07caa49ea17
[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 #ifdef _AIX
45 # include <sys/id.h>
46 #endif
47 #include <pwd.h>
48 #include <errno.h>
49 #include <grp.h>
50
51 #include "sudoers.h"
52
53 /*
54  * Prototypes
55  */
56 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID)
57 static struct group_list *runas_setgroups(void);
58 #endif
59
60 /*
61  * We keep track of the current permisstions and use a stack to restore
62  * the old permissions.  A depth of 16 is overkill.
63  */
64 struct perm_state {
65     uid_t ruid;
66     uid_t euid;
67 #if defined(HAVE_SETRESUID) || defined(ID_SAVED)
68     uid_t suid;
69 #endif
70     gid_t rgid;
71     gid_t egid;
72 #if defined(HAVE_SETRESUID) || defined(ID_SAVED)
73     gid_t sgid;
74 #endif
75     struct group_list *grlist;
76 };
77
78 #define PERM_STACK_MAX  16
79 static struct perm_state perm_stack[PERM_STACK_MAX];
80 static int perm_stack_depth = 0;
81
82 #undef ID
83 #define ID(x) (state->x == ostate->x ? -1 : state->x)
84 #undef OID
85 #define OID(x) (ostate->x == state->x ? -1 : ostate->x)
86
87 void
88 rewind_perms(void)
89 {
90     debug_decl(rewind_perms, SUDO_DEBUG_PERMS)
91
92     while (perm_stack_depth > 1)
93         restore_perms();
94     sudo_grlist_delref(perm_stack[0].grlist);
95
96     debug_return;
97 }
98
99 #if defined(HAVE_SETRESUID)
100
101 #define UID_CHANGED (state->ruid != ostate->ruid || state->euid != ostate->euid || state->suid != ostate->suid)
102 #define GID_CHANGED (state->rgid != ostate->rgid || state->egid != ostate->egid || state->sgid != ostate->sgid)
103
104 /*
105  * Set real and effective and saved uids and gids based on perm.
106  * We always retain a saved uid of 0 unless we are headed for an exec().
107  * We only flip the effective gid since it only changes for PERM_SUDOERS.
108  * This version of set_perms() works fine with the "stay_setuid" option.
109  */
110 int
111 set_perms(int perm)
112 {
113     struct perm_state *state, *ostate = NULL;
114     char errbuf[1024];
115     int noexit;
116     debug_decl(set_perms, SUDO_DEBUG_PERMS)
117
118     noexit = ISSET(perm, PERM_NOEXIT);
119     CLR(perm, PERM_MASK);
120
121     if (perm_stack_depth == PERM_STACK_MAX) {
122         strlcpy(errbuf, _("perm stack overflow"), sizeof(errbuf));
123         errno = EINVAL;
124         goto bad;
125     }
126
127     state = &perm_stack[perm_stack_depth];
128     if (perm != PERM_INITIAL) {
129         if (perm_stack_depth == 0) {
130             strlcpy(errbuf, _("perm stack underflow"), sizeof(errbuf));
131             errno = EINVAL;
132             goto bad;
133         }
134         ostate = &perm_stack[perm_stack_depth - 1];
135     }
136
137     switch (perm) {
138     case PERM_INITIAL:
139         /* Stash initial state */
140 #ifdef HAVE_GETRESUID
141         if (getresuid(&state->ruid, &state->euid, &state->suid)) {
142             strlcpy(errbuf, "PERM_INITIAL: getresuid", sizeof(errbuf));
143             goto bad;
144
145         }
146         if (getresgid(&state->rgid, &state->egid, &state->sgid)) {
147             strlcpy(errbuf, "PERM_INITIAL: getresgid", sizeof(errbuf));
148             goto bad;
149         }
150 #else
151         state->ruid = getuid();
152         state->euid = geteuid();
153         state->suid = state->euid; /* in case we are setuid */
154
155         state->rgid = getgid();
156         state->egid = getegid();
157         state->sgid = state->egid; /* in case we are setgid */
158 #endif
159         state->grlist = user_group_list;
160         sudo_grlist_addref(state->grlist);
161         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_INITIAL: "
162             "ruid: %d, euid: %d, suid: %d, rgid: %d, egid: %d, sgid: %d",
163             __func__, (int)state->ruid, (int)state->euid, (int)state->suid,
164             (int)state->rgid, (int)state->egid, (int)state->sgid);
165         break;
166
167     case PERM_ROOT:
168         state->ruid = ROOT_UID;
169         state->euid = ROOT_UID;
170         state->suid = ROOT_UID;
171         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: "
172             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
173             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
174             (int)state->ruid, (int)state->euid, (int)state->suid);
175         if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) {
176             snprintf(errbuf, sizeof(errbuf),
177                 "PERM_ROOT: setresuid(%d, %d, %d)",
178                 ID(ruid), ID(euid), ID(suid));
179             goto bad;
180         }
181         state->rgid = ostate->rgid;
182         state->egid = ostate->egid;
183         state->sgid = ostate->sgid;
184         state->grlist = ostate->grlist;
185         sudo_grlist_addref(state->grlist);
186         break;
187
188     case PERM_USER:
189         state->rgid = ostate->rgid;
190         state->egid = user_gid;
191         state->sgid = ostate->sgid;
192         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: gid: "
193             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
194             (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
195             (int)state->rgid, (int)state->egid, (int)state->sgid);
196         if (GID_CHANGED && setresgid(ID(rgid), ID(egid), ID(sgid))) {
197             snprintf(errbuf, sizeof(errbuf), "PERM_USER: setresgid(%d, %d, %d)",
198                 ID(rgid), ID(egid), ID(sgid));
199             goto bad;
200         }
201         state->grlist = user_group_list;
202         sudo_grlist_addref(state->grlist);
203         if (state->grlist != ostate->grlist) {
204             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
205                 strlcpy(errbuf, "PERM_USER: setgroups", sizeof(errbuf));
206                 goto bad;
207             }
208         }
209         state->ruid = user_uid;
210         state->euid = user_uid;
211         state->suid = ROOT_UID;
212         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: uid: "
213             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
214             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
215             (int)state->ruid, (int)state->euid, (int)state->suid);
216         if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) {
217             snprintf(errbuf, sizeof(errbuf), "PERM_USER: setresuid(%d, %d, %d)",
218                 ID(ruid), ID(euid), ID(suid));
219             goto bad;
220         }
221         break;
222
223     case PERM_FULL_USER:
224         /* headed for exec() */
225         state->rgid = user_gid;
226         state->egid = user_gid;
227         state->sgid = user_gid;
228         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: gid: "
229             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
230             (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
231             (int)state->rgid, (int)state->egid, (int)state->sgid);
232         if (GID_CHANGED && setresgid(ID(rgid), ID(egid), ID(sgid))) {
233             snprintf(errbuf, sizeof(errbuf),
234                 "PERM_FULL_USER: setresgid(%d, %d, %d)",
235                 ID(rgid), ID(egid), ID(sgid));
236             goto bad;
237         }
238         state->grlist = user_group_list;
239         sudo_grlist_addref(state->grlist);
240         if (state->grlist != ostate->grlist) {
241             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
242                 strlcpy(errbuf, "PERM_FULL_USER: setgroups", sizeof(errbuf));
243                 goto bad;
244             }
245         }
246         state->ruid = user_uid;
247         state->euid = user_uid;
248         state->suid = user_uid;
249         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: uid: "
250             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
251             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
252             (int)state->ruid, (int)state->euid, (int)state->suid);
253         if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) {
254             snprintf(errbuf, sizeof(errbuf),
255                 "PERM_FULL_USER: setresuid(%d, %d, %d)",
256                 ID(ruid), ID(euid), ID(suid));
257             goto bad;
258         }
259         break;
260
261     case PERM_RUNAS:
262         state->rgid = ostate->rgid;
263         state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
264         state->sgid = ostate->sgid;
265         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: gid: "
266             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
267             (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
268             (int)state->rgid, (int)state->egid, (int)state->sgid);
269         if (GID_CHANGED && setresgid(ID(rgid), ID(egid), ID(sgid))) {
270             strlcpy(errbuf, _("unable to change to runas gid"), sizeof(errbuf));
271             goto bad;
272         }
273         state->grlist = runas_setgroups();
274         state->ruid = ostate->ruid;
275         state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
276         state->suid = ostate->suid;
277         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: uid: "
278             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
279             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
280             (int)state->ruid, (int)state->euid, (int)state->suid);
281         if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) {
282             strlcpy(errbuf, _("unable to change to runas uid"), sizeof(errbuf));
283             goto bad;
284         }
285         break;
286
287     case PERM_SUDOERS:
288         state->grlist = ostate->grlist;
289         sudo_grlist_addref(state->grlist);
290
291         /* assumes euid == ROOT_UID, ruid == user */
292         state->rgid = ostate->rgid;
293         state->egid = sudoers_gid;
294         state->sgid = ostate->sgid;
295         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: gid: "
296             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
297             (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
298             (int)state->rgid, (int)state->egid, (int)state->sgid);
299         if (GID_CHANGED && setresgid(ID(rgid), ID(egid), ID(sgid))) {
300             strlcpy(errbuf, _("unable to change to sudoers gid"), sizeof(errbuf));
301             goto bad;
302         }
303
304         state->ruid = ROOT_UID;
305         /*
306          * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
307          * we use a non-zero uid in order to avoid NFS lossage.
308          * Using uid 1 is a bit bogus but should work on all OS's.
309          */
310         if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP))
311             state->euid = 1;
312         else
313             state->euid = sudoers_uid;
314         state->suid = ROOT_UID;
315         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: uid: "
316             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
317             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
318             (int)state->ruid, (int)state->euid, (int)state->suid);
319         if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) {
320             snprintf(errbuf, sizeof(errbuf),
321                 "PERM_SUDOERS: setresuid(%d, %d, %d)",
322                 ID(ruid), ID(euid), ID(suid));
323             goto bad;
324         }
325         break;
326
327     case PERM_TIMESTAMP:
328         state->grlist = ostate->grlist;
329         sudo_grlist_addref(state->grlist);
330         state->rgid = ostate->rgid;
331         state->egid = ostate->egid;
332         state->sgid = ostate->sgid;
333         state->ruid = ROOT_UID;
334         state->euid = timestamp_uid;
335         state->suid = ROOT_UID;
336         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_TIMESTAMP: uid: "
337             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
338             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
339             (int)state->ruid, (int)state->euid, (int)state->suid);
340         if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) {
341             snprintf(errbuf, sizeof(errbuf),
342                 "PERM_TIMESTAMP: setresuid(%d, %d, %d)",
343                 ID(ruid), ID(euid), ID(suid));
344             goto bad;
345         }
346         break;
347     }
348
349     perm_stack_depth++;
350     debug_return_bool(1);
351 bad:
352     warningx("%s: %s", errbuf,
353         errno == EAGAIN ? _("too many processes") : strerror(errno));
354     if (noexit)
355         debug_return_bool(0);
356     exit(1);
357 }
358
359 void
360 restore_perms(void)
361 {
362     struct perm_state *state, *ostate;
363     debug_decl(restore_perms, SUDO_DEBUG_PERMS)
364
365     if (perm_stack_depth < 2)
366         debug_return;
367
368     state = &perm_stack[perm_stack_depth - 1];
369     ostate = &perm_stack[perm_stack_depth - 2];
370     perm_stack_depth--;
371
372     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: uid: [%d, %d, %d] -> [%d, %d, %d]",
373         __func__, (int)state->ruid, (int)state->euid, (int)state->suid,
374         (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid);
375     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: gid: [%d, %d, %d] -> [%d, %d, %d]",
376         __func__, (int)state->rgid, (int)state->egid, (int)state->sgid,
377         (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid);
378
379     /* XXX - more cases here where euid != ruid */
380     if (OID(euid) == ROOT_UID) {
381         if (setresuid(-1, ROOT_UID, -1)) {
382             warning("setresuid() [%d, %d, %d] -> [%d, %d, %d]",
383                 (int)state->ruid, (int)state->euid, (int)state->suid,
384                 -1, ROOT_UID, -1);
385             goto bad;
386         }
387     }
388     if (setresuid(OID(ruid), OID(euid), OID(suid))) {
389         warning("setresuid() [%d, %d, %d] -> [%d, %d, %d]",
390             (int)state->ruid, (int)state->euid, (int)state->suid,
391             (int)OID(ruid), (int)OID(euid), (int)OID(suid));
392         goto bad;
393     }
394     if (setresgid(OID(rgid), OID(egid), OID(sgid))) {
395         warning("setresgid() [%d, %d, %d] -> [%d, %d, %d]",
396             (int)state->rgid, (int)state->egid, (int)state->sgid,
397             (int)OID(rgid), (int)OID(egid), (int)OID(sgid));
398         goto bad;
399     }
400     if (state->grlist != ostate->grlist) {
401         if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
402             warning("setgroups()");
403             goto bad;
404         }
405     }
406     sudo_grlist_delref(state->grlist);
407     debug_return;
408
409 bad:
410     exit(1);
411 }
412
413 #elif defined(_AIX) && defined(ID_SAVED)
414
415 #define UID_CHANGED (state->ruid != ostate->ruid || state->euid != ostate->euid || state->suid != ostate->suid)
416 #define GID_CHANGED (state->rgid != ostate->rgid || state->egid != ostate->egid || state->sgid != ostate->sgid)
417
418 /*
419  * Set real and effective and saved uids and gids based on perm.
420  * We always retain a saved uid of 0 unless we are headed for an exec().
421  * We only flip the effective gid since it only changes for PERM_SUDOERS.
422  * This version of set_perms() works fine with the "stay_setuid" option.
423  */
424 int
425 set_perms(int perm)
426 {
427     struct perm_state *state, *ostate = NULL;
428     char errbuf[1024];
429     int noexit;
430     debug_decl(set_perms, SUDO_DEBUG_PERMS)
431
432     noexit = ISSET(perm, PERM_NOEXIT);
433     CLR(perm, PERM_MASK);
434
435     if (perm_stack_depth == PERM_STACK_MAX) {
436         strlcpy(errbuf, _("perm stack overflow"), sizeof(errbuf));
437         errno = EINVAL;
438         goto bad;
439     }
440
441     state = &perm_stack[perm_stack_depth];
442     if (perm != PERM_INITIAL) {
443         if (perm_stack_depth == 0) {
444             strlcpy(errbuf, _("perm stack underflow"), sizeof(errbuf));
445             errno = EINVAL;
446             goto bad;
447         }
448         ostate = &perm_stack[perm_stack_depth - 1];
449     }
450
451     switch (perm) {
452     case PERM_INITIAL:
453         /* Stash initial state */
454         state->ruid = getuidx(ID_REAL);
455         state->euid = getuidx(ID_EFFECTIVE);
456         state->suid = getuidx(ID_SAVED);
457         state->rgid = getgidx(ID_REAL);
458         state->egid = getgidx(ID_EFFECTIVE);
459         state->sgid = getgidx(ID_SAVED);
460         state->grlist = user_group_list;
461         sudo_grlist_addref(state->grlist);
462         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_INITIAL: "
463             "ruid: %d, euid: %d, suid: %d, rgid: %d, egid: %d, sgid: %d",
464             __func__, (unsigned int)state->ruid, (unsigned int)state->euid,
465             (unsigned int)state->suid, (unsigned int)state->rgid,
466             (unsigned int)state->egid, (unsigned int)state->sgid);
467         break;
468
469     case PERM_ROOT:
470         state->ruid = ROOT_UID;
471         state->euid = ROOT_UID;
472         state->suid = ROOT_UID;
473         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: "
474             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
475             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
476             (int)state->ruid, (int)state->euid, (int)state->suid);
477         if (UID_CHANGED && setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID)) {
478             snprintf(errbuf, sizeof(errbuf),
479                 "PERM_ROOT: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)",
480                 ROOT_UID);
481             goto bad;
482         }
483         state->rgid = ostate->rgid;
484         state->egid = ostate->egid;
485         state->sgid = ostate->sgid;
486         state->grlist = ostate->grlist;
487         sudo_grlist_addref(state->grlist);
488         break;
489
490     case PERM_USER:
491         state->rgid = ostate->rgid;
492         state->egid = user_gid;
493         state->sgid = ostate->sgid;
494         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: gid: "
495             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
496             (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
497             (int)state->rgid, (int)state->egid, (int)state->sgid);
498         if (GID_CHANGED && setgidx(ID_EFFECTIVE, user_gid)) {
499             snprintf(errbuf, sizeof(errbuf),
500                 "PERM_USER: setgidx(ID_EFFECTIVE, %d)", user_gid);
501             goto bad;
502         }
503         state->grlist = user_group_list;
504         sudo_grlist_addref(state->grlist);
505         if (state->grlist != ostate->grlist) {
506             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
507                 strlcpy(errbuf, "PERM_USER: setgroups", sizeof(errbuf));
508                 goto bad;
509             }
510         }
511         state->ruid = user_uid;
512         state->euid = user_uid;
513         state->suid = ROOT_UID;
514         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: uid: "
515             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
516             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
517             (int)state->ruid, (int)state->euid, (int)state->suid);
518         if (ostate->euid != ROOT_UID || ostate->suid != ROOT_UID) {
519             if (setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID)) {
520                 snprintf(errbuf, sizeof(errbuf),
521                     "PERM_USER: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)",
522                     ROOT_UID);
523                 goto bad;
524             }
525         }
526         if (setuidx(ID_EFFECTIVE|ID_REAL, user_uid)) {
527             snprintf(errbuf, sizeof(errbuf),
528                 "PERM_USER: setuidx(ID_EFFECTIVE|ID_REAL, %d)", user_uid);
529             goto bad;
530         }
531         break;
532
533     case PERM_FULL_USER:
534         /* headed for exec() */
535         state->rgid = user_gid;
536         state->egid = user_gid;
537         state->sgid = user_gid;
538         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: gid: "
539             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
540             (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
541             (int)state->rgid, (int)state->egid, (int)state->sgid);
542         if (GID_CHANGED && setgidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, user_gid)) {
543             snprintf(errbuf, sizeof(errbuf),
544                 "PERM_FULL_USER: setgidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)",
545                 user_gid);
546             goto bad;
547         }
548         state->grlist = user_group_list;
549         sudo_grlist_addref(state->grlist);
550         if (state->grlist != ostate->grlist) {
551             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
552                 strlcpy(errbuf, "PERM_FULL_USER: setgroups", sizeof(errbuf));
553                 goto bad;
554             }
555         }
556         state->ruid = user_uid;
557         state->euid = user_uid;
558         state->suid = user_uid;
559         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: uid: "
560             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
561             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
562             (int)state->ruid, (int)state->euid, (int)state->suid);
563         if (UID_CHANGED && setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, user_uid)) {
564             snprintf(errbuf, sizeof(errbuf),
565                 "PERM_FULL_USER: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)",
566                 user_uid);
567             goto bad;
568         }
569         break;
570
571     case PERM_RUNAS:
572         state->rgid = ostate->rgid;
573         state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
574         state->sgid = ostate->sgid;
575         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: gid: "
576             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
577             (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
578             (int)state->rgid, (int)state->egid, (int)state->sgid);
579         if (GID_CHANGED && setgidx(ID_EFFECTIVE, state->egid)) {
580             strlcpy(errbuf, _("unable to change to runas gid"), sizeof(errbuf));
581             goto bad;
582         }
583         state->grlist = runas_setgroups();
584         state->ruid = ostate->ruid;
585         state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
586         state->suid = ostate->suid;
587         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: uid: "
588             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
589             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
590             (int)state->ruid, (int)state->euid, (int)state->suid);
591         if (UID_CHANGED && setuidx(ID_EFFECTIVE, state->euid)) {
592             strlcpy(errbuf, _("unable to change to runas uid"), sizeof(errbuf));
593             goto bad;
594         }
595         break;
596
597     case PERM_SUDOERS:
598         state->grlist = ostate->grlist;
599         sudo_grlist_addref(state->grlist);
600
601         /* assume euid == ROOT_UID, ruid == user */
602         state->rgid = ostate->rgid;
603         state->egid = sudoers_gid;
604         state->sgid = ostate->sgid;
605         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: gid: "
606             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
607             (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
608             (int)state->rgid, (int)state->egid, (int)state->sgid);
609         if (GID_CHANGED && setgidx(ID_EFFECTIVE, sudoers_gid)) {
610             strlcpy(errbuf, _("unable to change to sudoers gid"), sizeof(errbuf));
611             goto bad;
612         }
613
614         state->ruid = ROOT_UID;
615         /*
616          * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
617          * we use a non-zero uid in order to avoid NFS lossage.
618          * Using uid 1 is a bit bogus but should work on all OS's.
619          */
620         if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP))
621             state->euid = 1;
622         else
623             state->euid = sudoers_uid;
624         state->suid = ROOT_UID;
625         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: uid: "
626             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
627             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
628             (int)state->ruid, (int)state->euid, (int)state->suid);
629         if (UID_CHANGED) {
630             if (ostate->ruid != ROOT_UID || ostate->suid != ROOT_UID) {
631                 if (setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID)) {
632                     snprintf(errbuf, sizeof(errbuf),
633                         "PERM_SUDOERS: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)",
634                         ROOT_UID);
635                     goto bad;
636                 }
637             }
638             if (setuidx(ID_EFFECTIVE, state->euid)) {
639                 snprintf(errbuf, sizeof(errbuf),
640                     "PERM_SUDOERS: setuidx(ID_EFFECTIVE, %d)", sudoers_uid);
641                 goto bad;
642             }
643         }
644         break;
645
646     case PERM_TIMESTAMP:
647         state->grlist = ostate->grlist;
648         sudo_grlist_addref(state->grlist);
649         state->rgid = ostate->rgid;
650         state->egid = ostate->egid;
651         state->sgid = ostate->sgid;
652         state->ruid = ROOT_UID;
653         state->euid = timestamp_uid;
654         state->suid = ROOT_UID;
655         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_TIMESTAMP: uid: "
656             "[%d, %d, %d] -> [%d, %d, %d]", __func__,
657             (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
658             (int)state->ruid, (int)state->euid, (int)state->suid);
659         if (UID_CHANGED) {
660             if (ostate->ruid != ROOT_UID || ostate->suid != ROOT_UID) {
661                 if (setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID)) {
662                     snprintf(errbuf, sizeof(errbuf),
663                         "PERM_TIMESTAMP: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)",
664                         ROOT_UID);
665                     goto bad;
666                 }
667             }
668             if (setuidx(ID_EFFECTIVE, timestamp_uid)) {
669                 snprintf(errbuf, sizeof(errbuf),
670                     "PERM_TIMESTAMP: setuidx(ID_EFFECTIVE, %d)", timestamp_uid);
671                 goto bad;
672             }
673         }
674         break;
675     }
676
677     perm_stack_depth++;
678     debug_return_bool(1);
679 bad:
680     warningx("%s: %s", errbuf,
681         errno == EAGAIN ? _("too many processes") : strerror(errno));
682     if (noexit)
683         debug_return_bool(0);
684     exit(1);
685 }
686
687 void
688 restore_perms(void)
689 {
690     struct perm_state *state, *ostate;
691     debug_decl(restore_perms, SUDO_DEBUG_PERMS)
692
693     if (perm_stack_depth < 2)
694         debug_return;
695
696     state = &perm_stack[perm_stack_depth - 1];
697     ostate = &perm_stack[perm_stack_depth - 2];
698     perm_stack_depth--;
699
700     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: uid: [%d, %d, %d] -> [%d, %d, %d]",
701         __func__, (int)state->ruid, (int)state->euid, (int)state->suid,
702         (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid);
703     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: gid: [%d, %d, %d] -> [%d, %d, %d]",
704         __func__, (int)state->rgid, (int)state->egid, (int)state->sgid,
705         (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid);
706
707     if (OID(ruid) != -1 || OID(euid) != -1 || OID(suid) != -1) {
708         if (OID(euid) == ROOT_UID) {
709             sudo_debug_printf(SUDO_DEBUG_INFO, "%s: setuidx(ID_EFFECTIVE, %d)",
710                 __func__, ROOT_UID);
711             if (setuidx(ID_EFFECTIVE, ROOT_UID)) {
712                 warning("setuidx(ID_EFFECTIVE) [%d, %d, %d] -> [%d, %d, %d]",
713                     (int)state->ruid, (int)state->euid, (int)state->suid,
714                     -1, ROOT_UID, -1);
715                 goto bad;
716             }
717         }
718         if (OID(ruid) == OID(euid) && OID(euid) == OID(suid)) {
719             sudo_debug_printf(SUDO_DEBUG_INFO,
720                 "%s: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)",
721                 __func__, OID(ruid));
722             if (setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, OID(ruid))) {
723                 warning("setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED) [%d, %d, %d] -> [%d, %d, %d]",
724                     (int)state->ruid, (int)state->euid, (int)state->suid,
725                     (int)OID(ruid), (int)OID(euid), (int)OID(suid));
726                 goto bad;
727             }
728         } else if (OID(ruid) == -1 && OID(suid) == -1) {
729             /* May have already changed euid to ROOT_UID above. */
730             if (OID(euid) != ROOT_UID) {
731                 sudo_debug_printf(SUDO_DEBUG_INFO,
732                     "%s: setuidx(ID_EFFECTIVE, %d)", __func__, OID(euid));
733                 if (setuidx(ID_EFFECTIVE, OID(euid))) {
734                     warning("setuidx(ID_EFFECTIVE) [%d, %d, %d] -> [%d, %d, %d]",
735                         (int)state->ruid, (int)state->euid, (int)state->suid,
736                         (int)OID(ruid), (int)OID(euid), (int)OID(suid));
737                     goto bad;
738                 }
739             }
740         } else if (OID(suid) == -1) {
741             /* Cannot set the real uid alone. */
742             sudo_debug_printf(SUDO_DEBUG_INFO,
743                 "%s: setuidx(ID_REAL|ID_EFFECTIVE, %d)", __func__, OID(ruid));
744             if (setuidx(ID_REAL|ID_EFFECTIVE, OID(ruid))) {
745                 warning("setuidx(ID_REAL|ID_EFFECTIVE) [%d, %d, %d] -> [%d, %d, %d]",
746                     (int)state->ruid, (int)state->euid, (int)state->suid,
747                     (int)OID(ruid), (int)OID(euid), (int)OID(suid));
748                 goto bad;
749             }
750             /* Restore the effective euid if it doesn't match the ruid. */
751             if (OID(euid) != OID(ruid)) {
752                 sudo_debug_printf(SUDO_DEBUG_INFO,
753                     "%s: setuidx(ID_EFFECTIVE, %d)", __func__, ostate->euid);
754                 if (setuidx(ID_EFFECTIVE, ostate->euid)) {
755                     warning("setuidx(ID_EFFECTIVE, %d)", ostate->euid);
756                     goto bad;
757                 }
758             }
759         }
760     }
761     if (OID(rgid) != -1 || OID(egid) != -1 || OID(sgid) != -1) {
762         if (OID(rgid) == OID(egid) && OID(egid) == OID(sgid)) {
763             sudo_debug_printf(SUDO_DEBUG_INFO,
764                 "%s: setgidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)",
765                 __func__, OID(rgid));
766             if (setgidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, OID(rgid))) {
767                 warning("setgidx(ID_EFFECTIVE|ID_REAL|ID_SAVED) [%d, %d, %d] -> [%d, %d, %d]",
768                     (int)state->rgid, (int)state->egid, (int)state->sgid,
769                     (int)OID(rgid), (int)OID(egid), (int)OID(sgid));
770                 goto bad;
771             }
772         } else if (OID(rgid) == -1 && OID(sgid) == -1) {
773             sudo_debug_printf(SUDO_DEBUG_INFO, "%s: setgidx(ID_EFFECTIVE, %d)",
774                 __func__, OID(egid));
775             if (setgidx(ID_EFFECTIVE, OID(egid))) {
776                 warning("setgidx(ID_EFFECTIVE) [%d, %d, %d] -> [%d, %d, %d]",
777                     (int)state->rgid, (int)state->egid, (int)state->sgid,
778                     (int)OID(rgid), (int)OID(egid), (int)OID(sgid));
779                 goto bad;
780             }
781         } else if (OID(sgid) == -1) {
782             sudo_debug_printf(SUDO_DEBUG_INFO,
783                 "%s: setgidx(ID_EFFECTIVE|ID_REAL, %d)", __func__, OID(rgid));
784             if (setgidx(ID_REAL|ID_EFFECTIVE, OID(rgid))) {
785                 warning("setgidx(ID_REAL|ID_EFFECTIVE) [%d, %d, %d] -> [%d, %d, %d]",
786                     (int)state->rgid, (int)state->egid, (int)state->sgid,
787                     (int)OID(rgid), (int)OID(egid), (int)OID(sgid));
788                 goto bad;
789             }
790         }
791     }
792     if (state->grlist != ostate->grlist) {
793         if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
794             warning("setgroups()");
795             goto bad;
796         }
797     }
798     sudo_grlist_delref(state->grlist);
799     debug_return;
800
801 bad:
802     exit(1);
803 }
804
805 #elif defined(HAVE_SETREUID)
806
807 #define UID_CHANGED (state->ruid != ostate->ruid || state->euid != ostate->euid)
808 #define GID_CHANGED (state->rgid != ostate->rgid || state->egid != ostate->egid)
809
810 /*
811  * Set real and effective and saved uids and gids based on perm.
812  * We always retain a saved uid of 0 unless we are headed for an exec().
813  * We only flip the effective gid since it only changes for PERM_SUDOERS.
814  * This version of set_perms() works fine with the "stay_setuid" option.
815  */
816 int
817 set_perms(int perm)
818 {
819     struct perm_state *state, *ostate = NULL;
820     char errbuf[1024];
821     int noexit;
822     debug_decl(set_perms, SUDO_DEBUG_PERMS)
823
824     noexit = ISSET(perm, PERM_NOEXIT);
825     CLR(perm, PERM_MASK);
826
827     if (perm_stack_depth == PERM_STACK_MAX) {
828         strlcpy(errbuf, _("perm stack overflow"), sizeof(errbuf));
829         errno = EINVAL;
830         goto bad;
831     }
832
833     state = &perm_stack[perm_stack_depth];
834     if (perm != PERM_INITIAL) {
835         if (perm_stack_depth == 0) {
836             strlcpy(errbuf, _("perm stack underflow"), sizeof(errbuf));
837             errno = EINVAL;
838             goto bad;
839         }
840         ostate = &perm_stack[perm_stack_depth - 1];
841     }
842
843     switch (perm) {
844     case PERM_INITIAL:
845         /* Stash initial state */
846         state->ruid = getuid();
847         state->euid = geteuid();
848         state->rgid = getgid();
849         state->egid = getegid();
850         state->grlist = user_group_list;
851         sudo_grlist_addref(state->grlist);
852         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_INITIAL: "
853             "ruid: %d, euid: %d, rgid: %d, egid: %d", __func__,
854             (int)state->ruid, (int)state->euid,
855             (int)state->rgid, (int)state->egid);
856         break;
857
858     case PERM_ROOT:
859         state->ruid = ROOT_UID;
860         state->euid = ROOT_UID;
861         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: "
862             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
863             (int)ostate->euid, (int)state->ruid, (int)state->euid);
864         /*
865          * setreuid(0, 0) may fail on some systems if euid is not already 0.
866          */
867         if (ostate->euid != ROOT_UID) {
868             if (setreuid(-1, ROOT_UID)) {
869                 snprintf(errbuf, sizeof(errbuf),
870                     "PERM_ROOT: setreuid(-1, %d)", PERM_ROOT);
871                 goto bad;
872             }
873         }
874         if (ostate->ruid != ROOT_UID) {
875             if (setreuid(ROOT_UID, -1)) {
876                 snprintf(errbuf, sizeof(errbuf),
877                     "PERM_ROOT: setreuid(%d, -1)", ROOT_UID);
878                 goto bad;
879             }
880         }
881         state->rgid = ostate->rgid;
882         state->egid = ostate->rgid;
883         state->grlist = ostate->grlist;
884         sudo_grlist_addref(state->grlist);
885         break;
886
887     case PERM_USER:
888         state->rgid = ostate->rgid;
889         state->egid = user_gid;
890         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: gid: "
891             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
892             (int)ostate->egid, (int)state->rgid, (int)state->egid);
893         if (GID_CHANGED && setregid(ID(rgid), ID(egid))) {
894             snprintf(errbuf, sizeof(errbuf),
895                 "PERM_USER: setregid(%d, %d)", ID(rgid), ID(egid));
896             goto bad;
897         }
898         state->grlist = user_group_list;
899         sudo_grlist_addref(state->grlist);
900         if (state->grlist != ostate->grlist) {
901             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
902                 strlcpy(errbuf, "PERM_USER: setgroups", sizeof(errbuf));
903                 goto bad;
904             }
905         }
906         state->ruid = ROOT_UID;
907         state->euid = user_uid;
908         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: uid: "
909             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
910             (int)ostate->euid, (int)state->ruid, (int)state->euid);
911         if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) {
912             snprintf(errbuf, sizeof(errbuf),
913                 "PERM_USER: setreuid(%d, %d)", ID(ruid), ID(euid));
914             goto bad;
915         }
916         break;
917
918     case PERM_FULL_USER:
919         /* headed for exec() */
920         state->rgid = user_gid;
921         state->egid = user_gid;
922         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: gid: "
923             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
924             (int)ostate->egid, (int)state->rgid, (int)state->egid);
925         if (GID_CHANGED && setregid(ID(rgid), ID(egid))) {
926             snprintf(errbuf, sizeof(errbuf),
927                 "PERM_FULL_USER: setregid(%d, %d)", ID(rgid), ID(egid));
928             goto bad;
929         }
930         state->grlist = user_group_list;
931         sudo_grlist_addref(state->grlist);
932         if (state->grlist != ostate->grlist) {
933             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
934                 strlcpy(errbuf, "PERM_FULL_USER: setgroups", sizeof(errbuf));
935                 goto bad;
936             }
937         }
938         state->ruid = user_uid;
939         state->euid = user_uid;
940         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: uid: "
941             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
942             (int)ostate->euid, (int)state->ruid, (int)state->euid);
943         if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) {
944             snprintf(errbuf, sizeof(errbuf),
945                 "PERM_FULL_USER: setreuid(%d, %d)", ID(ruid), ID(euid));
946             goto bad;
947         }
948         break;
949
950     case PERM_RUNAS:
951         state->rgid = ostate->rgid;
952         state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
953         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: gid: "
954             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
955             (int)ostate->egid, (int)state->rgid, (int)state->egid);
956         if (GID_CHANGED && setregid(ID(rgid), ID(egid))) {
957             strlcpy(errbuf, _("unable to change to runas gid"), sizeof(errbuf));
958             goto bad;
959         }
960         state->grlist = runas_setgroups();
961         state->ruid = ROOT_UID;
962         state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
963         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: uid: "
964             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
965             (int)ostate->euid, (int)state->ruid, (int)state->euid);
966         if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) {
967             strlcpy(errbuf, _("unable to change to runas uid"), sizeof(errbuf));
968             goto bad;
969         }
970         break;
971
972     case PERM_SUDOERS:
973         state->grlist = ostate->grlist;
974         sudo_grlist_addref(state->grlist);
975
976         /* assume euid == ROOT_UID, ruid == user */
977         state->rgid = ostate->rgid;
978         state->egid = sudoers_gid;
979         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: gid: "
980             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
981             (int)ostate->egid, (int)state->rgid, (int)state->egid);
982         if (GID_CHANGED && setregid(ID(rgid), ID(egid))) {
983             strlcpy(errbuf, _("unable to change to sudoers gid"), sizeof(errbuf));
984             goto bad;
985         }
986
987         state->ruid = ROOT_UID;
988         /*
989          * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
990          * we use a non-zero uid in order to avoid NFS lossage.
991          * Using uid 1 is a bit bogus but should work on all OS's.
992          */
993         if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP))
994             state->euid = 1;
995         else
996             state->euid = sudoers_uid;
997         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: uid: "
998             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
999             (int)ostate->euid, (int)state->ruid, (int)state->euid);
1000         if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) {
1001             snprintf(errbuf, sizeof(errbuf),
1002                 "PERM_SUDOERS: setreuid(%d, %d)", ID(ruid), ID(euid));
1003             goto bad;
1004         }
1005         break;
1006
1007     case PERM_TIMESTAMP:
1008         state->grlist = ostate->grlist;
1009         sudo_grlist_addref(state->grlist);
1010         state->rgid = ostate->rgid;
1011         state->egid = ostate->egid;
1012         state->ruid = ROOT_UID;
1013         state->euid = timestamp_uid;
1014         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_TIMESTAMP: uid: "
1015             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
1016             (int)ostate->euid, (int)state->ruid, (int)state->euid);
1017         if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) {
1018             snprintf(errbuf, sizeof(errbuf),
1019                 "PERM_TIMESTAMP: setreuid(%d, %d)", ID(ruid), ID(euid));
1020             goto bad;
1021         }
1022         break;
1023     }
1024
1025     perm_stack_depth++;
1026     debug_return_bool(1);
1027 bad:
1028     warningx("%s: %s", errbuf,
1029         errno == EAGAIN ? _("too many processes") : strerror(errno));
1030     if (noexit)
1031         debug_return_bool(0);
1032     exit(1);
1033 }
1034
1035 void
1036 restore_perms(void)
1037 {
1038     struct perm_state *state, *ostate;
1039     debug_decl(restore_perms, SUDO_DEBUG_PERMS)
1040
1041     if (perm_stack_depth < 2)
1042         debug_return;
1043
1044     state = &perm_stack[perm_stack_depth - 1];
1045     ostate = &perm_stack[perm_stack_depth - 2];
1046     perm_stack_depth--;
1047
1048     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: uid: [%d, %d] -> [%d, %d]",
1049         __func__, (int)state->ruid, (int)state->euid,
1050         (int)ostate->ruid, (int)ostate->euid);
1051     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: gid: [%d, %d] -> [%d, %d]",
1052         __func__, (int)state->rgid, (int)state->egid,
1053         (int)ostate->rgid, (int)ostate->egid);
1054
1055     /*
1056      * When changing euid to ROOT_UID, setreuid() may fail even if
1057      * the ruid is ROOT_UID so call setuid() first.
1058      */
1059     if (OID(euid) == ROOT_UID) {
1060         /* setuid() may not set the saved ID unless the euid is ROOT_UID */
1061         if (ID(euid) != ROOT_UID)
1062             (void)setreuid(-1, ROOT_UID);
1063         if (setuid(ROOT_UID)) {
1064             warning("setuid() [%d, %d] -> %d)", (int)state->ruid,
1065                 (int)state->euid, ROOT_UID);
1066             goto bad;
1067         }
1068     }
1069     if (setreuid(OID(ruid), OID(euid))) {
1070         warning("setreuid() [%d, %d] -> [%d, %d]", (int)state->ruid,
1071             (int)state->euid, (int)OID(ruid), (int)OID(euid));
1072         goto bad;
1073     }
1074     if (setregid(OID(rgid), OID(egid))) {
1075         warning("setregid() [%d, %d] -> [%d, %d]", (int)state->rgid,
1076             (int)state->egid, (int)OID(rgid), (int)OID(egid));
1077         goto bad;
1078     }
1079     if (state->grlist != ostate->grlist) {
1080         if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
1081             warning("setgroups()");
1082             goto bad;
1083         }
1084     }
1085     sudo_grlist_delref(state->grlist);
1086     debug_return;
1087
1088 bad:
1089     exit(1);
1090 }
1091
1092 #elif defined(HAVE_SETEUID)
1093
1094 #define GID_CHANGED (state->rgid != ostate->rgid || state->egid != ostate->egid)
1095
1096 /*
1097  * Set real and effective uids and gids based on perm.
1098  * We always retain a real or effective uid of ROOT_UID unless
1099  * we are headed for an exec().
1100  * This version of set_perms() works fine with the "stay_setuid" option.
1101  */
1102 int
1103 set_perms(int perm)
1104 {
1105     struct perm_state *state, *ostate = NULL;
1106     char errbuf[1024];
1107     int noexit;
1108     debug_decl(set_perms, SUDO_DEBUG_PERMS)
1109
1110     noexit = ISSET(perm, PERM_NOEXIT);
1111     CLR(perm, PERM_MASK);
1112
1113     if (perm_stack_depth == PERM_STACK_MAX) {
1114         strlcpy(errbuf, _("perm stack overflow"), sizeof(errbuf));
1115         errno = EINVAL;
1116         goto bad;
1117     }
1118
1119     state = &perm_stack[perm_stack_depth];
1120     if (perm != PERM_INITIAL) {
1121         if (perm_stack_depth == 0) {
1122             strlcpy(errbuf, _("perm stack underflow"), sizeof(errbuf));
1123             errno = EINVAL;
1124             goto bad;
1125         }
1126         ostate = &perm_stack[perm_stack_depth - 1];
1127     }
1128
1129     /*
1130      * Since we only have setuid() and seteuid() and semantics
1131      * for these calls differ on various systems, we set
1132      * real and effective uids to ROOT_UID initially to be safe.
1133      */
1134     if (perm != PERM_INITIAL) {
1135         if (ostate->euid != ROOT_UID && seteuid(ROOT_UID)) {
1136             snprintf(errbuf, sizeof(errbuf), "set_perms: seteuid(%d)", ROOT_UID);
1137             goto bad;
1138         }
1139         if (ostate->ruid != ROOT_UID && setuid(ROOT_UID)) {
1140             snprintf(errbuf, sizeof(errbuf), "set_perms: setuid(%d)", ROOT_UID);
1141             goto bad;
1142         }
1143     }
1144
1145     switch (perm) {
1146     case PERM_INITIAL:
1147         /* Stash initial state */
1148         state->ruid = getuid();
1149         state->euid = geteuid();
1150         state->rgid = getgid();
1151         state->egid = getegid();
1152         state->grlist = user_group_list;
1153         sudo_grlist_addref(state->grlist);
1154         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_INITIAL: "
1155             "ruid: %d, euid: %d, rgid: %d, egid: %d", __func__,
1156             (int)state->ruid, (int)state->euid,
1157             (int)state->rgid, (int)state->egid);
1158         break;
1159
1160     case PERM_ROOT:
1161         /* We already set ruid/euid above. */
1162         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: "
1163             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
1164             (int)ostate->euid, ROOT_UID, ROOT_UID);
1165         state->ruid = ROOT_UID;
1166         state->euid = ROOT_UID;
1167         state->rgid = ostate->rgid;
1168         state->egid = ostate->egid;
1169         state->grlist = ostate->grlist;
1170         sudo_grlist_addref(state->grlist);
1171         break;
1172
1173     case PERM_USER:
1174         state->egid = user_gid;
1175         state->rgid = ostate->rgid;
1176         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: gid: "
1177             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
1178             (int)ostate->egid, (int)state->rgid, (int)state->egid);
1179         if (GID_CHANGED && setegid(user_gid)) {
1180             snprintf(errbuf, sizeof(errbuf),
1181                 "PERM_USER: setegid(%d)", user_gid);
1182             goto bad;
1183         }
1184         state->grlist = user_group_list;
1185         sudo_grlist_addref(state->grlist);
1186         if (state->grlist != ostate->grlist) {
1187             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
1188                 strlcpy(errbuf, "PERM_USER: setgroups", sizeof(errbuf));
1189                 goto bad;
1190             }
1191         }
1192         state->ruid = ROOT_UID;
1193         state->euid = user_uid;
1194         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: uid: "
1195             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
1196             (int)ostate->euid, (int)state->ruid, (int)state->euid);
1197         if (seteuid(user_uid)) {
1198             snprintf(errbuf, sizeof(errbuf),
1199                 "PERM_USER: seteuid(%d)", user_uid);
1200             goto bad;
1201         }
1202         break;
1203
1204     case PERM_FULL_USER:
1205         /* headed for exec() */
1206         state->rgid = user_gid;
1207         state->egid = user_gid;
1208         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: gid: "
1209             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
1210             (int)ostate->egid, (int)state->rgid, (int)state->egid);
1211         if (GID_CHANGED && setgid(user_gid)) {
1212             snprintf(errbuf, sizeof(errbuf),
1213                 "PERM_FULL_USER: setgid(%d)", user_gid);
1214             goto bad;
1215         }
1216         state->grlist = user_group_list;
1217         sudo_grlist_addref(state->grlist);
1218         if (state->grlist != ostate->grlist) {
1219             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
1220                 strlcpy(errbuf, "PERM_FULL_USER: setgroups", sizeof(errbuf));
1221                 goto bad;
1222             }
1223         }
1224         state->ruid = user_uid;
1225         state->euid = user_uid;
1226         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: uid: "
1227             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
1228             (int)ostate->euid, (int)state->ruid, (int)state->euid);
1229         if (setuid(user_uid)) {
1230             snprintf(errbuf, sizeof(errbuf),
1231                 "PERM_FULL_USER: setuid(%d)", user_uid);
1232             goto bad;
1233         }
1234         break;
1235
1236     case PERM_RUNAS:
1237         state->rgid = ostate->rgid;
1238         state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
1239         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: gid: "
1240             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
1241             (int)ostate->egid, (int)state->rgid, (int)state->egid);
1242         if (GID_CHANGED && setegid(state->egid)) {
1243             strlcpy(errbuf, _("unable to change to runas gid"), sizeof(errbuf));
1244             goto bad;
1245         }
1246         state->grlist = runas_setgroups();
1247         state->ruid = ostate->ruid;
1248         state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
1249         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: uid: "
1250             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
1251             (int)ostate->euid, (int)state->ruid, (int)state->euid);
1252         if (seteuid(state->euid)) {
1253             strlcpy(errbuf, _("unable to change to runas uid"), sizeof(errbuf));
1254             goto bad;
1255         }
1256         break;
1257
1258     case PERM_SUDOERS:
1259         state->grlist = ostate->grlist;
1260         sudo_grlist_addref(state->grlist);
1261
1262         /* assume euid == ROOT_UID, ruid == user */
1263         state->rgid = ostate->rgid;
1264         state->egid = sudoers_gid;
1265         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: gid: "
1266             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
1267             (int)ostate->egid, (int)state->rgid, (int)state->egid);
1268         if (GID_CHANGED && setegid(sudoers_gid)) {
1269             strlcpy(errbuf, _("unable to change to sudoers gid"), sizeof(errbuf));
1270             goto bad;
1271         }
1272
1273         state->ruid = ROOT_UID;
1274         /*
1275          * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
1276          * we use a non-zero uid in order to avoid NFS lossage.
1277          * Using uid 1 is a bit bogus but should work on all OS's.
1278          */
1279         if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP))
1280             state->euid = 1;
1281         else
1282             state->euid = sudoers_uid;
1283         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: uid: "
1284             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
1285             (int)ostate->euid, (int)state->ruid, (int)state->euid);
1286         if (seteuid(state->euid)) {
1287             snprintf(errbuf, sizeof(errbuf),
1288                 "PERM_SUDOERS: seteuid(%d)", state->euid);
1289             goto bad;
1290         }
1291         break;
1292
1293     case PERM_TIMESTAMP:
1294         state->grlist = ostate->grlist;
1295         sudo_grlist_addref(state->grlist);
1296         state->rgid = ostate->rgid;
1297         state->egid = ostate->egid;
1298         state->ruid = ROOT_UID;
1299         state->euid = timestamp_uid;
1300         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_TIMESTAMP: uid: "
1301             "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
1302             (int)ostate->euid, (int)state->ruid, (int)state->euid);
1303         if (seteuid(timestamp_uid)) {
1304             snprintf(errbuf, sizeof(errbuf),
1305                 "PERM_TIMESTAMP: seteuid(%d)", timestamp_uid);
1306             goto bad;
1307         }
1308         break;
1309     }
1310
1311     perm_stack_depth++;
1312     debug_return_bool(1);
1313 bad:
1314     warningx("%s: %s", errbuf,
1315         errno == EAGAIN ? _("too many processes") : strerror(errno));
1316     if (noexit)
1317         debug_return_bool(0);
1318     exit(1);
1319 }
1320
1321 void
1322 restore_perms(void)
1323 {
1324     struct perm_state *state, *ostate;
1325     debug_decl(restore_perms, SUDO_DEBUG_PERMS)
1326
1327     if (perm_stack_depth < 2)
1328         debug_return;
1329
1330     state = &perm_stack[perm_stack_depth - 1];
1331     ostate = &perm_stack[perm_stack_depth - 2];
1332     perm_stack_depth--;
1333
1334     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: uid: [%d, %d] -> [%d, %d]",
1335         __func__, (int)state->ruid, (int)state->euid,
1336         (int)ostate->ruid, (int)ostate->euid);
1337     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: gid: [%d, %d] -> [%d, %d]",
1338         __func__, (int)state->rgid, (int)state->egid,
1339         (int)ostate->rgid, (int)ostate->egid);
1340
1341     /*
1342      * Since we only have setuid() and seteuid() and semantics
1343      * for these calls differ on various systems, we set
1344      * real and effective uids to ROOT_UID initially to be safe.
1345      */
1346     if (seteuid(ROOT_UID)) {
1347         warningx("seteuid() [%d] -> [%d]", (int)state->euid, ROOT_UID);
1348         goto bad;
1349     }
1350     if (setuid(ROOT_UID)) {
1351         warningx("setuid() [%d, %d] -> [%d, %d]", (int)state->ruid, ROOT_UID,
1352             ROOT_UID, ROOT_UID);
1353         goto bad;
1354     }
1355
1356     if (OID(egid) != -1 && setegid(ostate->egid)) {
1357         warning("setegid(%d)", (int)ostate->egid);
1358         goto bad;
1359     }
1360     if (state->grlist != ostate->grlist) {
1361         if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
1362             warning("setgroups()");
1363             goto bad;
1364         }
1365     }
1366     if (OID(euid) != -1 && seteuid(ostate->euid)) {
1367         warning("seteuid(%d)", ostate->euid);
1368         goto bad;
1369     }
1370     sudo_grlist_delref(state->grlist);
1371     debug_return;
1372
1373 bad:
1374     exit(1);
1375 }
1376
1377 #else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
1378
1379 /*
1380  * Set uids and gids based on perm via setuid() and setgid().
1381  * NOTE: does not support the "stay_setuid" or timestampowner options.
1382  *       Also, sudoers_uid and sudoers_gid are not used.
1383  */
1384 int
1385 set_perms(int perm)
1386 {
1387     struct perm_state *state, *ostate = NULL;
1388     char errbuf[1024];
1389     int noexit;
1390     debug_decl(set_perms, SUDO_DEBUG_PERMS)
1391
1392     noexit = ISSET(perm, PERM_NOEXIT);
1393     CLR(perm, PERM_MASK);
1394
1395     if (perm_stack_depth == PERM_STACK_MAX) {
1396         strlcpy(errbuf, _("perm stack overflow"), sizeof(errbuf));
1397         errno = EINVAL;
1398         goto bad;
1399     }
1400
1401     state = &perm_stack[perm_stack_depth];
1402     if (perm != PERM_INITIAL) {
1403         if (perm_stack_depth == 0) {
1404             strlcpy(errbuf, _("perm stack underflow"), sizeof(errbuf));
1405             errno = EINVAL;
1406             goto bad;
1407         }
1408         ostate = &perm_stack[perm_stack_depth - 1];
1409     }
1410
1411     switch (perm) {
1412     case PERM_INITIAL:
1413         /* Stash initial state */
1414         state->ruid = geteuid() == ROOT_UID ? ROOT_UID : getuid();
1415         state->rgid = getgid();
1416         state->grlist = user_group_list;
1417         sudo_grlist_addref(state->grlist);
1418         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_INITIAL: "
1419             "ruid: %d, rgid: %d", __func__, (int)state->ruid, (int)state->rgid);
1420         break;
1421
1422     case PERM_ROOT:
1423         state->ruid = ROOT_UID;
1424         state->rgid = ostate->rgid;
1425         state->grlist = ostate->grlist;
1426         sudo_grlist_addref(state->grlist);
1427         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: "
1428             "[%d] -> [%d]", __func__, (int)ostate->ruid, (int)state->ruid);
1429         if (setuid(ROOT_UID)) {
1430             snprintf(errbuf, sizeof(errbuf), "PERM_ROOT: setuid(%d)", ROOT_UID);
1431             goto bad;
1432         }
1433         break;
1434
1435     case PERM_FULL_USER:
1436         state->rgid = user_gid;
1437         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: gid: "
1438             "[%d] -> [%d]", __func__, (int)ostate->rgid, (int)state->rgid);
1439         (void) setgid(user_gid);
1440         state->grlist = user_group_list;
1441         sudo_grlist_addref(state->grlist);
1442         if (state->grlist != ostate->grlist) {
1443             if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
1444                 strlcpy(errbuf, "PERM_FULL_USER: setgroups", sizeof(errbuf));
1445                 goto bad;
1446             }
1447         }
1448         state->ruid = user_uid;
1449         sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: "
1450             "[%d] -> [%d]", __func__, (int)ostate->ruid, (int)state->ruid);
1451         if (setuid(user_uid)) {
1452             snprintf(errbuf, sizeof(errbuf),
1453                 "PERM_FULL_USER: setuid(%d)", user_uid);
1454             goto bad;
1455         }
1456         break;
1457
1458     case PERM_USER:
1459     case PERM_SUDOERS:
1460     case PERM_RUNAS:
1461     case PERM_TIMESTAMP:
1462         /* Unsupported since we can't set euid. */
1463         state->ruid = ostate->ruid;
1464         state->rgid = ostate->rgid;
1465         state->grlist = ostate->grlist;
1466         sudo_grlist_addref(state->grlist);
1467         break;
1468     }
1469
1470     perm_stack_depth++;
1471     debug_return_bool(1);
1472 bad:
1473     warningx("%s: %s", errbuf,
1474         errno == EAGAIN ? _("too many processes") : strerror(errno));
1475     if (noexit)
1476         debug_return_bool(0);
1477     exit(1);
1478 }
1479
1480 void
1481 restore_perms(void)
1482 {
1483     struct perm_state *state, *ostate;
1484     debug_decl(restore_perms, SUDO_DEBUG_PERMS)
1485
1486     if (perm_stack_depth < 2)
1487         debug_return;
1488
1489     state = &perm_stack[perm_stack_depth - 1];
1490     ostate = &perm_stack[perm_stack_depth - 2];
1491     perm_stack_depth--;
1492
1493     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: uid: [%d] -> [%d]",
1494         __func__, (int)state->ruid, (int)ostate->ruid);
1495     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: gid: [%d] -> [%d]",
1496         __func__, (int)state->rgid, (int)ostate->rgid);
1497
1498     if (OID(rgid) != -1 && setgid(ostate->rgid)) {
1499         warning("setgid(%d)", (int)ostate->rgid);
1500         goto bad;
1501     }
1502     if (state->grlist != ostate->grlist) {
1503         if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
1504             warning("setgroups()");
1505             goto bad;
1506         }
1507     }
1508     sudo_grlist_delref(state->grlist);
1509     if (OID(ruid) != -1 && setuid(ostate->ruid)) {
1510         warning("setuid(%d)", (int)ostate->ruid);
1511         goto bad;
1512     }
1513     debug_return;
1514
1515 bad:
1516     exit(1);
1517 }
1518 #endif /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */
1519
1520 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID)
1521 static struct group_list *
1522 runas_setgroups(void)
1523 {
1524     struct passwd *pw;
1525     struct group_list *grlist;
1526     debug_decl(runas_setgroups, SUDO_DEBUG_PERMS)
1527
1528     if (def_preserve_groups) {
1529         sudo_grlist_addref(user_group_list);
1530         debug_return_ptr(user_group_list);
1531     }
1532
1533     pw = runas_pw ? runas_pw : sudo_user.pw;
1534 #ifdef HAVE_SETAUTHDB
1535     aix_setauthdb(pw->pw_name);
1536 #endif
1537     grlist = sudo_get_grlist(pw);
1538 #ifdef HAVE_SETAUTHDB
1539     aix_restoreauthdb();
1540 #endif
1541     if (sudo_setgroups(grlist->ngids, grlist->gids) < 0)
1542         log_fatal(USE_ERRNO|MSG_ONLY, _("unable to set runas group vector"));
1543     debug_return_ptr(grlist);
1544 }
1545 #endif /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */