File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / common / sudo_conf.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:54 2014 UTC (10 years 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) 2009-2014 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: 
   17: #include <config.h>
   18: 
   19: #include <sys/types.h>
   20: #include <sys/stat.h>
   21: #include <stdio.h>
   22: #ifdef STDC_HEADERS
   23: # include <stdlib.h>
   24: # include <stddef.h>
   25: #else
   26: # ifdef HAVE_STDLIB_H
   27: #  include <stdlib.h>
   28: # endif
   29: #endif /* STDC_HEADERS */
   30: #ifdef HAVE_STDBOOL_H
   31: # include <stdbool.h>
   32: #else
   33: # include "compat/stdbool.h"
   34: #endif
   35: #ifdef HAVE_STRING_H
   36: # include <string.h>
   37: #endif /* HAVE_STRING_H */
   38: #ifdef HAVE_STRINGS_H
   39: # include <strings.h>
   40: #endif /* HAVE_STRINGS_H */
   41: #ifdef HAVE_UNISTD_H
   42: # include <unistd.h>
   43: #endif /* HAVE_UNISTD_H */
   44: #include <ctype.h>
   45: #include <errno.h>
   46: #include <limits.h>
   47: 
   48: #define DEFAULT_TEXT_DOMAIN	"sudo"
   49: #include "gettext.h"		/* must be included before missing.h */
   50: 
   51: #define SUDO_ERROR_WRAP	0
   52: 
   53: #include "missing.h"
   54: #include "alloc.h"
   55: #include "fatal.h"
   56: #include "fileops.h"
   57: #include "pathnames.h"
   58: #include "sudo_plugin.h"
   59: #include "sudo_conf.h"
   60: #include "sudo_debug.h"
   61: #include "sudo_util.h"
   62: #include "secure_path.h"
   63: 
   64: #ifdef __TANDEM
   65: # define ROOT_UID	65535
   66: #else
   67: # define ROOT_UID	0
   68: #endif
   69: 
   70: struct sudo_conf_table {
   71:     const char *name;
   72:     unsigned int namelen;
   73:     void (*setter)(const char *entry, const char *conf_file);
   74: };
   75: 
   76: struct sudo_conf_paths {
   77:     const char *pname;
   78:     unsigned int pnamelen;
   79:     const char *pval;
   80: };
   81: 
   82: static void set_debug(const char *entry, const char *conf_file);
   83: static void set_path(const char *entry, const char *conf_file);
   84: static void set_plugin(const char *entry, const char *conf_file);
   85: static void set_variable(const char *entry, const char *conf_file);
   86: static void set_var_disable_coredump(const char *entry, const char *conf_file);
   87: static void set_var_group_source(const char *entry, const char *conf_file);
   88: static void set_var_max_groups(const char *entry, const char *conf_file);
   89: static void set_var_probe_interfaces(const char *entry, const char *conf_file);
   90: 
   91: static unsigned int conf_lineno;
   92: 
   93: static struct sudo_conf_table sudo_conf_table[] = {
   94:     { "Debug", sizeof("Debug") - 1, set_debug },
   95:     { "Path", sizeof("Path") - 1, set_path },
   96:     { "Plugin", sizeof("Plugin") - 1, set_plugin },
   97:     { "Set", sizeof("Set") - 1, set_variable },
   98:     { NULL }
   99: };
  100: 
  101: static struct sudo_conf_table sudo_conf_table_vars[] = {
  102:     { "disable_coredump", sizeof("disable_coredump") - 1, set_var_disable_coredump },
  103:     { "group_source", sizeof("group_source") - 1, set_var_group_source },
  104:     { "max_groups", sizeof("max_groups") - 1, set_var_max_groups },
  105:     { "probe_interfaces", sizeof("probe_interfaces") - 1, set_var_probe_interfaces },
  106:     { NULL }
  107: };
  108: 
  109: static struct sudo_conf_data {
  110:     bool disable_coredump;
  111:     bool probe_interfaces;
  112:     int group_source;
  113:     int max_groups;
  114:     const char *debug_flags;
  115:     struct plugin_info_list plugins;
  116:     struct sudo_conf_paths paths[5];
  117: } sudo_conf_data = {
  118:     true,
  119:     true,
  120:     GROUP_SOURCE_ADAPTIVE,
  121:     -1,
  122:     NULL,
  123:     TAILQ_HEAD_INITIALIZER(sudo_conf_data.plugins),
  124:     {
  125: #define SUDO_CONF_ASKPASS_IDX	0
  126: 	{ "askpass", sizeof("askpass") - 1, _PATH_SUDO_ASKPASS },
  127: #define SUDO_CONF_SESH_IDX	1
  128: 	{ "sesh", sizeof("sesh") - 1, _PATH_SUDO_SESH },
  129: #ifdef _PATH_SUDO_NOEXEC
  130: #define SUDO_CONF_NOEXEC_IDX	2
  131: 	{ "noexec", sizeof("noexec") - 1, _PATH_SUDO_NOEXEC },
  132: #endif
  133: #ifdef _PATH_SUDO_PLUGIN_DIR
  134: #define SUDO_CONF_PLUGIN_IDX	3
  135: 	{ "plugin", sizeof("plugin") - 1, _PATH_SUDO_PLUGIN_DIR },
  136: #endif
  137: 	{ NULL }
  138:     }
  139: };
  140: 
  141: /*
  142:  * "Set variable_name value"
  143:  */
  144: static void
  145: set_variable(const char *entry, const char *conf_file)
  146: {
  147:     struct sudo_conf_table *var;
  148: 
  149:     for (var = sudo_conf_table_vars; var->name != NULL; var++) {
  150: 	if (strncmp(entry, var->name, var->namelen) == 0 &&
  151: 	    isblank((unsigned char)entry[var->namelen])) {
  152: 	    entry += var->namelen + 1;
  153: 	    while (isblank((unsigned char)*entry))
  154: 		entry++;
  155: 	    var->setter(entry, conf_file);
  156: 	    break;
  157: 	}
  158:     }
  159: }
  160: 
  161: static void
  162: set_var_disable_coredump(const char *entry, const char *conf_file)
  163: {
  164:     int val = atobool(entry);
  165: 
  166:     if (val != -1)
  167: 	sudo_conf_data.disable_coredump = val;
  168: }
  169: 
  170: static void
  171: set_var_group_source(const char *entry, const char *conf_file)
  172: {
  173:     if (strcasecmp(entry, "adaptive") == 0) {
  174: 	sudo_conf_data.group_source = GROUP_SOURCE_ADAPTIVE;
  175:     } else if (strcasecmp(entry, "static") == 0) {
  176: 	sudo_conf_data.group_source = GROUP_SOURCE_STATIC;
  177:     } else if (strcasecmp(entry, "dynamic") == 0) {
  178: 	sudo_conf_data.group_source = GROUP_SOURCE_DYNAMIC;
  179:     } else {
  180: 	warningx(U_("unsupported group source `%s' in %s, line %d"), entry,
  181: 	    conf_file, conf_lineno);
  182:     }
  183: }
  184: 
  185: static void
  186: set_var_max_groups(const char *entry, const char *conf_file)
  187: {
  188:     int max_groups;
  189: 
  190:     max_groups = strtonum(entry, 1, INT_MAX, NULL);
  191:     if (max_groups > 0) {
  192: 	sudo_conf_data.max_groups = max_groups;
  193:     } else {
  194: 	warningx(U_("invalid max groups `%s' in %s, line %d"), entry,
  195: 	    conf_file, conf_lineno);
  196:     }
  197: }
  198: 
  199: static void
  200: set_var_probe_interfaces(const char *entry, const char *conf_file)
  201: {
  202:     int val = atobool(entry);
  203: 
  204:     if (val != -1)
  205: 	sudo_conf_data.probe_interfaces = val;
  206: }
  207: 
  208: /*
  209:  * "Debug progname debug_file debug_flags"
  210:  */
  211: static void
  212: set_debug(const char *entry, const char *conf_file)
  213: {
  214:     size_t filelen, proglen;
  215:     const char *progname;
  216:     char *debug_file, *debug_flags;
  217: 
  218:     /* Is this debug setting for me? */
  219:     progname = getprogname();
  220:     if (strcmp(progname, "sudoedit") == 0)
  221: 	progname = "sudo";
  222:     proglen = strlen(progname);
  223:     if (strncmp(entry, progname, proglen) != 0 ||
  224: 	!isblank((unsigned char)entry[proglen]))
  225:     	return;
  226:     entry += proglen + 1;
  227:     while (isblank((unsigned char)*entry))
  228: 	entry++;
  229: 
  230:     debug_flags = strpbrk(entry, " \t");
  231:     if (debug_flags == NULL)
  232:     	return;
  233:     filelen = (size_t)(debug_flags - entry);
  234:     while (isblank((unsigned char)*debug_flags))
  235: 	debug_flags++;
  236: 
  237:     /* Set debug file and parse the flags (init debug as soon as possible). */
  238:     debug_file = estrndup(entry, filelen);
  239:     debug_flags = estrdup(debug_flags);
  240:     sudo_debug_init(debug_file, debug_flags);
  241:     efree(debug_file);
  242: 
  243:     sudo_conf_data.debug_flags = debug_flags;
  244: }
  245: 
  246: static void
  247: set_path(const char *entry, const char *conf_file)
  248: {
  249:     const char *name, *path;
  250:     struct sudo_conf_paths *cur;
  251: 
  252:     /* Parse Path line */
  253:     name = entry;
  254:     path = strpbrk(entry, " \t");
  255:     if (path == NULL)
  256:     	return;
  257:     while (isblank((unsigned char)*path))
  258: 	path++;
  259: 
  260:     /* Match supported paths, ignore the rest. */
  261:     for (cur = sudo_conf_data.paths; cur->pname != NULL; cur++) {
  262: 	if (strncasecmp(name, cur->pname, cur->pnamelen) == 0 &&
  263: 	    isblank((unsigned char)name[cur->pnamelen])) {
  264: 	    cur->pval = estrdup(path);
  265: 	    break;
  266: 	}
  267:     }
  268: }
  269: 
  270: static void
  271: set_plugin(const char *entry, const char *conf_file)
  272: {
  273:     struct plugin_info *info;
  274:     const char *name, *path, *cp, *ep;
  275:     char **options = NULL;
  276:     size_t namelen, pathlen;
  277:     unsigned int nopts;
  278: 
  279:     /* Parse Plugin line */
  280:     name = entry;
  281:     path = strpbrk(entry, " \t");
  282:     if (path == NULL)
  283:     	return;
  284:     namelen = (size_t)(path - name);
  285:     while (isblank((unsigned char)*path))
  286: 	path++;
  287:     if ((cp = strpbrk(path, " \t")) != NULL) {
  288: 	/* Convert any options to an array. */
  289: 	pathlen = (size_t)(cp - path);
  290: 	while (isblank((unsigned char)*cp))
  291: 	    cp++;
  292: 	/* Count number of options and allocate array. */
  293: 	for (ep = cp, nopts = 1; (ep = strpbrk(ep, " \t")) != NULL; nopts++) {
  294: 	    while (isblank((unsigned char)*ep))
  295: 		ep++;
  296: 	}
  297: 	options = emalloc2(nopts + 1, sizeof(*options));
  298: 	/* Fill in options array, there is at least one element. */
  299: 	for (nopts = 0; (ep = strpbrk(cp, " \t")) != NULL; ) {
  300: 	    options[nopts++] = estrndup(cp, (size_t)(ep - cp));
  301: 	    while (isblank((unsigned char)*ep))
  302: 		ep++;
  303: 	    cp = ep;
  304: 	}
  305: 	options[nopts++] = estrdup(cp);
  306: 	options[nopts] = NULL;
  307:     } else {
  308: 	/* No extra options. */
  309: 	pathlen = strlen(path);
  310:     }
  311: 
  312:     info = ecalloc(1, sizeof(*info));
  313:     info->symbol_name = estrndup(name, namelen);
  314:     info->path = estrndup(path, pathlen);
  315:     info->options = options;
  316:     info->lineno = conf_lineno;
  317:     TAILQ_INSERT_TAIL(&sudo_conf_data.plugins, info, entries);
  318: }
  319: 
  320: const char *
  321: sudo_conf_askpass_path(void)
  322: {
  323:     return sudo_conf_data.paths[SUDO_CONF_ASKPASS_IDX].pval;
  324: }
  325: 
  326: const char *
  327: sudo_conf_sesh_path(void)
  328: {
  329:     return sudo_conf_data.paths[SUDO_CONF_SESH_IDX].pval;
  330: }
  331: 
  332: #ifdef _PATH_SUDO_NOEXEC
  333: const char *
  334: sudo_conf_noexec_path(void)
  335: {
  336:     return sudo_conf_data.paths[SUDO_CONF_NOEXEC_IDX].pval;
  337: }
  338: #endif
  339: 
  340: #ifdef _PATH_SUDO_PLUGIN_DIR
  341: const char *
  342: sudo_conf_plugin_dir_path(void)
  343: {
  344:     return sudo_conf_data.paths[SUDO_CONF_PLUGIN_IDX].pval;
  345: }
  346: #endif
  347: 
  348: const char *
  349: sudo_conf_debug_flags(void)
  350: {
  351:     return sudo_conf_data.debug_flags;
  352: }
  353: 
  354: int
  355: sudo_conf_group_source(void)
  356: {
  357:     return sudo_conf_data.group_source;
  358: }
  359: 
  360: int
  361: sudo_conf_max_groups(void)
  362: {
  363:     return sudo_conf_data.max_groups;
  364: }
  365: 
  366: struct plugin_info_list *
  367: sudo_conf_plugins(void)
  368: {
  369:     return &sudo_conf_data.plugins;
  370: }
  371: 
  372: bool
  373: sudo_conf_disable_coredump(void)
  374: {
  375:     return sudo_conf_data.disable_coredump;
  376: }
  377: 
  378: bool
  379: sudo_conf_probe_interfaces(void)
  380: {
  381:     return sudo_conf_data.probe_interfaces;
  382: }
  383: 
  384: /*
  385:  * Reads in /etc/sudo.conf and populates sudo_conf_data.
  386:  */
  387: void
  388: sudo_conf_read(const char *conf_file)
  389: {
  390:     struct sudo_conf_table *cur;
  391:     struct stat sb;
  392:     FILE *fp;
  393:     char *cp, *line = NULL;
  394:     char *prev_locale = estrdup(setlocale(LC_ALL, NULL));
  395:     size_t linesize = 0;
  396: 
  397:     /* Parse sudo.conf in the "C" locale. */
  398:     if (prev_locale[0] != 'C' || prev_locale[1] != '\0')
  399:         setlocale(LC_ALL, "C");
  400: 
  401:     if (conf_file == NULL) {
  402: 	conf_file = _PATH_SUDO_CONF;
  403: 	switch (sudo_secure_file(conf_file, ROOT_UID, -1, &sb)) {
  404: 	    case SUDO_PATH_SECURE:
  405: 		break;
  406: 	    case SUDO_PATH_MISSING:
  407: 		/* Root should always be able to read sudo.conf. */
  408: 		if (errno != ENOENT && geteuid() == ROOT_UID)
  409: 		    warning(U_("unable to stat %s"), conf_file);
  410: 		goto done;
  411: 	    case SUDO_PATH_BAD_TYPE:
  412: 		warningx(U_("%s is not a regular file"), conf_file);
  413: 		goto done;
  414: 	    case SUDO_PATH_WRONG_OWNER:
  415: 		warningx(U_("%s is owned by uid %u, should be %u"),
  416: 		    conf_file, (unsigned int) sb.st_uid, ROOT_UID);
  417: 		goto done;
  418: 	    case SUDO_PATH_WORLD_WRITABLE:
  419: 		warningx(U_("%s is world writable"), conf_file);
  420: 		goto done;
  421: 	    case SUDO_PATH_GROUP_WRITABLE:
  422: 		warningx(U_("%s is group writable"), conf_file);
  423: 		goto done;
  424: 	    default:
  425: 		/* NOTREACHED */
  426: 		goto done;
  427: 	}
  428:     }
  429: 
  430:     if ((fp = fopen(conf_file, "r")) == NULL) {
  431: 	if (errno != ENOENT && geteuid() == ROOT_UID)
  432: 	    warning(U_("unable to open %s"), conf_file);
  433: 	goto done;
  434:     }
  435: 
  436:     conf_lineno = 0;
  437:     while (sudo_parseln(&line, &linesize, &conf_lineno, fp) != -1) {
  438: 	if (*(cp = line) == '\0')
  439: 	    continue;		/* empty line or comment */
  440: 
  441: 	for (cur = sudo_conf_table; cur->name != NULL; cur++) {
  442: 	    if (strncasecmp(cp, cur->name, cur->namelen) == 0 &&
  443: 		isblank((unsigned char)cp[cur->namelen])) {
  444: 		cp += cur->namelen;
  445: 		while (isblank((unsigned char)*cp))
  446: 		    cp++;
  447: 		cur->setter(cp, conf_file);
  448: 		break;
  449: 	    }
  450: 	}
  451:     }
  452:     fclose(fp);
  453:     free(line);
  454: done:
  455:     /* Restore locale if needed. */
  456:     if (prev_locale[0] != 'C' || prev_locale[1] != '\0')
  457:         setlocale(LC_ALL, prev_locale);
  458:     efree(prev_locale);
  459: }

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