Annotation of embedaddon/sudo/common/sudo_conf.c, revision 1.1.1.3

1.1       misho       1: /*
1.1.1.3 ! misho       2:  * Copyright (c) 2009-2013 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       misho       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>
1.1.1.3 ! misho      46: #include <limits.h>
1.1       misho      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"
1.1.1.3 ! misho      59: 
        !            60: #define DEFAULT_TEXT_DOMAIN    "sudo"
1.1       misho      61: #include "gettext.h"
                     62: 
                     63: #ifdef __TANDEM
                     64: # define ROOT_UID      65535
                     65: #else
                     66: # define ROOT_UID      0
                     67: #endif
                     68: 
                     69: extern bool atobool(const char *str); /* atobool.c */
                     70: 
                     71: struct sudo_conf_table {
                     72:     const char *name;
                     73:     unsigned int namelen;
1.1.1.3 ! misho      74:     void (*setter)(const char *entry, const char *conf_file);
1.1       misho      75: };
                     76: 
                     77: struct sudo_conf_paths {
                     78:     const char *pname;
                     79:     unsigned int pnamelen;
                     80:     const char *pval;
                     81: };
                     82: 
1.1.1.3 ! misho      83: static void set_debug(const char *entry, const char *conf_file);
        !            84: static void set_path(const char *entry, const char *conf_file);
        !            85: static void set_plugin(const char *entry, const char *conf_file);
        !            86: static void set_variable(const char *entry, const char *conf_file);
        !            87: static void set_var_disable_coredump(const char *entry, const char *conf_file);
        !            88: static void set_var_group_source(const char *entry, const char *conf_file);
        !            89: static void set_var_max_groups(const char *entry, const char *conf_file);
        !            90: 
        !            91: static unsigned int conf_lineno;
1.1       misho      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: 
1.1.1.3 ! misho     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:     { NULL }
        !           106: };
        !           107: 
1.1       misho     108: static struct sudo_conf_data {
                    109:     bool disable_coredump;
1.1.1.3 ! misho     110:     int group_source;
        !           111:     int max_groups;
1.1       misho     112:     const char *debug_flags;
1.1.1.3 ! misho     113:     struct sudo_conf_paths paths[4];
1.1       misho     114:     struct plugin_info_list plugins;
                    115: } sudo_conf_data = {
                    116:     true,
1.1.1.3 ! misho     117:     GROUP_SOURCE_ADAPTIVE,
        !           118:     -1,
1.1       misho     119:     NULL,
                    120:     {
                    121: #define SUDO_CONF_ASKPASS_IDX  0
                    122:        { "askpass", sizeof("askpass") - 1, _PATH_SUDO_ASKPASS },
1.1.1.3 ! misho     123: #define SUDO_CONF_SESH_IDX     1
        !           124:        { "sesh", sizeof("sesh") - 1, _PATH_SUDO_SESH },
1.1       misho     125: #ifdef _PATH_SUDO_NOEXEC
1.1.1.3 ! misho     126: #define SUDO_CONF_NOEXEC_IDX   2
1.1       misho     127:        { "noexec", sizeof("noexec") - 1, _PATH_SUDO_NOEXEC },
                    128: #endif
                    129:        { NULL }
                    130:     }
                    131: };
                    132: 
                    133: /*
                    134:  * "Set variable_name value"
                    135:  */
1.1.1.3 ! misho     136: static void
        !           137: set_variable(const char *entry, const char *conf_file)
