Annotation of embedaddon/sudo/plugins/sudoers/set_perms.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>