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

1.1       misho       1: /*
1.1.1.4 ! 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_STRING_H
                     31: # include <string.h>
                     32: #endif /* HAVE_STRING_H */
                     33: #ifdef HAVE_STRINGS_H
                     34: # include <strings.h>
                     35: #endif /* HAVE_STRINGS_H */
                     36: #ifdef HAVE_UNISTD_H
                     37: # include <unistd.h>
                     38: #endif /* HAVE_UNISTD_H */
                     39: #ifdef HAVE_DLOPEN
                     40: # include <dlfcn.h>
                     41: #else
                     42: # include "compat/dlfcn.h"
                     43: #endif
                     44: #include <errno.h>
                     45: 
                     46: #include "sudo.h"
                     47: #include "sudo_plugin.h"
                     48: #include "sudo_plugin_int.h"
1.1.1.2   misho      49: #include "sudo_conf.h"
                     50: #include "sudo_debug.h"
1.1       misho      51: 
                     52: #ifndef RTLD_GLOBAL
                     53: # define RTLD_GLOBAL   0
                     54: #endif
                     55: 
1.1.1.4 ! misho      56: #ifndef SUDOERS_PLUGIN
        !            57: # define SUDOERS_PLUGIN        "sudoers.la"
        !            58: #endif
        !            59: 
        !            60: #ifdef _PATH_SUDO_PLUGIN_DIR
        !            61: static int
        !            62: sudo_stat_plugin(struct plugin_info *info, char *fullpath,
        !            63:     size_t pathsize, struct stat *sb)
1.1       misho      64: {
1.1.1.4 ! misho      65:     int status = -1;
        !            66:     debug_decl(sudo_stat_plugin, SUDO_DEBUG_PLUGIN)
1.1       misho      67: 
1.1.1.3   misho      68:     if (info->path[0] == '/') {
1.1.1.4 ! misho      69:        if (strlcpy(fullpath, info->path, pathsize) >= pathsize) {
        !            70:            warningx(_("error in %s, line %d while loading plugin `%s'"),
        !            71:                _PATH_SUDO_CONF, info->lineno, info->symbol_name);
1.1.1.3   misho      72:            warningx(_("%s: %s"), info->path, strerror(ENAMETOOLONG));
1.1       misho      73:            goto done;
                     74:        }
1.1.1.4 ! misho      75:        status = stat(fullpath, sb);
1.1.1.3   misho      76:     } else {
1.1.1.4 ! misho      77:        if (snprintf(fullpath, pathsize, "%s%s", _PATH_SUDO_PLUGIN_DIR,
        !            78:            info->path) >= pathsize) {
        !            79:            warningx(_("error in %s, line %d while loading plugin `%s'"),
        !            80:                _PATH_SUDO_CONF, info->lineno, info->symbol_name);
1.1.1.3   misho      81:            warningx(_("%s%s: %s"), _PATH_SUDO_PLUGIN_DIR, info->path,
                     82:                strerror(ENAMETOOLONG));
1.1       misho      83:            goto done;
                     84:        }
1.1.1.4 ! misho      85:        /* Try parent dir for compatibility with old plugindir default. */
        !            86:        if ((status = stat(fullpath, sb)) != 0) {
        !            87:            char *cp = strrchr(fullpath, '/');
        !            88:            if (cp > fullpath + 4 && cp[-5] == '/' && cp[-4] == 's' &&
        !            89:                cp[-3] == 'u' && cp[-2] == 'd' && cp[-1] == 'o') {
        !            90:                int serrno = errno;
        !            91:                strlcpy(cp - 4, info->path, pathsize - (cp - 4 - fullpath));
        !            92:                if ((status = stat(fullpath, sb)) != 0)
        !            93:                    errno = serrno;
        !            94:            }
        !            95:        }
        !            96: # ifdef __hpux
        !            97:        /* Try .sl instead of .so on HP-UX for backwards compatibility. */
        !            98:        if (status != 0) {
        !            99:            size_t len = strlen(info->path);
        !           100:            if (len >= 3 && info->path[len - 3] == '.' &&
        !           101:                info->path[len - 2] == 's' && info->path[len - 1] == 'o') {
        !           102:                const char *sopath = info->path;
        !           103:                char *slpath = estrdup(info->path);
        !           104:                int serrno = errno;
        !           105: 
        !           106:                slpath[len - 1] = 'l';
        !           107:                info->path = slpath;
        !           108:                status = sudo_stat_plugin(info, fullpath, pathsize, sb);
        !           109:                if (status == 0) {
        !           110:                    efree((void *)sopath);
        !           111:                } else {
        !           112:                    efree(slpath);
        !           113:                    info->path = sopath;
        !           114:                    errno = serrno;
        !           115:                }
        !           116:            }
        !           117:        }
        !           118: # endif /* __hpux */
1.1.1.3   misho     119:     }
1.1.1.4 ! misho     120: done:
        !           121:     debug_return_int(status);
        !           122: }
        !           123: 
        !           124: static bool
        !           125: sudo_check_plugin(struct plugin_info *info, char *fullpath, size_t pathsize)
        !           126: {
        !           127:     struct stat sb;
        !           128:     int rval = false;
        !           129:     debug_decl(sudo_check_plugin, SUDO_DEBUG_PLUGIN)
        !           130: 
        !           131:     if (sudo_stat_plugin(info, fullpath, pathsize, &sb) != 0) {
        !           132:        warningx(_("error in %s, line %d while loading plugin `%s'"),
        !           133:            _PATH_SUDO_CONF, info->lineno, info->symbol_name);
        !           134:        warning("%s%s", _PATH_SUDO_PLUGIN_DIR, info->path);
1.1.1.3   misho     135:        goto done;
                    136:     }
                    137:     if (sb.st_uid != ROOT_UID) {
1.1.1.4 ! misho     138:        warningx(_("error in %s, line %d while loading plugin `%s'"),
        !           139:            _PATH_SUDO_CONF, info->lineno, info->symbol_name);
        !           140:        warningx(_("%s must be owned by uid %d"), fullpath, ROOT_UID);
1.1.1.3   misho     141:        goto done;
                    142:     }
                    143:     if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
1.1.1.4 ! misho     144:        warningx(_("error in %s, line %d while loading plugin `%s'"),
        !           145:            _PATH_SUDO_CONF, info->lineno, info->symbol_name);
        !           146:        warningx(_("%s must be only be writable by owner"), fullpath);
1.1.1.3   misho     147:        goto done;
                    148:     }