1.1       misho     138: {
1.1.1.3 ! misho     139:     struct sudo_conf_table *var;
        !           140: 
        !           141:     for (var = sudo_conf_table_vars; var->name != NULL; var++) {
        !           142:        if (strncmp(entry, var->name, var->namelen) == 0 &&
        !           143:            isblank((unsigned char)entry[var->namelen])) {
        !           144:            entry += var->namelen + 1;
        !           145:            while (isblank((unsigned char)*entry))
        !           146:                entry++;
        !           147:            var->setter(entry, conf_file);
        !           148:            break;
        !           149:        }
        !           150:     }
        !           151: }
        !           152: 
        !           153: static void
        !           154: set_var_disable_coredump(const char *entry, const char *conf_file)
        !           155: {
        !           156:     int val = atobool(entry);
        !           157: 
        !           158:     if (val != -1)
        !           159:        sudo_conf_data.disable_coredump = val;
        !           160: }
        !           161: 
        !           162: static void
        !           163: set_var_group_source(const char *entry, const char *conf_file)
        !           164: {
        !           165:     if (strcasecmp(entry, "adaptive") == 0) {
        !           166:        sudo_conf_data.group_source = GROUP_SOURCE_ADAPTIVE;
        !           167:     } else if (strcasecmp(entry, "static") == 0) {
        !           168:        sudo_conf_data.group_source = GROUP_SOURCE_STATIC;
        !           169:     } else if (strcasecmp(entry, "dynamic") == 0) {
        !           170:        sudo_conf_data.group_source = GROUP_SOURCE_DYNAMIC;
        !           171:     } else {
        !           172:        warningx(_("unsupported group source `%s' in %s, line %d"), entry,
        !           173:            conf_file, conf_lineno);
        !           174:     }
        !           175: }
        !           176: 
        !           177: static void
        !           178: set_var_max_groups(const char *entry, const char *conf_file)
        !           179: {
        !           180:     long lval;
        !           181:     char *ep;
        !           182: 
        !           183:     lval = strtol(entry, &ep, 10);
        !           184:     if (*entry == '\0' || *ep != '\0' || lval < 0 || lval > INT_MAX ||
        !           185:        (errno == ERANGE && lval == LONG_MAX)) {
        !           186:        warningx(_("invalid max groups `%s' in %s, line %d"), entry,
        !           187:                    conf_file, conf_lineno);
        !           188:     } else {
        !           189:        sudo_conf_data.max_groups = (int)lval;
1.1       misho     190:     }
                    191: }
                    192: 
                    193: /*
                    194:  * "Debug progname debug_file debug_flags"
                    195:  */
1.1.1.3 ! misho     196: static void
        !           197: set_debug(const char *entry, const char *conf_file)
1.1       misho     198: {
                    199:     size_t filelen, proglen;
                    200:     const char *progname;
                    201:     char *debug_file, *debug_flags;
                    202: 
                    203:     /* Is this debug setting for me? */
                    204:     progname = getprogname();
                    205:     if (strcmp(progname, "sudoedit") == 0)
                    206:        progname = "sudo";
                    207:     proglen = strlen(progname);
                    208:     if (strncmp(entry, progname, proglen) != 0 ||
                    209:        !isblank((unsigned char)entry[proglen]))
1.1.1.3 ! misho     210:        return;
1.1       misho     211:     entry += proglen + 1;
                    212:     while (isblank((unsigned char)*entry))
                    213:        entry++;
                    214: 
                    215:     debug_flags = strpbrk(entry, " \t");
                    216:     if (debug_flags == NULL)
1.1.1.3 ! misho     217:        return;
1.1       misho     218:     filelen = (size_t)(debug_flags - entry);
                    219:     while (isblank((unsigned char)*debug_flags))
                    220:        debug_flags++;
                    221: 
                    222:     /* Set debug file and parse the flags (init debug as soon as possible). */
                    223:     debug_file = estrndup(entry, filelen);
                    224:     debug_flags = estrdup(debug_flags);
                    225:     sudo_debug_init(debug_file, debug_flags);
                    226:     efree(debug_file);
                    227: 
                    228:     sudo_conf_data.debug_flags = debug_flags;
                    229: }
                    230: 
1.1.1.3 ! misho     231: static void
        !           232: set_path(const char *entry, const char *conf_file)
1.1       misho     233: {
                    234:     const char *name, *path;
                    235:     struct sudo_conf_paths *cur;
                    236: 
                    237:     /* Parse Path line */
                    238:     name = entry;
                    239:     path = strpbrk(entry, " \t");
                    240:     if (path == NULL)
1.1.1.3 ! misho     241:        return;
1.1       misho     242:     while (isblank((unsigned char)*path))
                    243:        path++;
                    244: 
                    245:     /* Match supported paths, ignore the rest. */
                    246:     for (cur = sudo_conf_data.paths; cur->pname != NULL; cur++) {
                    247:        if (strncasecmp(name, cur->pname, cur->pnamelen) == 0 &&
                    248:            isblank((unsigned char)name[cur->pnamelen])) {
                    249:            cur->pval = estrdup(path);
                    250:            break;
                    251:        }
                    252:     }
                    253: }
                    254: 
