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
107typedef shl_t dll_handle;
108typedef void * dll_func;
109
110dll_handle
111dlopen(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
128int
129dlclose(dll_handle h)
130{
131    shl_t hp = *((shl_t *)h);
132    if (hp != NULL) free(hp);
133    return shl_unload(h);
134}
135
136dll_func
137dlsym(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
147char *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_ */
164typedef struct lib_list
165{
166    struct lib_list *next;
167    void *library;
168} lib_list_t;
169
170#ifndef _SUN_SDK_
171static lib_list_t *lib_list_head = NULL;
172#endif /* !_SUN_SDK_ */
173
174DEFINE_STATIC_MUTEX(global_mutex);
175
176#endif /* DO_DLOPEN || WIN_PLUG */ /* _SUN_SDK_ */
177
178int _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_
238static 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
244static 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
285static 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_
382int _sasl_get_plugin(_sasl_global_context_t *gctx,
383		     const char *file,
384		     const sasl_callback_t *verifyfile_cb,
385		     void **libraryptr)
386#else
387int _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
454static 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_
489int _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
495int _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_
751int
752_sasl_done_with_plugins(_sasl_global_context_t *gctx)
753#else
754int
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
796static HANDLE global_mutex = NULL;
797
798int 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
823int win_global_mutex_unlock()
824{
825    if (global_mutex == NULL)
826	return (-1);
827
828    return (ReleaseMutex(global_mutex) ? 0 : -1);
829}
830
831BOOL 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