Annotation of embedaddon/sudo/plugins/sudoers/set_perms.c, revision 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>