1/* 2 * Copyright (c) 1994-1996,1998-2012 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#ifdef HAVE_LOGIN_CAP_H 48# include <login_cap.h> 49#endif 50#ifdef HAVE_PROJECT_H 51# include <project.h> 52# include <sys/task.h> 53#endif 54 55#include "sudo.h" 56 57/* 58 * Prototypes 59 */ 60static void runas_setup __P((void)); 61static void runas_setgroups __P((void)); 62static void restore_groups __P((void)); 63 64static int current_perm = -1; 65 66#ifdef HAVE_SETRESUID 67/* 68 * Set real and effective and saved uids and gids based on perm. 69 * We always retain a saved uid of 0 unless we are headed for an exec(). 70 * We only flip the effective gid since it only changes for PERM_SUDOERS. 71 * This version of set_perms() works fine with the "stay_setuid" option. 72 */ 73int 74set_perms(perm) 75 int perm; 76{ 77 const char *errstr; 78 int noexit; 79 80 noexit = ISSET(perm, PERM_NOEXIT); 81 CLR(perm, PERM_MASK); 82 83 if (perm == current_perm) 84 return 1; 85 86 switch (perm) { 87 case PERM_ROOT: 88 if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) { 89 errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)"; 90 goto bad; 91 } 92 (void) setresgid(-1, ROOT_GID, -1); 93 if (current_perm == PERM_RUNAS) 94 restore_groups(); 95 break; 96 97 case PERM_USER: 98 (void) setresgid(-1, user_gid, -1); 99 if (setresuid(user_uid, user_uid, ROOT_UID)) { 100 errstr = "setresuid(user_uid, user_uid, ROOT_UID)"; 101 goto bad; 102 } 103 break; 104 105 case PERM_FULL_USER: 106 /* headed for exec() */ 107 (void) setgid(user_gid); 108 if (setresuid(user_uid, user_uid, user_uid)) { 109 errstr = "setresuid(user_uid, user_uid, user_uid)"; 110 goto bad; 111 } 112 break; 113 114 case PERM_RUNAS: 115 runas_setgroups(); 116 (void) setresgid(-1, runas_gr ? 117 runas_gr->gr_gid : runas_pw->pw_gid, -1); 118 if (setresuid(-1, runas_pw ? runas_pw->pw_uid : 119 user_uid, -1)) { 120 errstr = "unable to change to runas uid"; 121 goto bad; 122 } 123 break; 124 125 case PERM_FULL_RUNAS: 126 /* headed for exec(), assume euid == ROOT_UID */ 127 runas_setup(); 128 if (setresuid(def_stay_setuid ? 129 user_uid : runas_pw->pw_uid, 130 runas_pw->pw_uid, runas_pw->pw_uid)) { 131 errstr = "unable to change to runas uid"; 132 goto bad; 133 } 134 break; 135 136 case PERM_SUDOERS: 137 /* assume euid == ROOT_UID, ruid == user */ 138 if (setresgid(-1, SUDOERS_GID, -1)) { 139 errstr = "unable to change to sudoers gid"; 140 goto bad; 141 } 142 143 /* 144 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE 145 * is group readable we use a non-zero 146 * uid in order to avoid NFS lossage. 147 * Using uid 1 is a bit bogus but should 148 * work on all OS's. 149 */ 150 if (SUDOERS_UID == ROOT_UID) { 151 if ((SUDOERS_MODE & S_IRGRP) && setresuid(ROOT_UID, 1, ROOT_UID)) { 152 errstr = "setresuid(ROOT_UID, 1, ROOT_UID)"; 153 goto bad; 154 } 155 } else { 156 if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) { 157 errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)"; 158 goto bad; 159 } 160 } 161 break; 162 case PERM_TIMESTAMP: 163 if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) { 164 errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)"; 165 goto bad; 166 } 167 break; 168 } 169 170 current_perm = perm; 171 return 1; 172bad: 173 warningx("%s: %s", errstr, 174 errno == EAGAIN ? "too many processes" : strerror(errno)); 175 if (noexit) 176 return 0; 177 exit(1); 178} 179 180#else 181# ifdef HAVE_SETREUID 182 183/* 184 * Set real and effective uids and gids based on perm. 185 * We always retain a real or effective uid of ROOT_UID unless 186 * we are headed for an exec(). 187 * This version of set_perms() works fine with the "stay_setuid" option. 188 */ 189int 190set_perms(perm) 191 int perm; 192{ 193 const char *errstr; 194 int noexit; 195 196 noexit = ISSET(perm, PERM_NOEXIT); 197 CLR(perm, PERM_MASK); 198 199 if (perm == current_perm) 200 return 1; 201 202 switch (perm) { 203 case PERM_ROOT: 204 if (setreuid(-1, ROOT_UID)) { 205 errstr = "setreuid(-1, ROOT_UID)"; 206 goto bad; 207 } 208 if (setuid(ROOT_UID)) { 209 errstr = "setuid(ROOT_UID)"; 210 goto bad; 211 } 212 (void) setregid(-1, ROOT_GID); 213 if (current_perm == PERM_RUNAS) 214 restore_groups(); 215 break; 216 217 case PERM_USER: 218 (void) setregid(-1, user_gid); 219 if (setreuid(ROOT_UID, user_uid)) { 220 errstr = "setreuid(ROOT_UID, user_uid)"; 221 goto bad; 222 } 223 break; 224 225 case PERM_FULL_USER: 226 /* headed for exec() */ 227 (void) setgid(user_gid); 228 if (setreuid(user_uid, user_uid)) { 229 errstr = "setreuid(user_uid, user_uid)"; 230 goto bad; 231 } 232 break; 233 234 case PERM_RUNAS: 235 runas_setgroups(); 236 (void) setregid(-1, runas_gr ? 237 runas_gr->gr_gid : runas_pw->pw_gid); 238 if (setreuid(-1, 239 runas_pw ? runas_pw->pw_uid : user_uid)) { 240 errstr = "unable to change to runas uid"; 241 goto bad; 242 } 243 break; 244 245 case PERM_FULL_RUNAS: 246 /* headed for exec(), assume euid == ROOT_UID */ 247 runas_setup(); 248 if (setreuid(def_stay_setuid ? user_uid : 249 runas_pw->pw_uid, runas_pw->pw_uid)) { 250 errstr = "unable to change to runas uid"; 251 goto bad; 252 } 253 break; 254 255 case PERM_SUDOERS: 256 /* assume euid == ROOT_UID, ruid == user */ 257 if (setregid(-1, SUDOERS_GID)) { 258 errstr = "unable to change to sudoers gid"; 259 goto bad; 260 } 261 262 /* 263 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE 264 * is group readable we use a non-zero 265 * uid in order to avoid NFS lossage. 266 * Using uid 1 is a bit bogus but should 267 * work on all OS's. 268 */ 269 if (SUDOERS_UID == ROOT_UID) { 270 if ((SUDOERS_MODE & S_IRGRP) && setreuid(ROOT_UID, 1)) { 271 errstr = "setreuid(ROOT_UID, 1)"; 272 goto bad; 273 } 274 } else { 275 if (setreuid(ROOT_UID, SUDOERS_UID)) { 276 errstr = "setreuid(ROOT_UID, SUDOERS_UID)"; 277 goto bad; 278 } 279 } 280 break; 281 case PERM_TIMESTAMP: 282 if (setreuid(ROOT_UID, timestamp_uid)) { 283 errstr = "setreuid(ROOT_UID, timestamp_uid)"; 284 goto bad; 285 } 286 break; 287 } 288 289 current_perm = perm; 290 return 1; 291bad: 292 warningx("%s: %s", errstr, 293 errno == EAGAIN ? "too many processes" : strerror(errno)); 294 if (noexit) 295 return 0; 296 exit(1); 297} 298 299# else /* !HAVE_SETRESUID && !HAVE_SETREUID */ 300# ifdef HAVE_SETEUID 301 302/* 303 * Set real and effective uids and gids based on perm. 304 * NOTE: does not support the "stay_setuid" option. 305 */ 306int 307set_perms(perm) 308 int perm; 309{ 310 const char *errstr; 311 int noexit; 312 313 noexit = ISSET(perm, PERM_NOEXIT); 314 CLR(perm, PERM_MASK); 315 316 if (perm == current_perm) 317 return 1; 318 319 /* 320 * Since we only have setuid() and seteuid() and semantics 321 * for these calls differ on various systems, we set 322 * real and effective uids to ROOT_UID initially to be safe. 323 */ 324 if (seteuid(ROOT_UID)) { 325 errstr = "seteuid(ROOT_UID)"; 326 goto bad; 327 } 328 if (setuid(ROOT_UID)) { 329 errstr = "setuid(ROOT_UID)"; 330 goto bad; 331 } 332 333 switch (perm) { 334 case PERM_ROOT: 335 /* uid set above */ 336 (void) setegid(ROOT_GID); 337 if (current_perm == PERM_RUNAS) 338 restore_groups(); 339 break; 340 341 case PERM_USER: 342 (void) setegid(user_gid); 343 if (seteuid(user_uid)) { 344 errstr = "seteuid(user_uid)"; 345 goto bad; 346 } 347 break; 348 349 case PERM_FULL_USER: 350 /* headed for exec() */ 351 (void) setgid(user_gid); 352 if (setuid(user_uid)) { 353 errstr = "setuid(user_uid)"; 354 goto bad; 355 } 356 break; 357 358 case PERM_RUNAS: 359 runas_setgroups(); 360 (void) setegid(runas_gr ? 361 runas_gr->gr_gid : runas_pw->pw_gid); 362 if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) { 363 errstr = "unable to change to runas uid"; 364 goto bad; 365 } 366 break; 367 368 case PERM_FULL_RUNAS: 369 /* headed for exec() */ 370 runas_setup(); 371 if (setuid(runas_pw->pw_uid)) { 372 errstr = "unable to change to runas uid"; 373 goto bad; 374 } 375 break; 376 377 case PERM_SUDOERS: 378 if (setegid(SUDOERS_GID)) { 379 errstr = "unable to change to sudoers gid"; 380 goto bad; 381 } 382 383 /* 384 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE 385 * is group readable we use a non-zero 386 * uid in order to avoid NFS lossage. 387 * Using uid 1 is a bit bogus but should 388 * work on all OS's. 389 */ 390 if (SUDOERS_UID == ROOT_UID) { 391 if ((SUDOERS_MODE & S_IRGRP) && seteuid(1)) { 392 errstr = "seteuid(1)"; 393 goto bad; 394 } 395 } else { 396 if (seteuid(SUDOERS_UID)) { 397 errstr = "seteuid(SUDOERS_UID)"; 398 goto bad; 399 } 400 } 401 break; 402 case PERM_TIMESTAMP: 403 if (seteuid(timestamp_uid)) { 404 errstr = "seteuid(timestamp_uid)"; 405 goto bad; 406 } 407 break; 408 } 409 410 current_perm = perm; 411 return 1; 412bad: 413 warningx("%s: %s", errstr, 414 errno == EAGAIN ? "too many processes" : strerror(errno)); 415 if (noexit) 416 return 0; 417 exit(1); 418} 419 420# else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */ 421 422/* 423 * Set uids and gids based on perm via setuid() and setgid(). 424 * NOTE: does not support the "stay_setuid" or timestampowner options. 425 * Also, SUDOERS_UID and SUDOERS_GID are not used. 426 */ 427int 428set_perms(perm) 429 int perm; 430{ 431 const char *errstr; 432 int noexit; 433 434 noexit = ISSET(perm, PERM_NOEXIT); 435 CLR(perm, PERM_MASK); 436 437 if (perm == current_perm) 438 return 1; 439 440 switch (perm) { 441 case PERM_ROOT: 442 if (setuid(ROOT_UID)) { 443 errstr = "setuid(ROOT_UID)"; 444 goto bad; 445 } 446 (void) setgid(ROOT_GID); 447 if (current_perm == PERM_RUNAS) 448 restore_groups(); 449 break; 450 451 case PERM_FULL_USER: 452 (void) setgid(user_gid); 453 if (setuid(user_uid)) { 454 errstr = "setuid(user_uid)"; 455 goto bad; 456 } 457 break; 458 459 case PERM_FULL_RUNAS: 460 runas_setup(); 461 if (setuid(runas_pw->pw_uid)) { 462 errstr = "unable to change to runas uid"; 463 goto bad; 464 } 465 break; 466 467 case PERM_USER: 468 case PERM_SUDOERS: 469 case PERM_RUNAS: 470 case PERM_TIMESTAMP: 471 /* Unsupported since we can't set euid. */ 472 break; 473 } 474 475 current_perm = perm; 476 return 1; 477bad: 478 warningx("%s: %s", errstr, 479 errno == EAGAIN ? "too many processes" : strerror(errno)); 480 if (noexit) 481 return 0; 482 exit(1); 483} 484# endif /* HAVE_SETEUID */ 485# endif /* HAVE_SETREUID */ 486#endif /* HAVE_SETRESUID */ 487 488#ifdef HAVE_INITGROUPS 489static void 490runas_setgroups() 491{ 492 static int ngroups = -1; 493# ifdef HAVE_GETGROUPS 494 static GETGROUPS_T *groups; 495# endif 496 static struct passwd *pw; 497 struct passwd *opw = pw; 498 499 if (def_preserve_groups) 500 return; 501 502 /* 503 * Use stashed copy of runas groups if available, else initgroups and stash. 504 */ 505 pw = runas_pw ? runas_pw : sudo_user.pw; 506 if (pw != opw) { 507# ifdef HAVE_SETAUTHDB 508 aix_setauthdb(pw->pw_name); 509# endif 510 if (initgroups(pw->pw_name, pw->pw_gid) < 0) 511 log_fatal(USE_ERRNO|MSG_ONLY, "can't set runas group vector"); 512# ifdef HAVE_GETGROUPS 513 if (groups) { 514 efree(groups); 515 groups = NULL; 516 } 517 if ((ngroups = getgroups(0, NULL)) > 0) { 518 groups = emalloc2(ngroups, sizeof(GETGROUPS_T)); 519 if (getgroups(ngroups, groups) < 0) 520 log_fatal(USE_ERRNO|MSG_ONLY, "can't get runas group vector"); 521 } 522# ifdef HAVE_SETAUTHDB 523 aix_restoreauthdb(); 524# endif 525 } else { 526 if (setgroups(ngroups, groups) < 0) 527 log_fatal(USE_ERRNO|MSG_ONLY, "can't set runas group vector"); 528# endif /* HAVE_GETGROUPS */ 529 } 530} 531 532static void 533restore_groups() 534{ 535 if (user_ngroups >= 0 && setgroups(user_ngroups, user_groups) < 0) 536 log_fatal(USE_ERRNO|MSG_ONLY, "can't reset user group vector"); 537} 538 539#else 540 541static void 542runas_setgroups() 543{ 544 /* STUB */ 545} 546 547static void 548restore_groups() 549{ 550 /* STUB */ 551} 552 553#endif /* HAVE_INITGROUPS */ 554 555#ifdef HAVE_PROJECT_H 556static void 557set_project(pw) 558 struct passwd *pw; 559{ 560 struct project proj; 561 char buf[PROJECT_BUFSZ]; 562 int errval; 563 564 /* 565 * Collect the default project for the user and settaskid 566 */ 567 setprojent(); 568 if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) { 569 errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL); 570 switch(errval) { 571 case 0: 572 break; 573 case SETPROJ_ERR_TASK: 574 switch (errno) { 575 case EAGAIN: 576 warningx("resource control limit has been reached"); 577 break; 578 case ESRCH: 579 warningx("user \"%s\" is not a member of project \"%s\"", 580 pw->pw_name, proj.pj_name); 581 break; 582 case EACCES: 583 warningx("the invoking task is final"); 584 break; 585 default: 586 warningx("could not join project \"%s\"", proj.pj_name); 587 } 588 case SETPROJ_ERR_POOL: 589 switch (errno) { 590 case EACCES: 591 warningx("no resource pool accepting default bindings " 592 "exists for project \"%s\"", proj.pj_name); 593 break; 594 case ESRCH: 595 warningx("specified resource pool does not exist for " 596 "project \"%s\"", proj.pj_name); 597 break; 598 default: 599 warningx("could not bind to default resource pool for " 600 "project \"%s\"", proj.pj_name); 601 } 602 break; 603 default: 604 if (errval <= 0) { 605 warningx("setproject failed for project \"%s\"", proj.pj_name); 606 } else { 607 warningx("warning, resource control assignment failed for " 608 "project \"%s\"", proj.pj_name); 609 } 610 } 611 } else { 612 warning("getdefaultproj"); 613 } 614 endprojent(); 615} 616#endif /* HAVE_PROJECT_H */ 617 618static void 619runas_setup() 620{ 621 gid_t gid; 622#ifdef HAVE_LOGIN_CAP_H 623 int flags; 624 extern login_cap_t *lc; 625#endif 626 627 if (runas_pw->pw_name != NULL) { 628 gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid; 629#ifdef HAVE_PROJECT_H 630 set_project(runas_pw); 631#endif 632#ifdef HAVE_GETUSERATTR 633 aix_prep_user(runas_pw->pw_name, user_ttypath); 634#endif 635#ifdef HAVE_PAM 636 pam_begin_session(runas_pw); 637#endif /* HAVE_PAM */ 638 639#ifdef HAVE_LOGIN_CAP_H 640 if (def_use_loginclass) { 641 /* 642 * We only use setusercontext() to set the nice value and rlimits. 643 */ 644 flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; 645 if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) { 646 if (runas_pw->pw_uid != ROOT_UID) 647 error(1, "unable to set user context"); 648 else 649 warning("unable to set user context"); 650 } 651 } 652#endif /* HAVE_LOGIN_CAP_H */ 653 /* 654 * Initialize group vector 655 */ 656 runas_setgroups(); 657#ifdef HAVE_SETEUID 658 if (setegid(gid)) 659 warning("cannot set egid to runas gid"); 660#endif 661 if (setgid(gid)) 662 warning("cannot set gid to runas gid"); 663 } 664} 665