xref: /freebsd/crypto/heimdal/lib/krb5/plugin.c (revision c19800e8cd5640693f36f2040db4ab5e8d738146)
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