source: branches/samba-3.5.x/source4/heimdal/lib/krb5/plugin.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 7.5 KB
Line 
1/*
2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
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.
16 *
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.
20 *
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.
32 */
33
34#include "krb5_locl.h"
35
36#ifdef HAVE_DLFCN_H
37#include <dlfcn.h>
38#endif
39#include <dirent.h>
40
41struct krb5_plugin {
42 void *symbol;
43 struct krb5_plugin *next;
44};
45
46struct 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;
60};
61
62static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER;
63static struct plugin *registered = NULL;
64static int plugins_needs_scan = 1;
65
66static const char *sysplugin_dirs[] = {
67 LIBDIR "/plugin/krb5",
68#ifdef __APPLE__
69 "/System/Library/KerberosPlugins/KerberosFrameworkPlugins",
70#endif
71 NULL
72};
73
74/*
75 *
76 */
77
78void *
79_krb5_plugin_get_symbol(struct krb5_plugin *p)
80{
81 return p->symbol;
82}
83
84struct krb5_plugin *
85_krb5_plugin_get_next(struct krb5_plugin *p)
86{
87 return p->next;
88}
89
90/*
91 *
92 */
93
94#ifdef HAVE_DLOPEN
95
96static krb5_error_code
97loadlib(krb5_context context, char *path)
98{
99 struct plugin *e;
100
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;
106 }
107
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;
118
119 e->next = registered;
120 registered = e;
121
122 return 0;
123}
124#endif /* HAVE_DLOPEN */
125
126/**
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.
134 *
135 * @ingroup krb5_support
136 */
137
138krb5_error_code
139krb5_plugin_register(krb5_context context,
140 enum krb5_plugin_type type,
141 const char *name,
142 void *symbol)
143{
144 struct plugin *e;
145
146 HEIMDAL_MUTEX_lock(&plugin_mutex);
147
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;
155 }
156 }
157
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;
163 }
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;
172 }
173 e->u.symbol.symbol = symbol;
174
175 e->next = registered;
176 registered = e;
177 HEIMDAL_MUTEX_unlock(&plugin_mutex);
178
179 return 0;
180}
181
182static krb5_error_code
183load_plugins(krb5_context context)
184{
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;
191
192 if (!plugins_needs_scan)
193 return 0;
194 plugins_needs_scan = 0;
195
196#ifdef HAVE_DLOPEN
197
198 dirs = krb5_config_get_strings(context, NULL, "libdefaults",
199 "plugin_dir", NULL);
200 if (dirs == NULL)
201 dirs = rk_UNCONST(sysplugin_dirs);
202
203 for (di = dirs; *di != NULL; di++) {
204
205 d = opendir(*di);
206 if (d == NULL)
207 continue;
208 rk_cloexec(dirfd(d));
209
210 while ((entry = readdir(d)) != NULL) {
211 char *n = entry->d_name;
212
213 /* skip . and .. */
214 if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0')))
215 continue;
216
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);
223 }
224#endif
225 if (path == NULL)
226 asprintf(&path, "%s/%s", *di, n);
227
228 if (path == NULL) {
229 ret = ENOMEM;
230 krb5_set_error_message(context, ret, "malloc: out of memory");
231 return ret;
232 }
233
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 */
242 }
243 }
244 closedir(d);
245 }
246 if (dirs != rk_UNCONST(sysplugin_dirs))
247 krb5_config_free_strings(dirs);
248#endif /* HAVE_DLOPEN */
249 return 0;
250}
251
252static krb5_error_code
253add_symbol(krb5_context context, struct krb5_plugin **list, void *symbol)
254{
255 struct krb5_plugin *e;
256
257 e = calloc(1, sizeof(*e));
258 if (e == NULL) {
259 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
260 return ENOMEM;
261 }
262 e->symbol = symbol;
263 e->next = *list;
264 *list = e;
265 return 0;
266}
267
268krb5_error_code
269_krb5_plugin_find(krb5_context context,
270 enum krb5_plugin_type type,
271 const char *name,
272 struct krb5_plugin **list)
273{
274 struct plugin *e;
275 krb5_error_code ret;
276
277 *list = NULL;
278
279 HEIMDAL_MUTEX_lock(&plugin_mutex);
280
281 load_plugins(context);
282
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;
293 }
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;
298 }
299 if (ret) {
300 _krb5_plugin_free(*list);
301 *list = NULL;
302 }
303 }
304
305 HEIMDAL_MUTEX_unlock(&plugin_mutex);
306 if (ret)
307 return ret;
308
309 if (*list == NULL) {
310 krb5_set_error_message(context, ENOENT, "Did not find a plugin for %s", name);
311 return ENOENT;
312 }
313
314 return 0;
315}
316
317void
318_krb5_plugin_free(struct krb5_plugin *list)
319{
320 struct krb5_plugin *next;
321 while (list) {
322 next = list->next;
323 free(list);
324 list = next;
325 }
326}
Note: See TracBrowser for help on using the repository browser.