File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / sudoers.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:56:35 2013 UTC (10 years, 9 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_8p0, v1_8_8, HEAD
v 1.8.8

    1: /*
    2:  * Copyright (c) 1993-1996, 1998-2013 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: #define _SUDO_MAIN
   22: 
   23: #ifdef __TANDEM
   24: # include <floss.h>
   25: #endif
   26: 
   27: #include <config.h>
   28: 
   29: #include <sys/types.h>
   30: #include <sys/stat.h>
   31: #include <sys/socket.h>
   32: #include <stdio.h>
   33: #ifdef STDC_HEADERS
   34: # include <stdlib.h>
   35: # include <stddef.h>
   36: #else
   37: # ifdef HAVE_STDLIB_H
   38: #  include <stdlib.h>
   39: # endif
   40: #endif /* STDC_HEADERS */
   41: #ifdef HAVE_STRING_H
   42: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
   43: #  include <memory.h>
   44: # endif
   45: # include <string.h>
   46: #endif /* HAVE_STRING_H */
   47: #ifdef HAVE_STRINGS_H
   48: # include <strings.h>
   49: #endif /* HAVE_STRINGS_H */
   50: #ifdef HAVE_UNISTD_H
   51: # include <unistd.h>
   52: #endif /* HAVE_UNISTD_H */
   53: #include <pwd.h>
   54: #include <errno.h>
   55: #include <fcntl.h>
   56: #include <signal.h>
   57: #include <grp.h>
   58: #include <time.h>
   59: #include <netdb.h>
   60: #ifdef HAVE_LOGIN_CAP_H
   61: # include <login_cap.h>
   62: # ifndef LOGIN_DEFROOTCLASS
   63: #  define LOGIN_DEFROOTCLASS	"daemon"
   64: # endif
   65: # ifndef LOGIN_SETENV
   66: #  define LOGIN_SETENV	0
   67: # endif
   68: #endif
   69: #ifdef HAVE_SELINUX
   70: # include <selinux/selinux.h>
   71: #endif
   72: #include <ctype.h>
   73: #ifndef HAVE_GETADDRINFO
   74: # include "compat/getaddrinfo.h"
   75: #endif
   76: 
   77: #include "sudoers.h"
   78: #include "auth/sudo_auth.h"
   79: #include "secure_path.h"
   80: 
   81: /*
   82:  * Prototypes
   83:  */
   84: static char *find_editor(int nfiles, char **files, char ***argv_out);
   85: static int cb_runas_default(const char *);
   86: static int cb_sudoers_locale(const char *);
   87: static int set_cmnd(void);
   88: static void create_admin_success_flag(void);
   89: static void init_vars(char * const *);
   90: static void set_fqdn(void);
   91: static void set_loginclass(struct passwd *);
   92: static void set_runasgr(const char *);
   93: static void set_runaspw(const char *);
   94: static bool tty_present(void);
   95: 
   96: /*
   97:  * Globals
   98:  */
   99: struct sudo_user sudo_user;
  100: struct passwd *list_pw;
  101: int long_list;
  102: uid_t timestamp_uid;
  103: extern int errorlineno;
  104: extern bool parse_error;
  105: extern char *errorfile;
  106: #ifdef HAVE_BSD_AUTH_H
  107: char *login_style;
  108: #endif /* HAVE_BSD_AUTH_H */
  109: int sudo_mode;
  110: 
  111: static char *prev_user;
  112: static char *runas_user;
  113: static char *runas_group;
  114: static struct sudo_nss_list *snl;
  115: 
  116: /* XXX - must be extern for audit bits of sudo_auth.c */
  117: int NewArgc;
  118: char **NewArgv;
  119: 
  120: int
  121: sudoers_policy_init(void *info, char * const envp[])
  122: {
  123:     volatile int sources = 0;
  124:     struct sudo_nss *nss, *nss_next;
  125:     debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN)
  126: 
  127:     bindtextdomain("sudoers", LOCALEDIR);
  128: 
  129:     sudo_setpwent();
  130:     sudo_setgrent();
  131: 
  132:     /* Register fatal/fatalx callback. */
  133:     fatal_callback_register(sudoers_cleanup);
  134: 
  135:     /* Initialize environment functions (including replacements). */
  136:     env_init(envp);
  137: 
  138:     /* Setup defaults data structures. */
  139:     init_defaults();
  140: 
  141:     /* Parse info from front-end. */
  142:     sudo_mode = sudoers_policy_deserialize_info(info, &runas_user, &runas_group);
  143: 
  144:     init_vars(envp);		/* XXX - move this later? */
  145: 
  146:     /* Parse nsswitch.conf for sudoers order. */
  147:     snl = sudo_read_nss();
  148: 
  149:     /* LDAP or NSS may modify the euid so we need to be root for the open. */
  150:     set_perms(PERM_ROOT);
  151: 
  152:     /* Open and parse sudoers, set global defaults */
  153:     for (nss = snl->first; nss != NULL; nss = nss_next) {
  154:         nss_next = nss->next;
  155:         if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
  156:             sources++;
  157:             if (nss->setdefs(nss) != 0)
  158:                 log_warning(NO_STDERR, N_("problem with defaults entries"));
  159:         } else {
  160:             tq_remove(snl, nss);
  161:         }
  162:     }
  163:     if (sources == 0) {
  164: 	warningx(_("no valid sudoers sources found, quitting"));
  165: 	debug_return_bool(-1);
  166:     }
  167: 
  168:     /* XXX - collect post-sudoers parse settings into a function */
  169: 
  170:     /*
  171:      * Initialize external group plugin, if any.
  172:      */
  173:     if (def_group_plugin) {
  174: 	if (group_plugin_load(def_group_plugin) != true)
  175: 	    def_group_plugin = NULL;
  176:     }
  177: 
  178:     /*
  179:      * Set runas passwd/group entries based on command line or sudoers.
  180:      * Note that if runas_group was specified without runas_user we
  181:      * defer setting runas_pw so the match routines know to ignore it.
  182:      */
  183:     /* XXX - qpm4u does more here as it may have already set runas_pw */
  184:     if (runas_group != NULL) {
  185: 	set_runasgr(runas_group);
  186: 	if (runas_user != NULL)
  187: 	    set_runaspw(runas_user);
  188:     } else
  189: 	set_runaspw(runas_user ? runas_user : def_runas_default);
  190: 
  191:     if (!update_defaults(SETDEF_RUNAS))
  192: 	log_warning(NO_STDERR, N_("problem with defaults entries"));
  193: 
  194:     if (def_fqdn)
  195: 	set_fqdn();	/* deferred until after sudoers is parsed */
  196: 
  197:     /* Set login class if applicable. */
  198:     set_loginclass(runas_pw ? runas_pw : sudo_user.pw);
  199: 
  200:     restore_perms();
  201: 
  202:     debug_return_bool(true);
  203: }
  204: 
  205: int
  206: sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
  207:     void *closure)
  208: {
  209:     char **edit_argv = NULL;
  210:     char *iolog_path = NULL;
  211:     mode_t cmnd_umask = 0777;
  212:     struct sudo_nss *nss;
  213:     int cmnd_status = -1, oldlocale, validated;
  214:     volatile int rval = true;
  215:     debug_decl(sudoers_policy_main, SUDO_DEBUG_PLUGIN)
  216: 
  217:     /* XXX - would like to move this to policy.c but need the cleanup. */
  218:     if (fatal_setjmp() != 0) {
  219: 	/* error recovery via fatal(), fatalx() or log_fatal() */
  220: 	rval = -1;
  221: 	goto done;
  222:     }
  223: 
  224:     /* Is root even allowed to run sudo? */
  225:     if (user_uid == 0 && !def_root_sudo) {
  226:         warningx(_("sudoers specifies that root is not allowed to sudo"));
  227:         goto bad;
  228:     }    
  229: 
  230:     set_perms(PERM_INITIAL);
  231: 
  232:     /* Environment variables specified on the command line. */
  233:     if (env_add != NULL && env_add[0] != NULL)
  234: 	sudo_user.env_vars = env_add;
  235: 
  236:     /*
  237:      * Make a local copy of argc/argv, with special handling
  238:      * for pseudo-commands and the '-i' option.
  239:      */
  240:     if (argc == 0) {
  241: 	NewArgc = 1;
  242: 	NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
  243: 	NewArgv[0] = user_cmnd;
  244: 	NewArgv[1] = NULL;
  245:     } else {
  246: 	/* Must leave an extra slot before NewArgv for bash's --login */
  247: 	NewArgc = argc;
  248: 	NewArgv = emalloc2(NewArgc + 2, sizeof(char *));
  249: 	memcpy(++NewArgv, argv, argc * sizeof(char *));
  250: 	NewArgv[NewArgc] = NULL;
  251: 	if (ISSET(sudo_mode, MODE_LOGIN_SHELL) && runas_pw != NULL)
  252: 	    NewArgv[0] = estrdup(runas_pw->pw_shell);
  253:     }
  254: 
  255:     /* If given the -P option, set the "preserve_groups" flag. */
  256:     if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
  257: 	def_preserve_groups = true;
  258: 
  259:     /* Find command in path and apply per-command Defaults. */
  260:     cmnd_status = set_cmnd();
  261: 
  262:     /* Check for -C overriding def_closefrom. */
  263:     if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
  264: 	if (!def_closefrom_override) {
  265: 	    warningx(_("you are not permitted to use the -C option"));
  266: 	    goto bad;
  267: 	}
  268: 	def_closefrom = user_closefrom;
  269:     }
  270: 
  271:     /*
  272:      * Check sudoers sources, using the locale specified in sudoers.
  273:      */
  274:     sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
  275:     validated = FLAG_NO_USER | FLAG_NO_HOST;
  276:     tq_foreach_fwd(snl, nss) {
  277: 	validated = nss->lookup(nss, validated, pwflag);
  278: 
  279: 	if (ISSET(validated, VALIDATE_OK)) {
  280: 	    /* Handle [SUCCESS=return] */
  281: 	    if (nss->ret_if_found)
  282: 		break;
  283: 	} else {
  284: 	    /* Handle [NOTFOUND=return] */
  285: 	    if (nss->ret_if_notfound)
  286: 		break;
  287: 	}
  288:     }
  289: 
  290:     /* Restore user's locale. */
  291:     sudoers_setlocale(oldlocale, NULL);
  292: 
  293:     if (safe_cmnd == NULL)
  294: 	safe_cmnd = estrdup(user_cmnd);
  295: 
  296:     /* If only a group was specified, set runas_pw based on invoking user. */
  297:     if (runas_pw == NULL)
  298: 	set_runaspw(user_name);
  299: 
  300:     /*
  301:      * Look up the timestamp dir owner if one is specified.
  302:      */
  303:     if (def_timestampowner) {
  304: 	struct passwd *pw;
  305: 
  306: 	if (*def_timestampowner == '#')
  307: 	    pw = sudo_getpwuid(atoi(def_timestampowner + 1));
  308: 	else
  309: 	    pw = sudo_getpwnam(def_timestampowner);
  310: 	if (pw != NULL) {
  311: 	    timestamp_uid = pw->pw_uid;
  312: 	    sudo_pw_delref(pw);
  313: 	} else {
  314: 	    log_warning(0, N_("timestamp owner (%s): No such user"),
  315: 		def_timestampowner);
  316: 	    timestamp_uid = ROOT_UID;
  317: 	}
  318:     }
  319: 
  320:     /* If no command line args and "shell_noargs" is not set, error out. */
  321:     if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) {
  322: 	rval = -2; /* usage error */
  323: 	goto done;
  324:     }
  325: 
  326:     /* Bail if a tty is required and we don't have one.  */
  327:     if (def_requiretty && !tty_present()) {
  328: 	audit_failure(NewArgv, N_("no tty"));
  329: 	warningx(_("sorry, you must have a tty to run sudo"));
  330: 	goto bad;
  331:     }
  332: 
  333:     /*
  334:      * We don't reset the environment for sudoedit or if the user
  335:      * specified the -E command line flag and they have setenv privs.
  336:      */
  337:     if (ISSET(sudo_mode, MODE_EDIT) ||
  338: 	(ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv))
  339: 	def_env_reset = false;
  340: 
  341:     /* Build a new environment that avoids any nasty bits. */
  342:     rebuild_env();
  343: 
  344:     /* Require a password if sudoers says so.  */
  345:     rval = check_user(validated, sudo_mode);
  346:     if (rval != true) {
  347: 	if (!ISSET(validated, VALIDATE_OK))
  348: 	    log_denial(validated, false);
  349: 	goto done;
  350:     }
  351: 
  352:     /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
  353:     /* XXX - causes confusion when root is not listed in sudoers */
  354:     if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
  355: 	if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
  356: 	    struct passwd *pw;
  357: 
  358: 	    if ((pw = sudo_getpwnam(prev_user)) != NULL) {
  359: 		    if (sudo_user.pw != NULL)
  360: 			sudo_pw_delref(sudo_user.pw);
  361: 		    sudo_user.pw = pw;
  362: 	    }
  363: 	}
  364:     }
  365: 
  366:     /* If the user was not allowed to run the command we are done. */
  367:     if (!ISSET(validated, VALIDATE_OK)) {
  368: 	log_failure(validated, cmnd_status);
  369: 	goto bad;
  370:     }
  371: 
  372:     /* Create Ubuntu-style dot file to indicate sudo was successful. */
  373:     create_admin_success_flag();
  374: 
  375:     /* Finally tell the user if the command did not exist. */
  376:     if (cmnd_status == NOT_FOUND_DOT) {
  377: 	audit_failure(NewArgv, N_("command in current directory"));
  378: 	warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd);
  379: 	goto bad;
  380:     } else if (cmnd_status == NOT_FOUND) {
  381: 	if (ISSET(sudo_mode, MODE_CHECK)) {
  382: 	    audit_failure(NewArgv, N_("%s: command not found"), NewArgv[0]);
  383: 	    warningx(_("%s: command not found"), NewArgv[0]);
  384: 	} else {
  385: 	    audit_failure(NewArgv, N_("%s: command not found"), user_cmnd);
  386: 	    warningx(_("%s: command not found"), user_cmnd);
  387: 	}
  388: 	goto bad;
  389:     }
  390: 
  391:     /* If user specified env vars make sure sudoers allows it. */
  392:     if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
  393: 	if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) {
  394: 	    warningx(_("sorry, you are not allowed to preserve the environment"));
  395: 	    goto bad;
  396: 	} else
  397: 	    validate_env_vars(sudo_user.env_vars);
  398:     }
  399: 
  400:     if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT))) {
  401: 	if ((def_log_input || def_log_output) && def_iolog_file && def_iolog_dir) {
  402: 	    const char prefix[] = "iolog_path=";
  403: 	    iolog_path = expand_iolog_path(prefix, def_iolog_dir,
  404: 		def_iolog_file, &sudo_user.iolog_file);
  405: 	    sudo_user.iolog_file++;
  406: 	}
  407:     }
  408: 
  409:     log_allowed(validated);
  410:     if (ISSET(sudo_mode, MODE_CHECK))
  411: 	rval = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
  412:     else if (ISSET(sudo_mode, MODE_LIST))
  413: 	display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* XXX - return val */
  414: 
  415:     /* Cleanup sudoers sources */
  416:     tq_foreach_fwd(snl, nss) {
  417: 	nss->close(nss);
  418:     }
  419:     if (def_group_plugin)
  420: 	group_plugin_unload();
  421: 
  422:     if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) {
  423: 	/* rval already set appropriately */
  424: 	goto done;
  425:     }
  426: 
  427:     /*
  428:      * Set umask based on sudoers.
  429:      * If user's umask is more restrictive, OR in those bits too
  430:      * unless umask_override is set.
  431:      */
  432:     if (def_umask != 0777) {
  433: 	cmnd_umask = def_umask;
  434: 	if (!def_umask_override)
  435: 	    cmnd_umask |= user_umask;
  436:     }
  437: 
  438:     if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
  439: 	char *p;
  440: 
  441: 	/* Convert /bin/sh -> -sh so shell knows it is a login shell */
  442: 	if ((p = strrchr(NewArgv[0], '/')) == NULL)
  443: 	    p = NewArgv[0];
  444: 	*p = '-';
  445: 	NewArgv[0] = p;
  446: 
  447: 	/*
  448: 	 * Newer versions of bash require the --login option to be used
  449: 	 * in conjunction with the -c option even if the shell name starts
  450: 	 * with a '-'.  Unfortunately, bash 1.x uses -login, not --login
  451: 	 * so this will cause an error for that.
  452: 	 */
  453: 	if (NewArgc > 1 && strcmp(NewArgv[0], "-bash") == 0 &&
  454: 	    strcmp(NewArgv[1], "-c") == 0) {
  455: 	    /* Use the extra slot before NewArgv so we can store --login. */
  456: 	    NewArgv--;
  457: 	    NewArgc++;
  458: 	    NewArgv[0] = NewArgv[1];
  459: 	    NewArgv[1] = "--login";
  460: 	}
  461: 
  462: #if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM))
  463: 	/* Insert system-wide environment variables. */
  464: 	read_env_file(_PATH_ENVIRONMENT, true);
  465: #endif
  466: #ifdef HAVE_LOGIN_CAP_H
  467: 	/* Set environment based on login class. */
  468: 	if (login_class) {
  469: 	    login_cap_t *lc = login_getclass(login_class);
  470: 	    if (lc != NULL) {
  471: 		setusercontext(lc, runas_pw, runas_pw->pw_uid, LOGIN_SETPATH|LOGIN_SETENV);
  472: 		login_close(lc);
  473: 	    }
  474: 	}
  475: #endif /* HAVE_LOGIN_CAP_H */
  476:     }
  477: 
  478:     /* Insert system-wide environment variables. */
  479:     if (def_env_file)
  480: 	read_env_file(def_env_file, false);
  481: 
  482:     /* Insert user-specified environment variables. */
  483:     insert_env_vars(sudo_user.env_vars);
  484: 
  485:     if (ISSET(sudo_mode, MODE_EDIT)) {
  486: 	efree(safe_cmnd);
  487: 	safe_cmnd = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv);
  488: 	if (safe_cmnd == NULL)
  489: 	    goto bad;
  490:     }
  491: 
  492:     /* Must audit before uid change. */
  493:     audit_success(NewArgv);
  494: 
  495:     /* Setup execution environment to pass back to front-end. */
  496:     rval = sudoers_policy_exec_setup(edit_argv ? edit_argv : NewArgv,
  497: 	env_get(), cmnd_umask, iolog_path, closure);
  498: 
  499:     /* Zero out stashed copy of environment, it is owned by the front-end. */
  500:     env_init(NULL);
  501: 
  502:     goto done;
  503: 
  504: bad:
  505:     rval = false;
  506: 
  507: done:
  508:     fatal_disable_setjmp();
  509:     rewind_perms();
  510: 
  511:     /* Close the password and group files and free up memory. */
  512:     sudo_endpwent();
  513:     sudo_endgrent();
  514: 
  515:     debug_return_bool(rval);
  516: }
  517: 
  518: /*
  519:  * Initialize timezone and fill in ``sudo_user'' struct.
  520:  */
  521: static void
  522: init_vars(char * const envp[])
  523: {
  524:     char * const * ep;
  525:     bool unknown_user = false;
  526:     debug_decl(init_vars, SUDO_DEBUG_PLUGIN)
  527: 
  528:     sudoers_initlocale(setlocale(LC_ALL, NULL), def_sudoers_locale);
  529: 
  530:     for (ep = envp; *ep; ep++) {
  531: 	/* XXX - don't fill in if empty string */
  532: 	switch (**ep) {
  533: 	    case 'K':
  534: 		if (strncmp("KRB5CCNAME=", *ep, 11) == 0)
  535: 		    user_ccname = *ep + 11;
  536: 		break;
  537: 	    case 'P':
  538: 		if (strncmp("PATH=", *ep, 5) == 0)
  539: 		    user_path = *ep + 5;
  540: 		break;
  541: 	    case 'S':
  542: 		if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
  543: 		    user_prompt = *ep + 12;
  544: 		else if (strncmp("SUDO_USER=", *ep, 10) == 0)
  545: 		    prev_user = *ep + 10;
  546: 		break;
  547: 	    }
  548:     }
  549: 
  550:     /*
  551:      * Get a local copy of the user's struct passwd if we don't already
  552:      * have one.
  553:      */
  554:     if (sudo_user.pw == NULL) {
  555: 	if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) {
  556: 	    /*
  557: 	     * It is not unusual for users to place "sudo -k" in a .logout
  558: 	     * file which can cause sudo to be run during reboot after the
  559: 	     * YP/NIS/NIS+/LDAP/etc daemon has died.
  560: 	     */
  561: 	    if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
  562: 		fatalx(_("unknown uid: %u"), (unsigned int) user_uid);
  563: 
  564: 	    /* Need to make a fake struct passwd for the call to log_fatal(). */
  565: 	    sudo_user.pw = sudo_mkpwent(user_name, user_uid, user_gid, NULL, NULL);
  566: 	    unknown_user = true;
  567: 	}
  568:     }
  569: 
  570:     /*
  571:      * Get group list and store initialize permissions.
  572:      */
  573:     if (user_group_list == NULL)
  574: 	user_group_list = sudo_get_grlist(sudo_user.pw);
  575:     set_perms(PERM_INITIAL);
  576: 
  577:     /* Set runas callback. */
  578:     sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default;
  579: 
  580:     /* Set locale callback. */
  581:     sudo_defs_table[I_SUDOERS_LOCALE].callback = cb_sudoers_locale;
  582: 
  583:     /* Set maxseq callback. */
  584:     sudo_defs_table[I_MAXSEQ].callback = io_set_max_sessid;
  585: 
  586:     /* It is now safe to use log_fatal() and set_perms() */
  587:     if (unknown_user)
  588: 	log_fatal(0, N_("unknown uid: %u"), (unsigned int) user_uid);
  589:     debug_return;
  590: }
  591: 
  592: /*
  593:  * Fill in user_cmnd, user_args, user_base and user_stat variables
  594:  * and apply any command-specific defaults entries.
  595:  */
  596: static int
  597: set_cmnd(void)
  598: {
  599:     int rval;
  600:     char *path = user_path;
  601:     debug_decl(set_cmnd, SUDO_DEBUG_PLUGIN)
  602: 
  603:     /* Resolve the path and return. */
  604:     rval = FOUND;
  605:     user_stat = ecalloc(1, sizeof(struct stat));
  606: 
  607:     /* Default value for cmnd, overridden below. */
  608:     if (user_cmnd == NULL)
  609: 	user_cmnd = NewArgv[0];
  610: 
  611:     if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
  612: 	if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
  613: 	    if (def_secure_path && !user_is_exempt())
  614: 		path = def_secure_path;
  615: 	    set_perms(PERM_RUNAS);
  616: 	    rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
  617: 		def_ignore_dot);
  618: 	    restore_perms();
  619: 	    if (rval != FOUND) {
  620: 		/* Failed as root, try as invoking user. */
  621: 		set_perms(PERM_USER);
  622: 		rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
  623: 		    def_ignore_dot);
  624: 		restore_perms();
  625: 	    }
  626: 	}
  627: 
  628: 	/* set user_args */
  629: 	if (NewArgc > 1) {
  630: 	    char *to, *from, **av;
  631: 	    size_t size, n;
  632: 
  633: 	    /* Alloc and build up user_args. */
  634: 	    for (size = 0, av = NewArgv + 1; *av; av++)
  635: 		size += strlen(*av) + 1;
  636: 	    user_args = emalloc(size);
  637: 	    if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
  638: 		/*
  639: 		 * When running a command via a shell, the sudo front-end
  640: 		 * escapes potential meta chars.  We unescape non-spaces
  641: 		 * for sudoers matching and logging purposes.
  642: 		 */
  643: 		for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
  644: 		    while (*from) {
  645: 			if (from[0] == '\\' && !isspace((unsigned char)from[1]))
  646: 			    from++;
  647: 			*to++ = *from++;
  648: 		    }
  649: 		    *to++ = ' ';
  650: 		}
  651: 		*--to = '\0';
  652: 	    } else {
  653: 		for (to = user_args, av = NewArgv + 1; *av; av++) {
  654: 		    n = strlcpy(to, *av, size - (to - user_args));
  655: 		    if (n >= size - (to - user_args))
  656: 			fatalx(_("internal error, %s overflow"), "set_cmnd()");
  657: 		    to += n;
  658: 		    *to++ = ' ';
  659: 		}
  660: 		*--to = '\0';
  661: 	    }
  662: 	}
  663:     }
  664:     if (strlen(user_cmnd) >= PATH_MAX) {
  665: 	errno = ENAMETOOLONG;
  666: 	fatal("%s", user_cmnd);
  667:     }
  668: 
  669:     if ((user_base = strrchr(user_cmnd, '/')) != NULL)
  670: 	user_base++;
  671:     else
  672: 	user_base = user_cmnd;
  673: 
  674:     if (!update_defaults(SETDEF_CMND))
  675: 	log_warning(NO_STDERR, N_("problem with defaults entries"));
  676: 
  677:     debug_return_int(rval);
  678: }
  679: 
  680: /*
  681:  * Open sudoers and sanity check mode/owner/type.
  682:  * Returns a handle to the sudoers file or NULL on error.
  683:  */
  684: FILE *
  685: open_sudoers(const char *sudoers, bool doedit, bool *keepopen)
  686: {
  687:     struct stat sb;
  688:     FILE *fp = NULL;
  689:     debug_decl(open_sudoers, SUDO_DEBUG_PLUGIN)
  690: 
  691:     set_perms(PERM_SUDOERS);
  692: 
  693:     switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) {
  694: 	case SUDO_PATH_SECURE:
  695: 	    /*
  696: 	     * If we are expecting sudoers to be group readable but
  697: 	     * it is not, we must open the file as root, not uid 1.
  698: 	     */
  699: 	    if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP)) {
  700: 		if ((sb.st_mode & S_IRGRP) == 0) {
  701: 		    restore_perms();
  702: 		    set_perms(PERM_ROOT);
  703: 		}
  704: 	    }
  705: 	    /*
  706: 	     * Open sudoers and make sure we can read it so we can present
  707: 	     * the user with a reasonable error message (unlike the lexer).
  708: 	     */
  709: 	    if ((fp = fopen(sudoers, "r")) == NULL) {
  710: 		log_warning(USE_ERRNO, N_("unable to open %s"), sudoers);
  711: 	    } else {
  712: 		if (sb.st_size != 0 && fgetc(fp) == EOF) {
  713: 		    log_warning(USE_ERRNO, N_("unable to read %s"),
  714: 			sudoers);
  715: 		    fclose(fp);
  716: 		    fp = NULL;
  717: 		} else {
  718: 		    /* Rewind fp and set close on exec flag. */
  719: 		    rewind(fp);
  720: 		    (void) fcntl(fileno(fp), F_SETFD, 1);
  721: 		}
  722: 	    }
  723: 	    break;
  724: 	case SUDO_PATH_MISSING:
  725: 	    log_warning(USE_ERRNO, N_("unable to stat %s"), sudoers);
  726: 	    break;
  727: 	case SUDO_PATH_BAD_TYPE:
  728: 	    log_warning(0, N_("%s is not a regular file"), sudoers);
  729: 	    break;
  730: 	case SUDO_PATH_WRONG_OWNER:
  731: 	    log_warning(0, N_("%s is owned by uid %u, should be %u"),
  732: 		sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid);
  733: 	    break;
  734: 	case SUDO_PATH_WORLD_WRITABLE:
  735: 	    log_warning(0, N_("%s is world writable"), sudoers);
  736: 	    break;
  737: 	case SUDO_PATH_GROUP_WRITABLE:
  738: 	    log_warning(0, N_("%s is owned by gid %u, should be %u"),
  739: 		sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid);
  740: 	    break;
  741: 	default:
  742: 	    /* NOTREACHED */
  743: 	    break;
  744:     }
  745: 
  746:     restore_perms();		/* change back to root */
  747: 
  748:     debug_return_ptr(fp);
  749: }
  750: 
  751: #ifdef HAVE_LOGIN_CAP_H
  752: static void
  753: set_loginclass(struct passwd *pw)
  754: {
  755:     const int errflags = NO_MAIL|MSG_ONLY;
  756:     login_cap_t *lc;
  757:     debug_decl(set_loginclass, SUDO_DEBUG_PLUGIN)
  758: 
  759:     if (!def_use_loginclass)
  760: 	debug_return;
  761: 
  762:     if (login_class && strcmp(login_class, "-") != 0) {
  763: 	if (user_uid != 0 &&
  764: 	    strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
  765: 	    fatalx(_("only root can use `-c %s'"), login_class);
  766:     } else {
  767: 	login_class = pw->pw_class;
  768: 	if (!login_class || !*login_class)
  769: 	    login_class =
  770: 		(pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
  771:     }
  772: 
  773:     /* Make sure specified login class is valid. */
  774:     lc = login_getclass(login_class);
  775:     if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
  776: 	/*
  777: 	 * Don't make it a fatal error if the user didn't specify the login
  778: 	 * class themselves.  We do this because if login.conf gets
  779: 	 * corrupted we want the admin to be able to use sudo to fix it.
  780: 	 */
  781: 	if (login_class)
  782: 	    log_fatal(errflags, N_("unknown login class: %s"), login_class);
  783: 	else
  784: 	    log_warning(errflags, N_("unknown login class: %s"), login_class);
  785: 	def_use_loginclass = false;
  786:     }
  787:     login_close(lc);
  788:     debug_return;
  789: }
  790: #else
  791: static void
  792: set_loginclass(struct passwd *pw)
  793: {
  794: }
  795: #endif /* HAVE_LOGIN_CAP_H */
  796: 
  797: #ifndef AI_FQDN
  798: # define AI_FQDN AI_CANONNAME
  799: #endif
  800: 
  801: /*
  802:  * Look up the fully qualified domain name and set user_host and user_shost.
  803:  * Use AI_FQDN if available since "canonical" is not always the same as fqdn.
  804:  */
  805: static void
  806: set_fqdn(void)
  807: {
  808:     struct addrinfo *res0, hint;
  809:     char *p;
  810:     debug_decl(set_fqdn, SUDO_DEBUG_PLUGIN)
  811: 
  812:     memset(&hint, 0, sizeof(hint));
  813:     hint.ai_family = PF_UNSPEC;
  814:     hint.ai_flags = AI_FQDN;
  815:     if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
  816: 	log_warning(MSG_ONLY, N_("unable to resolve host %s"), user_host);
  817:     } else {
  818: 	if (user_shost != user_host)
  819: 	    efree(user_shost);
  820: 	efree(user_host);
  821: 	user_host = estrdup(res0->ai_canonname);
  822: 	freeaddrinfo(res0);
  823: 	if ((p = strchr(user_host, '.')) != NULL)
  824: 	    user_shost = estrndup(user_host, (size_t)(p - user_host));
  825: 	else
  826: 	    user_shost = user_host;
  827:     }
  828:     debug_return;
  829: }
  830: 
  831: /*
  832:  * Get passwd entry for the user we are going to run commands as
  833:  * and store it in runas_pw.  By default, commands run as "root".
  834:  */
  835: static void
  836: set_runaspw(const char *user)
  837: {
  838:     debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN)
  839: 
  840:     if (runas_pw != NULL)
  841: 	sudo_pw_delref(runas_pw);
  842:     if (*user == '#') {
  843: 	if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
  844: 	    runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
  845:     } else {
  846: 	if ((runas_pw = sudo_getpwnam(user)) == NULL)
  847: 	    log_fatal(NO_MAIL|MSG_ONLY, N_("unknown user: %s"), user);
  848:     }
  849:     debug_return;
  850: }
  851: 
  852: /*
  853:  * Get group entry for the group we are going to run commands as
  854:  * and store it in runas_gr.
  855:  */
  856: static void
  857: set_runasgr(const char *group)
  858: {
  859:     debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN)
  860: 
  861:     if (runas_gr != NULL)
  862: 	sudo_gr_delref(runas_gr);
  863:     if (*group == '#') {
  864: 	if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
  865: 	    runas_gr = sudo_fakegrnam(group);
  866:     } else {
  867: 	if ((runas_gr = sudo_getgrnam(group)) == NULL)
  868: 	    log_fatal(NO_MAIL|MSG_ONLY, N_("unknown group: %s"), group);
  869:     }
  870:     debug_return;
  871: }
  872: 
  873: /*
  874:  * Callback for runas_default sudoers setting.
  875:  */
  876: static int
  877: cb_runas_default(const char *user)
  878: {
  879:     /* Only reset runaspw if user didn't specify one. */
  880:     if (!runas_user && !runas_group)
  881: 	set_runaspw(user);
  882:     return true;
  883: }
  884: 
  885: /*
  886:  * Callback for sudoers_locale sudoers setting.
  887:  */
  888: static int
  889: cb_sudoers_locale(const char *locale)
  890: {
  891:     sudoers_initlocale(NULL, locale);
  892:     return true;
  893: }
  894: 
  895: /*
  896:  * Cleanup hook for fatal()/fatalx()
  897:  */
  898: void
  899: sudoers_cleanup(void)
  900: {
  901:     struct sudo_nss *nss;
  902:     debug_decl(sudoers_cleanup, SUDO_DEBUG_PLUGIN)
  903: 
  904:     if (snl != NULL) {
  905: 	tq_foreach_fwd(snl, nss)
  906: 	    nss->close(nss);
  907:     }
  908:     if (def_group_plugin)
  909: 	group_plugin_unload();
  910:     sudo_endpwent();
  911:     sudo_endgrent();
  912: 
  913:     debug_return;
  914: }
  915: 
  916: static char *
  917: resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, char ***argv_out)
  918: {
  919:     char *cp, **nargv, *editor, *editor_path = NULL;
  920:     int ac, i, nargc;
  921:     bool wasblank;
  922:     debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN)
  923: 
  924:     /* Note: editor becomes part of argv_out and is not freed. */
  925:     editor = emalloc(edlen + 1);
  926:     memcpy(editor, ed, edlen);
  927:     editor[edlen] = '\0';
  928: 
  929:     /*
  930:      * Split editor into an argument vector; editor is reused (do not free).
  931:      * The EDITOR and VISUAL environment variables may contain command
  932:      * line args so look for those and alloc space for them too.
  933:      */
  934:     nargc = 1;
  935:     for (wasblank = false, cp = editor; *cp != '\0'; cp++) {
  936: 	if (isblank((unsigned char) *cp))
  937: 	    wasblank = true;
  938: 	else if (wasblank) {
  939: 	    wasblank = false;
  940: 	    nargc++;
  941: 	}
  942:     }
  943:     /* If we can't find the editor in the user's PATH, give up. */
  944:     cp = strtok(editor, " \t");
  945:     if (cp == NULL ||
  946: 	find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
  947: 	efree(editor);
  948: 	debug_return_str(NULL);
  949:     }
  950:     nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *));
  951:     for (ac = 0; cp != NULL && ac < nargc; ac++) {
  952: 	nargv[ac] = cp;
  953: 	cp = strtok(NULL, " \t");
  954:     }
  955:     nargv[ac++] = "--";
  956:     for (i = 0; i < nfiles; )
  957: 	nargv[ac++] = files[i++];
  958:     nargv[ac] = NULL;
  959: 
  960:     *argv_out = nargv;
  961:     debug_return_str(editor_path);
  962: }
  963: 
  964: /*
  965:  * Determine which editor to use.  We don't need to worry about restricting
  966:  * this to a "safe" editor since it runs with the uid of the invoking user,
  967:  * not the runas (privileged) user.
  968:  */
  969: static char *
  970: find_editor(int nfiles, char **files, char ***argv_out)
  971: {
  972:     const char *cp, *ep, *editor;
  973:     char *editor_path = NULL, **ev, *ev0[4];
  974:     size_t len;
  975:     debug_decl(find_editor, SUDO_DEBUG_PLUGIN)
  976: 
  977:     /*
  978:      * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one.
  979:      */
  980:     ev0[0] = "SUDO_EDITOR";
  981:     ev0[1] = "VISUAL";
  982:     ev0[2] = "EDITOR";
  983:     ev0[3] = NULL;
  984:     for (ev = ev0; editor_path == NULL && *ev != NULL; ev++) {
  985: 	if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
  986: 	    editor_path = resolve_editor(editor, strlen(editor), nfiles,
  987: 		files, argv_out);
  988: 	}
  989:     }
  990:     if (editor_path == NULL) {
  991: 	/* def_editor could be a path, split it up, avoiding strtok() */
  992: 	cp = editor = def_editor;
  993: 	do {
  994: 	    if ((ep = strchr(cp, ':')) != NULL)
  995: 		len = ep - cp;
  996: 	    else
  997: 		len = strlen(cp);
  998: 	    editor_path = resolve_editor(cp, len, nfiles, files, argv_out);
  999: 	    cp = ep + 1;
 1000: 	} while (ep != NULL && editor_path == NULL);
 1001:     }
 1002:     if (!editor_path) {
 1003: 	audit_failure(NewArgv, N_("%s: command not found"), editor);
 1004: 	warningx(_("%s: command not found"), editor);
 1005:     }
 1006:     debug_return_str(editor_path);
 1007: }
 1008: 
 1009: #ifdef USE_ADMIN_FLAG
 1010: static void
 1011: create_admin_success_flag(void)
 1012: {
 1013:     struct stat statbuf;
 1014:     char flagfile[PATH_MAX];
 1015:     int fd, n;
 1016:     debug_decl(create_admin_success_flag, SUDO_DEBUG_PLUGIN)
 1017: 
 1018:     /* Check whether the user is in the admin group. */
 1019:     if (!user_in_group(sudo_user.pw, "admin"))
 1020: 	debug_return;
 1021: 
 1022:     /* Build path to flag file. */
 1023:     n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful",
 1024: 	user_dir);
 1025:     if (n <= 0 || n >= sizeof(flagfile))
 1026: 	debug_return;
 1027: 
 1028:     /* Create admin flag file if it doesn't already exist. */
 1029:     set_perms(PERM_USER);
 1030:     if (stat(flagfile, &statbuf) != 0) {
 1031: 	fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
 1032: 	close(fd);
 1033:     }
 1034:     restore_perms();
 1035:     debug_return;
 1036: }
 1037: #else /* !USE_ADMIN_FLAG */
 1038: static void
 1039: create_admin_success_flag(void)
 1040: {
 1041:     /* STUB */
 1042: }
 1043: #endif /* USE_ADMIN_FLAG */
 1044: 
 1045: static bool
 1046: tty_present(void)
 1047: {
 1048: #if defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) || defined(HAVE_PSTAT_GETPROC) || defined(__linux__)
 1049:     return user_ttypath != NULL;
 1050: #else
 1051:     int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
 1052:     if (fd != -1)
 1053: 	close(fd);
 1054:     return fd != -1;
 1055: #endif
 1056: }

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