1.1.1.3 ! misho     255: static void
        !           256: set_plugin(const char *entry, const char *conf_file)
1.1       misho     257: {
                    258:     struct plugin_info *info;
                    259:     const char *name, *path, *cp, *ep;
                    260:     char **options = NULL;
                    261:     size_t namelen, pathlen;
                    262:     unsigned int nopts;
                    263: 
                    264:     /* Parse Plugin line */
                    265:     name = entry;
                    266:     path = strpbrk(entry, " \t");
                    267:     if (path == NULL)
1.1.1.3 ! misho     268:        return;
1.1       misho     269:     namelen = (size_t)(path - name);
                    270:     while (isblank((unsigned char)*path))
                    271:        path++;
                    272:     if ((cp = strpbrk(path, " \t")) != NULL) {
                    273:        /* Convert any options to an array. */
                    274:        pathlen = (size_t)(cp - path);
                    275:        while (isblank((unsigned char)*cp))
                    276:            cp++;
                    277:        /* Count number of options and allocate array. */
                    278:        for (ep = cp, nopts = 1; (ep = strpbrk(ep, " \t")) != NULL; nopts++) {
                    279:            while (isblank((unsigned char)*ep))
                    280:                ep++;
                    281:        }
                    282:        options = emalloc2(nopts + 1, sizeof(*options));
                    283:        /* Fill in options array, there is at least one element. */
                    284:        for (nopts = 0; (ep = strpbrk(cp, " \t")) != NULL; ) {
                    285:            options[nopts++] = estrndup(cp, (size_t)(ep - cp));
                    286:            while (isblank((unsigned char)*ep))
                    287:                ep++;
                    288:            cp = ep;
                    289:        }
                    290:        options[nopts++] = estrdup(cp);
                    291:        options[nopts] = NULL;
                    292:     } else {
                    293:        /* No extra options. */
                    294:        pathlen = strlen(path);
                    295:     }
                    296: 
                    297:     info = ecalloc(1, sizeof(*info));
                    298:     info->symbol_name = estrndup(name, namelen);
                    299:     info->path = estrndup(path, pathlen);
                    300:     info->options = options;
                    301:     info->prev = info;
                    302:     /* info->next = NULL; */
1.1.1.3 ! misho     303:     info->lineno = conf_lineno;
1.1       misho     304:     tq_append(&sudo_conf_data.plugins, info);
                    305: }
                    306: 
                    307: const char *
                    308: sudo_conf_askpass_path(void)
                    309: {
                    310:     return sudo_conf_data.paths[SUDO_CONF_ASKPASS_IDX].pval;
                    311: }
                    312: 
1.1.1.3 ! misho     313: const char *
        !           314: sudo_conf_sesh_path(void)
        !           315: {
        !           316:     return sudo_conf_data.paths[SUDO_CONF_SESH_IDX].pval;
        !           317: }
        !           318: 
1.1       misho     319: #ifdef _PATH_SUDO_NOEXEC
                    320: const char *
                    321: sudo_conf_noexec_path(void)
                    322: {
                    323:     return sudo_conf_data.paths[SUDO_CONF_NOEXEC_IDX].pval;
                    324: }
                    325: #endif
                    326: 
                    327: const char *
                    328: sudo_conf_debug_flags(void)
                    329: {
                    330:     return sudo_conf_data.debug_flags;
                    331: }
                    332: 
1.1.1.3 ! misho     333: int
        !           334: sudo_conf_group_source(void)
        !           335: {
        !           336:     return sudo_conf_data.group_source;
        !           337: }
        !           338: 
        !           339: int
        !           340: sudo_conf_max_groups(void)
        !           341: {
        !           342:     return sudo_conf_data.max_groups;
        !           343: }
        !           344: 
