turn off v4 conversion stuff
[heimdal.git] / lib / krb5 / plugin.c
blob027f2a72a707dc7934083eb7bac6a78e52e8450e
1 /*
2 * Copyright (c) 2006 - 2007 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"
36 #ifdef HAVE_DLFCN_H
37 #include <dlfcn.h>
38 #endif
39 #include <dirent.h>
41 struct krb5_plugin {
42 void *symbol;
43 struct krb5_plugin *next;
46 struct plugin {
47 enum { DSO, SYMBOL } type;
48 union {
49 struct {
50 char *path;
51 void *dsohandle;
52 } dso;
53 struct {
54 enum krb5_plugin_type type;
55 char *name;
56 char *symbol;
57 } symbol;
58 } u;
59 struct plugin *next;
62 static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER;
63 static struct plugin *registered = NULL;
64 static int plugins_needs_scan = 1;
66 static const char *sysplugin_dirs[] = {
67 LIBDIR "/plugin/krb5",
68 #ifdef __APPLE__
69 "/System/Library/KerberosPlugins/KerberosFrameworkPlugins",
70 #endif
71 NULL
78 void *
79 _krb5_plugin_get_symbol(struct krb5_plugin *p)
81 return p->symbol;
84 struct krb5_plugin *
85 _krb5_plugin_get_next(struct krb5_plugin *p)
87 return p->next;
94 #ifdef HAVE_DLOPEN
96 static krb5_error_code
97 loadlib(krb5_context context, char *path)
99 struct plugin *e;
101 e = calloc(1, sizeof(*e));
102 if (e == NULL) {
103 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
104 free(path);
105 return ENOMEM;
108 #ifndef RTLD_LAZY
109 #define RTLD_LAZY 0
110 #endif
111 #ifndef RTLD_LOCAL
112 #define RTLD_LOCAL 0
113 #endif
114 e->type = DSO;
115 /* ignore error from dlopen, and just keep it as negative cache entry */
116 e->u.dso.dsohandle = dlopen(path, RTLD_LOCAL|RTLD_LAZY);
117 e->u.dso.path = path;
119 e->next = registered;
120 registered = e;
122 return 0;
124 #endif /* HAVE_DLOPEN */
127 * Register a plugin symbol name of specific type.
128 * @param context a Keberos context
129 * @param type type of plugin symbol
130 * @param name name of plugin symbol
131 * @param symbol a pointer to the named symbol
132 * @return In case of error a non zero error com_err error is returned
133 * and the Kerberos error string is set.
135 * @ingroup krb5_support
138 krb5_error_code
139 krb5_plugin_register(krb5_context context,
140 enum krb5_plugin_type type,
141 const char *name,
142 void *symbol)
144 struct plugin *e;
146 HEIMDAL_MUTEX_lock(&plugin_mutex);
148 /* check for duplicates */
149 for (e = registered; e != NULL; e = e->next) {
150 if (e->type == SYMBOL &&
151 strcmp(e->u.symbol.name, name) == 0 &&
152 e->u.symbol.type == type && e->u.symbol.symbol == symbol) {
153 HEIMDAL_MUTEX_unlock(&plugin_mutex);
154 return 0;
158 e = calloc(1, sizeof(*e));
159 if (e == NULL) {
160 HEIMDAL_MUTEX_unlock(&plugin_mutex);
161 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
162 return ENOMEM;
164 e->type = SYMBOL;
165 e->u.symbol.type = type;
166 e->u.symbol.name = strdup(name);
167 if (e->u.symbol.name == NULL) {
168 HEIMDAL_MUTEX_unlock(&plugin_mutex);
169 free(e);
170 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
171 return ENOMEM;
173 e->u.symbol.symbol = symbol;
175 e->next = registered;
176 registered = e;
177 HEIMDAL_MUTEX_unlock(&plugin_mutex);
179 return 0;
182 static krb5_error_code
183 load_plugins(krb5_context context)
185 struct plugin *e;
186 krb5_error_code ret;
187 char **dirs = NULL, **di;
188 struct dirent *entry;
189 char *path;
190 DIR *d = NULL;
192 if (!plugins_needs_scan)
193 return 0;
194 plugins_needs_scan = 0;
196 #ifdef HAVE_DLOPEN
198 dirs = krb5_config_get_strings(context, NULL, "libdefaults",
199 "plugin_dir", NULL);
200 if (dirs == NULL)
201 dirs = rk_UNCONST(sysplugin_dirs);
203 for (di = dirs; *di != NULL; di++) {
205 d = opendir(*di);
206 if (d == NULL)
207 continue;
208 rk_cloexec(dirfd(d));
210 while ((entry = readdir(d)) != NULL) {
211 char *n = entry->d_name;
213 /* skip . and .. */
214 if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0')))
215 continue;
217 path = NULL;
218 #ifdef __APPLE__
219 { /* support loading bundles on MacOS */
220 size_t len = strlen(n);
221 if (len > 7 && strcmp(&n[len - 7], ".bundle") == 0)
222 asprintf(&path, "%s/%s/Contents/MacOS/%.*s", *di, n, (int)(len - 7), n);
224 #endif
225 if (path == NULL)
226 asprintf(&path, "%s/%s", *di, n);
228 if (path == NULL) {
229 ret = ENOMEM;
230 krb5_set_error_message(context, ret, "malloc: out of memory");
231 return ret;
234 /* check if already tried */
235 for (e = registered; e != NULL; e = e->next)
236 if (e->type == DSO && strcmp(e->u.dso.path, path) == 0)
237 break;
238 if (e) {
239 free(path);
240 } else {
241 loadlib(context, path); /* store or frees path */
244 closedir(d);
246 if (dirs != rk_UNCONST(sysplugin_dirs))
247 krb5_config_free_strings(dirs);
248 #endif /* HAVE_DLOPEN */
249 return 0;
252 static krb5_error_code
253 add_symbol(krb5_context context, struct krb5_plugin **list, void *symbol)
255 struct krb5_plugin *e;
257 e = calloc(1, sizeof(*e));
258 if (e == NULL) {
259 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
260 return ENOMEM;
262 e->symbol = symbol;
263 e->next = *list;
264 *list = e;
265 return 0;
268 krb5_error_code
269 _krb5_plugin_find(krb5_context context,
270 enum krb5_plugin_type type,
271 const char *name,
272 struct krb5_plugin **list)
274 struct plugin *e;
275 krb5_error_code ret;
277 *list = NULL;
279 HEIMDAL_MUTEX_lock(&plugin_mutex);
281 load_plugins(context);
283 for (ret = 0, e = registered; e != NULL; e = e->next) {
284 switch(e->type) {
285 case DSO: {
286 void *sym;
287 if (e->u.dso.dsohandle == NULL)
288 continue;
289 sym = dlsym(e->u.dso.dsohandle, name);
290 if (sym)
291 ret = add_symbol(context, list, sym);
292 break;
294 case SYMBOL:
295 if (strcmp(e->u.symbol.name, name) == 0 && e->u.symbol.type == type)
296 ret = add_symbol(context, list, e->u.symbol.symbol);
297 break;
299 if (ret) {
300 _krb5_plugin_free(*list);
301 *list = NULL;
305 HEIMDAL_MUTEX_unlock(&plugin_mutex);
306 if (ret)
307 return ret;
309 if (*list == NULL) {
310 krb5_set_error_message(context, ENOENT, "Did not find a plugin for %s", name);
311 return ENOENT;
314 return 0;
317 void
318 _krb5_plugin_free(struct krb5_plugin *list)
320 struct krb5_plugin *next;
321 while (list) {
322 next = list->next;
323 free(list);
324 list = next;