Return to sudoers.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers |
1.1 ! misho 1: /* ! 2: * Copyright (c) 1993-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: * For a brief history of sudo, please see the HISTORY file included ! 21: * with this distribution. ! 22: */ ! 23: ! 24: #define _SUDO_MAIN ! 25: ! 26: #ifdef __TANDEM ! 27: # include <floss.h> ! 28: #endif ! 29: ! 30: #include <config.h> ! 31: ! 32: #include <sys/types.h> ! 33: #include <sys/stat.h> ! 34: #include <sys/param.h> ! 35: #include <sys/socket.h> ! 36: #include <stdio.h> ! 37: #ifdef STDC_HEADERS ! 38: # include <stdlib.h> ! 39: # include <stddef.h> ! 40: #else ! 41: # ifdef HAVE_STDLIB_H ! 42: # include <stdlib.h> ! 43: # endif ! 44: #endif /* STDC_HEADERS */ ! 45: #ifdef HAVE_STRING_H ! 46: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) ! 47: # include <memory.h> ! 48: # endif ! 49: # include <string.h> ! 50: #endif /* HAVE_STRING_H */ ! 51: #ifdef HAVE_STRINGS_H ! 52: # include <strings.h> ! 53: #endif /* HAVE_STRINGS_H */ ! 54: #ifdef HAVE_UNISTD_H ! 55: # include <unistd.h> ! 56: #endif /* HAVE_UNISTD_H */ ! 57: #include <pwd.h> ! 58: #include <errno.h> ! 59: #include <fcntl.h> ! 60: #include <signal.h> ! 61: #include <grp.h> ! 62: #include <time.h> ! 63: #ifdef HAVE_SETLOCALE ! 64: # include <locale.h> ! 65: #endif ! 66: #include <netinet/in.h> ! 67: #include <netdb.h> ! 68: #ifdef HAVE_LOGIN_CAP_H ! 69: # include <login_cap.h> ! 70: # ifndef LOGIN_DEFROOTCLASS ! 71: # define LOGIN_DEFROOTCLASS "daemon" ! 72: # endif ! 73: #endif ! 74: #ifdef HAVE_SELINUX ! 75: # include <selinux/selinux.h> ! 76: #endif ! 77: #include <ctype.h> ! 78: #include <setjmp.h> ! 79: ! 80: #include "sudoers.h" ! 81: #include "interfaces.h" ! 82: #include "sudoers_version.h" ! 83: #include "auth/sudo_auth.h" ! 84: ! 85: /* ! 86: * Prototypes ! 87: */ ! 88: static void init_vars(char * const *); ! 89: static int set_cmnd(void); ! 90: static void set_loginclass(struct passwd *); ! 91: static void set_runaspw(const char *); ! 92: static void set_runasgr(const char *); ! 93: static int cb_runas_default(const char *); ! 94: static int sudoers_policy_version(int verbose); ! 95: static int deserialize_info(char * const settings[], char * const user_info[]); ! 96: static char *find_editor(int nfiles, char **files, char ***argv_out); ! 97: static void create_admin_success_flag(void); ! 98: ! 99: /* ! 100: * Globals ! 101: */ ! 102: const char *sudoers_file = _PATH_SUDOERS; ! 103: mode_t sudoers_mode = SUDOERS_MODE; ! 104: uid_t sudoers_uid = SUDOERS_UID; ! 105: gid_t sudoers_gid = SUDOERS_GID; ! 106: struct sudo_user sudo_user; ! 107: struct passwd *list_pw; ! 108: struct interface *interfaces; ! 109: int long_list; ! 110: int debug_level; ! 111: uid_t timestamp_uid; ! 112: extern int errorlineno; ! 113: extern int parse_error; ! 114: extern char *errorfile; ! 115: #ifdef HAVE_LOGIN_CAP_H ! 116: login_cap_t *lc; ! 117: #endif /* HAVE_LOGIN_CAP_H */ ! 118: #ifdef HAVE_BSD_AUTH_H ! 119: char *login_style; ! 120: #endif /* HAVE_BSD_AUTH_H */ ! 121: sudo_conv_t sudo_conv; ! 122: sudo_printf_t sudo_printf; ! 123: int sudo_mode; ! 124: ! 125: static char *prev_user; ! 126: static char *runas_user; ! 127: static char *runas_group; ! 128: static struct sudo_nss_list *snl; ! 129: static const char *interfaces_string; ! 130: static sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp; ! 131: ! 132: /* XXX - must be extern for audit bits of sudo_auth.c */ ! 133: int NewArgc; ! 134: char **NewArgv; ! 135: ! 136: /* plugin_error.c */ ! 137: extern sigjmp_buf error_jmp; ! 138: ! 139: static int ! 140: sudoers_policy_open(unsigned int version, sudo_conv_t conversation, ! 141: sudo_printf_t plugin_printf, char * const settings[], ! 142: char * const user_info[], char * const envp[]) ! 143: { ! 144: volatile int sources = 0; ! 145: sigaction_t sa; ! 146: struct sudo_nss *nss; ! 147: ! 148: if (!sudo_conv) ! 149: sudo_conv = conversation; ! 150: if (!sudo_printf) ! 151: sudo_printf = plugin_printf; ! 152: ! 153: if (sigsetjmp(error_jmp, 1)) { ! 154: /* called via error(), errorx() or log_error() */ ! 155: rewind_perms(); ! 156: return -1; ! 157: } ! 158: ! 159: bindtextdomain("sudoers", LOCALEDIR); ! 160: ! 161: /* ! 162: * Signal setup: ! 163: * Ignore keyboard-generated signals so the user cannot interrupt ! 164: * us at some point and avoid the logging. ! 165: * Install handler to wait for children when they exit. ! 166: */ ! 167: zero_bytes(&sa, sizeof(sa)); ! 168: sigemptyset(&sa.sa_mask); ! 169: sa.sa_flags = SA_RESTART; ! 170: sa.sa_handler = SIG_IGN; ! 171: (void) sigaction(SIGINT, &sa, &saved_sa_int); ! 172: (void) sigaction(SIGQUIT, &sa, &saved_sa_quit); ! 173: (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp); ! 174: ! 175: sudo_setpwent(); ! 176: sudo_setgrent(); ! 177: ! 178: /* Initialize environment functions (including replacements). */ ! 179: env_init(envp); ! 180: ! 181: /* Setup defaults data structures. */ ! 182: init_defaults(); ! 183: ! 184: /* Parse settings and user_info */ ! 185: sudo_mode = deserialize_info(settings, user_info); ! 186: ! 187: init_vars(envp); /* XXX - move this later? */ ! 188: ! 189: /* Parse nsswitch.conf for sudoers order. */ ! 190: snl = sudo_read_nss(); ! 191: ! 192: /* LDAP or NSS may modify the euid so we need to be root for the open. */ ! 193: set_perms(PERM_INITIAL); ! 194: set_perms(PERM_ROOT); ! 195: ! 196: /* Open and parse sudoers, set global defaults */ ! 197: tq_foreach_fwd(snl, nss) { ! 198: if (nss->open(nss) == 0 && nss->parse(nss) == 0) { ! 199: sources++; ! 200: if (nss->setdefs(nss) != 0) ! 201: log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries")); ! 202: } ! 203: } ! 204: if (sources == 0) { ! 205: warningx(_("no valid sudoers sources found, quitting")); ! 206: return -1; ! 207: } ! 208: ! 209: /* XXX - collect post-sudoers parse settings into a function */ ! 210: ! 211: /* ! 212: * Initialize external group plugin, if any. ! 213: */ ! 214: if (def_group_plugin) { ! 215: if (group_plugin_load(def_group_plugin) != TRUE) ! 216: def_group_plugin = NULL; ! 217: } ! 218: ! 219: /* ! 220: * Set runas passwd/group entries based on command line or sudoers. ! 221: * Note that if runas_group was specified without runas_user we ! 222: * defer setting runas_pw so the match routines know to ignore it. ! 223: */ ! 224: if (runas_group != NULL) { ! 225: set_runasgr(runas_group); ! 226: if (runas_user != NULL) ! 227: set_runaspw(runas_user); ! 228: } else ! 229: set_runaspw(runas_user ? runas_user : def_runas_default); ! 230: ! 231: if (!update_defaults(SETDEF_RUNAS)) ! 232: log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries")); ! 233: ! 234: if (def_fqdn) ! 235: set_fqdn(); /* deferred until after sudoers is parsed */ ! 236: ! 237: /* Set login class if applicable. */ ! 238: set_loginclass(sudo_user.pw); ! 239: ! 240: restore_perms(); ! 241: ! 242: return TRUE; ! 243: } ! 244: ! 245: static void ! 246: sudoers_policy_close(int exit_status, int error_code) ! 247: { ! 248: if (sigsetjmp(error_jmp, 1)) { ! 249: /* called via error(), errorx() or log_error() */ ! 250: return; ! 251: } ! 252: ! 253: /* We do not currently log the exit status. */ ! 254: if (error_code) ! 255: warningx(_("unable to execute %s: %s"), safe_cmnd, strerror(error_code)); ! 256: ! 257: /* Close the session we opened in sudoers_policy_init_session(). */ ! 258: if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT)) ! 259: (void)sudo_auth_end_session(runas_pw); ! 260: ! 261: /* Free remaining references to password and group entries. */ ! 262: pw_delref(sudo_user.pw); ! 263: pw_delref(runas_pw); ! 264: if (runas_gr != NULL) ! 265: gr_delref(runas_gr); ! 266: if (user_group_list != NULL) ! 267: grlist_delref(user_group_list); ! 268: } ! 269: ! 270: /* ! 271: * The init_session function is called before executing the command ! 272: * and before uid/gid changes occur. ! 273: */ ! 274: static int ! 275: sudoers_policy_init_session(struct passwd *pwd) ! 276: { ! 277: if (sigsetjmp(error_jmp, 1)) { ! 278: /* called via error(), errorx() or log_error() */ ! 279: return -1; ! 280: } ! 281: ! 282: return sudo_auth_begin_session(pwd); ! 283: } ! 284: ! 285: static int ! 286: sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], ! 287: char **command_infop[], char **argv_out[], char **user_env_out[]) ! 288: { ! 289: static char *command_info[32]; /* XXX */ ! 290: char **edit_argv = NULL; ! 291: struct sudo_nss *nss; ! 292: int cmnd_status = -1, validated; ! 293: volatile int info_len = 0; ! 294: volatile int rval = TRUE; ! 295: ! 296: if (sigsetjmp(error_jmp, 1)) { ! 297: /* error recovery via error(), errorx() or log_error() */ ! 298: rval = -1; ! 299: goto done; ! 300: } ! 301: ! 302: /* Is root even allowed to run sudo? */ ! 303: if (user_uid == 0 && !def_root_sudo) { ! 304: warningx(_("sudoers specifies that root is not allowed to sudo")); ! 305: goto bad; ! 306: } ! 307: ! 308: /* Check for -C overriding def_closefrom. */ ! 309: if (user_closefrom >= 0 && user_closefrom != def_closefrom) { ! 310: if (!def_closefrom_override) { ! 311: warningx(_("you are not permitted to use the -C option")); ! 312: goto bad; ! 313: } ! 314: def_closefrom = user_closefrom; ! 315: } ! 316: ! 317: set_perms(PERM_INITIAL); ! 318: ! 319: /* Environment variables specified on the command line. */ ! 320: if (env_add != NULL && env_add[0] != NULL) ! 321: sudo_user.env_vars = env_add; ! 322: ! 323: /* ! 324: * Make a local copy of argc/argv, with special handling ! 325: * for pseudo-commands and the '-i' option. ! 326: */ ! 327: if (argc == 0) { ! 328: NewArgc = 1; ! 329: NewArgv = emalloc2(NewArgc + 1, sizeof(char *)); ! 330: NewArgv[0] = user_cmnd; ! 331: NewArgv[1] = NULL; ! 332: } else { ! 333: /* Must leave an extra slot before NewArgv for bash's --login */ ! 334: NewArgc = argc; ! 335: NewArgv = emalloc2(NewArgc + 2, sizeof(char *)); ! 336: memcpy(++NewArgv, argv, argc * sizeof(char *)); ! 337: NewArgv[NewArgc] = NULL; ! 338: if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) ! 339: NewArgv[0] = estrdup(runas_pw->pw_shell); ! 340: } ! 341: ! 342: /* If given the -P option, set the "preserve_groups" flag. */ ! 343: if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS)) ! 344: def_preserve_groups = TRUE; ! 345: ! 346: /* Find command in path */ ! 347: cmnd_status = set_cmnd(); ! 348: if (cmnd_status == -1) { ! 349: rval = -1; ! 350: goto done; ! 351: } ! 352: ! 353: #ifdef HAVE_SETLOCALE ! 354: if (!setlocale(LC_ALL, def_sudoers_locale)) { ! 355: warningx(_("unable to set locale to \"%s\", using \"C\""), ! 356: def_sudoers_locale); ! 357: setlocale(LC_ALL, "C"); ! 358: } ! 359: #endif ! 360: ! 361: /* ! 362: * Check sudoers sources. ! 363: */ ! 364: validated = FLAG_NO_USER | FLAG_NO_HOST; ! 365: tq_foreach_fwd(snl, nss) { ! 366: validated = nss->lookup(nss, validated, pwflag); ! 367: ! 368: if (ISSET(validated, VALIDATE_OK)) { ! 369: /* Handle "= auth" in netsvc.conf */ ! 370: if (nss->ret_if_found) ! 371: break; ! 372: } else { ! 373: /* Handle [NOTFOUND=return] */ ! 374: if (nss->ret_if_notfound) ! 375: break; ! 376: } ! 377: } ! 378: ! 379: if (safe_cmnd == NULL) ! 380: safe_cmnd = estrdup(user_cmnd); ! 381: ! 382: #ifdef HAVE_SETLOCALE ! 383: setlocale(LC_ALL, ""); ! 384: #endif ! 385: ! 386: /* If only a group was specified, set runas_pw based on invoking user. */ ! 387: if (runas_pw == NULL) ! 388: set_runaspw(user_name); ! 389: ! 390: /* ! 391: * Look up the timestamp dir owner if one is specified. ! 392: */ ! 393: if (def_timestampowner) { ! 394: struct passwd *pw; ! 395: ! 396: if (*def_timestampowner == '#') ! 397: pw = sudo_getpwuid(atoi(def_timestampowner + 1)); ! 398: else ! 399: pw = sudo_getpwnam(def_timestampowner); ! 400: if (!pw) ! 401: log_error(0, _("timestamp owner (%s): No such user"), ! 402: def_timestampowner); ! 403: timestamp_uid = pw->pw_uid; ! 404: pw_delref(pw); ! 405: } ! 406: ! 407: /* If no command line args and "shell_noargs" is not set, error out. */ ! 408: if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) { ! 409: rval = -2; /* usage error */ ! 410: goto done; ! 411: } ! 412: ! 413: /* Bail if a tty is required and we don't have one. */ ! 414: if (def_requiretty) { ! 415: int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY); ! 416: if (fd == -1) { ! 417: audit_failure(NewArgv, _("no tty")); ! 418: warningx(_("sorry, you must have a tty to run sudo")); ! 419: goto bad; ! 420: } else ! 421: (void) close(fd); ! 422: } ! 423: ! 424: /* ! 425: * We don't reset the environment for sudoedit or if the user ! 426: * specified the -E command line flag and they have setenv privs. ! 427: */ ! 428: if (ISSET(sudo_mode, MODE_EDIT) || ! 429: (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv)) ! 430: def_env_reset = FALSE; ! 431: ! 432: /* Build a new environment that avoids any nasty bits. */ ! 433: rebuild_env(); ! 434: ! 435: /* Require a password if sudoers says so. */ ! 436: rval = check_user(validated, sudo_mode); ! 437: if (rval != TRUE) ! 438: goto done; ! 439: ! 440: /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */ ! 441: /* XXX - causes confusion when root is not listed in sudoers */ ! 442: if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) { ! 443: if (user_uid == 0 && strcmp(prev_user, "root") != 0) { ! 444: struct passwd *pw; ! 445: ! 446: if ((pw = sudo_getpwnam(prev_user)) != NULL) { ! 447: if (sudo_user.pw != NULL) ! 448: pw_delref(sudo_user.pw); ! 449: sudo_user.pw = pw; ! 450: } ! 451: } ! 452: } ! 453: ! 454: /* If the user was not allowed to run the command we are done. */ ! 455: if (!ISSET(validated, VALIDATE_OK)) { ! 456: if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) { ! 457: audit_failure(NewArgv, _("No user or host")); ! 458: log_denial(validated, 1); ! 459: } else { ! 460: if (def_path_info) { ! 461: /* ! 462: * We'd like to not leak path info at all here, but that can ! 463: * *really* confuse the users. To really close the leak we'd ! 464: * have to say "not allowed to run foo" even when the problem ! 465: * is just "no foo in path" since the user can trivially set ! 466: * their path to just contain a single dir. ! 467: */ ! 468: log_denial(validated, ! 469: !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND)); ! 470: if (cmnd_status == NOT_FOUND) ! 471: warningx(_("%s: command not found"), user_cmnd); ! 472: else if (cmnd_status == NOT_FOUND_DOT) ! 473: warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd); ! 474: } else { ! 475: /* Just tell the user they are not allowed to run foo. */ ! 476: log_denial(validated, 1); ! 477: } ! 478: audit_failure(NewArgv, _("validation failure")); ! 479: } ! 480: goto bad; ! 481: } ! 482: ! 483: /* Create Ubuntu-style dot file to indicate sudo was successful. */ ! 484: create_admin_success_flag(); ! 485: ! 486: /* Finally tell the user if the command did not exist. */ ! 487: if (cmnd_status == NOT_FOUND_DOT) { ! 488: audit_failure(NewArgv, _("command in current directory")); ! 489: warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd); ! 490: goto bad; ! 491: } else if (cmnd_status == NOT_FOUND) { ! 492: audit_failure(NewArgv, _("%s: command not found"), user_cmnd); ! 493: warningx(_("%s: command not found"), user_cmnd); ! 494: goto bad; ! 495: } ! 496: ! 497: /* If user specified env vars make sure sudoers allows it. */ ! 498: if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) { ! 499: if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) { ! 500: warningx(_("sorry, you are not allowed to preserve the environment")); ! 501: goto bad; ! 502: } else ! 503: validate_env_vars(sudo_user.env_vars); ! 504: } ! 505: ! 506: if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT)) && (def_log_input || def_log_output)) { ! 507: if (def_iolog_file && def_iolog_dir) { ! 508: command_info[info_len++] = expand_iolog_path("iolog_path=", ! 509: def_iolog_dir, def_iolog_file, &sudo_user.iolog_file); ! 510: sudo_user.iolog_file++; ! 511: } ! 512: if (def_log_input) { ! 513: command_info[info_len++] = estrdup("iolog_stdin=true"); ! 514: command_info[info_len++] = estrdup("iolog_ttyin=true"); ! 515: } ! 516: if (def_log_output) { ! 517: command_info[info_len++] = estrdup("iolog_stdout=true"); ! 518: command_info[info_len++] = estrdup("iolog_stderr=true"); ! 519: command_info[info_len++] = estrdup("iolog_ttyout=true"); ! 520: } ! 521: if (def_compress_io) ! 522: command_info[info_len++] = estrdup("iolog_compress=true"); ! 523: } ! 524: ! 525: log_allowed(validated); ! 526: if (ISSET(sudo_mode, MODE_CHECK)) ! 527: rval = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw); ! 528: else if (ISSET(sudo_mode, MODE_LIST)) ! 529: display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* XXX - return val */ ! 530: ! 531: /* Cleanup sudoers sources */ ! 532: tq_foreach_fwd(snl, nss) { ! 533: nss->close(nss); ! 534: } ! 535: if (def_group_plugin) ! 536: group_plugin_unload(); ! 537: ! 538: if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) { ! 539: /* rval already set appropriately */ ! 540: goto done; ! 541: } ! 542: ! 543: /* ! 544: * Set umask based on sudoers. ! 545: * If user's umask is more restrictive, OR in those bits too ! 546: * unless umask_override is set. ! 547: */ ! 548: if (def_umask != 0777) { ! 549: mode_t mask = def_umask; ! 550: if (!def_umask_override) { ! 551: mode_t omask = umask(mask); ! 552: mask |= omask; ! 553: umask(omask); ! 554: } ! 555: easprintf(&command_info[info_len++], "umask=0%o", (unsigned int)mask); ! 556: } ! 557: ! 558: if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { ! 559: char *p; ! 560: ! 561: /* Convert /bin/sh -> -sh so shell knows it is a login shell */ ! 562: if ((p = strrchr(NewArgv[0], '/')) == NULL) ! 563: p = NewArgv[0]; ! 564: *p = '-'; ! 565: NewArgv[0] = p; ! 566: ! 567: /* Set cwd to run user's homedir. */ ! 568: command_info[info_len++] = fmt_string("cwd", runas_pw->pw_dir); ! 569: ! 570: /* ! 571: * Newer versions of bash require the --login option to be used ! 572: * in conjunction with the -c option even if the shell name starts ! 573: * with a '-'. Unfortunately, bash 1.x uses -login, not --login ! 574: * so this will cause an error for that. ! 575: */ ! 576: if (NewArgc > 1 && strcmp(NewArgv[0], "-bash") == 0 && ! 577: strcmp(NewArgv[1], "-c") == 0) { ! 578: /* Use the extra slot before NewArgv so we can store --login. */ ! 579: NewArgv--; ! 580: NewArgc++; ! 581: NewArgv[0] = NewArgv[1]; ! 582: NewArgv[1] = "--login"; ! 583: } ! 584: ! 585: #if defined(__linux__) || defined(_AIX) ! 586: /* Insert system-wide environment variables. */ ! 587: read_env_file(_PATH_ENVIRONMENT, TRUE); ! 588: #endif ! 589: } ! 590: ! 591: /* Insert system-wide environment variables. */ ! 592: if (def_env_file) ! 593: read_env_file(def_env_file, FALSE); ! 594: ! 595: /* Insert user-specified environment variables. */ ! 596: insert_env_vars(sudo_user.env_vars); ! 597: ! 598: /* Restore signal handlers before we exec. */ ! 599: (void) sigaction(SIGINT, &saved_sa_int, NULL); ! 600: (void) sigaction(SIGQUIT, &saved_sa_quit, NULL); ! 601: (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL); ! 602: ! 603: if (ISSET(sudo_mode, MODE_EDIT)) { ! 604: char *editor = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv); ! 605: if (editor == NULL) ! 606: goto bad; ! 607: command_info[info_len++] = fmt_string("command", editor); ! 608: command_info[info_len++] = estrdup("sudoedit=true"); ! 609: } else { ! 610: command_info[info_len++] = fmt_string("command", safe_cmnd); ! 611: } ! 612: if (def_stay_setuid) { ! 613: easprintf(&command_info[info_len++], "runas_uid=%u", ! 614: (unsigned int)user_uid); ! 615: easprintf(&command_info[info_len++], "runas_gid=%u", ! 616: (unsigned int)user_gid); ! 617: easprintf(&command_info[info_len++], "runas_euid=%u", ! 618: (unsigned int)runas_pw->pw_uid); ! 619: easprintf(&command_info[info_len++], "runas_egid=%u", ! 620: runas_gr ? (unsigned int)runas_gr->gr_gid : ! 621: (unsigned int)runas_pw->pw_gid); ! 622: } else { ! 623: easprintf(&command_info[info_len++], "runas_uid=%u", ! 624: (unsigned int)runas_pw->pw_uid); ! 625: easprintf(&command_info[info_len++], "runas_gid=%u", ! 626: runas_gr ? (unsigned int)runas_gr->gr_gid : ! 627: (unsigned int)runas_pw->pw_gid); ! 628: } ! 629: if (def_preserve_groups) { ! 630: command_info[info_len++] = "preserve_groups=true"; ! 631: } else { ! 632: int i, len; ! 633: size_t glsize; ! 634: char *cp, *gid_list; ! 635: struct group_list *grlist = get_group_list(runas_pw); ! 636: ! 637: glsize = sizeof("runas_groups=") - 1 + (grlist->ngids * (MAX_UID_T_LEN + 1)); ! 638: gid_list = emalloc(glsize); ! 639: memcpy(gid_list, "runas_groups=", sizeof("runas_groups=") - 1); ! 640: cp = gid_list + sizeof("runas_groups=") - 1; ! 641: for (i = 0; i < grlist->ngids; i++) { ! 642: /* XXX - check rval */ ! 643: len = snprintf(cp, glsize - (cp - gid_list), "%s%u", ! 644: i ? "," : "", (unsigned int) grlist->gids[i]); ! 645: cp += len; ! 646: } ! 647: command_info[info_len++] = gid_list; ! 648: grlist_delref(grlist); ! 649: } ! 650: if (def_closefrom >= 0) ! 651: easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom); ! 652: if (def_noexec) ! 653: command_info[info_len++] = estrdup("noexec=true"); ! 654: if (def_noexec_file) ! 655: command_info[info_len++] = fmt_string("noexec_file", def_noexec_file); ! 656: if (def_set_utmp) ! 657: command_info[info_len++] = estrdup("set_utmp=true"); ! 658: if (def_use_pty) ! 659: command_info[info_len++] = estrdup("use_pty=true"); ! 660: if (def_utmp_runas) ! 661: command_info[info_len++] = fmt_string("utmp_user", runas_pw->pw_name); ! 662: #ifdef HAVE_LOGIN_CAP_H ! 663: if (lc != NULL) ! 664: command_info[info_len++] = fmt_string("login_class", lc->lc_class); ! 665: #endif /* HAVE_LOGIN_CAP_H */ ! 666: #ifdef HAVE_SELINUX ! 667: if (user_role != NULL) ! 668: command_info[info_len++] = fmt_string("selinux_role", user_role); ! 669: if (user_type != NULL) ! 670: command_info[info_len++] = fmt_string("selinux_type", user_type); ! 671: #endif /* HAVE_SELINUX */ ! 672: ! 673: /* Must audit before uid change. */ ! 674: audit_success(NewArgv); ! 675: ! 676: *command_infop = command_info; ! 677: ! 678: *argv_out = edit_argv ? edit_argv : NewArgv; ! 679: *user_env_out = env_get(); /* our private copy */ ! 680: ! 681: goto done; ! 682: ! 683: bad: ! 684: rval = FALSE; ! 685: ! 686: done: ! 687: rewind_perms(); ! 688: ! 689: /* Close the password and group files and free up memory. */ ! 690: sudo_endpwent(); ! 691: sudo_endgrent(); ! 692: ! 693: return rval; ! 694: } ! 695: ! 696: static int ! 697: sudoers_policy_check(int argc, char * const argv[], char *env_add[], ! 698: char **command_infop[], char **argv_out[], char **user_env_out[]) ! 699: { ! 700: if (!ISSET(sudo_mode, MODE_EDIT)) ! 701: SET(sudo_mode, MODE_RUN); ! 702: ! 703: return sudoers_policy_main(argc, argv, 0, env_add, command_infop, ! 704: argv_out, user_env_out); ! 705: } ! 706: ! 707: static int ! 708: sudoers_policy_validate(void) ! 709: { ! 710: user_cmnd = "validate"; ! 711: SET(sudo_mode, MODE_VALIDATE); ! 712: ! 713: return sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL, NULL, NULL); ! 714: } ! 715: ! 716: static void ! 717: sudoers_policy_invalidate(int remove) ! 718: { ! 719: user_cmnd = "kill"; ! 720: if (sigsetjmp(error_jmp, 1) == 0) { ! 721: remove_timestamp(remove); ! 722: plugin_cleanup(0); ! 723: } ! 724: } ! 725: ! 726: static int ! 727: sudoers_policy_list(int argc, char * const argv[], int verbose, ! 728: const char *list_user) ! 729: { ! 730: int rval; ! 731: ! 732: user_cmnd = "list"; ! 733: if (argc) ! 734: SET(sudo_mode, MODE_CHECK); ! 735: else ! 736: SET(sudo_mode, MODE_LIST); ! 737: if (verbose) ! 738: long_list = 1; ! 739: if (list_user) { ! 740: list_pw = sudo_getpwnam(list_user); ! 741: if (list_pw == NULL) { ! 742: warningx(_("unknown user: %s"), list_user); ! 743: return -1; ! 744: } ! 745: } ! 746: rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL, NULL, NULL); ! 747: if (list_user) { ! 748: pw_delref(list_pw); ! 749: list_pw = NULL; ! 750: } ! 751: ! 752: return rval; ! 753: } ! 754: ! 755: /* ! 756: * Initialize timezone, set umask, fill in ``sudo_user'' struct and ! 757: * load the ``interfaces'' array. ! 758: */ ! 759: static void ! 760: init_vars(char * const envp[]) ! 761: { ! 762: char * const * ep; ! 763: ! 764: #ifdef HAVE_TZSET ! 765: (void) tzset(); /* set the timezone if applicable */ ! 766: #endif /* HAVE_TZSET */ ! 767: ! 768: for (ep = envp; *ep; ep++) { ! 769: /* XXX - don't fill in if empty string */ ! 770: switch (**ep) { ! 771: case 'K': ! 772: if (strncmp("KRB5CCNAME=", *ep, 11) == 0) ! 773: user_ccname = *ep + 11; ! 774: break; ! 775: case 'P': ! 776: if (strncmp("PATH=", *ep, 5) == 0) ! 777: user_path = *ep + 5; ! 778: break; ! 779: case 'S': ! 780: if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0) ! 781: user_prompt = *ep + 12; ! 782: else if (strncmp("SUDO_USER=", *ep, 10) == 0) ! 783: prev_user = *ep + 10; ! 784: break; ! 785: } ! 786: } ! 787: ! 788: /* ! 789: * Get a local copy of the user's struct passwd with the shadow password ! 790: * if necessary. It is assumed that euid is 0 at this point so we ! 791: * can read the shadow passwd file if necessary. ! 792: */ ! 793: if ((sudo_user.pw = sudo_getpwuid(user_uid)) == NULL) { ! 794: /* ! 795: * It is not unusual for users to place "sudo -k" in a .logout ! 796: * file which can cause sudo to be run during reboot after the ! 797: * YP/NIS/NIS+/LDAP/etc daemon has died. ! 798: */ ! 799: if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) ! 800: errorx(1, _("unknown uid: %u"), (unsigned int) user_uid); ! 801: ! 802: /* Need to make a fake struct passwd for the call to log_error(). */ ! 803: sudo_user.pw = sudo_fakepwnamid(user_name, user_uid, user_gid); ! 804: log_error(0, _("unknown uid: %u"), (unsigned int) user_uid); ! 805: /* NOTREACHED */ ! 806: } ! 807: ! 808: /* ! 809: * Get group list. ! 810: */ ! 811: if (user_group_list == NULL) ! 812: user_group_list = get_group_list(sudo_user.pw); ! 813: ! 814: /* Set runas callback. */ ! 815: sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default; ! 816: ! 817: /* It is now safe to use log_error() and set_perms() */ ! 818: } ! 819: ! 820: /* ! 821: * Fill in user_cmnd, user_args, user_base and user_stat variables ! 822: * and apply any command-specific defaults entries. ! 823: */ ! 824: static int ! 825: set_cmnd(void) ! 826: { ! 827: int rval; ! 828: char *path = user_path; ! 829: ! 830: /* Resolve the path and return. */ ! 831: rval = FOUND; ! 832: user_stat = emalloc(sizeof(struct stat)); ! 833: ! 834: /* Default value for cmnd, overridden below. */ ! 835: if (user_cmnd == NULL) ! 836: user_cmnd = NewArgv[0]; ! 837: ! 838: if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { ! 839: if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) { ! 840: if (def_secure_path && !user_is_exempt()) ! 841: path = def_secure_path; ! 842: set_perms(PERM_RUNAS); ! 843: rval = find_path(NewArgv[0], &user_cmnd, user_stat, path, ! 844: def_ignore_dot); ! 845: restore_perms(); ! 846: if (rval != FOUND) { ! 847: /* Failed as root, try as invoking user. */ ! 848: set_perms(PERM_USER); ! 849: rval = find_path(NewArgv[0], &user_cmnd, user_stat, path, ! 850: def_ignore_dot); ! 851: restore_perms(); ! 852: } ! 853: } ! 854: ! 855: /* set user_args */ ! 856: if (NewArgc > 1) { ! 857: char *to, *from, **av; ! 858: size_t size, n; ! 859: ! 860: /* Alloc and build up user_args. */ ! 861: for (size = 0, av = NewArgv + 1; *av; av++) ! 862: size += strlen(*av) + 1; ! 863: user_args = emalloc(size); ! 864: if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) { ! 865: /* ! 866: * When running a command via a shell, the sudo front-end ! 867: * escapes potential meta chars. We unescape non-spaces ! 868: * for sudoers matching and logging purposes. ! 869: */ ! 870: for (to = user_args, av = NewArgv + 1; (from = *av); av++) { ! 871: while (*from) { ! 872: if (from[0] == '\\' && !isspace((unsigned char)from[1])) ! 873: from++; ! 874: *to++ = *from++; ! 875: } ! 876: *to++ = ' '; ! 877: } ! 878: *--to = '\0'; ! 879: } else { ! 880: for (to = user_args, av = NewArgv + 1; *av; av++) { ! 881: n = strlcpy(to, *av, size - (to - user_args)); ! 882: if (n >= size - (to - user_args)) ! 883: errorx(1, _("internal error, set_cmnd() overflow")); ! 884: to += n; ! 885: *to++ = ' '; ! 886: } ! 887: *--to = '\0'; ! 888: } ! 889: } ! 890: } ! 891: if (strlen(user_cmnd) >= PATH_MAX) ! 892: errorx(1, _("%s: %s"), user_cmnd, strerror(ENAMETOOLONG)); ! 893: ! 894: if ((user_base = strrchr(user_cmnd, '/')) != NULL) ! 895: user_base++; ! 896: else ! 897: user_base = user_cmnd; ! 898: ! 899: if (!update_defaults(SETDEF_CMND)) ! 900: log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries")); ! 901: ! 902: return rval; ! 903: } ! 904: ! 905: /* ! 906: * Open sudoers and sanity check mode/owner/type. ! 907: * Returns a handle to the sudoers file or NULL on error. ! 908: */ ! 909: FILE * ! 910: open_sudoers(const char *sudoers, int doedit, int *keepopen) ! 911: { ! 912: struct stat statbuf; ! 913: FILE *fp = NULL; ! 914: int rootstat; ! 915: ! 916: /* ! 917: * Fix the mode and group on sudoers file from old default. ! 918: * Only works if file system is readable/writable by root. ! 919: */ ! 920: if ((rootstat = stat_sudoers(sudoers, &statbuf)) == 0 && ! 921: sudoers_uid == statbuf.st_uid && sudoers_mode != 0400 && ! 922: (statbuf.st_mode & 0007777) == 0400) { ! 923: ! 924: if (chmod(sudoers, sudoers_mode) == 0) { ! 925: warningx(_("fixed mode on %s"), sudoers); ! 926: SET(statbuf.st_mode, sudoers_mode); ! 927: if (statbuf.st_gid != sudoers_gid) { ! 928: if (chown(sudoers, (uid_t) -1, sudoers_gid) == 0) { ! 929: warningx(_("set group on %s"), sudoers); ! 930: statbuf.st_gid = sudoers_gid; ! 931: } else ! 932: warning(_("unable to set group on %s"), sudoers); ! 933: } ! 934: } else ! 935: warning(_("unable to fix mode on %s"), sudoers); ! 936: } ! 937: ! 938: /* ! 939: * Sanity checks on sudoers file. Must be done as sudoers ! 940: * file owner. We already did a stat as root, so use that ! 941: * data if we can't stat as sudoers file owner. ! 942: */ ! 943: set_perms(PERM_SUDOERS); ! 944: ! 945: if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0) ! 946: log_error(USE_ERRNO|NO_EXIT, _("unable to stat %s"), sudoers); ! 947: else if (!S_ISREG(statbuf.st_mode)) ! 948: log_error(NO_EXIT, _("%s is not a regular file"), sudoers); ! 949: else if ((statbuf.st_mode & 07577) != sudoers_mode) ! 950: log_error(NO_EXIT, _("%s is mode 0%o, should be 0%o"), sudoers, ! 951: (unsigned int) (statbuf.st_mode & 07777), ! 952: (unsigned int) sudoers_mode); ! 953: else if (statbuf.st_uid != sudoers_uid) ! 954: log_error(NO_EXIT, _("%s is owned by uid %u, should be %u"), sudoers, ! 955: (unsigned int) statbuf.st_uid, (unsigned int) sudoers_uid); ! 956: else if (statbuf.st_gid != sudoers_gid && ISSET(statbuf.st_mode, S_IRGRP|S_IWGRP)) ! 957: log_error(NO_EXIT, _("%s is owned by gid %u, should be %u"), sudoers, ! 958: (unsigned int) statbuf.st_gid, (unsigned int) sudoers_gid); ! 959: else if ((fp = fopen(sudoers, "r")) == NULL) ! 960: log_error(USE_ERRNO|NO_EXIT, _("unable to open %s"), sudoers); ! 961: else { ! 962: /* ! 963: * Make sure we can actually read sudoers so we can present the ! 964: * user with a reasonable error message (unlike the lexer). ! 965: */ ! 966: if (statbuf.st_size != 0 && fgetc(fp) == EOF) { ! 967: log_error(USE_ERRNO|NO_EXIT, _("unable to read %s"), sudoers); ! 968: fclose(fp); ! 969: fp = NULL; ! 970: } ! 971: } ! 972: ! 973: if (fp != NULL) { ! 974: rewind(fp); ! 975: (void) fcntl(fileno(fp), F_SETFD, 1); ! 976: } ! 977: ! 978: restore_perms(); /* change back to root */ ! 979: return fp; ! 980: } ! 981: ! 982: #ifdef HAVE_LOGIN_CAP_H ! 983: static void ! 984: set_loginclass(struct passwd *pw) ! 985: { ! 986: int errflags; ! 987: ! 988: /* ! 989: * Don't make it a fatal error if the user didn't specify the login ! 990: * class themselves. We do this because if login.conf gets ! 991: * corrupted we want the admin to be able to use sudo to fix it. ! 992: */ ! 993: if (login_class) ! 994: errflags = NO_MAIL|MSG_ONLY; ! 995: else ! 996: errflags = NO_MAIL|MSG_ONLY|NO_EXIT; ! 997: ! 998: if (login_class && strcmp(login_class, "-") != 0) { ! 999: if (user_uid != 0 && ! 1000: strcmp(runas_user ? runas_user : def_runas_default, "root") != 0) ! 1001: errorx(1, _("only root can use `-c %s'"), login_class); ! 1002: } else { ! 1003: login_class = pw->pw_class; ! 1004: if (!login_class || !*login_class) ! 1005: login_class = ! 1006: (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; ! 1007: } ! 1008: ! 1009: lc = login_getclass(login_class); ! 1010: if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) { ! 1011: log_error(errflags, _("unknown login class: %s"), login_class); ! 1012: if (!lc) ! 1013: lc = login_getclass(NULL); /* needed for login_getstyle() later */ ! 1014: } ! 1015: } ! 1016: #else ! 1017: static void ! 1018: set_loginclass(struct passwd *pw) ! 1019: { ! 1020: } ! 1021: #endif /* HAVE_LOGIN_CAP_H */ ! 1022: ! 1023: /* ! 1024: * Look up the fully qualified domain name and set user_host and user_shost. ! 1025: */ ! 1026: void ! 1027: set_fqdn(void) ! 1028: { ! 1029: #ifdef HAVE_GETADDRINFO ! 1030: struct addrinfo *res0, hint; ! 1031: #else ! 1032: struct hostent *hp; ! 1033: #endif ! 1034: char *p; ! 1035: ! 1036: #ifdef HAVE_GETADDRINFO ! 1037: zero_bytes(&hint, sizeof(hint)); ! 1038: hint.ai_family = PF_UNSPEC; ! 1039: hint.ai_flags = AI_CANONNAME; ! 1040: if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) { ! 1041: #else ! 1042: if (!(hp = gethostbyname(user_host))) { ! 1043: #endif ! 1044: log_error(MSG_ONLY|NO_EXIT, ! 1045: _("unable to resolve host %s"), user_host); ! 1046: } else { ! 1047: if (user_shost != user_host) ! 1048: efree(user_shost); ! 1049: efree(user_host); ! 1050: #ifdef HAVE_GETADDRINFO ! 1051: user_host = estrdup(res0->ai_canonname); ! 1052: freeaddrinfo(res0); ! 1053: #else ! 1054: user_host = estrdup(hp->h_name); ! 1055: #endif ! 1056: } ! 1057: if ((p = strchr(user_host, '.')) != NULL) ! 1058: user_shost = estrndup(user_host, (size_t)(p - user_host)); ! 1059: else ! 1060: user_shost = user_host; ! 1061: } ! 1062: ! 1063: /* ! 1064: * Get passwd entry for the user we are going to run commands as ! 1065: * and store it in runas_pw. By default, commands run as "root". ! 1066: */ ! 1067: void ! 1068: set_runaspw(const char *user) ! 1069: { ! 1070: if (runas_pw != NULL) ! 1071: pw_delref(runas_pw); ! 1072: if (*user == '#') { ! 1073: if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) ! 1074: runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); ! 1075: } else { ! 1076: if ((runas_pw = sudo_getpwnam(user)) == NULL) ! 1077: log_error(NO_MAIL|MSG_ONLY, _("unknown user: %s"), user); ! 1078: } ! 1079: } ! 1080: ! 1081: /* ! 1082: * Get group entry for the group we are going to run commands as ! 1083: * and store it in runas_gr. ! 1084: */ ! 1085: static void ! 1086: set_runasgr(const char *group) ! 1087: { ! 1088: if (runas_gr != NULL) ! 1089: gr_delref(runas_gr); ! 1090: if (*group == '#') { ! 1091: if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) ! 1092: runas_gr = sudo_fakegrnam(group); ! 1093: } else { ! 1094: if ((runas_gr = sudo_getgrnam(group)) == NULL) ! 1095: log_error(NO_MAIL|MSG_ONLY, _("unknown group: %s"), group); ! 1096: } ! 1097: } ! 1098: ! 1099: /* ! 1100: * Callback for runas_default sudoers setting. ! 1101: */ ! 1102: static int ! 1103: cb_runas_default(const char *user) ! 1104: { ! 1105: /* Only reset runaspw if user didn't specify one. */ ! 1106: if (!runas_user && !runas_group) ! 1107: set_runaspw(user); ! 1108: return TRUE; ! 1109: } ! 1110: ! 1111: /* ! 1112: * Cleanup hook for error()/errorx() ! 1113: */ ! 1114: void ! 1115: plugin_cleanup(int gotsignal) ! 1116: { ! 1117: struct sudo_nss *nss; ! 1118: ! 1119: if (!gotsignal) { ! 1120: if (snl != NULL) { ! 1121: tq_foreach_fwd(snl, nss) ! 1122: nss->close(nss); ! 1123: } ! 1124: if (def_group_plugin) ! 1125: group_plugin_unload(); ! 1126: sudo_endpwent(); ! 1127: sudo_endgrent(); ! 1128: } ! 1129: } ! 1130: ! 1131: static int ! 1132: sudoers_policy_version(int verbose) ! 1133: { ! 1134: if (sigsetjmp(error_jmp, 1)) { ! 1135: /* error recovery via error(), errorx() or log_error() */ ! 1136: return -1; ! 1137: } ! 1138: ! 1139: sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers policy plugin version %s\n"), ! 1140: PACKAGE_VERSION); ! 1141: sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers file grammar version %d\n"), ! 1142: SUDOERS_GRAMMAR_VERSION); ! 1143: ! 1144: if (verbose) { ! 1145: sudo_printf(SUDO_CONV_INFO_MSG, _("\nSudoers path: %s\n"), sudoers_file); ! 1146: #ifdef HAVE_LDAP ! 1147: # ifdef _PATH_NSSWITCH_CONF ! 1148: sudo_printf(SUDO_CONV_INFO_MSG, _("nsswitch path: %s\n"), _PATH_NSSWITCH_CONF); ! 1149: # endif ! 1150: sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.conf path: %s\n"), _PATH_LDAP_CONF); ! 1151: sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.secret path: %s\n"), _PATH_LDAP_SECRET); ! 1152: #endif ! 1153: dump_auth_methods(); ! 1154: dump_defaults(); ! 1155: sudo_printf(SUDO_CONV_INFO_MSG, "\n"); ! 1156: dump_interfaces(interfaces_string); ! 1157: sudo_printf(SUDO_CONV_INFO_MSG, "\n"); ! 1158: } ! 1159: return TRUE; ! 1160: } ! 1161: ! 1162: static int ! 1163: deserialize_info(char * const settings[], char * const user_info[]) ! 1164: { ! 1165: char * const *cur; ! 1166: const char *p, *groups = NULL; ! 1167: int flags = 0; ! 1168: ! 1169: #define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0) ! 1170: ! 1171: /* Parse command line settings. */ ! 1172: user_closefrom = -1; ! 1173: for (cur = settings; *cur != NULL; cur++) { ! 1174: if (MATCHES(*cur, "closefrom=")) { ! 1175: user_closefrom = atoi(*cur + sizeof("closefrom=") - 1); ! 1176: continue; ! 1177: } ! 1178: if (MATCHES(*cur, "debug_level=")) { ! 1179: debug_level = atoi(*cur + sizeof("debug_level=") - 1); ! 1180: continue; ! 1181: } ! 1182: if (MATCHES(*cur, "runas_user=")) { ! 1183: runas_user = *cur + sizeof("runas_user=") - 1; ! 1184: continue; ! 1185: } ! 1186: if (MATCHES(*cur, "runas_group=")) { ! 1187: runas_group = *cur + sizeof("runas_group=") - 1; ! 1188: continue; ! 1189: } ! 1190: if (MATCHES(*cur, "prompt=")) { ! 1191: user_prompt = *cur + sizeof("prompt=") - 1; ! 1192: def_passprompt_override = TRUE; ! 1193: continue; ! 1194: } ! 1195: if (MATCHES(*cur, "set_home=")) { ! 1196: if (atobool(*cur + sizeof("set_home=") - 1) == TRUE) ! 1197: SET(flags, MODE_RESET_HOME); ! 1198: continue; ! 1199: } ! 1200: if (MATCHES(*cur, "preserve_environment=")) { ! 1201: if (atobool(*cur + sizeof("preserve_environment=") - 1) == TRUE) ! 1202: SET(flags, MODE_PRESERVE_ENV); ! 1203: continue; ! 1204: } ! 1205: if (MATCHES(*cur, "run_shell=")) { ! 1206: if (atobool(*cur + sizeof("run_shell=") - 1) == TRUE) ! 1207: SET(flags, MODE_SHELL); ! 1208: continue; ! 1209: } ! 1210: if (MATCHES(*cur, "login_shell=")) { ! 1211: if (atobool(*cur + sizeof("login_shell=") - 1) == TRUE) { ! 1212: SET(flags, MODE_LOGIN_SHELL); ! 1213: def_env_reset = TRUE; ! 1214: } ! 1215: continue; ! 1216: } ! 1217: if (MATCHES(*cur, "implied_shell=")) { ! 1218: if (atobool(*cur + sizeof("implied_shell=") - 1) == TRUE) ! 1219: SET(flags, MODE_IMPLIED_SHELL); ! 1220: continue; ! 1221: } ! 1222: if (MATCHES(*cur, "preserve_groups=")) { ! 1223: if (atobool(*cur + sizeof("preserve_groups=") - 1) == TRUE) ! 1224: SET(flags, MODE_PRESERVE_GROUPS); ! 1225: continue; ! 1226: } ! 1227: if (MATCHES(*cur, "ignore_ticket=")) { ! 1228: if (atobool(*cur + sizeof("ignore_ticket=") - 1) == TRUE) ! 1229: SET(flags, MODE_IGNORE_TICKET); ! 1230: continue; ! 1231: } ! 1232: if (MATCHES(*cur, "noninteractive=")) { ! 1233: if (atobool(*cur + sizeof("noninteractive=") - 1) == TRUE) ! 1234: SET(flags, MODE_NONINTERACTIVE); ! 1235: continue; ! 1236: } ! 1237: if (MATCHES(*cur, "sudoedit=")) { ! 1238: if (atobool(*cur + sizeof("sudoedit=") - 1) == TRUE) ! 1239: SET(flags, MODE_EDIT); ! 1240: continue; ! 1241: } ! 1242: if (MATCHES(*cur, "login_class=")) { ! 1243: login_class = *cur + sizeof("login_class=") - 1; ! 1244: def_use_loginclass = TRUE; ! 1245: continue; ! 1246: } ! 1247: #ifdef HAVE_SELINUX ! 1248: if (MATCHES(*cur, "selinux_role=")) { ! 1249: user_role = *cur + sizeof("selinux_role=") - 1; ! 1250: continue; ! 1251: } ! 1252: if (MATCHES(*cur, "selinux_type=")) { ! 1253: user_type = *cur + sizeof("selinux_type=") - 1; ! 1254: continue; ! 1255: } ! 1256: #endif /* HAVE_SELINUX */ ! 1257: #ifdef HAVE_BSD_AUTH_H ! 1258: if (MATCHES(*cur, "bsdauth_type=")) { ! 1259: login_style = *cur + sizeof("bsdauth_type=") - 1; ! 1260: continue; ! 1261: } ! 1262: #endif /* HAVE_BSD_AUTH_H */ ! 1263: #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) ! 1264: if (MATCHES(*cur, "progname=")) { ! 1265: setprogname(*cur + sizeof("progname=") - 1); ! 1266: continue; ! 1267: } ! 1268: #endif ! 1269: if (MATCHES(*cur, "network_addrs=")) { ! 1270: interfaces_string = *cur + sizeof("network_addrs=") - 1; ! 1271: set_interfaces(interfaces_string); ! 1272: continue; ! 1273: } ! 1274: if (MATCHES(*cur, "sudoers_file=")) { ! 1275: sudoers_file = *cur + sizeof("sudoers_file=") - 1; ! 1276: continue; ! 1277: } ! 1278: if (MATCHES(*cur, "sudoers_uid=")) { ! 1279: sudoers_uid = (uid_t) atoi(*cur + sizeof("sudoers_uid=") - 1); ! 1280: continue; ! 1281: } ! 1282: if (MATCHES(*cur, "sudoers_gid=")) { ! 1283: sudoers_gid = (gid_t) atoi(*cur + sizeof("sudoers_gid=") - 1); ! 1284: continue; ! 1285: } ! 1286: if (MATCHES(*cur, "sudoers_mode=")) { ! 1287: sudoers_mode = (mode_t) strtol(*cur + sizeof("sudoers_mode=") - 1, ! 1288: NULL, 8); ! 1289: continue; ! 1290: } ! 1291: } ! 1292: ! 1293: for (cur = user_info; *cur != NULL; cur++) { ! 1294: if (MATCHES(*cur, "user=")) { ! 1295: user_name = estrdup(*cur + sizeof("user=") - 1); ! 1296: continue; ! 1297: } ! 1298: if (MATCHES(*cur, "uid=")) { ! 1299: user_uid = (uid_t) atoi(*cur + sizeof("uid=") - 1); ! 1300: continue; ! 1301: } ! 1302: if (MATCHES(*cur, "gid=")) { ! 1303: p = *cur + sizeof("gid=") - 1; ! 1304: user_gid = (gid_t) atoi(p); ! 1305: continue; ! 1306: } ! 1307: if (MATCHES(*cur, "groups=")) { ! 1308: groups = *cur + sizeof("groups=") - 1; ! 1309: continue; ! 1310: } ! 1311: if (MATCHES(*cur, "cwd=")) { ! 1312: user_cwd = estrdup(*cur + sizeof("cwd=") - 1); ! 1313: continue; ! 1314: } ! 1315: if (MATCHES(*cur, "tty=")) { ! 1316: user_tty = user_ttypath = estrdup(*cur + sizeof("tty=") - 1); ! 1317: if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) ! 1318: user_tty += sizeof(_PATH_DEV) - 1; ! 1319: continue; ! 1320: } ! 1321: if (MATCHES(*cur, "host=")) { ! 1322: user_host = user_shost = estrdup(*cur + sizeof("host=") - 1); ! 1323: if ((p = strchr(user_host, '.'))) ! 1324: user_shost = estrndup(user_host, (size_t)(p - user_host)); ! 1325: continue; ! 1326: } ! 1327: if (MATCHES(*cur, "lines=")) { ! 1328: sudo_user.lines = atoi(*cur + sizeof("lines=") - 1); ! 1329: continue; ! 1330: } ! 1331: if (MATCHES(*cur, "cols=")) { ! 1332: sudo_user.cols = atoi(*cur + sizeof("cols=") - 1); ! 1333: continue; ! 1334: } ! 1335: } ! 1336: if (user_cwd == NULL) ! 1337: user_cwd = "unknown"; ! 1338: if (user_tty == NULL) ! 1339: user_tty = "unknown"; /* user_ttypath remains NULL */ ! 1340: ! 1341: if (groups != NULL && groups[0] != '\0') { ! 1342: const char *cp; ! 1343: GETGROUPS_T *gids; ! 1344: int ngids; ! 1345: ! 1346: /* Count number of groups, including passwd gid. */ ! 1347: ngids = 2; ! 1348: for (cp = groups; *cp != '\0'; cp++) { ! 1349: if (*cp == ',') ! 1350: ngids++; ! 1351: } ! 1352: ! 1353: /* The first gid in the list is the passwd group gid. */ ! 1354: gids = emalloc2(ngids, sizeof(GETGROUPS_T)); ! 1355: gids[0] = user_gid; ! 1356: ngids = 1; ! 1357: cp = groups; ! 1358: for (;;) { ! 1359: gids[ngids] = atoi(cp); ! 1360: if (gids[0] != gids[ngids]) ! 1361: ngids++; ! 1362: cp = strchr(cp, ','); ! 1363: if (cp == NULL) ! 1364: break; ! 1365: cp++; /* skip over comma */ ! 1366: } ! 1367: set_group_list(user_name, gids, ngids); ! 1368: efree(gids); ! 1369: } ! 1370: ! 1371: #undef MATCHES ! 1372: return flags; ! 1373: } ! 1374: ! 1375: static char * ! 1376: resolve_editor(char *editor, int nfiles, char **files, char ***argv_out) ! 1377: { ! 1378: char *cp, **nargv, *editor_path = NULL; ! 1379: int ac, i, nargc, wasblank; ! 1380: ! 1381: editor = estrdup(editor); /* becomes part of argv_out */ ! 1382: ! 1383: /* ! 1384: * Split editor into an argument vector; editor is reused (do not free). ! 1385: * The EDITOR and VISUAL environment variables may contain command ! 1386: * line args so look for those and alloc space for them too. ! 1387: */ ! 1388: nargc = 1; ! 1389: for (wasblank = FALSE, cp = editor; *cp != '\0'; cp++) { ! 1390: if (isblank((unsigned char) *cp)) ! 1391: wasblank = TRUE; ! 1392: else if (wasblank) { ! 1393: wasblank = FALSE; ! 1394: nargc++; ! 1395: } ! 1396: } ! 1397: /* If we can't find the editor in the user's PATH, give up. */ ! 1398: cp = strtok(editor, " \t"); ! 1399: if (cp == NULL || ! 1400: find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) { ! 1401: efree(editor); ! 1402: return NULL; ! 1403: } ! 1404: nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *)); ! 1405: for (ac = 0; cp != NULL && ac < nargc; ac++) { ! 1406: nargv[ac] = cp; ! 1407: cp = strtok(NULL, " \t"); ! 1408: } ! 1409: nargv[ac++] = "--"; ! 1410: for (i = 0; i < nfiles; ) ! 1411: nargv[ac++] = files[i++]; ! 1412: nargv[ac] = NULL; ! 1413: ! 1414: *argv_out = nargv; ! 1415: return editor_path; ! 1416: } ! 1417: ! 1418: /* ! 1419: * Determine which editor to use. We don't need to worry about restricting ! 1420: * this to a "safe" editor since it runs with the uid of the invoking user, ! 1421: * not the runas (privileged) user. ! 1422: */ ! 1423: static char * ! 1424: find_editor(int nfiles, char **files, char ***argv_out) ! 1425: { ! 1426: char *cp, *editor, *editor_path = NULL, **ev, *ev0[4]; ! 1427: ! 1428: /* ! 1429: * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one. ! 1430: */ ! 1431: ev0[0] = "SUDO_EDITOR"; ! 1432: ev0[1] = "VISUAL"; ! 1433: ev0[2] = "EDITOR"; ! 1434: ev0[3] = NULL; ! 1435: for (ev = ev0; *ev != NULL; ev++) { ! 1436: if ((editor = getenv(*ev)) != NULL && *editor != '\0') { ! 1437: editor_path = resolve_editor(editor, nfiles, files, argv_out); ! 1438: if (editor_path != NULL) ! 1439: break; ! 1440: } ! 1441: } ! 1442: if (editor_path == NULL) { ! 1443: /* def_editor could be a path, split it up */ ! 1444: editor = estrdup(def_editor); ! 1445: cp = strtok(editor, ":"); ! 1446: while (cp != NULL && editor_path == NULL) { ! 1447: editor_path = resolve_editor(cp, nfiles, files, argv_out); ! 1448: cp = strtok(NULL, ":"); ! 1449: } ! 1450: if (editor_path) ! 1451: efree(editor); ! 1452: } ! 1453: if (!editor_path) { ! 1454: audit_failure(NewArgv, _("%s: command not found"), editor); ! 1455: warningx(_("%s: command not found"), editor); ! 1456: } ! 1457: return editor_path; ! 1458: } ! 1459: ! 1460: #ifdef USE_ADMIN_FLAG ! 1461: static void ! 1462: create_admin_success_flag(void) ! 1463: { ! 1464: struct stat statbuf; ! 1465: char flagfile[PATH_MAX]; ! 1466: int fd, n; ! 1467: ! 1468: /* Check whether the user is in the admin group. */ ! 1469: if (!user_in_group(sudo_user.pw, "admin")) ! 1470: return; ! 1471: ! 1472: /* Build path to flag file. */ ! 1473: n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful", ! 1474: user_dir); ! 1475: if (n <= 0 || n >= sizeof(flagfile)) ! 1476: return; ! 1477: ! 1478: /* Create admin flag file if it doesn't already exist. */ ! 1479: set_perms(PERM_USER); ! 1480: if (stat(flagfile, &statbuf) != 0) { ! 1481: fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644); ! 1482: close(fd); ! 1483: } ! 1484: restore_perms(); ! 1485: } ! 1486: #else /* !USE_ADMIN_FLAG */ ! 1487: static void ! 1488: create_admin_success_flag(void) ! 1489: { ! 1490: /* STUB */ ! 1491: } ! 1492: #endif /* USE_ADMIN_FLAG */ ! 1493: ! 1494: struct policy_plugin sudoers_policy = { ! 1495: SUDO_POLICY_PLUGIN, ! 1496: SUDO_API_VERSION, ! 1497: sudoers_policy_open, ! 1498: sudoers_policy_close, ! 1499: sudoers_policy_version, ! 1500: sudoers_policy_check, ! 1501: sudoers_policy_list, ! 1502: sudoers_policy_validate, ! 1503: sudoers_policy_invalidate, ! 1504: sudoers_policy_init_session ! 1505: };