1 /* dlopen.c--Unix dlopen() dynamic loader interface
4 * $Id: dlopen.c,v 1.49 2005/03/15 13:33:30 mel Exp $
7 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
21 * 3. The name "Carnegie Mellon University" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For permission or any other legal
24 * details, please contact
25 * Office of Technology Transfer
26 * Carnegie Mellon University
28 * Pittsburgh, PA 15213-3890
29 * (412) 268-4387, fax: (412) 268-7395
30 * tech-transfer@andrew.cmu.edu
32 * 4. Redistributions of any form whatsoever must retain the following
34 * "This product includes software developed by Computing Services
35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
37 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
61 #include "staticopen.h"
67 # define NAMLEN(dirent) strlen((dirent)->d_name)
68 #else /* HAVE_DIRENT_H */
69 # define dirent direct
70 # define NAMLEN(dirent) (dirent)->d_namlen
72 # include <sys/ndir.h>
80 #endif /* ! HAVE_DIRENT_H */
83 # ifdef _POSIX_NAME_MAX
84 # define NAME_MAX _POSIX_NAME_MAX
98 typedef shl_t dll_handle;
99 typedef void * dll_func;
102 dlopen(char *fname, int mode)
104 shl_t h = shl_load(fname, BIND_DEFERRED, 0L);
108 hp = (shl_t *)malloc(sizeof (shl_t));
116 return (dll_handle)hp;
120 dlclose(dll_handle h)
122 shl_t hp = *((shl_t *)h);
123 if (hp != NULL) free(hp);
124 return shl_unload(h);
128 dlsym(dll_handle h, char *n)
132 if (shl_findsym ((shl_t *)h, n, TYPE_PROCEDURE, &handle))
135 return (dll_func)handle;
141 return strerror(errno);
143 return "Generic shared library error";
146 #endif /* HAVE_DLFCN_H */
147 #define SO_SUFFIX ".sl"
149 #define SO_SUFFIX ".so"
152 #define LA_SUFFIX ".la"
154 typedef struct lib_list
156 struct lib_list *next;
160 static lib_list_t *lib_list_head = NULL;
162 #endif /* DO_DLOPEN */
164 int _sasl_locate_entry(void *library, const char *entryname,
168 /* note that we still check for known problem systems in
169 * case we are cross-compiling */
170 #if defined(DLSYM_NEEDS_UNDERSCORE) || (defined(__OpenBSD__) && !defined(__ELF__))
171 char adj_entryname[1024];
173 #define adj_entryname entryname
177 _sasl_log(NULL, SASL_LOG_ERR,
178 "no entryname in _sasl_locate_entry");
179 return SASL_BADPARAM;
183 _sasl_log(NULL, SASL_LOG_ERR,
184 "no library in _sasl_locate_entry");
185 return SASL_BADPARAM;
189 _sasl_log(NULL, SASL_LOG_ERR,
190 "no entrypoint output pointer in _sasl_locate_entry");
191 return SASL_BADPARAM;
194 #if defined(DLSYM_NEEDS_UNDERSCORE) || (defined(__OpenBSD__) && !defined(__ELF__))
195 snprintf(adj_entryname, sizeof adj_entryname, "_%s", entryname);
199 *entry_point = dlsym(library, adj_entryname);
200 if (*entry_point == NULL) {
201 #if 0 /* This message appears to confuse people */
202 _sasl_log(NULL, SASL_LOG_DEBUG,
203 "unable to get entry point %s: %s", adj_entryname,
212 #endif /* DO_DLOPEN */
217 static int _sasl_plugin_load(char *plugin, void *library,
218 const char *entryname,
219 int (*add_plugin)(const char *, void *))
224 result = _sasl_locate_entry(library, entryname, &entry_point);
225 if(result == SASL_OK) {
226 result = add_plugin(plugin, entry_point);
227 if(result != SASL_OK)
228 _sasl_log(NULL, SASL_LOG_DEBUG,
229 "_sasl_plugin_load failed on %s for plugin: %s\n",
236 /* this returns the file to actually open.
237 * out should be a buffer of size PATH_MAX
238 * and may be the same as in. */
240 /* We'll use a static buffer for speed unless someone complains */
241 #define MAX_LINE 2048
243 static int _parse_la(const char *prefix, const char *in, char *out)
250 if(!in || !out || !prefix || out == in) return SASL_BADPARAM;
252 /* Set this so we can detect failure */
257 if (strcmp(in + (length - strlen(LA_SUFFIX)), LA_SUFFIX)) {
258 if(!strcmp(in + (length - strlen(SO_SUFFIX)),SO_SUFFIX)) {
259 /* check for a .la file */
260 strcpy(line, prefix);
262 length = strlen(line);
263 *(line + (length - strlen(SO_SUFFIX))) = '\0';
264 strcat(line, LA_SUFFIX);
265 file = fopen(line, "r");
267 /* We'll get it on the .la open */
277 strcpy(line, prefix);
280 file = fopen(line, "r");
282 _sasl_log(NULL, SASL_LOG_WARN,
283 "unable to open LA file: %s", line);
288 if(!fgets(line, MAX_LINE, file)) break;
289 if(line[strlen(line) - 1] != '\n') {
290 _sasl_log(NULL, SASL_LOG_WARN,
291 "LA file has too long of a line: %s", in);
294 if(line[0] == '\n' || line[0] == '#') continue;
295 if(!strncmp(line, "dlname=", sizeof("dlname=") - 1)) {
296 /* We found the line with the name in it */
300 end = strrchr(line, '\'');
302 start = &line[sizeof("dlname=")-1];
304 if(len > 3 && start[0] == '\'') {
307 /* Do we have dlname="" ? */
309 _sasl_log(NULL, SASL_LOG_DEBUG,
310 "dlname is empty in .la file: %s", in);
319 if(ferror(file) || feof(file)) {
320 _sasl_log(NULL, SASL_LOG_WARN,
321 "Error reading .la: %s\n", in);
328 _sasl_log(NULL, SASL_LOG_WARN,
329 "Could not find a dlname line in .la file: %s", in);
335 #endif /* DO_DLOPEN */
337 /* loads a plugin library */
338 int _sasl_get_plugin(const char *file,
339 const sasl_callback_t *verifyfile_cb,
348 r = ((sasl_verifyfile_t *)(verifyfile_cb->proc))
349 (verifyfile_cb->context, file, SASL_VRFY_PLUGIN);
350 if (r != SASL_OK) return r;
358 newhead = sasl_ALLOC(sizeof(lib_list_t));
359 if(!newhead) return SASL_NOMEM;
361 if (!(library = dlopen(file, flag))) {
362 _sasl_log(NULL, SASL_LOG_ERR,
363 "unable to dlopen %s: %s", file, dlerror());
368 newhead->library = library;
369 newhead->next = lib_list_head;
370 lib_list_head = newhead;
372 *libraryptr = library;
376 #endif /* DO_DLOPEN */
379 /* gets the list of mechanisms */
380 int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
381 const sasl_callback_t *getpath_cb,
382 const sasl_callback_t *verifyfile_cb)
385 const add_plugin_list_t *cur_ep;
387 char str[PATH_MAX], tmp[PATH_MAX+2], prefix[PATH_MAX+2];
388 /* 1 for '/' 1 for trailing '\0' */
391 const char *path=NULL;
397 add_plugin_t *add_plugin;
398 _sasl_plug_type type;
404 || getpath_cb->id != SASL_CB_GETPATH
405 || ! getpath_cb->proc
407 || verifyfile_cb->id != SASL_CB_VERIFYFILE
408 || ! verifyfile_cb->proc)
409 return SASL_BADPARAM;
412 /* do all the static plugins first */
414 for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
416 /* What type of plugin are we looking for? */
417 if(!strcmp(cur_ep->entryname, "sasl_server_plug_init")) {
419 add_plugin = (add_plugin_t *)sasl_server_add_plugin;
420 } else if (!strcmp(cur_ep->entryname, "sasl_client_plug_init")) {
422 add_plugin = (add_plugin_t *)sasl_client_add_plugin;
423 } else if (!strcmp(cur_ep->entryname, "sasl_auxprop_plug_init")) {
425 add_plugin = (add_plugin_t *)sasl_auxprop_add_plugin;
426 } else if (!strcmp(cur_ep->entryname, "sasl_canonuser_init")) {
428 add_plugin = (add_plugin_t *)sasl_canonuser_add_plugin;
430 /* What are we looking for then? */
433 for (p=_sasl_static_plugins; p->type; p++) {
435 result = add_plugin(p->name, p->plug);
440 /* only do the following if:
442 * we support dlopen()
443 * AND we are not staticly compiled
444 * OR we are staticly compiled and TRY_DLOPEN_WHEN_STATIC is defined
446 #if defined(DO_DLOPEN) && (defined(PIC) || (!defined(PIC) && defined(TRY_DLOPEN_WHEN_STATIC)))
447 /* get the path to the plugins */
448 result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context,
450 if (result != SASL_OK) return result;
451 if (! path) return SASL_FAIL;
453 if (strlen(path) >= PATH_MAX) { /* no you can't buffer overrun */
465 } while ((c!=':') && (c!='=') && (c!=0));
471 if ((dp=opendir(str)) !=NULL) /* ignore errors */
473 while ((dir=readdir(dp)) != NULL)
478 char plugname[PATH_MAX];
481 length = NAMLEN(dir);
483 continue; /* can not possibly be what we're looking for */
485 if (length + pos>=PATH_MAX) continue; /* too big */
487 if (strcmp(dir->d_name + (length - strlen(SO_SUFFIX)),
489 && strcmp(dir->d_name + (length - strlen(LA_SUFFIX)),
493 memcpy(name,dir->d_name,length);
496 result = _parse_la(prefix, name, tmp);
497 if(result != SASL_OK)
500 /* skip "lib" and cut off suffix --
501 this only need be approximate */
502 strcpy(plugname, name + 3);
503 c = strchr(plugname, (int)'.');
506 result = _sasl_get_plugin(tmp, verifyfile_cb, &library);
508 if(result != SASL_OK)
511 for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
512 _sasl_plugin_load(plugname, library, cur_ep->entryname,
514 /* If this fails, it's not the end of the world */
520 _sasl_log(NULL, SASL_LOG_DEBUG,
521 "looking for plugins in '%s', failed to open directory, error: %s",
526 } while ((c!='=') && (c!=0));
527 #endif /* defined(DO_DLOPEN) && (!defined(PIC) || (defined(PIC) && defined(TRY_DLOPEN_WHEN_STATIC))) */
533 _sasl_done_with_plugins(void)
536 lib_list_t *libptr, *libptr_next;
538 for(libptr = lib_list_head; libptr; libptr = libptr_next) {
539 libptr_next = libptr->next;
541 dlclose(libptr->library);
545 lib_list_head = NULL;
546 #endif /* DO_DLOPEN */