/* windlopen.c--Windows dynamic loader interface * Ryan Troll * $Id: windlopen.c,v 1.1 2004/03/31 18:12:22 dasenbro Exp $ */ /* * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any other legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "saslint.h" #define DLL_SUFFIX ".dll" #define DLL_MASK "*" DLL_SUFFIX #define DLL_MASK_LEN 5 const int _is_sasl_server_static = 0; /* : inefficient representation, but works */ typedef struct lib_list { struct lib_list *next; HMODULE library; } lib_list_t; static lib_list_t *lib_list_head = NULL; int _sasl_locate_entry(void *library, const char *entryname, void **entry_point) { if(entryname == NULL) { _sasl_log(NULL, SASL_LOG_ERR, "no entryname in _sasl_locate_entry"); return SASL_BADPARAM; } if(library == NULL) { _sasl_log(NULL, SASL_LOG_ERR, "no library in _sasl_locate_entry"); return SASL_BADPARAM; } if(entry_point == NULL) { _sasl_log(NULL, SASL_LOG_ERR, "no entrypoint output pointer in _sasl_locate_entry"); return SASL_BADPARAM; } *entry_point = GetProcAddress(library, entryname); if (*entry_point == NULL) { #if 0 /* This message appears to confuse people */ _sasl_log(NULL, SASL_LOG_DEBUG, "unable to get entry point %s: %s", entryname, GetLastError()); #endif return SASL_FAIL; } return SASL_OK; } static int _sasl_plugin_load(char *plugin, void *library, const char *entryname, int (*add_plugin)(const char *, void *)) { void *entry_point; int result; result = _sasl_locate_entry(library, entryname, &entry_point); if(result == SASL_OK) { result = add_plugin(plugin, entry_point); if(result != SASL_OK) _sasl_log(NULL, SASL_LOG_DEBUG, "_sasl_plugin_load failed on %s for plugin: %s\n", entryname, plugin); } return result; } /* loads a plugin library */ int _sasl_get_plugin(const char *file, const sasl_callback_t *verifyfile_cb, void **libraryptr) { int r = 0; HINSTANCE library; lib_list_t *newhead; r = ((sasl_verifyfile_t *)(verifyfile_cb->proc)) (verifyfile_cb->context, file, SASL_VRFY_PLUGIN); if (r != SASL_OK) return r; newhead = sasl_ALLOC(sizeof(lib_list_t)); if(!newhead) return SASL_NOMEM; if (!(library = LoadLibrary (file))) { _sasl_log(NULL, SASL_LOG_ERR, "unable to LoadLibrary %s: %s", file, GetLastError()); sasl_FREE(newhead); return SASL_FAIL; } newhead->library = library; newhead->next = lib_list_head; lib_list_head = newhead; *libraryptr = library; return SASL_OK; } /* gets the list of mechanisms */ int _sasl_load_plugins(const add_plugin_list_t *entrypoints, const sasl_callback_t *getpath_cb, const sasl_callback_t *verifyfile_cb) { int result; char cur_dir[PATH_MAX], full_name[PATH_MAX+2], prefix[PATH_MAX+2]; /* 1 for '\\' 1 for trailing '\0' */ char * pattern; char c; int pos; const char *path=NULL; int position; const add_plugin_list_t *cur_ep; struct stat statbuf; /* filesystem entry information */ intptr_t fhandle; /* file handle for _findnext function */ struct _finddata_t finddata; /* data returned by _findnext() */ size_t prefix_len; if (! entrypoints || ! getpath_cb || getpath_cb->id != SASL_CB_GETPATH || ! getpath_cb->proc || ! verifyfile_cb || verifyfile_cb->id != SASL_CB_VERIFYFILE || ! verifyfile_cb->proc) return SASL_BADPARAM; /* get the path to the plugins */ result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context, &path); if (result != SASL_OK) return result; if (! path) return SASL_FAIL; if (strlen(path) >= PATH_MAX) { /* no you can't buffer overrun */ return SASL_FAIL; } position=0; do { pos=0; do { c=path[position]; position++; cur_dir[pos]=c; pos++; } while ((c!=PATHS_DELIMITER) && (c!=0)); cur_dir[pos-1]='\0'; /* : check to make sure that a valid directory name was passed in */ if (stat (cur_dir, &statbuf) < 0) { continue; } if ((statbuf.st_mode & S_IFDIR) == 0) { continue; } strcpy (prefix, cur_dir); prefix_len = strlen (prefix); /* : Don't append trailing \ unless required */ if (prefix[prefix_len-1] != '\\') { strcat (prefix,"\\"); prefix_len++; } pattern = prefix; /* : Check that we have enough space for "*.dll" */ if ((prefix_len + DLL_MASK_LEN) > (sizeof(prefix) - 1)) { _sasl_log(NULL, SASL_LOG_WARN, "plugin search mask is too big"); continue; } strcat (prefix + prefix_len, "*" DLL_SUFFIX); fhandle = _findfirst (pattern, &finddata); if (fhandle == -1) { /* no matching files */ continue; } /* : Truncate "*.dll" */ prefix[prefix_len] = '\0'; do { size_t length; void *library; char *c; char plugname[PATH_MAX]; length = strlen(finddata.name); if (length < 5) { /* At least .dll */ continue; /* can not possibly be what we're looking for */ } /* : Check for overflow */ if (length + prefix_len >= PATH_MAX) continue; /* too big */ if (stricmp(finddata.name + (length - strlen(DLL_SUFFIX)), DLL_SUFFIX) != 0) { continue; } /* : Check that it is not a directory */ if ((finddata.attrib & _A_SUBDIR) == _A_SUBDIR) { continue; } /* : Construct full name from prefix and name */ strcpy (full_name, prefix); strcat (full_name, finddata.name); /* cut off .dll suffix -- this only need be approximate */ strcpy (plugname, finddata.name); c = strrchr(plugname, '.'); if (c != NULL) *c = '\0'; result = _sasl_get_plugin (full_name, verifyfile_cb, &library); if (result != SASL_OK) { continue; } for (cur_ep = entrypoints; cur_ep->entryname; cur_ep++) { _sasl_plugin_load(plugname, library, cur_ep->entryname, cur_ep->add_plugin); /* If this fails, it's not the end of the world */ } } while (_findnext (fhandle, &finddata) == 0); _findclose (fhandle); } while ((c!='=') && (c!=0)); return SASL_OK; } int _sasl_done_with_plugins(void) { lib_list_t *libptr, *libptr_next; for(libptr = lib_list_head; libptr; libptr = libptr_next) { libptr_next = libptr->next; if (libptr->library != NULL) { FreeLibrary(libptr->library); } sasl_FREE(libptr); } lib_list_head = NULL; return SASL_OK; }