xref: /illumos-gate/usr/src/lib/libsasl/lib/dlopen.c (revision 004388ebfdfe2ed7dfd2d153a876dfcc22d2c006)
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@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