1/* windlopen.c--Windows dynamic loader interface
2 * Ryan Troll
3 * $Id: windlopen.c,v 1.3 2004/07/07 22:48:35 snsimon Exp $
4 */
5/*
6 * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in
17 *    the documentation and/or other materials provided with the
18 *    distribution.
19 *
20 * 3. The name "Carnegie Mellon University" must not be used to
21 *    endorse or promote products derived from this software without
22 *    prior written permission. For permission or any other legal
23 *    details, please contact
24 *      Office of Technology Transfer
25 *      Carnegie Mellon University
26 *      5000 Forbes Avenue
27 *      Pittsburgh, PA  15213-3890
28 *      (412) 268-4387, fax: (412) 268-7395
29 *      tech-transfer@andrew.cmu.edu
30 *
31 * 4. Redistributions of any form whatsoever must retain the following
32 *    acknowledgment:
33 *    "This product includes software developed by Computing Services
34 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
35 *
36 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
37 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
38 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
39 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
41 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
42 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43 */
44
45#include <stdio.h>
46#include <io.h>
47#include <sys/stat.h>
48
49#include <config.h>
50#include <sasl.h>
51#include "saslint.h"
52
53#define DLL_SUFFIX	".dll"
54#define DLL_MASK	"*" DLL_SUFFIX
55#define DLL_MASK_LEN	5
56
57const int _is_sasl_server_static = 0;
58
59/* : inefficient representation, but works */
60typedef struct lib_list
61{
62    struct lib_list *next;
63    HMODULE library;
64} lib_list_t;
65
66static lib_list_t *lib_list_head = NULL;
67
68int _sasl_locate_entry(void *library,
69		       const char *entryname,
70		       void **entry_point)
71{
72    if(entryname == NULL) {
73	_sasl_log(NULL, SASL_LOG_ERR,
74		  "no entryname in _sasl_locate_entry");
75	return SASL_BADPARAM;
76    }
77
78    if(library == NULL) {
79	_sasl_log(NULL, SASL_LOG_ERR,
80		  "no library in _sasl_locate_entry");
81	return SASL_BADPARAM;
82    }
83
84    if(entry_point == NULL) {
85	_sasl_log(NULL, SASL_LOG_ERR,
86		  "no entrypoint output pointer in _sasl_locate_entry");
87	return SASL_BADPARAM;
88    }
89
90    *entry_point = GetProcAddress(library, entryname);
91
92    if (*entry_point == NULL) {
93#if 0 /* This message appears to confuse people */
94	_sasl_log(NULL, SASL_LOG_DEBUG,
95		  "unable to get entry point %s: %s", entryname,
96		  GetLastError());
97#endif
98	return SASL_FAIL;
99    }
100
101    return SASL_OK;
102}
103
104static int _sasl_plugin_load(char *plugin, void *library,
105			     const char *entryname,
106			     int (*add_plugin)(const char *, void *))
107{
108    void *entry_point;
109    int result;
110
111    result = _sasl_locate_entry(library, entryname, &entry_point);
112    if(result == SASL_OK) {
113	result = add_plugin(plugin, entry_point);
114	if(result != SASL_OK)
115	    _sasl_log(NULL, SASL_LOG_DEBUG,
116		      "_sasl_plugin_load failed on %s for plugin: %s\n",
117		      entryname, plugin);
118    }
119
120    return result;
121}
122
123/* loads a plugin library */
124int _sasl_get_plugin(const char *file,
125		     const sasl_callback_t *verifyfile_cb,
126		     void **libraryptr)
127{
128    int r = 0;
129    HINSTANCE library;
130    lib_list_t *newhead;
131
132    r = ((sasl_verifyfile_t *)(verifyfile_cb->proc))
133		    (verifyfile_cb->context, file, SASL_VRFY_PLUGIN);
134    if (r != SASL_OK) return r;
135
136    newhead = sasl_ALLOC(sizeof(lib_list_t));
137    if (!newhead) return SASL_NOMEM;
138
139    if (!(library = LoadLibrary (file))) {
140	_sasl_log(NULL, SASL_LOG_ERR,
141		  "unable to LoadLibrary %s: %s", file, GetLastError());
142	sasl_FREE(newhead);
143	return SASL_FAIL;
144    }
145
146    newhead->library = library;
147    newhead->next = lib_list_head;
148    lib_list_head = newhead;
149
150    *libraryptr = library;
151    return SASL_OK;
152}
153
154/* undoes actions done by _sasl_get_plugin */
155void _sasl_remove_last_plugin()
156{
157    lib_list_t *last_plugin = lib_list_head;
158    lib_list_head = lib_list_head->next;
159    if (last_plugin->library) {
160	FreeLibrary(last_plugin->library);
161    }
162    sasl_FREE(last_plugin);
163}
164
165/* gets the list of mechanisms */
166int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
167		       const sasl_callback_t *getpath_cb,
168		       const sasl_callback_t *verifyfile_cb)
169{
170    int result;
171    char cur_dir[PATH_MAX], full_name[PATH_MAX+2], prefix[PATH_MAX+2];
172				/* 1 for '\\' 1 for trailing '\0' */
173    char * pattern;
174    char c;
175    int pos;
176    const char *path=NULL;
177    int position;
178    const add_plugin_list_t *cur_ep;
179    struct stat statbuf;		/* filesystem entry information */
180    intptr_t fhandle;			/* file handle for _findnext function */
181    struct _finddata_t finddata;	/* data returned by _findnext() */
182    size_t prefix_len;
183
184    if (! entrypoints
185	|| ! getpath_cb
186	|| getpath_cb->id != SASL_CB_GETPATH
187	|| ! getpath_cb->proc
188	|| ! verifyfile_cb
189	|| verifyfile_cb->id != SASL_CB_VERIFYFILE
190	|| ! verifyfile_cb->proc)
191	return SASL_BADPARAM;
192
193    /* get the path to the plugins */
194    result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context,
195						    &path);
196    if (result != SASL_OK) return result;
197    if (! path) return SASL_FAIL;
198
199    if (strlen(path) >= PATH_MAX) { /* no you can't buffer overrun */
200	return SASL_FAIL;
201    }
202
203    position=0;
204    do {
205	pos=0;
206	do {
207	    c=path[position];
208	    position++;
209	    cur_dir[pos]=c;
210	    pos++;
211	} while ((c!=PATHS_DELIMITER) && (c!=0));
212	cur_dir[pos-1]='\0';
213
214
215/* : check to make sure that a valid directory name was passed in */
216	if (stat (cur_dir, &statbuf) < 0) {
217	    continue;
218	}
219	if ((statbuf.st_mode & S_IFDIR) == 0) {
220	    continue;
221	}
222
223	strcpy (prefix, cur_dir);
224	prefix_len = strlen (prefix);
225
226/* : Don't append trailing \ unless required */
227	if (prefix[prefix_len-1] != '\\') {
228	    strcat (prefix,"\\");
229	    prefix_len++;
230	}
231
232	pattern = prefix;
233
234/* : Check that we have enough space for "*.dll" */
235	if ((prefix_len + DLL_MASK_LEN) > (sizeof(prefix) - 1)) {
236	    _sasl_log(NULL, SASL_LOG_WARN, "plugin search mask is too big");
237            continue;
238	}
239
240	strcat (prefix + prefix_len, "*" DLL_SUFFIX);
241
242        fhandle = _findfirst (pattern, &finddata);
243        if (fhandle == -1) {	/* no matching files */
244            continue;
245        }
246
247/* : Truncate "*.dll" */
248	prefix[prefix_len] = '\0';
249
250	do {
251	    size_t length;
252	    void *library;
253	    char *c;
254	    char plugname[PATH_MAX];
255	    int entries;
256
257	    length = strlen(finddata.name);
258	    if (length < 5) { /* At least <Ch>.dll */
259		continue; /* can not possibly be what we're looking for */
260	    }
261
262/* : Check for overflow */
263	    if (length + prefix_len >= PATH_MAX) continue; /* too big */
264
265	    if (stricmp(finddata.name + (length - strlen(DLL_SUFFIX)), DLL_SUFFIX) != 0) {
266		continue;
267	    }
268
269/* : Check that it is not a directory */
270	    if ((finddata.attrib & _A_SUBDIR) == _A_SUBDIR) {
271		continue;
272	    }
273
274/* : Construct full name from prefix and name */
275
276	    strcpy (full_name, prefix);
277	    strcat (full_name, finddata.name);
278
279/* cut off .dll suffix -- this only need be approximate */
280	    strcpy (plugname, finddata.name);
281	    c = strrchr(plugname, '.');
282	    if (c != NULL) *c = '\0';
283
284	    result = _sasl_get_plugin (full_name, verifyfile_cb, &library);
285
286	    if (result != SASL_OK) {
287		continue;
288	    }
289
290	    entries = 0;
291	    for (cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
292		result = _sasl_plugin_load(plugname,
293					   library,
294					   cur_ep->entryname,
295					   cur_ep->add_plugin);
296		if (result == SASL_OK) {
297		    ++entries;
298		}
299		/* If this fails, it's not the end of the world */
300	    }
301	    if (entries == 0) {
302		_sasl_remove_last_plugin();
303	    }
304
305	} while (_findnext (fhandle, &finddata) == 0);
306
307	_findclose (fhandle);
308
309    } while ((c!='=') && (c!=0));
310
311    return SASL_OK;
312}
313
314int
315_sasl_done_with_plugins(void)
316{
317    lib_list_t *libptr, *libptr_next;
318
319    for(libptr = lib_list_head; libptr; libptr = libptr_next) {
320	libptr_next = libptr->next;
321	if (libptr->library != NULL) {
322	    FreeLibrary(libptr->library);
323	}
324	sasl_FREE(libptr);
325    }
326
327    lib_list_head = NULL;
328
329    return SASL_OK;
330}
331