diff options
Diffstat (limited to 'plugins/sudoers/group_plugin.c')
-rw-r--r-- | plugins/sudoers/group_plugin.c | 137 |
1 files changed, 116 insertions, 21 deletions
diff --git a/plugins/sudoers/group_plugin.c b/plugins/sudoers/group_plugin.c index e11cfb1f1..72a35b6ef 100644 --- a/plugins/sudoers/group_plugin.c +++ b/plugins/sudoers/group_plugin.c @@ -41,17 +41,102 @@ static struct sudoers_group_plugin *group_plugin; const char *path_plugin_dir = _PATH_SUDO_PLUGIN_DIR; /* + * Check for a fallback path when the original group plugin is not loadable. + * Returns true on success, rewriting path and filling in sb, else false. + */ +static bool +group_plugin_fallback(char *path, size_t pathsize, struct stat *sb) +{ +#if defined(__LP64__) + char newpath[PATH_MAX]; + bool ret = false; + int len; + debug_decl(group_plugin_fallback, SUDOERS_DEBUG_UTIL); + +# if defined(__sun__) || defined(__linux__) + /* + * Solaris uses /lib/64 and /usr/lib/64 for 64-bit libraries. + * Linux may use /lib64 and /usr/lib64 for 64-bit libraries. + * If dirname(path) ends in /lib, try /lib/64 (Solaris) or /lib64 (Linux). + */ +# if defined(__sun__) + const char *lib64 = "lib/64"; +# else + const char *lib64 = "lib64"; +# endif + const char *base, *slash; + int dirlen; + + slash = strrchr(path, '/'); + if (slash == NULL) { + goto done; + } + base = slash + 1; + + /* Collapse consecutive slashes. */ + while (slash > path && slash[-1] == '/') { + slash--; + } + + /* If directory ends in /lib/, try again with /lib/64/ or /lib64/. */ + dirlen = slash - path; + if (dirlen < 4 || strncmp(slash - 4, "/lib", 4) != 0) { + goto done; + } + dirlen -= 4; + len = snprintf(newpath, sizeof(newpath), "%.*s/%s/%s", dirlen, path, lib64, + base); +# else /* !__sun__ && !__linux__ */ + /* + * Multilib not supported, check for a path of the form libfoo64.so. + */ + const char *dot; + int plen; + + dot = strrchr(path, '.'); + if (dot == NULL) { + goto done; + } + plen = dot - path; + + /* If basename(path) doesn't match libfoo64.so, try adding the 64. */ + if (plen >= 2 && strncmp(dot - 2, "64", 2) == 0) { + goto done; + } + len = snprintf(newpath, sizeof(newpath), "%.*s64%s", plen, path, dot); +# endif /* __sun__ || __linux__ */ + if (len < 0 || len >= ssizeof(newpath)) { + errno = ENAMETOOLONG; + goto done; + } + if (stat(newpath, sb) == -1) { + goto done; + } + if (strlcpy(path, newpath, pathsize) >= pathsize) { + errno = ENAMETOOLONG; + goto done; + } + ret = true; +done: + debug_return_bool(ret); +#else + return false; +#endif /* __LP64__ */ +} + +/* * Load the specified plugin and run its init function. * Returns -1 if unable to open the plugin, else it returns * the value from the plugin's init function. */ int -group_plugin_load(char *plugin_info) +group_plugin_load(const char *plugin_info) { struct stat sb; char *args, path[PATH_MAX]; char **argv = NULL; int len, rc = -1; + bool retry = true; debug_decl(group_plugin_load, SUDOERS_DEBUG_UTIL); /* @@ -72,31 +157,41 @@ group_plugin_load(char *plugin_info) (*plugin_info != '/') ? path_plugin_dir : "", plugin_info); goto done; } - - /* Check owner and mode of plugin path. */ if (stat(path, &sb) != 0) { sudo_warn("%s", path); goto done; } - if (!sudo_conf_developer_mode()) { - if (sb.st_uid != ROOT_UID) { - sudo_warnx(U_("%s must be owned by uid %d"), path, ROOT_UID); - goto done; - } - if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - sudo_warnx(U_("%s must only be writable by owner"), path); - goto done; - } - } - /* Open plugin and map in symbol. */ - group_handle = sudo_dso_load(path, SUDO_DSO_LAZY|SUDO_DSO_GLOBAL); - if (!group_handle) { - const char *errstr = sudo_dso_strerror(); - sudo_warnx(U_("unable to load %s: %s"), path, - errstr ? errstr : "unknown error"); - goto done; + for (;;) { + if (!sudo_conf_developer_mode()) { + /* Check owner and mode of plugin path. */ + if (sb.st_uid != ROOT_UID) { + sudo_warnx(U_("%s must be owned by uid %d"), path, ROOT_UID); + goto done; + } + if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) { + sudo_warnx(U_("%s must only be writable by owner"), path); + goto done; + } + } + + group_handle = sudo_dso_load(path, SUDO_DSO_LAZY|SUDO_DSO_GLOBAL); + if (group_handle != NULL) { + break; + } + + if (!retry || !group_plugin_fallback(path, sizeof(path), &sb)) { + const char *errstr = sudo_dso_strerror(); + sudo_warnx(U_("unable to load %s: %s"), path, + errstr ? errstr : "unknown error"); + goto done; + } + + /* Retry once with the fallback path. */ + retry = false; } + + /* Map in symbol from group plugin. */ group_plugin = sudo_dso_findsym(group_handle, "group_plugin"); if (group_plugin == NULL) { sudo_warnx(U_("unable to find symbol \"group_plugin\" in %s"), path); @@ -193,7 +288,7 @@ group_plugin_query(const char *user, const char *group, */ int -group_plugin_load(char *plugin_info) +group_plugin_load(const char *plugin_info) { debug_decl(group_plugin_load, SUDOERS_DEBUG_UTIL); debug_return_int(false); |