File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / common / sudo_conf.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:26:49 2012 UTC (12 years, 1 month ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /*
    2:  * Copyright (c) 2009-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: 
   17: #include <config.h>
   18: 
   19: #include <sys/types.h>
   20: #include <sys/param.h>
   21: #include <sys/stat.h>
   22: #include <stdio.h>
   23: #ifdef STDC_HEADERS
   24: # include <stdlib.h>
   25: # include <stddef.h>
   26: #else
   27: # ifdef HAVE_STDLIB_H
   28: #  include <stdlib.h>
   29: # endif
   30: #endif /* STDC_HEADERS */
   31: #ifdef HAVE_STDBOOL_H
   32: # include <stdbool.h>
   33: #else
   34: # include "compat/stdbool.h"
   35: #endif
   36: #ifdef HAVE_STRING_H
   37: # include <string.h>
   38: #endif /* HAVE_STRING_H */
   39: #ifdef HAVE_STRINGS_H
   40: # include <strings.h>
   41: #endif /* HAVE_STRINGS_H */
   42: #ifdef HAVE_UNISTD_H
   43: # include <unistd.h>
   44: #endif /* HAVE_UNISTD_H */
   45: #include <ctype.h>
   46: #include <errno.h>
   47: 
   48: #define SUDO_ERROR_WRAP	0
   49: 
   50: #include "missing.h"
   51: #include "alloc.h"
   52: #include "error.h"
   53: #include "fileops.h"
   54: #include "pathnames.h"
   55: #include "sudo_plugin.h"
   56: #include "sudo_conf.h"
   57: #include "sudo_debug.h"
   58: #include "secure_path.h"
   59: #include "gettext.h"
   60: 
   61: #ifdef __TANDEM
   62: # define ROOT_UID	65535
   63: #else
   64: # define ROOT_UID	0
   65: #endif
   66: 
   67: #ifndef _PATH_SUDO_ASKPASS
   68: # define _PATH_SUDO_ASKPASS	NULL
   69: #endif
   70: 
   71: extern bool atobool(const char *str); /* atobool.c */
   72: 
   73: struct sudo_conf_table {
   74:     const char *name;
   75:     unsigned int namelen;
   76:     bool (*setter)(const char *entry);
   77: };
   78: 
   79: struct sudo_conf_paths {
   80:     const char *pname;
   81:     unsigned int pnamelen;
   82:     const char *pval;
   83: };
   84: 
   85: static bool set_debug(const char *entry);
   86: static bool set_path(const char *entry);
   87: static bool set_plugin(const char *entry);
   88: static bool set_variable(const char *entry);
   89: 
   90: static struct sudo_conf_table sudo_conf_table[] = {
   91:     { "Debug", sizeof("Debug") - 1, set_debug },
   92:     { "Path", sizeof("Path") - 1, set_path },
   93:     { "Plugin", sizeof("Plugin") - 1, set_plugin },
   94:     { "Set", sizeof("Set") - 1, set_variable },
   95:     { NULL }
   96: };
   97: 
   98: static struct sudo_conf_data {
   99:     bool disable_coredump;
  100:     const char *debug_flags;
  101:     struct sudo_conf_paths paths[3];
  102:     struct plugin_info_list plugins;
  103: } sudo_conf_data = {
  104:     true,
  105:     NULL,
  106:     {
  107: #define SUDO_CONF_ASKPASS_IDX	0
  108: 	{ "askpass", sizeof("askpass") - 1, _PATH_SUDO_ASKPASS },
  109: #ifdef _PATH_SUDO_NOEXEC
  110: #define SUDO_CONF_NOEXEC_IDX	1
  111: 	{ "noexec", sizeof("noexec") - 1, _PATH_SUDO_NOEXEC },
  112: #endif
  113: 	{ NULL }
  114:     }
  115: };
  116: 
  117: /*
  118:  * "Set variable_name value"
  119:  */
  120: static bool
  121: set_variable(const char *entry)
  122: {
  123: #undef DC_LEN
  124: #define DC_LEN (sizeof("disable_coredump") - 1)
  125:     /* Currently the only variable supported is "disable_coredump". */
  126:     if (strncmp(entry, "disable_coredump", DC_LEN) == 0 &&
  127: 	isblank((unsigned char)entry[DC_LEN])) {
  128: 	entry += DC_LEN + 1;
  129: 	while (isblank((unsigned char)*entry))
  130: 	    entry++;
  131: 	sudo_conf_data.disable_coredump = atobool(entry);
  132:     }
  133: #undef DC_LEN
  134:     return true;
  135: }
  136: 
  137: /*
  138:  * "Debug progname debug_file debug_flags"
  139:  */
  140: static bool
  141: set_debug(const char *entry)
  142: {
  143:     size_t filelen, proglen;
  144:     const char *progname;
  145:     char *debug_file, *debug_flags;
  146: 
  147:     /* Is this debug setting for me? */
  148:     progname = getprogname();
  149:     if (strcmp(progname, "sudoedit") == 0)
  150: 	progname = "sudo";
  151:     proglen = strlen(progname);
  152:     if (strncmp(entry, progname, proglen) != 0 ||
  153: 	!isblank((unsigned char)entry[proglen]))
  154:     	return false;
  155:     entry += proglen + 1;
  156:     while (isblank((unsigned char)*entry))
  157: 	entry++;
  158: 
  159:     debug_flags = strpbrk(entry, " \t");
  160:     if (debug_flags == NULL)
  161:     	return false;
  162:     filelen = (size_t)(debug_flags - entry);
  163:     while (isblank((unsigned char)*debug_flags))
  164: 	debug_flags++;
  165: 
  166:     /* Set debug file and parse the flags (init debug as soon as possible). */
  167:     debug_file = estrndup(entry, filelen);
  168:     debug_flags = estrdup(debug_flags);
  169:     sudo_debug_init(debug_file, debug_flags);
  170:     efree(debug_file);
  171: 
  172:     sudo_conf_data.debug_flags = debug_flags;
  173: 
  174:     return true;
  175: }
  176: 
  177: static bool
  178: set_path(const char *entry)
  179: {
  180:     const char *name, *path;
  181:     struct sudo_conf_paths *cur;
  182: 
  183:     /* Parse Path line */
  184:     name = entry;
  185:     path = strpbrk(entry, " \t");
  186:     if (path == NULL)
  187:     	return false;
  188:     while (isblank((unsigned char)*path))
  189: 	path++;
  190: 
  191:     /* Match supported paths, ignore the rest. */
  192:     for (cur = sudo_conf_data.paths; cur->pname != NULL; cur++) {
  193: 	if (strncasecmp(name, cur->pname, cur->pnamelen) == 0 &&
  194: 	    isblank((unsigned char)name[cur->pnamelen])) {
  195: 	    cur->pval = estrdup(path);
  196: 	    break;
  197: 	}
  198:     }
  199: 
  200:     return true;
  201: }
  202: 
  203: static bool
  204: set_plugin(const char *entry)
  205: {
  206:     struct plugin_info *info;
  207:     const char *name, *path, *cp, *ep;
  208:     char **options = NULL;
  209:     size_t namelen, pathlen;
  210:     unsigned int nopts;
  211: 
  212:     /* Parse Plugin line */
  213:     name = entry;
  214:     path = strpbrk(entry, " \t");
  215:     if (path == NULL)
  216:     	return false;
  217:     namelen = (size_t)(path - name);
  218:     while (isblank((unsigned char)*path))
  219: 	path++;
  220:     if ((cp = strpbrk(path, " \t")) != NULL) {
  221: 	/* Convert any options to an array. */
  222: 	pathlen = (size_t)(cp - path);
  223: 	while (isblank((unsigned char)*cp))
  224: 	    cp++;
  225: 	/* Count number of options and allocate array. */
  226: 	for (ep = cp, nopts = 1; (ep = strpbrk(ep, " \t")) != NULL; nopts++) {
  227: 	    while (isblank((unsigned char)*ep))
  228: 		ep++;
  229: 	}
  230: 	options = emalloc2(nopts + 1, sizeof(*options));
  231: 	/* Fill in options array, there is at least one element. */
  232: 	for (nopts = 0; (ep = strpbrk(cp, " \t")) != NULL; ) {
  233: 	    options[nopts++] = estrndup(cp, (size_t)(ep - cp));
  234: 	    while (isblank((unsigned char)*ep))
  235: 		ep++;
  236: 	    cp = ep;
  237: 	}
  238: 	options[nopts++] = estrdup(cp);
  239: 	options[nopts] = NULL;
  240:     } else {
  241: 	/* No extra options. */
  242: 	pathlen = strlen(path);
  243:     }
  244: 
  245:     info = ecalloc(1, sizeof(*info));
  246:     info->symbol_name = estrndup(name, namelen);
  247:     info->path = estrndup(path, pathlen);
  248:     info->options = options;
  249:     info->prev = info;
  250:     /* info->next = NULL; */
  251:     tq_append(&sudo_conf_data.plugins, info);
  252: 
  253:     return true;
  254: }
  255: 
  256: const char *
  257: sudo_conf_askpass_path(void)
  258: {
  259:     return sudo_conf_data.paths[SUDO_CONF_ASKPASS_IDX].pval;
  260: }
  261: 
  262: #ifdef _PATH_SUDO_NOEXEC
  263: const char *
  264: sudo_conf_noexec_path(void)
  265: {
  266:     return sudo_conf_data.paths[SUDO_CONF_NOEXEC_IDX].pval;
  267: }
  268: #endif
  269: 
  270: const char *
  271: sudo_conf_debug_flags(void)
  272: {
  273:     return sudo_conf_data.debug_flags;
  274: }
  275: 
  276: struct plugin_info_list *
  277: sudo_conf_plugins(void)
  278: {
  279:     return &sudo_conf_data.plugins;
  280: }
  281: 
  282: bool
  283: sudo_conf_disable_coredump(void)
  284: {
  285:     return sudo_conf_data.disable_coredump;
  286: }
  287: 
  288: /*
  289:  * Reads in /etc/sudo.conf and populates sudo_conf_data.
  290:  */
  291: void
  292: sudo_conf_read(void)
  293: {
  294:     struct sudo_conf_table *cur;
  295:     struct plugin_info *info;
  296:     struct stat sb;
  297:     FILE *fp;
  298:     char *cp;
  299: 
  300:     switch (sudo_secure_file(_PATH_SUDO_CONF, ROOT_UID, -1, &sb)) {
  301: 	case SUDO_PATH_SECURE:
  302: 	    break;
  303: 	case SUDO_PATH_MISSING:
  304: 	    /* Root should always be able to read sudo.conf. */
  305: 	    if (errno != ENOENT && geteuid() == ROOT_UID)
  306: 		warning(_("unable to stat %s"), _PATH_SUDO_CONF);
  307: 	    goto done;
  308: 	case SUDO_PATH_BAD_TYPE:
  309: 	    warningx(_("%s is not a regular file"), _PATH_SUDO_CONF);
  310: 	    goto done;
  311: 	case SUDO_PATH_WRONG_OWNER:
  312: 	    warningx(_("%s is owned by uid %u, should be %u"),
  313: 		_PATH_SUDO_CONF, (unsigned int) sb.st_uid, ROOT_UID);
  314: 	    goto done;
  315: 	case SUDO_PATH_WORLD_WRITABLE:
  316: 	    warningx(_("%s is world writable"), _PATH_SUDO_CONF);
  317: 	    goto done;
  318: 	case SUDO_PATH_GROUP_WRITABLE:
  319: 	    warningx(_("%s is group writable"), _PATH_SUDO_CONF);
  320: 	    goto done;
  321: 	default:
  322: 	    /* NOTREACHED */
  323: 	    goto done;
  324:     }
  325: 
  326:     if ((fp = fopen(_PATH_SUDO_CONF, "r")) == NULL) {
  327: 	if (errno != ENOENT && geteuid() == ROOT_UID)
  328: 	    warning(_("unable to open %s"), _PATH_SUDO_CONF);
  329: 	goto done;
  330:     }
  331: 
  332:     while ((cp = sudo_parseln(fp)) != NULL) {
  333: 	/* Skip blank or comment lines */
  334: 	if (*cp == '\0')
  335: 	    continue;
  336: 
  337: 	for (cur = sudo_conf_table; cur->name != NULL; cur++) {
  338: 	    if (strncasecmp(cp, cur->name, cur->namelen) == 0 &&
  339: 		isblank((unsigned char)cp[cur->namelen])) {
  340: 		cp += cur->namelen;
  341: 		while (isblank((unsigned char)*cp))
  342: 		    cp++;
  343: 		if (cur->setter(cp))
  344: 		    break;
  345: 	    }
  346: 	}
  347:     }
  348:     fclose(fp);
  349: 
  350: done:
  351:     if (tq_empty(&sudo_conf_data.plugins)) {
  352: 	/* Default policy plugin */
  353: 	info = ecalloc(1, sizeof(*info));
  354: 	info->symbol_name = "sudoers_policy";
  355: 	info->path = SUDOERS_PLUGIN;
  356: 	/* info->options = NULL; */
  357: 	info->prev = info;
  358: 	/* info->next = NULL; */
  359: 	tq_append(&sudo_conf_data.plugins, info);
  360: 
  361: 	/* Default I/O plugin */
  362: 	info = ecalloc(1, sizeof(*info));
  363: 	info->symbol_name = "sudoers_io";
  364: 	info->path = SUDOERS_PLUGIN;
  365: 	/* info->options = NULL; */
  366: 	info->prev = info;
  367: 	/* info->next = NULL; */
  368: 	tq_append(&sudo_conf_data.plugins, info);
  369:     }
  370: }

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