Annotation of embedaddon/sudo/src/load_plugins.c, revision 1.1

1.1     ! misho       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_STRING_H
        !            32: # include <string.h>
        !            33: #endif /* HAVE_STRING_H */
        !            34: #ifdef HAVE_STRINGS_H
        !            35: # include <strings.h>
        !            36: #endif /* HAVE_STRINGS_H */
        !            37: #ifdef HAVE_UNISTD_H
        !            38: # include <unistd.h>
        !            39: #endif /* HAVE_UNISTD_H */
        !            40: #ifdef HAVE_DLOPEN
        !            41: # include <dlfcn.h>
        !            42: #else
        !            43: # include "compat/dlfcn.h"
        !            44: #endif
        !            45: #include <errno.h>
        !            46: 
        !            47: #include "sudo.h"
        !            48: #include "sudo_plugin.h"
        !            49: #include "sudo_plugin_int.h"
        !            50: 
        !            51: #ifndef RTLD_GLOBAL
        !            52: # define RTLD_GLOBAL   0
        !            53: #endif
        !            54: 
        !            55: #ifdef _PATH_SUDO_NOEXEC
        !            56: const char *noexec_path = _PATH_SUDO_NOEXEC;
        !            57: #endif
        !            58: 
        !            59: /*
        !            60:  * Read in /etc/sudo.conf
        !            61:  * Returns a list of plugins.
        !            62:  */
        !            63: static struct plugin_info_list *
        !            64: sudo_read_conf(const char *conf_file)
        !            65: {
        !            66:     FILE *fp;
        !            67:     char *cp, *name, *path;
        !            68:     struct plugin_info *info;
        !            69:     static struct plugin_info_list pil; /* XXX */
        !            70: 
        !            71:     if ((fp = fopen(conf_file, "r")) == NULL)
        !            72:        goto done;
        !            73: 
        !            74:     while ((cp = sudo_parseln(fp)) != NULL) {
        !            75:        /* Skip blank or comment lines */
        !            76:        if (*cp == '\0')
        !            77:            continue;
        !            78: 
        !            79:        /* Look for a line starting with "Path" */
        !            80:        if (strncasecmp(cp, "Path", 4) == 0) {
        !            81:            /* Parse line */
        !            82:            if ((name = strtok(cp + 4, " \t")) == NULL ||
        !            83:                (path = strtok(NULL, " \t")) == NULL) {
        !            84:                continue;
        !            85:            }
        !            86:            if (strcasecmp(name, "askpass") == 0)
        !            87:                askpass_path = estrdup(path);
        !            88: #ifdef _PATH_SUDO_NOEXEC
        !            89:            else if (strcasecmp(name, "noexec") == 0)
        !            90:                noexec_path = estrdup(path);
        !            91: #endif
        !            92:            continue;
        !            93:        }
        !            94: 
        !            95:        /* Look for a line starting with "Plugin" */
        !            96:        if (strncasecmp(cp, "Plugin", 6) == 0) {
        !            97:            /* Parse line */
        !            98:            if ((name = strtok(cp + 6, " \t")) == NULL ||
        !            99:                (path = strtok(NULL, " \t")) == NULL) {
        !           100:                continue;
        !           101:            }
        !           102:            info = emalloc(sizeof(*info));
        !           103:            info->symbol_name = estrdup(name);
        !           104:            info->path = estrdup(path);
        !           105:            info->prev = info;
        !           106:            info->next = NULL;
        !           107:            tq_append(&pil, info);
        !           108:            continue;
        !           109:        }
        !           110:     }
        !           111:     fclose(fp);
        !           112: 
        !           113: done:
        !           114:     if (tq_empty(&pil)) {
        !           115:        /* Default policy plugin */
        !           116:        info = emalloc(sizeof(*info));
        !           117:        info->symbol_name = "sudoers_policy";
        !           118:        info->path = SUDOERS_PLUGIN;
        !           119:        info->prev = info;
        !           120:        info->next = NULL;
        !           121:        tq_append(&pil, info);
        !           122: 
        !           123:        /* Default I/O plugin */
        !           124:        info = emalloc(sizeof(*info));
        !           125:        info->symbol_name = "sudoers_io";
        !           126:        info->path = SUDOERS_PLUGIN;
        !           127:        info->prev = info;
        !           128:        info->next = NULL;
        !           129:        tq_append(&pil, info);
        !           130:     }
        !           131: 
        !           132:     return &pil;
        !           133: }
        !           134: 
        !           135: /*
        !           136:  * Load the plugins listed in conf_file.
        !           137:  */
        !           138: int
        !           139: sudo_load_plugins(const char *conf_file,
        !           140:     struct plugin_container *policy_plugin,
        !           141:     struct plugin_container_list *io_plugins)
        !           142: {
        !           143:     struct generic_plugin *plugin;
        !           144:     struct plugin_container *container;
        !           145:     struct plugin_info *info;
        !           146:     struct plugin_info_list *plugin_list;
        !           147:     struct stat sb;
        !           148:     void *handle;
        !           149:     char path[PATH_MAX];
        !           150:     int rval = FALSE;
        !           151: 
        !           152:     /* Parse sudo.conf */
        !           153:     plugin_list = sudo_read_conf(conf_file);
        !           154: 
        !           155:     tq_foreach_fwd(plugin_list, info) {
        !           156:        if (info->path[0] == '/') {
        !           157:            if (strlcpy(path, info->path, sizeof(path)) >= sizeof(path)) {
        !           158:                warningx(_("%s: %s"), info->path, strerror(ENAMETOOLONG));
        !           159:                goto done;
        !           160:            }
        !           161:        } else {
        !           162:            if (snprintf(path, sizeof(path), "%s%s", _PATH_SUDO_PLUGIN_DIR,
        !           163:                info->path) >= sizeof(path)) {
        !           164:                warningx(_("%s%s: %s"), _PATH_SUDO_PLUGIN_DIR, info->path,
        !           165:                    strerror(ENAMETOOLONG));
        !           166:                goto done;
        !           167:            }
        !           168:        }
        !           169:        if (stat(path, &sb) != 0) {
        !           170:            warning("%s", path);
        !           171:            goto done;
        !           172:        }
        !           173:        if (sb.st_uid != ROOT_UID) {
        !           174:            warningx(_("%s must be owned by uid %d"), path, ROOT_UID);
        !           175:            goto done;
        !           176:        }
        !           177:        if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
        !           178:            warningx(_("%s must be only be writable by owner"), path);
        !           179:            goto done;
        !           180:        }
        !           181: 
        !           182:        /* Open plugin and map in symbol */
        !           183:        handle = dlopen(path, RTLD_LAZY|RTLD_GLOBAL);
        !           184:        if (!handle) {
        !           185:            warningx(_("unable to dlopen %s: %s"), path, dlerror());
        !           186:            goto done;
        !           187:        }
        !           188:        plugin = dlsym(handle, info->symbol_name);
        !           189:        if (!plugin) {
        !           190:            warningx(_("%s: unable to find symbol %s"), path,
        !           191:                info->symbol_name);
        !           192:            goto done;
        !           193:        }
        !           194: 
        !           195:        if (plugin->type != SUDO_POLICY_PLUGIN && plugin->type != SUDO_IO_PLUGIN) {
        !           196:            warningx(_("%s: unknown policy type %d"), path, plugin->type);
        !           197:            goto done;
        !           198:        }
        !           199:        if (SUDO_API_VERSION_GET_MAJOR(plugin->version) != SUDO_API_VERSION_MAJOR) {
        !           200:            warningx(_("%s: incompatible policy major version %d, expected %d"),
        !           201:                path, SUDO_API_VERSION_GET_MAJOR(plugin->version),
        !           202:                SUDO_API_VERSION_MAJOR);
        !           203:            goto done;
        !           204:        }
        !           205:        if (plugin->type == SUDO_POLICY_PLUGIN) {
        !           206:            if (policy_plugin->handle) {
        !           207:                warningx(_("%s: only a single policy plugin may be loaded"),
        !           208:                    conf_file);
        !           209:                goto done;
        !           210:            }
        !           211:            policy_plugin->handle = handle;
        !           212:            policy_plugin->name = info->symbol_name;
        !           213:            policy_plugin->u.generic = plugin;
        !           214:        } else if (plugin->type == SUDO_IO_PLUGIN) {
        !           215:            container = emalloc(sizeof(*container));
        !           216:            container->prev = container;
        !           217:            container->next = NULL;
        !           218:            container->handle = handle;
        !           219:            container->name = info->symbol_name;
        !           220:            container->u.generic = plugin;
        !           221:            tq_append(io_plugins, container);
        !           222:        }
        !           223:     }
        !           224:     if (policy_plugin->handle == NULL) {
        !           225:        warningx(_("%s: at least one policy plugin must be specified"),
        !           226:            conf_file);
        !           227:        goto done;
        !           228:     }
        !           229:     if (policy_plugin->u.policy->check_policy == NULL) {
        !           230:        warningx(_("policy plugin %s does not include a check_policy method"),
        !           231:            policy_plugin->name);
        !           232:        goto done;
        !           233:     }
        !           234: 
        !           235:     rval = TRUE;
        !           236: 
        !           237: done:
        !           238:     return rval;
        !           239: }

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