Return to set_perms.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers |
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: }