File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / sudoers.c
Revision 1.1.1.6 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:54 2014 UTC (10 years, 3 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_10p3_0, v1_8_10p3, HEAD
sudo v 1.8.10p3

    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: #ifdef HAVE_BSD_AUTH_H
  104: char *login_style;
  105: #endif /* HAVE_BSD_AUTH_H */
  106: int sudo_mode;
  107: 
  108: static char *prev_user;
  109: static char *runas_user;
  110: static char *runas_group;
  111: static struct sudo_nss_list *snl;
  112: 
  113: /* XXX - must be extern for audit bits of sudo_auth.c */
  114: int NewArgc;
  115: char **NewArgv;
  116: 
  117: int
  118: sudoers_policy_init(void *info, char * const envp[])
  119: {
  120:     volatile int sources = 0;
  121:     struct sudo_nss *nss, *nss_next;
  122:     debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN)
  123: 
  124:     bindtextdomain("sudoers", LOCALEDIR);
  125: 
  126:     sudo_setpwent();
  127:     sudo_setgrent();
  128: 
  129:     /* Register fatal/fatalx callback. */
  130:     fatal_callback_register(sudoers_cleanup);
  131: 
  132:     /* Initialize environment functions (including replacements). */
  133:     env_init(envp);
  134: 
  135:     /* Setup defaults data structures. */
  136:     init_defaults();
  137: 
  138:     /* Parse info from front-end. */
  139:     sudo_mode = sudoers_policy_deserialize_info(info, &runas_user, &runas_group);
  140: 
  141:     init_vars(envp);		/* XXX - move this later? */
  142: 
  143:     /* Parse nsswitch.conf for sudoers order. */
  144:     snl = sudo_read_nss();
  145: 
  146:     /* LDAP or NSS may modify the euid so we need to be root for the open. */
  147:     set_perms(PERM_ROOT);
  148: 
  149:     /* Open and parse sudoers, set global defaults */
  150:     TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) {
  151:         if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
  152:             sources++;
  153:             if (nss->setdefs(nss) != 0)
  154:                 log_warning(NO_STDERR, N_("problem with defaults entries"));
  155:         } else {
  156: 	    TAILQ_REMOVE(snl, nss, entries);
  157:         }
  158:     }
  159:     if (sources == 0) {
  160: 	warningx(U_("no valid sudoers sources found, quitting"));
  161: 	debug_return_bool(-1);
  162:     }
  163: 
  164:     /* XXX - collect post-sudoers parse settings into a function */
  165: 
  166:     /*
  167:      * Initialize external group plugin, if any.
  168:      */
  169:     if (def_group_plugin) {
  170: 	if (group_plugin_load(def_group_plugin) != true)
  171: 	    def_group_plugin = NULL;
  172:     }
  173: 
  174:     /*
  175:      * Set runas passwd/group entries based on command line or sudoers.
  176:      * Note that if runas_group was specified without runas_user we
  177:      * defer setting runas_pw so the match routines know to ignore it.
  178:      */
  179:     /* XXX - qpm4u does more here as it may have already set runas_pw */
  180:     if (runas_group != NULL) {
  181: 	set_runasgr(runas_group);
  182: 	if (runas_user != NULL)
  183: 	    set_runaspw(runas_user);
  184:     } else
  185: 	set_runaspw(runas_user ? runas_user : def_runas_default);
  186: 
  187:     if (!update_defaults(SETDEF_RUNAS))
  188: 	log_warning(NO_STDERR, N_("problem with defaults entries"));
  189: 
  190:     if (def_fqdn)
  191: 	set_fqdn();	/* deferred until after sudoers is parsed */
  192: 
  193:     /* Set login class if applicable. */
  194:     set_loginclass(runas_pw ? runas_pw : sudo_user.pw);
  195: 
  196:     restore_perms();
  197: 
  198:     debug_return_bool(true);
  199: }
  200: 
  201: int
  202: sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
  203:     void *closure)
  204: {
  205:     char **edit_argv = NULL;
  206:     char *iolog_path = NULL;
  207:     mode_t cmnd_umask = 0777;
  208:     struct sudo_nss *nss;
  209:     int cmnd_status = -1, oldlocale, validated;
  210:     volatile int rval = true;
  211:     debug_decl(sudoers_policy_main, SUDO_DEBUG_PLUGIN)
  212: 
  213:     /* XXX - would like to move this to policy.c but need the cleanup. */
  214:     if (fatal_setjmp() != 0) {
  215: 	/* error recovery via fatal(), fatalx() or log_fatal() */
  216: 	rval = -1;
  217: 	goto done;
  218:     }
  219: 
  220:     /* Is root even allowed to run sudo? */
  221:     if (user_uid == 0 && !def_root_sudo) {
  222:         warningx(U_("sudoers specifies that root is not allowed to sudo"));
  223:         goto bad;
  224:     }    
  225: 
  226:     set_perms(PERM_INITIAL);
  227: 
  228:     /* Environment variables specified on the command line. */
  229:     if (env_add != NULL && env_add[0] != NULL)
  230: 	sudo_user.env_vars = env_add;
  231: 
  232:     /*
  233:      * Make a local copy of argc/argv, with special handling
  234:      * for pseudo-commands and the '-i' option.
  235:      */
  236:     if (argc == 0) {
  237: 	NewArgc = 1;
  238: 	NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
  239: 	NewArgv[0] = user_cmnd;
  240: 	NewArgv[1] = NULL;
  241:     } else {
  242: 	/* Must leave an extra slot before NewArgv for bash's --login */
  243: 	NewArgc = argc;
  244: 	NewArgv = emalloc2(NewArgc + 2, sizeof(char *));
  245: 	memcpy(++NewArgv, argv, argc * sizeof(char *));
  246: 	NewArgv[NewArgc] = NULL;
  247: 	if (ISSET(sudo_mode, MODE_LOGIN_SHELL) && runas_pw != NULL)
  248: 	    NewArgv[0] = estrdup(runas_pw->pw_shell);
  249:     }
  250: 
  251:     /* If given the -P option, set the "preserve_groups" flag. */
  252:     if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
  253: 	def_preserve_groups = true;
  254: 
  255:     /* Find command in path and apply per-command Defaults. */
  256:     cmnd_status = set_cmnd();
  257: 
  258:     /* Check for -C overriding def_closefrom. */
  259:     if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
  260: 	if (!def_closefrom_override) {
  261: 	    warningx(U_("you are not permitted to use the -C option"));
  262: 	    goto bad;
  263: 	}
  264: 	def_closefrom = user_closefrom;
  265:     }
  266: 
  267:     /*
  268:      * Check sudoers sources, using the locale specified in sudoers.
  269:      */
  270:     sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
  271:     validated = FLAG_NO_USER | FLAG_NO_HOST;
  272:     TAILQ_FOREACH(nss, snl, entries) {
  273: 	validated = nss->lookup(nss, validated, pwflag);
  274: 
  275: 	if (ISSET(validated, VALIDATE_OK)) {
  276: 	    /* Handle [SUCCESS=return] */
  277: 	    if (nss->ret_if_found)
  278: 		break;
  279: 	} else {
  280: 	    /* Handle [NOTFOUND=return] */
  281: 	    if (nss->ret_if_notfound)
  282: 		break;
  283: 	}
  284:     }
  285: 
  286:     /* Restore user's locale. */
  287:     sudoers_setlocale(oldlocale, NULL);
  288: 
  289:     if (safe_cmnd == NULL)
  290: 	safe_cmnd = estrdup(user_cmnd);
  291: 
  292:     /* If only a group was specified, set runas_pw based on invoking user. */
  293:     if (runas_pw == NULL)
  294: 	set_runaspw(user_name);
  295: 
  296:     /*
  297:      * Look up the timestamp dir owner if one is specified.
  298:      */
  299:     if (def_timestampowner) {
  300: 	struct passwd *pw = NULL;
  301: 
  302: 	if (*def_timestampowner == '#') {
  303: 	    const char *errstr;
  304: 	    uid_t uid = atoid(def_timestampowner + 1, NULL, NULL, &errstr);
  305: 	    if (errstr == NULL)
  306: 		pw = sudo_getpwuid(uid);
  307: 	}
  308: 	if (pw == NULL)
  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(U_("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(U_("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(U_("%s: command not found"), NewArgv[0]);
  384: 	} else {
  385: 	    audit_failure(NewArgv, N_("%s: command not found"), user_cmnd);
  386: 	    warningx(U_("%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(U_("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:     TAILQ_FOREACH(nss, snl, entries) {
  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(U_("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(U_("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 by
  697: 	     * SUDOERS_GID but it is not, we must open the file as root,
  698: 	     * not uid 1.
  699: 	     */
  700: 	    if (sudoers_uid == ROOT_UID && ISSET(sudoers_mode, S_IRGRP)) {
  701: 		if (!ISSET(sb.st_mode, S_IRGRP) || sb.st_gid != SUDOERS_GID) {
  702: 		    restore_perms();
  703: 		    set_perms(PERM_ROOT);
  704: 		}
  705: 	    }
  706: 	    /*
  707: 	     * Open sudoers and make sure we can read it so we can present
  708: 	     * the user with a reasonable error message (unlike the lexer).
  709: 	     */
  710: 	    if ((fp = fopen(sudoers, "r")) == NULL) {
  711: 		log_warning(USE_ERRNO, N_("unable to open %s"), sudoers);
  712: 	    } else {
  713: 		if (sb.st_size != 0 && fgetc(fp) == EOF) {
  714: 		    log_warning(USE_ERRNO, N_("unable to read %s"),
  715: 			sudoers);
  716: 		    fclose(fp);
  717: 		    fp = NULL;
  718: 		} else {
  719: 		    /* Rewind fp and set close on exec flag. */
  720: 		    rewind(fp);
  721: 		    (void) fcntl(fileno(fp), F_SETFD, 1);
  722: 		}
  723: 	    }
  724: 	    break;
  725: 	case SUDO_PATH_MISSING:
  726: 	    log_warning(USE_ERRNO, N_("unable to stat %s"), sudoers);
  727: 	    break;
  728: 	case SUDO_PATH_BAD_TYPE:
  729: 	    log_warning(0, N_("%s is not a regular file"), sudoers);
  730: 	    break;
  731: 	case SUDO_PATH_WRONG_OWNER:
  732: 	    log_warning(0, N_("%s is owned by uid %u, should be %u"),
  733: 		sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid);
  734: 	    break;
  735: 	case SUDO_PATH_WORLD_WRITABLE:
  736: 	    log_warning(0, N_("%s is world writable"), sudoers);
  737: 	    break;
  738: 	case SUDO_PATH_GROUP_WRITABLE:
  739: 	    log_warning(0, N_("%s is owned by gid %u, should be %u"),
  740: 		sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid);
  741: 	    break;
  742: 	default:
  743: 	    /* NOTREACHED */
  744: 	    break;
  745:     }
  746: 
  747:     restore_perms();		/* change back to root */
  748: 
  749:     debug_return_ptr(fp);
  750: }
  751: 
  752: #ifdef HAVE_LOGIN_CAP_H
  753: static void
  754: set_loginclass(struct passwd *pw)
  755: {
  756:     const int errflags = NO_MAIL|MSG_ONLY;
  757:     login_cap_t *lc;
  758:     debug_decl(set_loginclass, SUDO_DEBUG_PLUGIN)
  759: 
  760:     if (!def_use_loginclass)
  761: 	debug_return;
  762: 
  763:     if (login_class && strcmp(login_class, "-") != 0) {
  764: 	if (user_uid != 0 && pw->pw_uid != 0)
  765: 	    fatalx(U_("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:     struct passwd *pw = NULL;
  839:     debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN)
  840: 
  841:     if (*user == '#') {
  842: 	const char *errstr;
  843: 	uid_t uid = atoid(user + 1, NULL, NULL, &errstr);
  844: 	if (errstr == NULL) {
  845: 	    if ((pw = sudo_getpwuid(uid)) == NULL)
  846: 		pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
  847: 	}
  848:     }
  849:     if (pw == NULL) {
  850: 	if ((pw = sudo_getpwnam(user)) == NULL)
  851: 	    log_fatal(NO_MAIL|MSG_ONLY, N_("unknown user: %s"), user);
  852:     }
  853:     if (runas_pw != NULL)
  854: 	sudo_pw_delref(runas_pw);
  855:     runas_pw = pw;
  856:     debug_return;
  857: }
  858: 
  859: /*
  860:  * Get group entry for the group we are going to run commands as
  861:  * and store it in runas_gr.
  862:  */
  863: static void
  864: set_runasgr(const char *group)
  865: {
  866:     struct group *gr = NULL;
  867:     debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN)
  868: 
  869:     if (*group == '#') {
  870: 	const char *errstr;
  871: 	gid_t gid = atoid(group + 1, NULL, NULL, &errstr);
  872: 	if (errstr == NULL) {
  873: 	    if ((gr = sudo_getgrgid(gid)) == NULL)
  874: 		gr = sudo_fakegrnam(group);
  875: 	}
  876:     }
  877:     if (gr == NULL) {
  878: 	if ((gr = sudo_getgrnam(group)) == NULL)
  879: 	    log_fatal(NO_MAIL|MSG_ONLY, N_("unknown group: %s"), group);
  880:     }
  881:     if (runas_gr != NULL)
  882: 	sudo_gr_delref(runas_gr);
  883:     runas_gr = gr;
  884:     debug_return;
  885: }
  886: 
  887: /*
  888:  * Callback for runas_default sudoers setting.
  889:  */
  890: static int
  891: cb_runas_default(const char *user)
  892: {
  893:     /* Only reset runaspw if user didn't specify one. */
  894:     if (!runas_user && !runas_group)
  895: 	set_runaspw(user);
  896:     return true;
  897: }
  898: 
  899: /*
  900:  * Callback for sudoers_locale sudoers setting.
  901:  */
  902: static int
  903: cb_sudoers_locale(const char *locale)
  904: {
  905:     sudoers_initlocale(NULL, locale);
  906:     return true;
  907: }
  908: 
  909: /*
  910:  * Cleanup hook for fatal()/fatalx()
  911:  */
  912: void
  913: sudoers_cleanup(void)
  914: {
  915:     struct sudo_nss *nss;
  916:     debug_decl(sudoers_cleanup, SUDO_DEBUG_PLUGIN)
  917: 
  918:     if (snl != NULL) {
  919: 	TAILQ_FOREACH(nss, snl, entries) {
  920: 	    nss->close(nss);
  921: 	}
  922:     }
  923:     if (def_group_plugin)
  924: 	group_plugin_unload();
  925:     sudo_endpwent();
  926:     sudo_endgrent();
  927: 
  928:     debug_return;
  929: }
  930: 
  931: static char *
  932: resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, char ***argv_out)
  933: {
  934:     char *cp, **nargv, *editor, *editor_path = NULL;
  935:     int ac, i, nargc;
  936:     bool wasblank;
  937:     debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN)
  938: 
  939:     /* Note: editor becomes part of argv_out and is not freed. */
  940:     editor = emalloc(edlen + 1);
  941:     memcpy(editor, ed, edlen);
  942:     editor[edlen] = '\0';
  943: 
  944:     /*
  945:      * Split editor into an argument vector; editor is reused (do not free).
  946:      * The EDITOR and VISUAL environment variables may contain command
  947:      * line args so look for those and alloc space for them too.
  948:      */
  949:     nargc = 1;
  950:     for (wasblank = false, cp = editor; *cp != '\0'; cp++) {
  951: 	if (isblank((unsigned char) *cp))
  952: 	    wasblank = true;
  953: 	else if (wasblank) {
  954: 	    wasblank = false;
  955: 	    nargc++;
  956: 	}
  957:     }
  958:     /* If we can't find the editor in the user's PATH, give up. */
  959:     cp = strtok(editor, " \t");
  960:     if (cp == NULL ||
  961: 	find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
  962: 	efree(editor);
  963: 	debug_return_str(NULL);
  964:     }
  965:     nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *));
  966:     for (ac = 0; cp != NULL && ac < nargc; ac++) {
  967: 	nargv[ac] = cp;
  968: 	cp = strtok(NULL, " \t");
  969:     }
  970:     nargv[ac++] = "--";
  971:     for (i = 0; i < nfiles; )
  972: 	nargv[ac++] = files[i++];
  973:     nargv[ac] = NULL;
  974: 
  975:     *argv_out = nargv;
  976:     debug_return_str(editor_path);
  977: }
  978: 
  979: /*
  980:  * Determine which editor to use.  We don't need to worry about restricting
  981:  * this to a "safe" editor since it runs with the uid of the invoking user,
  982:  * not the runas (privileged) user.
  983:  */
  984: static char *
  985: find_editor(int nfiles, char **files, char ***argv_out)
  986: {
  987:     const char *cp, *ep, *editor;
  988:     char *editor_path = NULL, **ev, *ev0[4];
  989:     size_t len;
  990:     debug_decl(find_editor, SUDO_DEBUG_PLUGIN)
  991: 
  992:     /*
  993:      * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one.
  994:      */
  995:     ev0[0] = "SUDO_EDITOR";
  996:     ev0[1] = "VISUAL";
  997:     ev0[2] = "EDITOR";
  998:     ev0[3] = NULL;
  999:     for (ev = ev0; editor_path == NULL && *ev != NULL; ev++) {
 1000: 	if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
 1001: 	    editor_path = resolve_editor(editor, strlen(editor), nfiles,
 1002: 		files, argv_out);
 1003: 	}
 1004:     }
 1005:     if (editor_path == NULL) {
 1006: 	/* def_editor could be a path, split it up, avoiding strtok() */
 1007: 	cp = editor = def_editor;
 1008: 	do {
 1009: 	    if ((ep = strchr(cp, ':')) != NULL)
 1010: 		len = ep - cp;
 1011: 	    else
 1012: 		len = strlen(cp);
 1013: 	    editor_path = resolve_editor(cp, len, nfiles, files, argv_out);
 1014: 	    cp = ep + 1;
 1015: 	} while (ep != NULL && editor_path == NULL);
 1016:     }
 1017:     if (!editor_path) {
 1018: 	audit_failure(NewArgv, N_("%s: command not found"), editor);
 1019: 	warningx(U_("%s: command not found"), editor);
 1020:     }
 1021:     debug_return_str(editor_path);
 1022: }
 1023: 
 1024: #ifdef USE_ADMIN_FLAG
 1025: static void
 1026: create_admin_success_flag(void)
 1027: {
 1028:     struct stat statbuf;
 1029:     char flagfile[PATH_MAX];
 1030:     int fd, n;
 1031:     debug_decl(create_admin_success_flag, SUDO_DEBUG_PLUGIN)
 1032: 
 1033:     /* Check whether the user is in the admin group. */
 1034:     if (!user_in_group(sudo_user.pw, "admin"))
 1035: 	debug_return;
 1036: 
 1037:     /* Build path to flag file. */
 1038:     n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful",
 1039: 	user_dir);
 1040:     if (n <= 0 || (size_t)n >= sizeof(flagfile))
 1041: 	debug_return;
 1042: 
 1043:     /* Create admin flag file if it doesn't already exist. */
 1044:     set_perms(PERM_USER);
 1045:     if (stat(flagfile, &statbuf) != 0) {
 1046: 	fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
 1047: 	close(fd);
 1048:     }
 1049:     restore_perms();
 1050:     debug_return;
 1051: }
 1052: #else /* !USE_ADMIN_FLAG */
 1053: static void
 1054: create_admin_success_flag(void)
 1055: {
 1056:     /* STUB */
 1057: }
 1058: #endif /* USE_ADMIN_FLAG */
 1059: 
 1060: static bool
 1061: tty_present(void)
 1062: {
 1063: #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__)
 1064:     return user_ttypath != NULL;
 1065: #else
 1066:     int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
 1067:     if (fd != -1)
 1068: 	close(fd);
 1069:     return fd != -1;
 1070: #endif
 1071: }

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