GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / lib / windlopen.c
1 /* windlopen.c--Windows dynamic loader interface
2  * Ryan Troll
3  * $Id: windlopen.c,v 1.16 2003/10/20 15:19:59 rjs3 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
57 const int _is_sasl_server_static = 0;
58
59 /* : inefficient representation, but works */
60 typedef struct lib_list 
61 {
62     struct lib_list *next;
63     HMODULE library;
64 } lib_list_t;
65
66 static lib_list_t *lib_list_head = NULL;
67
68 int _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
104 static 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 */
124 int _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
155
156 /* gets the list of mechanisms */
157 int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
158                        const sasl_callback_t *getpath_cb,
159                        const sasl_callback_t *verifyfile_cb)
160 {
161     int result;
162     char cur_dir[PATH_MAX], full_name[PATH_MAX+2], prefix[PATH_MAX+2];
163                                 /* 1 for '\\' 1 for trailing '\0' */
164     char * pattern;
165     char c;
166     int pos;
167     const char *path=NULL;
168     int position;
169     const add_plugin_list_t *cur_ep;
170     struct stat statbuf;                /* filesystem entry information */
171     intptr_t fhandle;                   /* file handle for _findnext function */
172     struct _finddata_t finddata;        /* data returned by _findnext() */
173     size_t prefix_len;
174
175     if (! entrypoints
176         || ! getpath_cb
177         || getpath_cb->id != SASL_CB_GETPATH
178         || ! getpath_cb->proc
179         || ! verifyfile_cb
180         || verifyfile_cb->id != SASL_CB_VERIFYFILE
181         || ! verifyfile_cb->proc)
182         return SASL_BADPARAM;
183
184     /* get the path to the plugins */
185     result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context,
186                                                     &path);
187     if (result != SASL_OK) return result;
188     if (! path) return SASL_FAIL;
189
190     if (strlen(path) >= PATH_MAX) { /* no you can't buffer overrun */
191         return SASL_FAIL;
192     }
193
194     position=0;
195     do {
196         pos=0;
197         do {
198             c=path[position];
199             position++;
200             cur_dir[pos]=c;
201             pos++;
202         } while ((c!=PATHS_DELIMITER) && (c!=0));
203         cur_dir[pos-1]='\0';
204
205
206 /* : check to make sure that a valid directory name was passed in */
207         if (stat (cur_dir, &statbuf) < 0) {
208             continue;
209         }
210         if ((statbuf.st_mode & S_IFDIR) == 0) {
211             continue;
212         }
213
214         strcpy (prefix, cur_dir);
215         prefix_len = strlen (prefix);
216
217 /* : Don't append trailing \ unless required */
218         if (prefix[prefix_len-1] != '\\') {
219             strcat (prefix,"\\");
220             prefix_len++;
221         }
222
223         pattern = prefix;
224
225 /* : Check that we have enough space for "*.dll" */
226         if ((prefix_len + DLL_MASK_LEN) > (sizeof(prefix) - 1)) {
227             _sasl_log(NULL, SASL_LOG_WARN, "plugin search mask is too big");
228             continue;
229         }
230
231         strcat (prefix + prefix_len, "*" DLL_SUFFIX);
232
233         fhandle = _findfirst (pattern, &finddata);
234         if (fhandle == -1) {    /* no matching files */
235             continue;
236         }
237
238 /* : Truncate "*.dll" */
239         prefix[prefix_len] = '\0';
240
241         do {
242             size_t length;
243             void *library;
244             char *c;
245             char plugname[PATH_MAX];
246
247             length = strlen(finddata.name);
248             if (length < 5) { /* At least <Ch>.dll */
249                 continue; /* can not possibly be what we're looking for */
250             }
251
252 /* : Check for overflow */
253             if (length + prefix_len >= PATH_MAX) continue; /* too big */
254
255             if (stricmp(finddata.name + (length - strlen(DLL_SUFFIX)), DLL_SUFFIX) != 0) {
256                 continue;
257             }
258
259 /* : Check that it is not a directory */
260             if ((finddata.attrib & _A_SUBDIR) == _A_SUBDIR) {
261                 continue;
262             }
263
264 /* : Construct full name from prefix and name */
265
266             strcpy (full_name, prefix);
267             strcat (full_name, finddata.name);
268                 
269 /* cut off .dll suffix -- this only need be approximate */
270             strcpy (plugname, finddata.name);
271             c = strrchr(plugname, '.');
272             if (c != NULL) *c = '\0';
273
274             result = _sasl_get_plugin (full_name, verifyfile_cb, &library);
275
276             if (result != SASL_OK) {
277                 continue;
278             }
279
280             for (cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
281                     _sasl_plugin_load(plugname, library, cur_ep->entryname,
282                                       cur_ep->add_plugin);
283                 /* If this fails, it's not the end of the world */
284             }
285         } while (_findnext (fhandle, &finddata) == 0);
286         
287         _findclose (fhandle);
288
289     } while ((c!='=') && (c!=0));
290
291     return SASL_OK;
292 }
293
294 int
295 _sasl_done_with_plugins(void)
296 {
297     lib_list_t *libptr, *libptr_next;
298     
299     for(libptr = lib_list_head; libptr; libptr = libptr_next) {
300         libptr_next = libptr->next;
301         if (libptr->library != NULL) {
302             FreeLibrary(libptr->library);
303         }
304         sasl_FREE(libptr);
305     }
306
307     lib_list_head = NULL;
308
309     return SASL_OK;
310 }