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