2 * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
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.
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.
19 #if defined(HAVE_DLOPEN) || defined(HAVE_SHL_LOAD)
21 #include <sys/types.h>
22 #include <sys/param.h>
33 #endif /* STDC_HEADERS */
36 #endif /* HAVE_STRING_H */
39 #endif /* HAVE_STRINGS_H */
42 #endif /* HAVE_UNISTD_H */
43 #if TIME_WITH_SYS_TIME
49 # include "compat/dlfcn.h"
58 # define RTLD_GLOBAL 0
61 static void *group_handle;
62 static struct sudoers_group_plugin *group_plugin;
65 * Load the specified plugin and run its init function.
66 * Returns -1 if unable to open the plugin, else it returns
67 * the value from the plugin's init function.
70 group_plugin_load(char *plugin_info)
73 char *args, path[PATH_MAX];
78 * Fill in .so path and split out args (if any).
80 if ((args = strpbrk(plugin_info, " \t")) != NULL) {
81 len = snprintf(path, sizeof(path), "%s%.*s",
82 (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "",
83 (int)(args - plugin_info), plugin_info);
86 len = snprintf(path, sizeof(path), "%s%s",
87 (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "", plugin_info);
89 if (len <= 0 || len >= sizeof(path)) {
90 warningx(_("%s%s: %s"),
91 (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "", plugin_info,
92 strerror(ENAMETOOLONG));
96 /* Sanity check plugin path. */
97 if (stat(path, &sb) != 0) {
101 if (sb.st_uid != ROOT_UID) {
102 warningx(_("%s must be owned by uid %d"), path, ROOT_UID);
105 if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
106 warningx(_("%s must only be writable by owner"), path);
110 /* Open plugin and map in symbol. */
111 group_handle = dlopen(path, RTLD_LAZY|RTLD_GLOBAL);
113 warningx(_("unable to dlopen %s: %s"), path, dlerror());
116 group_plugin = dlsym(group_handle, "group_plugin");
117 if (group_plugin == NULL) {
118 warningx(_("unable to find symbol \"group_plugin\" in %s"), path);
122 if (GROUP_API_VERSION_GET_MAJOR(group_plugin->version) != GROUP_API_VERSION_MAJOR) {
123 warningx(_("%s: incompatible group plugin major version %d, expected %d"),
124 path, GROUP_API_VERSION_GET_MAJOR(group_plugin->version),
125 GROUP_API_VERSION_MAJOR);
130 * Split args into a vector if specified.
133 int ac = 0, wasblank = TRUE;
136 for (cp = args; *cp != '\0'; cp++) {
137 if (isblank((unsigned char)*cp)) {
139 } else if (wasblank) {
145 argv = emalloc2(ac, sizeof(char *));
147 for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t")))
152 rc = (group_plugin->init)(GROUP_API_VERSION, sudo_printf, argv);
158 if (group_handle != NULL) {
159 dlclose(group_handle);
169 group_plugin_unload(void)
171 if (group_plugin != NULL) {
172 (group_plugin->cleanup)();
175 if (group_handle != NULL) {
176 dlclose(group_handle);
182 group_plugin_query(const char *user, const char *group,
183 const struct passwd *pwd)
185 if (group_plugin == NULL)
187 return (group_plugin->query)(user, group, pwd);
190 #else /* !HAVE_DLOPEN && !HAVE_SHL_LOAD */
193 * No loadable shared object support.
203 group_plugin_load(char *plugin_info)
209 group_plugin_unload(void)
215 group_plugin_query(const char *user, const char *group,
216 const struct passwd *pwd)
221 #endif /* HAVE_DLOPEN || HAVE_SHL_LOAD */