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