/* * Copyright (c) 2010, 2012-2013 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #ifndef HAVE_DLOPEN #include #include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif /* STDC_HEADERS */ #ifdef HAVE_STRING_H # include #endif /* HAVE_STRING_H */ #ifdef HAVE_STRINGS_H # include #endif /* HAVE_STRINGS_H */ #include #include "compat/dlfcn.h" #include "missing.h" #ifdef HAVE_SHL_LOAD /* * Emulate dlopen() using shl_load(). */ #include #ifndef DYNAMIC_PATH # define DYNAMIC_PATH 0 #endif void * sudo_dlopen(const char *path, int mode) { int flags = DYNAMIC_PATH | BIND_VERBOSE; if (mode == 0) mode = RTLD_LAZY; /* default behavior */ /* We don't support RTLD_GLOBAL or RTLD_LOCAL yet. */ if (ISSET(mode, RTLD_LAZY)) flags |= BIND_DEFERRED; if (ISSET(mode, RTLD_NOW)) flags |= BIND_IMMEDIATE; return (void *)shl_load(path, flags, 0L); } int sudo_dlclose(void *handle) { return shl_unload((shl_t)handle); } void * sudo_dlsym(void *vhandle, const char *symbol) { shl_t handle = vhandle; void *value = NULL; /* * Note that the behavior of of RTLD_NEXT and RTLD_SELF * differs from most implementations when called from * a shared library. */ if (vhandle == RTLD_NEXT) { /* Iterate over all shared libs looking for symbol. */ struct shl_descriptor *desc; int idx = 0; while (shl_get(idx++, &desc) == 0) { if (shl_findsym(&desc->handle, symbol, TYPE_UNDEFINED, &value) == 0) break; } } else { if (vhandle == RTLD_DEFAULT) handle = NULL; else if (vhandle == RTLD_SELF) handle = PROG_HANDLE; (void)shl_findsym(&handle, symbol, TYPE_UNDEFINED, &value); } return value; } char * sudo_dlerror(void) { return strerror(errno); } #else /* !HAVE_SHL_LOAD */ /* * Emulate dlopen() using a static list of symbols compiled into sudo. */ struct sudo_preload_table { const char *name; void *address; }; extern struct sudo_preload_table sudo_preload_table[]; void * sudo_dlopen(const char *path, int mode) { return (void *)path; } int sudo_dlclose(void *handle) { return 0; } void * sudo_dlsym(void *handle, const char *symbol) { struct sudo_preload_table *sym; if (symbol != RTLD_NEXT && symbol != RTLD_DEFAULT && symbol != RTLD_SELF) { for (sym = sudo_preload_table; sym->name != NULL; sym++) { if (strcmp(symbol, sym->name) == 0) return sym->address; } } return NULL; } char * sudo_dlerror(void) { return strerror(errno); } #endif /* HAVE_SHL_LOAD */ #endif /* HAVE_DLOPEN */