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

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