Merge tag 'debian/1.8.5p2-1' into squeeze
[debian/sudo] / compat / dlopen.c
diff --git a/compat/dlopen.c b/compat/dlopen.c
new file mode 100644 (file)
index 0000000..f5f62fe
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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 <config.h>
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <errno.h>
+
+#include "compat/dlfcn.h"
+#include "missing.h"
+
+#ifdef HAVE_SHL_LOAD
+/*
+ * Emulate dlopen() using shl_load().
+ */
+#include <dl.h>
+
+#ifndef DYNAMIC_PATH
+# define DYNAMIC_PATH  0
+#endif
+
+void *
+sudo_dlopen(const char *path, int mode)
+{
+    int flags = DYNAMIC_PATH;
+
+    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 */