1c19800e8SDoug Rabson /* 2c19800e8SDoug Rabson * Copyright (c) 2006 - 2007 Kungliga Tekniska H�gskolan 3c19800e8SDoug Rabson * (Royal Institute of Technology, Stockholm, Sweden). 4c19800e8SDoug Rabson * All rights reserved. 5c19800e8SDoug Rabson * 6c19800e8SDoug Rabson * Redistribution and use in source and binary forms, with or without 7c19800e8SDoug Rabson * modification, are permitted provided that the following conditions 8c19800e8SDoug Rabson * are met: 9c19800e8SDoug Rabson * 10c19800e8SDoug Rabson * 1. Redistributions of source code must retain the above copyright 11c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer. 12c19800e8SDoug Rabson * 13c19800e8SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 14c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer in the 15c19800e8SDoug Rabson * documentation and/or other materials provided with the distribution. 16c19800e8SDoug Rabson * 17c19800e8SDoug Rabson * 3. Neither the name of the Institute nor the names of its contributors 18c19800e8SDoug Rabson * may be used to endorse or promote products derived from this software 19c19800e8SDoug Rabson * without specific prior written permission. 20c19800e8SDoug Rabson * 21c19800e8SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22c19800e8SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23c19800e8SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24c19800e8SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25c19800e8SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26c19800e8SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27c19800e8SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28c19800e8SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29c19800e8SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30c19800e8SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31c19800e8SDoug Rabson * SUCH DAMAGE. 32c19800e8SDoug Rabson */ 33c19800e8SDoug Rabson 34c19800e8SDoug Rabson #include "krb5_locl.h" 35c19800e8SDoug Rabson RCSID("$Id: plugin.c 22033 2007-11-10 10:39:47Z lha $"); 36c19800e8SDoug Rabson #ifdef HAVE_DLFCN_H 37c19800e8SDoug Rabson #include <dlfcn.h> 38c19800e8SDoug Rabson #endif 39c19800e8SDoug Rabson #include <dirent.h> 40c19800e8SDoug Rabson 41c19800e8SDoug Rabson struct krb5_plugin { 42c19800e8SDoug Rabson void *symbol; 43c19800e8SDoug Rabson void *dsohandle; 44c19800e8SDoug Rabson struct krb5_plugin *next; 45c19800e8SDoug Rabson }; 46c19800e8SDoug Rabson 47c19800e8SDoug Rabson struct plugin { 48c19800e8SDoug Rabson enum krb5_plugin_type type; 49c19800e8SDoug Rabson void *name; 50c19800e8SDoug Rabson void *symbol; 51c19800e8SDoug Rabson struct plugin *next; 52c19800e8SDoug Rabson }; 53c19800e8SDoug Rabson 54c19800e8SDoug Rabson static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER; 55c19800e8SDoug Rabson static struct plugin *registered = NULL; 56c19800e8SDoug Rabson 57c19800e8SDoug Rabson static const char *plugin_dir = LIBDIR "/plugin/krb5"; 58c19800e8SDoug Rabson 59c19800e8SDoug Rabson /* 60c19800e8SDoug Rabson * 61c19800e8SDoug Rabson */ 62c19800e8SDoug Rabson 63c19800e8SDoug Rabson void * 64c19800e8SDoug Rabson _krb5_plugin_get_symbol(struct krb5_plugin *p) 65c19800e8SDoug Rabson { 66c19800e8SDoug Rabson return p->symbol; 67c19800e8SDoug Rabson } 68c19800e8SDoug Rabson 69c19800e8SDoug Rabson struct krb5_plugin * 70c19800e8SDoug Rabson _krb5_plugin_get_next(struct krb5_plugin *p) 71c19800e8SDoug Rabson { 72c19800e8SDoug Rabson return p->next; 73c19800e8SDoug Rabson } 74c19800e8SDoug Rabson 75c19800e8SDoug Rabson /* 76c19800e8SDoug Rabson * 77c19800e8SDoug Rabson */ 78c19800e8SDoug Rabson 79c19800e8SDoug Rabson #ifdef HAVE_DLOPEN 80c19800e8SDoug Rabson 81c19800e8SDoug Rabson static krb5_error_code 82c19800e8SDoug Rabson loadlib(krb5_context context, 83c19800e8SDoug Rabson enum krb5_plugin_type type, 84c19800e8SDoug Rabson const char *name, 85c19800e8SDoug Rabson const char *lib, 86c19800e8SDoug Rabson struct krb5_plugin **e) 87c19800e8SDoug Rabson { 88c19800e8SDoug Rabson *e = calloc(1, sizeof(**e)); 89c19800e8SDoug Rabson if (*e == NULL) { 90c19800e8SDoug Rabson krb5_set_error_string(context, "out of memory"); 91c19800e8SDoug Rabson return ENOMEM; 92c19800e8SDoug Rabson } 93c19800e8SDoug Rabson 94c19800e8SDoug Rabson #ifndef RTLD_LAZY 95c19800e8SDoug Rabson #define RTLD_LAZY 0 96c19800e8SDoug Rabson #endif 97c19800e8SDoug Rabson 98c19800e8SDoug Rabson (*e)->dsohandle = dlopen(lib, RTLD_LAZY); 99c19800e8SDoug Rabson if ((*e)->dsohandle == NULL) { 100c19800e8SDoug Rabson free(*e); 101c19800e8SDoug Rabson *e = NULL; 102c19800e8SDoug Rabson krb5_set_error_string(context, "Failed to load %s: %s", 103c19800e8SDoug Rabson lib, dlerror()); 104c19800e8SDoug Rabson return ENOMEM; 105c19800e8SDoug Rabson } 106c19800e8SDoug Rabson 107c19800e8SDoug Rabson /* dlsym doesn't care about the type */ 108c19800e8SDoug Rabson (*e)->symbol = dlsym((*e)->dsohandle, name); 109c19800e8SDoug Rabson if ((*e)->symbol == NULL) { 110c19800e8SDoug Rabson dlclose((*e)->dsohandle); 111c19800e8SDoug Rabson free(*e); 112c19800e8SDoug Rabson krb5_clear_error_string(context); 113c19800e8SDoug Rabson return ENOMEM; 114c19800e8SDoug Rabson } 115c19800e8SDoug Rabson 116c19800e8SDoug Rabson return 0; 117c19800e8SDoug Rabson } 118c19800e8SDoug Rabson #endif /* HAVE_DLOPEN */ 119c19800e8SDoug Rabson 120c19800e8SDoug Rabson /** 121c19800e8SDoug Rabson * Register a plugin symbol name of specific type. 122c19800e8SDoug Rabson * @param context a Keberos context 123c19800e8SDoug Rabson * @param type type of plugin symbol 124c19800e8SDoug Rabson * @param name name of plugin symbol 125c19800e8SDoug Rabson * @param symbol a pointer to the named symbol 126c19800e8SDoug Rabson * @return In case of error a non zero error com_err error is returned 127c19800e8SDoug Rabson * and the Kerberos error string is set. 128c19800e8SDoug Rabson * 129c19800e8SDoug Rabson * @ingroup krb5_support 130c19800e8SDoug Rabson */ 131c19800e8SDoug Rabson 132c19800e8SDoug Rabson krb5_error_code 133c19800e8SDoug Rabson krb5_plugin_register(krb5_context context, 134c19800e8SDoug Rabson enum krb5_plugin_type type, 135c19800e8SDoug Rabson const char *name, 136c19800e8SDoug Rabson void *symbol) 137c19800e8SDoug Rabson { 138c19800e8SDoug Rabson struct plugin *e; 139c19800e8SDoug Rabson 140c19800e8SDoug Rabson e = calloc(1, sizeof(*e)); 141c19800e8SDoug Rabson if (e == NULL) { 142c19800e8SDoug Rabson krb5_set_error_string(context, "out of memory"); 143c19800e8SDoug Rabson return ENOMEM; 144c19800e8SDoug Rabson } 145c19800e8SDoug Rabson e->type = type; 146c19800e8SDoug Rabson e->name = strdup(name); 147c19800e8SDoug Rabson if (e->name == NULL) { 148c19800e8SDoug Rabson free(e); 149c19800e8SDoug Rabson krb5_set_error_string(context, "out of memory"); 150c19800e8SDoug Rabson return ENOMEM; 151c19800e8SDoug Rabson } 152c19800e8SDoug Rabson e->symbol = symbol; 153c19800e8SDoug Rabson 154c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&plugin_mutex); 155c19800e8SDoug Rabson e->next = registered; 156c19800e8SDoug Rabson registered = e; 157c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&plugin_mutex); 158c19800e8SDoug Rabson 159c19800e8SDoug Rabson return 0; 160c19800e8SDoug Rabson } 161c19800e8SDoug Rabson 162c19800e8SDoug Rabson krb5_error_code 163c19800e8SDoug Rabson _krb5_plugin_find(krb5_context context, 164c19800e8SDoug Rabson enum krb5_plugin_type type, 165c19800e8SDoug Rabson const char *name, 166c19800e8SDoug Rabson struct krb5_plugin **list) 167c19800e8SDoug Rabson { 168c19800e8SDoug Rabson struct krb5_plugin *e; 169c19800e8SDoug Rabson struct plugin *p; 170c19800e8SDoug Rabson krb5_error_code ret; 171c19800e8SDoug Rabson char *sysdirs[2] = { NULL, NULL }; 172c19800e8SDoug Rabson char **dirs = NULL, **di; 173c19800e8SDoug Rabson struct dirent *entry; 174c19800e8SDoug Rabson char *path; 175c19800e8SDoug Rabson DIR *d = NULL; 176c19800e8SDoug Rabson 177c19800e8SDoug Rabson *list = NULL; 178c19800e8SDoug Rabson 179c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&plugin_mutex); 180c19800e8SDoug Rabson 181c19800e8SDoug Rabson for (p = registered; p != NULL; p = p->next) { 182c19800e8SDoug Rabson if (p->type != type || strcmp(p->name, name) != 0) 183c19800e8SDoug Rabson continue; 184c19800e8SDoug Rabson 185c19800e8SDoug Rabson e = calloc(1, sizeof(*e)); 186c19800e8SDoug Rabson if (e == NULL) { 187c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&plugin_mutex); 188c19800e8SDoug Rabson krb5_set_error_string(context, "out of memory"); 189c19800e8SDoug Rabson ret = ENOMEM; 190c19800e8SDoug Rabson goto out; 191c19800e8SDoug Rabson } 192c19800e8SDoug Rabson e->symbol = p->symbol; 193c19800e8SDoug Rabson e->dsohandle = NULL; 194c19800e8SDoug Rabson e->next = *list; 195c19800e8SDoug Rabson *list = e; 196c19800e8SDoug Rabson } 197c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&plugin_mutex); 198c19800e8SDoug Rabson 199c19800e8SDoug Rabson #ifdef HAVE_DLOPEN 200c19800e8SDoug Rabson 201c19800e8SDoug Rabson dirs = krb5_config_get_strings(context, NULL, "libdefaults", 202c19800e8SDoug Rabson "plugin_dir", NULL); 203c19800e8SDoug Rabson if (dirs == NULL) { 204c19800e8SDoug Rabson sysdirs[0] = rk_UNCONST(plugin_dir); 205c19800e8SDoug Rabson dirs = sysdirs; 206c19800e8SDoug Rabson } 207c19800e8SDoug Rabson 208c19800e8SDoug Rabson for (di = dirs; *di != NULL; di++) { 209c19800e8SDoug Rabson 210c19800e8SDoug Rabson d = opendir(*di); 211c19800e8SDoug Rabson if (d == NULL) 212c19800e8SDoug Rabson continue; 213c19800e8SDoug Rabson 214c19800e8SDoug Rabson while ((entry = readdir(d)) != NULL) { 215c19800e8SDoug Rabson asprintf(&path, "%s/%s", *di, entry->d_name); 216c19800e8SDoug Rabson if (path == NULL) { 217c19800e8SDoug Rabson krb5_set_error_string(context, "out of memory"); 218c19800e8SDoug Rabson ret = ENOMEM; 219c19800e8SDoug Rabson goto out; 220c19800e8SDoug Rabson } 221c19800e8SDoug Rabson ret = loadlib(context, type, name, path, &e); 222c19800e8SDoug Rabson free(path); 223c19800e8SDoug Rabson if (ret) 224c19800e8SDoug Rabson continue; 225c19800e8SDoug Rabson 226c19800e8SDoug Rabson e->next = *list; 227c19800e8SDoug Rabson *list = e; 228c19800e8SDoug Rabson } 229c19800e8SDoug Rabson closedir(d); 230c19800e8SDoug Rabson } 231c19800e8SDoug Rabson if (dirs != sysdirs) 232c19800e8SDoug Rabson krb5_config_free_strings(dirs); 233c19800e8SDoug Rabson #endif /* HAVE_DLOPEN */ 234c19800e8SDoug Rabson 235c19800e8SDoug Rabson if (*list == NULL) { 236c19800e8SDoug Rabson krb5_set_error_string(context, "Did not find a plugin for %s", name); 237c19800e8SDoug Rabson return ENOENT; 238c19800e8SDoug Rabson } 239c19800e8SDoug Rabson 240c19800e8SDoug Rabson return 0; 241c19800e8SDoug Rabson 242c19800e8SDoug Rabson out: 243c19800e8SDoug Rabson if (dirs && dirs != sysdirs) 244c19800e8SDoug Rabson krb5_config_free_strings(dirs); 245c19800e8SDoug Rabson if (d) 246c19800e8SDoug Rabson closedir(d); 247c19800e8SDoug Rabson _krb5_plugin_free(*list); 248c19800e8SDoug Rabson *list = NULL; 249c19800e8SDoug Rabson 250c19800e8SDoug Rabson return ret; 251c19800e8SDoug Rabson } 252c19800e8SDoug Rabson 253c19800e8SDoug Rabson void 254c19800e8SDoug Rabson _krb5_plugin_free(struct krb5_plugin *list) 255c19800e8SDoug Rabson { 256c19800e8SDoug Rabson struct krb5_plugin *next; 257c19800e8SDoug Rabson while (list) { 258c19800e8SDoug Rabson next = list->next; 259c19800e8SDoug Rabson if (list->dsohandle) 260c19800e8SDoug Rabson dlclose(list->dsohandle); 261c19800e8SDoug Rabson free(list); 262c19800e8SDoug Rabson list = next; 263c19800e8SDoug Rabson } 264c19800e8SDoug Rabson } 265