Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      6 
      7 /* dlopen.c--Unix dlopen() dynamic loader interface
      8  * Rob Siemborski
      9  * Rob Earhart
     10  * $Id: dlopen.c,v 1.45 2003/07/14 20:08:50 rbraun Exp $
     11  */
     12 /*
     13  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
     14  *
     15  * Redistribution and use in source and binary forms, with or without
     16  * modification, are permitted provided that the following conditions
     17  * are met:
     18  *
     19  * 1. Redistributions of source code must retain the above copyright
     20  *    notice, this list of conditions and the following disclaimer.
     21  *
     22  * 2. Redistributions in binary form must reproduce the above copyright
     23  *    notice, this list of conditions and the following disclaimer in
     24  *    the documentation and/or other materials provided with the
     25  *    distribution.
     26  *
     27  * 3. The name "Carnegie Mellon University" must not be used to
     28  *    endorse or promote products derived from this software without
     29  *    prior written permission. For permission or any other legal
     30  *    details, please contact
     31  *      Office of Technology Transfer
     32  *      Carnegie Mellon University
     33  *      5000 Forbes Avenue
     34  *      Pittsburgh, PA  15213-3890
     35  *      (412) 268-4387, fax: (412) 268-7395
     36  *      tech-transfer (at) andrew.cmu.edu
     37  *
     38  * 4. Redistributions of any form whatsoever must retain the following
     39  *    acknowledgment:
     40  *    "This product includes software developed by Computing Services
     41  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
     42  *
     43  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
     44  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     45  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
     46  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     47  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     48  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     49  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     50  */
     51 
     52 #include <config.h>
     53 #ifdef HAVE_DLFCN_H
     54 #include <dlfcn.h>
     55 #endif
     56 
     57 #include <stdlib.h>
     58 #include <errno.h>
     59 #include <stdio.h>
     60 #include <limits.h>
     61 
     62 #include <sasl.h>
     63 #include "saslint.h"
     64 
     65 #ifndef PIC
     66 #include <saslplug.h>
     67 #include "staticopen.h"
     68 #endif
     69 
     70 #ifdef _SUN_SDK_
     71 #include <sys/stat.h>
     72 #endif /* _SUN_SDK_ */
     73 
     74 #ifdef DO_DLOPEN
     75 #if HAVE_DIRENT_H
     76 # include <dirent.h>
     77 # define NAMLEN(dirent) strlen((dirent)->d_name)
     78 #else /* HAVE_DIRENT_H */
     79 # define dirent direct
     80 # define NAMLEN(dirent) (dirent)->d_namlen
     81 # if HAVE_SYS_NDIR_H
     82 #  include <sys/ndir.h>
     83 # endif
     84 # if HAVE_SYS_DIR_H
     85 #  include <sys/dir.h>
     86 # endif
     87 # if HAVE_NDIR_H
     88 #  include <ndir.h>
     89 # endif
     90 #endif /* ! HAVE_DIRENT_H */
     91 
     92 #ifndef NAME_MAX
     93 # ifdef _POSIX_NAME_MAX
     94 #  define NAME_MAX _POSIX_NAME_MAX
     95 # else
     96 #  define NAME_MAX 16
     97 # endif
     98 #endif
     99 
    100 #if NAME_MAX < 8
    101 #  define NAME_MAX 8
    102 #endif
    103 
    104 #ifdef __hpux
    105 #include <dl.h>
    106 
    107 typedef shl_t dll_handle;
    108 typedef void * dll_func;
    109 
    110 dll_handle
    111 dlopen(char *fname, int mode)
    112 {
    113     shl_t h = shl_load(fname, BIND_DEFERRED, 0L);
    114     shl_t *hp = NULL;
    115 
    116     if (h) {
    117 	hp = (shl_t *)malloc(sizeof (shl_t));
    118 	if (!hp) {
    119 	    shl_unload(h);
    120 	} else {
    121 	    *hp = h;
    122 	}
    123     }
    124 
    125     return (dll_handle)hp;
    126 }
    127 
    128 int
    129 dlclose(dll_handle h)
    130 {
    131     shl_t hp = *((shl_t *)h);
    132     if (hp != NULL) free(hp);
    133     return shl_unload(h);
    134 }
    135 
    136 dll_func
    137 dlsym(dll_handle h, char *n)
    138 {
    139     dll_func handle;
    140 
    141     if (shl_findsym ((shl_t *)h, n, TYPE_PROCEDURE, &handle))
    142 	return NULL;
    143 
    144     return (dll_func)handle;
    145 }
    146 
    147 char *dlerror()
    148 {
    149     if (errno != 0) {
    150 	return strerror(errno);
    151     }
    152     return "Generic shared library error";
    153 }
    154 
    155 #define SO_SUFFIX	".sl"
    156 #else /* __hpux */
    157 #define SO_SUFFIX	".so"
    158 #endif /* __hpux */
    159 
    160 #define LA_SUFFIX       ".la"
    161 #endif /* DO_DLOPEN */
    162 
    163 #if defined DO_DLOPEN || defined WIN_PLUG /* _SUN_SDK_ */
    164 typedef struct lib_list
    165 {
    166     struct lib_list *next;
    167     void *library;
    168 } lib_list_t;
    169 
    170 #ifndef _SUN_SDK_
    171 static lib_list_t *lib_list_head = NULL;
    172 #endif /* !_SUN_SDK_ */
    173 
    174 DEFINE_STATIC_MUTEX(global_mutex);
    175 
    176 #endif /* DO_DLOPEN || WIN_PLUG */ /* _SUN_SDK_ */
    177 
    178 int _sasl_locate_entry(void *library, const char *entryname,
    179 		       void **entry_point)
    180 {
    181 #ifdef DO_DLOPEN
    182 /* note that we still check for known problem systems in
    183  * case we are cross-compiling */
    184 #if defined(DLSYM_NEEDS_UNDERSCORE) || defined(__OpenBSD__)
    185     char adj_entryname[1024];
    186 #else
    187 #define adj_entryname entryname
    188 #endif
    189 
    190     if(!entryname) {
    191 #ifndef _SUN_SDK_
    192 	_sasl_log(NULL, SASL_LOG_ERR,
    193 		  "no entryname in _sasl_locate_entry");
    194 #endif /* _SUN_SDK_ */
    195 	return SASL_BADPARAM;
    196     }
    197 
    198     if(!library) {
    199 #ifndef _SUN_SDK_
    200 	_sasl_log(NULL, SASL_LOG_ERR,
    201 		  "no library in _sasl_locate_entry");
    202 #endif /* _SUN_SDK_ */
    203 	return SASL_BADPARAM;
    204     }
    205 
    206     if(!entry_point) {
    207 #ifndef _SUN_SDK_
    208 	_sasl_log(NULL, SASL_LOG_ERR,
    209 		  "no entrypoint output pointer in _sasl_locate_entry");
    210 #endif /* _SUN_SDK_ */
    211 	return SASL_BADPARAM;
    212     }
    213 
    214 #if defined(DLSYM_NEEDS_UNDERSCORE) || defined(__OpenBSD__)
    215     snprintf(adj_entryname, sizeof adj_entryname, "_%s", entryname);
    216 #endif
    217 
    218     *entry_point = NULL;
    219     *entry_point = dlsym(library, adj_entryname);
    220     if (*entry_point == NULL) {
    221 #if 0 /* This message appears to confuse people */
    222 	_sasl_log(NULL, SASL_LOG_DEBUG,
    223 		  "unable to get entry point %s: %s", adj_entryname,
    224 		  dlerror());
    225 #endif
    226 	return SASL_FAIL;
    227     }
    228 
    229     return SASL_OK;
    230 #else
    231     return SASL_FAIL;
    232 #endif /* DO_DLOPEN */
    233 }
    234 
    235 #ifdef DO_DLOPEN
    236 
    237 #ifdef _SUN_SDK_
    238 static int _sasl_plugin_load(_sasl_global_context_t *gctx,
    239 			     char *plugin, void *library,
    240 			     const char *entryname,
    241 			     int (*add_plugin)(_sasl_global_context_t *gctx,
    242 					       const char *, void *))
    243 #else
    244 static int _sasl_plugin_load(char *plugin, void *library,
    245 			     const char *entryname,
    246 			     int (*add_plugin)(const char *, void *))
    247 #endif /* _SUN_SDK_ */
    248 {
    249     void *entry_point;
    250     int result;
    251 
    252     result = _sasl_locate_entry(library, entryname, &entry_point);
    253     if(result == SASL_OK) {
    254 #ifdef _SUN_SDK_
    255 	result = add_plugin(gctx, plugin, entry_point);
    256 #else
    257 	result = add_plugin(plugin, entry_point);
    258 #endif /* _SUN_SDK_ */
    259 	if(result != SASL_OK)
    260 #ifdef _SUN_SDK_
    261 	    __sasl_log(gctx, gctx->server_global_callbacks.callbacks == NULL ?
    262 	    	       gctx->client_global_callbacks.callbacks :
    263 	    	       gctx->server_global_callbacks.callbacks,
    264 	    	       SASL_LOG_DEBUG,
    265 		       "_sasl_plugin_load failed on %s for plugin: %s\n",
    266 		       entryname, plugin);
    267 #else
    268 	    _sasl_log(NULL, SASL_LOG_DEBUG,
    269 		      "_sasl_plugin_load failed on %s for plugin: %s\n",
    270 		      entryname, plugin);
    271 #endif /* _SUN_SDK_ */
    272     }
    273 
    274     return result;
    275 }
    276 
    277 #ifndef _SUN_SDK_
    278 /* this returns the file to actually open.
    279  *  out should be a buffer of size PATH_MAX
    280  *  and may be the same as in. */
    281 
    282 /* We'll use a static buffer for speed unless someone complains */
    283 #define MAX_LINE 2048
    284 
    285 static int _parse_la(const char *prefix, const char *in, char *out)
    286 {
    287     FILE *file;
    288     size_t length;
    289     char line[MAX_LINE];
    290     char *ntmp = NULL;
    291 
    292     if(!in || !out || !prefix || out == in) return SASL_BADPARAM;
    293 
    294     /* Set this so we can detect failure */
    295     *out = '\0';
    296 
    297     length = strlen(in);
    298 
    299     if (strcmp(in + (length - strlen(LA_SUFFIX)), LA_SUFFIX)) {
    300 	if(!strcmp(in + (length - strlen(SO_SUFFIX)),SO_SUFFIX)) {
    301 	    /* check for a .la file */
    302 	    strcpy(line, prefix);
    303 	    strcat(line, in);
    304 	    length = strlen(line);
    305 	    *(line + (length - strlen(SO_SUFFIX))) = '\0';
    306 	    strcat(line, LA_SUFFIX);
    307 	    file = fopen(line, "rF");
    308 	    if(file) {
    309 		/* We'll get it on the .la open */
    310 		fclose(file);
    311 		return SASL_FAIL;
    312 	    }
    313 	}
    314 	strcpy(out, prefix);
    315 	strcat(out, in);
    316 	return SASL_OK;
    317     }
    318 
    319     strcpy(line, prefix);
    320     strcat(line, in);
    321 
    322     file = fopen(line, "rF");
    323     if(!file) {
    324 	_sasl_log(NULL, SASL_LOG_WARN,
    325 		  "unable to open LA file: %s", line);
    326 	return SASL_FAIL;
    327     }
    328 
    329     while(!feof(file)) {
    330 	if(!fgets(line, MAX_LINE, file)) break;
    331 	if(line[strlen(line) - 1] != '\n') {
    332 	    _sasl_log(NULL, SASL_LOG_WARN,
    333 		      "LA file has too long of a line: %s", in);
    334 	    return SASL_BUFOVER;
    335 	}
    336 	if(line[0] == '\n' || line[0] == '#') continue;
    337 	if(!strncmp(line, "dlname=", sizeof("dlname=") - 1)) {
    338 	    /* We found the line with the name in it */
    339 	    char *end;
    340 	    char *start;
    341 	    size_t len;
    342 	    end = strrchr(line, '\'');
    343 	    if(!end) continue;
    344 	    start = &line[sizeof("dlname=")-1];
    345 	    len = strlen(start);
    346 	    if(len > 3 && start[0] == '\'') {
    347 		ntmp=&start[1];
    348 		*end='\0';
    349 		/* Do we have dlname="" ? */
    350 		if(ntmp == end) {
    351 		    _sasl_log(NULL, SASL_LOG_DEBUG,
    352 			      "dlname is empty in .la file: %s", in);
    353 		    return SASL_FAIL;
    354 		}
    355 		strcpy(out, prefix);
    356 		strcat(out, ntmp);
    357 	    }
    358 	    break;
    359 	}
    360     }
    361     if(ferror(file) || feof(file)) {
    362 	_sasl_log(NULL, SASL_LOG_WARN,
    363 		  "Error reading .la: %s\n", in);
    364 	fclose(file);
    365 	return SASL_FAIL;
    366     }
    367     fclose(file);
    368 
    369     if(!(*out)) {
    370 	_sasl_log(NULL, SASL_LOG_WARN,
    371 		  "Could not find a dlname line in .la file: %s", in);
    372 	return SASL_FAIL;
    373     }
    374 
    375     return SASL_OK;
    376 }
    377 #endif /* !_SUN_SDK_ */
    378 #endif /* DO_DLOPEN */
    379 
    380 /* loads a plugin library */
    381 #ifdef _SUN_SDK_
    382 int _sasl_get_plugin(_sasl_global_context_t *gctx,
    383 		     const char *file,
    384 		     const sasl_callback_t *verifyfile_cb,
    385 		     void **libraryptr)
    386 #else
    387 int _sasl_get_plugin(const char *file,
    388 		     const sasl_callback_t *verifyfile_cb,
    389 		     void **libraryptr)
    390 #endif /* _SUN_SDK_ */
    391 {
    392 #ifdef DO_DLOPEN
    393     int r = 0;
    394     int flag;
    395     void *library;
    396     lib_list_t *newhead;
    397 
    398     r = ((sasl_verifyfile_t *)(verifyfile_cb->proc))
    399 		    (verifyfile_cb->context, file, SASL_VRFY_PLUGIN);
    400     if (r != SASL_OK) return r;
    401 
    402 #ifdef RTLD_NOW
    403     flag = RTLD_NOW;
    404 #else
    405     flag = 0;
    406 #endif
    407 
    408     newhead = sasl_ALLOC(sizeof(lib_list_t));
    409     if(!newhead) return SASL_NOMEM;
    410 
    411     if (!(library = dlopen(file, flag))) {
    412 #ifdef _SUN_SDK_
    413 	__sasl_log(gctx, gctx->server_global_callbacks.callbacks == NULL ?
    414 	    	   gctx->client_global_callbacks.callbacks :
    415 	    	   gctx->server_global_callbacks.callbacks,
    416 		   SASL_LOG_ERR,
    417 		   "unable to dlopen %s: %s", file, dlerror());
    418 #else
    419 	_sasl_log(NULL, SASL_LOG_ERR,
    420 		  "unable to dlopen %s: %s", file, dlerror());
    421 #endif /* _SUN_SDK_ */
    422 	sasl_FREE(newhead);
    423 	return SASL_FAIL;
    424     }
    425 
    426 #ifdef _SUN_SDK_
    427     if (LOCK_MUTEX(&global_mutex) < 0) {
    428 	sasl_FREE(newhead);
    429 	dlclose(library);
    430 	return (SASL_FAIL);
    431     }
    432 #endif /* _SUN_SDK_ */
    433 
    434     newhead->library = library;
    435 #ifdef _SUN_SDK_
    436     newhead->next = gctx->lib_list_head;
    437     gctx->lib_list_head = newhead;
    438     UNLOCK_MUTEX(&global_mutex);
    439 #else
    440     newhead->next = lib_list_head;
    441     lib_list_head = newhead;
    442 #endif /* _SUN_SDK_ */
    443 
    444     *libraryptr = library;
    445     return SASL_OK;
    446 #else
    447     return SASL_FAIL;
    448 #endif /* DO_DLOPEN */
    449 }
    450 
    451 #ifdef _SUN_SDK_
    452 #if defined DO_DLOPEN || defined WIN_PLUG /* _SUN_SDK_ */
    453 
    454 static void release_plugin(_sasl_global_context_t *gctx, void *library)
    455 {
    456     lib_list_t *libptr, *libptr_next = NULL, *libptr_prev = NULL;
    457     int r;
    458 
    459     r = LOCK_MUTEX(&global_mutex);
    460     if (r < 0)
    461 	return;
    462 
    463     for(libptr = gctx->lib_list_head; libptr; libptr = libptr_next) {
    464 	libptr_next = libptr->next;
    465 	if (library == libptr->library) {
    466 	    if(libptr->library)
    467 #if defined DO_DLOPEN /* _SUN_SDK_ */
    468 		dlclose(libptr->library);
    469 #else
    470 		FreeLibrary(libptr->library);
    471 #endif /* DO_DLOPEN */ /* _SUN_SDK_ */
    472 	    sasl_FREE(libptr);
    473 	    break;
    474 	}
    475 	libptr_prev = libptr;
    476     }
    477     if (libptr_prev == NULL)
    478 	gctx->lib_list_head = libptr_next;
    479     else
    480 	libptr_prev->next = libptr_next;
    481 
    482     UNLOCK_MUTEX(&global_mutex);
    483 }
    484 #endif /* DO_DLOPEN || WIN_PLUG */ /* _SUN_SDK_ */
    485 #endif /* _SUN_SDK_ */
    486 
    487 /* gets the list of mechanisms */
    488 #ifdef _SUN_SDK_
    489 int _sasl_load_plugins(_sasl_global_context_t *gctx,
    490 		       int server,
    491 		       const add_plugin_list_t *entrypoints,
    492 		       const sasl_callback_t *getpath_cb,
    493 		       const sasl_callback_t *verifyfile_cb)
    494 #else
    495 int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
    496 		       const sasl_callback_t *getpath_cb,
    497 		       const sasl_callback_t *verifyfile_cb)
    498 #endif /* _SUN_SDK_ */
    499 {
    500     int result;
    501     const add_plugin_list_t *cur_ep;
    502 #ifdef _SUN_SDK_
    503     _sasl_path_info_t *path_info, *p_info;
    504 #endif /* _SUN_SDK_ */
    505 #ifdef DO_DLOPEN
    506     char str[PATH_MAX], tmp[PATH_MAX+2], prefix[PATH_MAX+2];
    507 				/* 1 for '/' 1 for trailing '\0' */
    508     char c;
    509     int pos;
    510     const char *path=NULL;
    511     int position;
    512     DIR *dp;
    513     struct dirent *dir;
    514 #ifdef _SUN_SDK_
    515     int plugin_loaded;
    516     struct stat b;
    517 #endif /* _SUN_SDK_ */
    518 #endif
    519 #ifndef PIC
    520     add_plugin_t *add_plugin;
    521     _sasl_plug_type type;
    522     _sasl_plug_rec *p;
    523 #endif
    524 
    525     if (! entrypoints
    526 	|| ! getpath_cb
    527 	|| getpath_cb->id != SASL_CB_GETPATH
    528 	|| ! getpath_cb->proc
    529 	|| ! verifyfile_cb
    530 	|| verifyfile_cb->id != SASL_CB_VERIFYFILE
    531 	|| ! verifyfile_cb->proc)
    532 	return SASL_BADPARAM;
    533 
    534 #ifndef PIC
    535     /* do all the static plugins first */
    536 
    537     for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
    538 
    539 	/* What type of plugin are we looking for? */
    540 	if(!strcmp(cur_ep->entryname, "sasl_server_plug_init")) {
    541 	    type = SERVER;
    542 #ifdef _SUN_SDK_
    543 	    add_plugin = (add_plugin_t *)_sasl_server_add_plugin;
    544 #else
    545 	    add_plugin = (add_plugin_t *)sasl_server_add_plugin;
    546 #endif /* _SUN_SDK_ */
    547 	} else if (!strcmp(cur_ep->entryname, "sasl_client_plug_init")) {
    548 	    type = CLIENT;
    549 #ifdef _SUN_SDK_
    550 	    add_plugin = (add_plugin_t *)_sasl_client_add_plugin;
    551 #else
    552 	    add_plugin = (add_plugin_t *)sasl_client_add_plugin;
    553 #endif /* _SUN_SDK_ */
    554 	} else if (!strcmp(cur_ep->entryname, "sasl_auxprop_plug_init")) {
    555 	    type = AUXPROP;
    556 #ifdef _SUN_SDK_
    557 	    add_plugin = (add_plugin_t *)_sasl_auxprop_add_plugin;
    558 #else
    559 	    add_plugin = (add_plugin_t *)sasl_auxprop_add_plugin;
    560 #endif /* _SUN_SDK_ */
    561 	} else if (!strcmp(cur_ep->entryname, "sasl_canonuser_init")) {
    562 	    type = CANONUSER;
    563 #ifdef _SUN_SDK_
    564 	    add_plugin = (add_plugin_t *)_sasl_canonuser_add_plugin;
    565 #else
    566 	    add_plugin = (add_plugin_t *)sasl_canonuser_add_plugin;
    567 #endif /* _SUN_SDK_ */
    568 	} else {
    569 	    /* What are we looking for then? */
    570 	    return SASL_FAIL;
    571 	}
    572 	for (p=_sasl_static_plugins; p->type; p++) {
    573 	    if(type == p->type)
    574 #ifdef _SUN_SDK_
    575 	    	result = add_plugin(gctx, p->name, (void *)p->plug);
    576 #else
    577 	    	result = add_plugin(p->name, p->plug);
    578 #endif /* _SUN_SDK_ */
    579 	}
    580     }
    581 #endif /* !PIC */
    582 
    583 /* only do the following if:
    584  *
    585  * we support dlopen()
    586  *  AND we are not staticly compiled
    587  *      OR we are staticly compiled and TRY_DLOPEN_WHEN_STATIC is defined
    588  */
    589 #if defined(DO_DLOPEN) && (defined(PIC) || (!defined(PIC) && defined(TRY_DLOPEN_WHEN_STATIC)))
    590     /* get the path to the plugins */
    591     result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context,
    592 						    &path);
    593     if (result != SASL_OK) return result;
    594     if (! path) return SASL_FAIL;
    595 
    596     if (strlen(path) >= PATH_MAX) { /* no you can't buffer overrun */
    597 	return SASL_FAIL;
    598     }
    599 
    600     position=0;
    601     do {
    602 	pos=0;
    603 	do {
    604 	    c=path[position];
    605 	    position++;
    606 	    str[pos]=c;
    607 	    pos++;
    608 	} while ((c!=':') && (c!='=') && (c!=0));
    609 	str[pos-1]='\0';
    610 
    611 	strcpy(prefix,str);
    612 	strcat(prefix,"/");
    613 #ifdef _SUN_SDK_
    614 	path_info = server ? gctx->splug_path_info : gctx->cplug_path_info;
    615 	while (path_info != NULL) {
    616 	    if (strcmp(path_info->path, prefix) == 0)
    617 		break;
    618 	    path_info = path_info->next;
    619 	}
    620 	if (stat(prefix, &b) != 0) {
    621 	    continue;
    622 	}
    623 	if ( path_info == NULL) {
    624 	    p_info = (_sasl_path_info_t *)
    625 		sasl_ALLOC(sizeof (_sasl_path_info_t));
    626 	    if (p_info == NULL) {
    627 		return SASL_NOMEM;
    628 	    }
    629 	    if(_sasl_strdup(prefix, &p_info->path, NULL) != SASL_OK) {
    630 		sasl_FREE(p_info);
    631 		return SASL_NOMEM;
    632 	    }
    633 	    p_info->last_changed = b.st_mtime;
    634 	    if (server) {
    635 		p_info->next = gctx->splug_path_info;
    636 		gctx->splug_path_info = p_info;
    637 	    } else {
    638 		p_info->next = gctx->cplug_path_info;
    639 		gctx->cplug_path_info = p_info;
    640 	    }
    641 	} else {
    642 	    if (b.st_mtime <= path_info->last_changed) {
    643 		continue;
    644 	    }
    645 	}
    646 #endif /* _SUN_SDK_ */
    647 
    648 	if ((dp=opendir(str)) !=NULL) /* ignore errors */
    649 	{
    650 	    while ((dir=readdir(dp)) != NULL)
    651 	    {
    652 		size_t length;
    653 		void *library;
    654 #ifndef _SUN_SDK_
    655 		char *c;
    656 #endif /* !_SUN_SDK_ */
    657 		char plugname[PATH_MAX];
    658 		char name[PATH_MAX];
    659 
    660 		length = NAMLEN(dir);
    661 #ifndef _SUN_SDK_
    662 		if (length < 4)
    663 		    continue; /* can not possibly be what we're looking for */
    664 #endif /* !_SUN_SDK_ */
    665 
    666 		if (length + pos>=PATH_MAX) continue; /* too big */
    667 
    668 #ifdef _SUN_SDK_
    669 		if (dir->d_name[0] == '.')
    670 		    continue;
    671 #else
    672 		if (strcmp(dir->d_name + (length - strlen(SO_SUFFIX)),
    673 			   SO_SUFFIX)
    674 		    && strcmp(dir->d_name + (length - strlen(LA_SUFFIX)),
    675 			   LA_SUFFIX))
    676 		    continue;
    677 #endif /* _SUN_SDK_ */
    678 
    679 		memcpy(name,dir->d_name,length);
    680 		name[length]='\0';
    681 
    682 #ifdef _SUN_SDK_
    683 		snprintf(tmp, sizeof (tmp), "%s%s", prefix, name);
    684 #else
    685 		result = _parse_la(prefix, name, tmp);
    686 		if(result != SASL_OK)
    687 		    continue;
    688 #endif /* _SUN_SDK_ */
    689 
    690 #ifdef _SUN_SDK_
    691 		if (stat(tmp, &b))
    692 			continue;	/* Can't stat it */
    693 		if (!S_ISREG(b.st_mode))
    694 			continue;
    695 		/* Sun plugins don't have lib prefix */
    696 		strcpy(plugname, name);
    697 #else
    698 		/* skip "lib" and cut off suffix --
    699 		   this only need be approximate */
    700 		strcpy(plugname, name + 3);
    701 		c = strchr(plugname, (int)'.');
    702 		if(c) *c = '\0';
    703 #endif /* _SUN_SDK_ */
    704 
    705 #ifdef _SUN_SDK_
    706 		result = _sasl_get_plugin(gctx, tmp, verifyfile_cb,
    707                         &library);
    708 #else
    709 		result = _sasl_get_plugin(tmp, verifyfile_cb, &library);
    710 #endif /* _SUN_SDK_ */
    711 
    712 		if(result != SASL_OK)
    713 		    continue;
    714 
    715 #ifdef _SUN_SDK_
    716 		plugin_loaded = 0;
    717 		for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
    718 			/* If this fails, it's not the end of the world */
    719 			if (_sasl_plugin_load(gctx, plugname, library,
    720 					cur_ep->entryname,
    721 					cur_ep->add_plugin) == SASL_OK) {
    722 			    plugin_loaded = 1;
    723 			}
    724 		}
    725 		if (!plugin_loaded)
    726 			release_plugin(gctx, library);
    727 #else
    728 		for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
    729 			_sasl_plugin_load(plugname, library, cur_ep->entryname,
    730 					  cur_ep->add_plugin);
    731 			/* If this fails, it's not the end of the world */
    732 		}
    733 #endif /* _SUN_SDK_ */
    734 	    }
    735 
    736 	    closedir(dp);
    737 	}
    738 
    739     } while ((c!='=') && (c!=0));
    740 #elif defined _SUN_SDK_ && defined WIN_PLUG
    741     result =
    742 	_sasl_load_win_plugins(gctx, entrypoints, getpath_cb, verifyfile_cb);
    743     if (result != SASL_OK)
    744 	return (result);
    745 #endif /* defined(DO_DLOPEN) && (!defined(PIC) || (defined(PIC) && defined(TRY_DLOPEN_WHEN_STATIC))) */
    746 
    747     return SASL_OK;
    748 }
    749 
    750 #ifdef _SUN_SDK_
    751 int
    752 _sasl_done_with_plugins(_sasl_global_context_t *gctx)
    753 #else
    754 int
    755 _sasl_done_with_plugins(void)
    756 #endif /* _SUN_SDK_ */
    757 {
    758 #if defined DO_DLOPEN || defined WIN_PLUG /* _SUN_SDK_ */
    759     lib_list_t *libptr, *libptr_next;
    760 
    761 #ifdef _SUN_SDK_
    762     if (LOCK_MUTEX(&global_mutex) < 0)
    763 	return (SASL_FAIL);
    764 #endif /* _SUN_SDK_ */
    765 
    766 #ifdef _SUN_SDK_
    767     for(libptr = gctx->lib_list_head; libptr; libptr = libptr_next) {
    768 #else
    769     for(libptr = lib_list_head; libptr; libptr = libptr_next) {
    770 #endif /* _SUN_SDK_ */
    771 	libptr_next = libptr->next;
    772 	if(libptr->library)
    773 #ifdef DO_DLOPEN /* _SUN_SDK_ */
    774 	    dlclose(libptr->library);
    775 #else
    776 	    FreeLibrary(libptr->library);
    777 #endif /* DO_DLOPEN */ /* _SUN_SDK_ */
    778 	sasl_FREE(libptr);
    779     }
    780 
    781 #ifdef _SUN_SDK_
    782     gctx->lib_list_head = NULL;
    783 #else
    784     lib_list_head = NULL;
    785 #endif /* _SUN_SDK_ */
    786 
    787 #ifdef _SUN_SDK_
    788     UNLOCK_MUTEX(&global_mutex);
    789 #endif /* _SUN_SDK_ */
    790 #endif /* DO_DLOPEN || WIN_PLUG */ /* _SUN_SDK_ */
    791     return SASL_OK;
    792 }
    793 
    794 #ifdef WIN_MUTEX
    795 
    796 static HANDLE global_mutex = NULL;
    797 
    798 int win_global_mutex_lock()
    799 {
    800     DWORD dwWaitResult;
    801 
    802     if (global_mutex == NULL) {
    803 	global_mutex = CreateMutex(NULL, FALSE, NULL);
    804 	if (global_mutex == NULL)
    805 	    return (-1);
    806     }
    807 
    808     dwWaitResult = WaitForSingleObject(global_mutex, INFINITE);
    809 
    810     switch (dwWaitResult) {
    811 	case WAIT_OBJECT_0:
    812 		return (0);
    813 
    814            case WAIT_TIMEOUT:
    815                return (-1); /* Shouldn't happen */
    816 
    817            case WAIT_ABANDONED:
    818                return (-1); /* Shouldn't happen */
    819     }
    820     return (-1); /* Unexpected result */
    821 }
    822 
    823 int win_global_mutex_unlock()
    824 {
    825     if (global_mutex == NULL)
    826 	return (-1);
    827 
    828     return (ReleaseMutex(global_mutex) ? 0 : -1);
    829 }
    830 
    831 BOOL APIENTRY DllMain(HANDLE hModule,
    832                          DWORD  ul_reason_for_call,
    833                          LPVOID lpReserved)
    834 {
    835     switch( ul_reason_for_call ) {
    836 	case DLL_PROCESS_ATTACH:
    837 	    global_mutex = CreateMutex(NULL, FALSE, NULL);
    838 	    if (global_mutex == NULL)
    839 		return (FALSE);
    840 	    break;
    841 	case DLL_THREAD_ATTACH:
    842 	case DLL_THREAD_DETACH:
    843 	case DLL_PROCESS_DETACH:
    844 	    break;
    845     }
    846     return TRUE;
    847 }
    848 #endif
    849