1.1       misho     345: struct plugin_info_list *
                    346: sudo_conf_plugins(void)
                    347: {
                    348:     return &sudo_conf_data.plugins;
                    349: }
                    350: 
                    351: bool
                    352: sudo_conf_disable_coredump(void)
                    353: {
                    354:     return sudo_conf_data.disable_coredump;
                    355: }
                    356: 
                    357: /*
                    358:  * Reads in /etc/sudo.conf and populates sudo_conf_data.
                    359:  */
                    360: void
1.1.1.3 ! misho     361: sudo_conf_read(const char *conf_file)
1.1       misho     362: {
                    363:     struct sudo_conf_table *cur;
                    364:     struct stat sb;
                    365:     FILE *fp;
1.1.1.3 ! misho     366:     char *cp, *line = NULL;
        !           367:     char *prev_locale = estrdup(setlocale(LC_ALL, NULL));
        !           368:     size_t linesize = 0;
        !           369: 
        !           370:     /* Parse sudo.conf in the "C" locale. */
        !           371:     if (prev_locale[0] != 'C' || prev_locale[1] != '\0')
        !           372:         setlocale(LC_ALL, "C");
        !           373: 
        !           374:     if (conf_file == NULL) {
        !           375:        conf_file = _PATH_SUDO_CONF;
        !           376:        switch (sudo_secure_file(conf_file, ROOT_UID, -1, &sb)) {
        !           377:            case SUDO_PATH_SECURE:
        !           378:                break;
        !           379:            case SUDO_PATH_MISSING:
        !           380:                /* Root should always be able to read sudo.conf. */
        !           381:                if (errno != ENOENT && geteuid() == ROOT_UID)
        !           382:                    warning(_("unable to stat %s"), conf_file);
        !           383:                goto done;
        !           384:            case SUDO_PATH_BAD_TYPE:
        !           385:                warningx(_("%s is not a regular file"), conf_file);
        !           386:                goto done;
        !           387:            case SUDO_PATH_WRONG_OWNER:
        !           388:                warningx(_("%s is owned by uid %u, should be %u"),
        !           389:                    conf_file, (unsigned int) sb.st_uid, ROOT_UID);
        !           390:                goto done;
        !           391:            case SUDO_PATH_WORLD_WRITABLE:
        !           392:                warningx(_("%s is world writable"), conf_file);
        !           393:                goto done;
        !           394:            case SUDO_PATH_GROUP_WRITABLE:
        !           395:                warningx(_("%s is group writable"), conf_file);
        !           396:                goto done;
        !           397:            default:
        !           398:                /* NOTREACHED */
        !           399:                goto done;
        !           400:        }
1.1       misho     401:     }
                    402: 
1.1.1.3 ! misho     403:     if ((fp = fopen(conf_file, "r")) == NULL) {
1.1       misho     404:        if (errno != ENOENT && geteuid() == ROOT_UID)
1.1.1.3 ! misho     405:            warning(_("unable to open %s"), conf_file);
1.1       misho     406:        goto done;
                    407:     }
                    408: 
1.1.1.3 ! misho     409:     conf_lineno = 0;
        !           410:     while (sudo_parseln(&line, &linesize, &conf_lineno, fp) != -1) {
        !           411:        if (*(cp = line) == '\0')
        !           412:            continue;           /* empty line or comment */
1.1       misho     413: 
                    414:        for (cur = sudo_conf_table; cur->name != NULL; cur++) {
                    415:            if (strncasecmp(cp, cur->name, cur->namelen) == 0 &&
                    416:                isblank((unsigned char)cp[cur->namelen])) {
                    417:                cp += cur->namelen;
                    418:                while (isblank((unsigned char)*cp))
                    419:                    cp++;
1.1.1.3 ! misho     420:                cur->setter(cp, conf_file);
        !           421:                break;
1.1       misho     422:            }
                    423:        }
                    424:     }
                    425:     fclose(fp);
1.1.1.3 ! misho     426:     free(line);
1.1       misho     427: done:
1.1.1.3 ! misho     428:     /* Restore locale if needed. */
        !           429:     if (prev_locale[0] != 'C' || prev_locale[1] != '\0')
        !           430:         setlocale(LC_ALL, prev_locale);
        !           431:     efree(prev_locale);
1.1       misho     432: }

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