r19681: Update to current lorikeet-heimdal. I'm looking at using the realm
[Samba.git] / source / heimdal / lib / krb5 / plugin.c
blob294807faab15bf059581603e0d326f2191727084
1 /*
2 * Copyright (c) 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "krb5_locl.h"
35 RCSID("$Id: plugin.c,v 1.2 2006/11/12 21:39:43 lha Exp $");
36 #ifdef HAVE_DLFCN_H
37 #include <dlfcn.h>
38 #endif
39 #include <dirent.h>
41 struct krb5_plugin {
42 void *symbol;
43 void *dsohandle;
44 struct krb5_plugin *next;
47 struct plugin {
48 enum plugin_type type;
49 void *name;
50 void *symbol;
51 struct plugin *next;
54 static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER;
55 static struct plugin *registered = NULL;
57 static const char *plugin_dir = LIBDIR "/plugin/krb5";
63 void *
64 _krb5_plugin_get_symbol(struct krb5_plugin *p)
66 return p->symbol;
69 struct krb5_plugin *
70 _krb5_plugin_get_next(struct krb5_plugin *p)
72 return p->next;
79 static krb5_error_code
80 loadlib(krb5_context context,
81 enum plugin_type type,
82 const char *name,
83 const char *lib,
84 struct krb5_plugin **e)
86 *e = calloc(1, sizeof(**e));
87 if (*e == NULL) {
88 krb5_set_error_string(context, "out of memory");
89 return ENOMEM;
92 (*e)->dsohandle = dlopen(lib, 0);
93 if ((*e)->dsohandle == NULL) {
94 free(*e);
95 krb5_set_error_string(context, "Failed to load %s: %s",
96 lib, dlerror());
97 return ENOMEM;
100 /* dlsym doesn't care about the type */
101 (*e)->symbol = dlsym((*e)->dsohandle, name);
102 if ((*e)->symbol == NULL) {
103 dlclose((*e)->dsohandle);
104 free(*e);
105 krb5_clear_error_string(context);
106 return ENOMEM;
109 return 0;
112 krb5_error_code
113 _krb5_plugin_register(krb5_context context,
114 enum plugin_type type,
115 const char *name,
116 void *symbol)
118 struct plugin *e;
120 e = calloc(1, sizeof(*e));
121 if (e == NULL) {
122 krb5_set_error_string(context, "out of memory");
123 return ENOMEM;
125 e->type = type;
126 e->name = strdup(name);
127 if (e->name == NULL) {
128 free(e);
129 krb5_set_error_string(context, "out of memory");
130 return ENOMEM;
132 e->symbol = symbol;
134 HEIMDAL_MUTEX_lock(&plugin_mutex);
135 e->next = registered;
136 registered = e;
137 HEIMDAL_MUTEX_unlock(&plugin_mutex);
139 return 0;
142 krb5_error_code
143 _krb5_plugin_find(krb5_context context,
144 enum plugin_type type,
145 const char *name,
146 struct krb5_plugin **list)
148 struct krb5_plugin *e;
149 struct plugin *p;
150 krb5_error_code ret;
151 char *sysdirs[2] = { NULL, NULL };
152 char **dirs = NULL, **di;
153 struct dirent *entry;
154 char *path;
155 DIR *d = NULL;
157 *list = NULL;
159 HEIMDAL_MUTEX_lock(&plugin_mutex);
161 for (p = registered; p != NULL; p = p->next) {
162 if (p->type != type || strcmp(p->name, name) != 0)
163 continue;
165 e = calloc(1, sizeof(*e));
166 if (e == NULL) {
167 HEIMDAL_MUTEX_unlock(&plugin_mutex);
168 krb5_set_error_string(context, "out of memory");
169 ret = ENOMEM;
170 goto out;
172 e->symbol = p->symbol;
173 e->dsohandle = NULL;
174 e->next = *list;
175 *list = e;
177 HEIMDAL_MUTEX_unlock(&plugin_mutex);
179 dirs = krb5_config_get_strings(context, NULL, "libdefaults",
180 "plugin_dir", NULL);
181 if (dirs == NULL) {
182 sysdirs[0] = rk_UNCONST(plugin_dir);
183 dirs = sysdirs;
186 for (di = dirs; *di != NULL; di++) {
188 d = opendir(*di);
189 if (d == NULL)
190 continue;
192 while ((entry = readdir(d)) != NULL) {
193 asprintf(&path, "%s/%s", *di, entry->d_name);
194 if (path == NULL) {
195 krb5_set_error_string(context, "out of memory");
196 ret = ENOMEM;
197 goto out;
199 ret = loadlib(context, type, name, path, &e);
200 free(path);
201 if (ret)
202 continue;
204 e->next = *list;
205 *list = e;
207 closedir(d);
209 if (dirs != sysdirs)
210 krb5_config_free_strings(dirs);
212 if (*list == NULL) {
213 krb5_set_error_string(context, "Did not find a plugin for %s", name);
214 return ENOENT;
217 return 0;
219 out:
220 if (dirs && dirs != sysdirs)
221 krb5_config_free_strings(dirs);
222 if (d)
223 closedir(d);
224 _krb5_plugin_free(*list);
225 *list = NULL;
227 return ret;
230 void
231 _krb5_plugin_free(struct krb5_plugin *list)
233 struct krb5_plugin *next;
234 while (list) {
235 next = list->next;
236 if (list->dsohandle)
237 dlclose(list->dsohandle);
238 free(list);
239 list = next;