1.1.1.4 ! misho     149:     rval = true;
        !           150: 
        !           151: done:
        !           152:     debug_return_bool(rval);
        !           153: }
        !           154: #else
        !           155: static bool
        !           156: sudo_check_plugin(struct plugin_info *info, char *fullpath, size_t pathsize)
        !           157: {
        !           158:     debug_decl(sudo_check_plugin, SUDO_DEBUG_PLUGIN)
        !           159:     (void)strlcpy(fullpath, info->path, pathsize);
        !           160:     debug_return_bool(true);
        !           161: }
        !           162: #endif /* _PATH_SUDO_PLUGIN_DIR */
        !           163: 
        !           164: /*
        !           165:  * Load the plugin specified by "info".
        !           166:  */
        !           167: static bool
        !           168: sudo_load_plugin(struct plugin_container *policy_plugin,
        !           169:     struct plugin_container_list *io_plugins, struct plugin_info *info)
        !           170: {
        !           171:     struct plugin_container *container;
        !           172:     struct generic_plugin *plugin;
        !           173:     char path[PATH_MAX];
        !           174:     bool rval = false;
        !           175:     void *handle;
        !           176:     debug_decl(sudo_load_plugin, SUDO_DEBUG_PLUGIN)
        !           177: 
        !           178:     /* Sanity check plugin and fill in path */
        !           179:     if (!sudo_check_plugin(info, path, sizeof(path)))
        !           180:        goto done;
1.1       misho     181: 
1.1.1.3   misho     182:     /* Open plugin and map in symbol */
                    183:     handle = dlopen(path, RTLD_LAZY|RTLD_GLOBAL);
                    184:     if (!handle) {
1.1.1.4 ! misho     185:        warningx(_("error in %s, line %d while loading plugin `%s'"),
        !           186:            _PATH_SUDO_CONF, info->lineno, info->symbol_name);
1.1.1.3   misho     187:        warningx(_("unable to dlopen %s: %s"), path, dlerror());
                    188:        goto done;
                    189:     }
                    190:     plugin = dlsym(handle, info->symbol_name);
                    191:     if (!plugin) {
1.1.1.4 ! misho     192:        warningx(_("error in %s, line %d while loading plugin `%s'"),
        !           193:            _PATH_SUDO_CONF, info->lineno, info->symbol_name);
        !           194:        warningx(_("unable to find symbol `%s' in %s"), info->symbol_name, path);
1.1.1.3   misho     195:        goto done;
                    196:     }
1.1       misho     197: 
1.1.1.3   misho     198:     if (plugin->type != SUDO_POLICY_PLUGIN && plugin->type != SUDO_IO_PLUGIN) {
1.1.1.4 ! misho     199:        warningx(_("error in %s, line %d while loading plugin `%s'"),
        !           200:            _PATH_SUDO_CONF, info->lineno, info->symbol_name);
        !           201:        warningx(_("unknown policy type %d found in %s"), plugin->type, path);
1.1.1.3   misho     202:        goto done;
                    203:     }
                    204:     if (SUDO_API_VERSION_GET_MAJOR(plugin->version) != SUDO_API_VERSION_MAJOR) {
1.1.1.4 ! misho     205:        warningx(_("error in %s, line %d while loading plugin `%s'"),
        !           206:            _PATH_SUDO_CONF, info->lineno, info->symbol_name);
        !           207:        warningx(_("incompatible plugin major version %d (expected %d) found in %s"),
        !           208:            SUDO_API_VERSION_GET_MAJOR(plugin->version),
        !           209:            SUDO_API_VERSION_MAJOR, path);
1.1.1.3   misho     210:        goto done;
                    211:     }
                    212:     if (plugin->type == SUDO_POLICY_PLUGIN) {
                    213:        if (policy_plugin->handle) {
1.1.1.4 ! misho     214:            /* Ignore duplicate entries. */
        !           215:            if (strcmp(policy_plugin->name, info->symbol_name) != 0) {
        !           216:                warningx(_("ignoring policy plugin `%s' in %s, line %d"),
        !           217:                    info->symbol_name, _PATH_SUDO_CONF, info->lineno);
        !           218:                warningx(_("only a single policy plugin may be specified"));
        !           219:                goto done;
        !           220:            }
        !           221:            warningx(_("ignoring duplicate policy plugin `%s' in %s, line %d"),
        !           222:                info->symbol_name, _PATH_SUDO_CONF, info->lineno);
        !           223:            dlclose(handle);
        !           224:            handle = NULL;
        !           225:        }
        !           226:        if (handle != NULL) {
        !           227:            policy_plugin->handle = handle;
        !           228:            policy_plugin->name = info->symbol_name;
        !           229:            policy_plugin->options = info->options;
        !           230:            policy_plugin->u.generic = plugin;
1.1.1.3   misho     231:        }
                    232:     } else if (plugin->type == SUDO_IO_PLUGIN) {
1.1.1.4 ! misho     233:        /* Check for duplicate entries. */
        !           234:        tq_foreach_fwd(io_plugins, container) {
        !           235:            if (strcmp(container->name, info->symbol_name) == 0) {
        !           236:                warningx(_("ignoring duplicate I/O plugin `%s' in %s, line %d"),
        !           237:                    info->symbol_name, _PATH_SUDO_CONF, info->lineno);
        !           238:                dlclose(handle);
        !           239:                handle = NULL;
        !           240:                break;
        !           241:            }
        !           242:        }
        !           243:        if (handle != NULL) {
        !           244:            container = ecalloc(1, sizeof(*container));
        !           245:            container->prev = container;
        !           246:            /* container->next = NULL; */
        !           247:            container->handle = handle;
        !           248:            container->name = info->symbol_name;
        !           249:            container->options = info->options;
        !           250:            container->u.generic = plugin;
        !           251:            tq_append(io_plugins, container);
        !           252:        }
1.1.1.3   misho     253:     }
                    254: 
                    255:     rval = true;
                    256: done:
                    257:     debug_return_bool(rval);
                    258: }
                    259: 
                    260: /*
                    261:  * Load the plugins listed in sudo.conf.
                    262:  */
                    263: bool
                    264: sudo_load_plugins(struct plugin_container *policy_plugin,
                    265:     struct plugin_container_list *io_plugins)
                    266: {
                    267:     struct plugin_container *container;
                    268:     struct plugin_info_list *plugins;
                    269:     struct plugin_info *info;
                    270:     bool rval = false;
                    271:     debug_decl(sudo_load_plugins, SUDO_DEBUG_PLUGIN)
                    272: 
                    273:     /* Walk the plugin list from sudo.conf, if any. */
                    274:     plugins = sudo_conf_plugins();
                    275:     tq_foreach_fwd(plugins, info) {
                    276:        rval = sudo_load_plugin(policy_plugin, io_plugins, info);
                    277:        if (!rval)
1.1       misho     278:            goto done;
                    279:     }
1.1.1.3   misho     280: 
                    281:     /*
                    282:      * If no policy plugin, fall back to the default (sudoers).
                    283:      * If there is also no I/O log plugin, sudoers for that too.
                    284:      */
1.1       misho     285:     if (policy_plugin->handle == NULL) {
1.1.1.3   misho     286:        /* Default policy plugin */
                    287:        info = ecalloc(1, sizeof(*info));
                    288:        info->symbol_name = "sudoers_policy";
                    289:        info->path = SUDOERS_PLUGIN;
                    290:        /* info->options = NULL; */
                    291:        info->prev = info;
                    292:        /* info->next = NULL; */
                    293:        rval = sudo_load_plugin(policy_plugin, io_plugins, info);
                    294:        efree(info);
                    295:        if (!rval)
                    296:            goto done;
                    297: 
                    298:        /* Default I/O plugin */
                    299:        if (tq_empty(io_plugins)) {
                    300:            info = ecalloc(1, sizeof(*info));
                    301:            info->symbol_name = "sudoers_io";
                    302:            info->path = SUDOERS_PLUGIN;
                    303:            /* info->options = NULL; */
                    304:            info->prev = info;
                    305:            /* info->next = NULL; */
                    306:            rval = sudo_load_plugin(policy_plugin, io_plugins, info);
                    307:            efree(info);
                    308:            if (!rval)
                    309:                goto done;
                    310:        }
1.1       misho     311:     }
                    312:     if (policy_plugin->u.policy->check_policy == NULL) {
                    313:        warningx(_("policy plugin %s does not include a check_policy method"),
                    314:            policy_plugin->name);
1.1.1.3   misho     315:        rval = false;
1.1       misho     316:        goto done;
                    317:     }
                    318: 
1.1.1.2   misho     319:     /* Install hooks (XXX - later). */
                    320:     if (policy_plugin->u.policy->version >= SUDO_API_MKVERSION(1, 2)) {
                    321:        if (policy_plugin->u.policy->register_hooks != NULL)
                    322:            policy_plugin->u.policy->register_hooks(SUDO_HOOK_VERSION, register_hook);
1.1.1.3   misho     323:     }
                    324:     tq_foreach_fwd(io_plugins, container) {
                    325:        if (container->u.io->version >= SUDO_API_MKVERSION(1, 2)) {
1.1.1.2   misho     326:            if (container->u.io->register_hooks != NULL)
                    327:                container->u.io->register_hooks(SUDO_HOOK_VERSION, register_hook);
                    328:        }
                    329:     }
                    330: 
1.1       misho     331: done:
1.1.1.2   misho     332:     debug_return_bool(rval);
1.1       misho     333: }

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