1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray * All rights reserved.
5b528cefcSMark Murray *
6*ae771770SStanislav Sedov * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7*ae771770SStanislav Sedov *
8b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without
9b528cefcSMark Murray * modification, are permitted provided that the following conditions
10b528cefcSMark Murray * are met:
11b528cefcSMark Murray *
12b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright
13b528cefcSMark Murray * notice, this list of conditions and the following disclaimer.
14b528cefcSMark Murray *
15b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
16b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the
17b528cefcSMark Murray * documentation and/or other materials provided with the distribution.
18b528cefcSMark Murray *
19b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors
20b528cefcSMark Murray * may be used to endorse or promote products derived from this software
21b528cefcSMark Murray * without specific prior written permission.
22b528cefcSMark Murray *
23b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33b528cefcSMark Murray * SUCH DAMAGE.
34b528cefcSMark Murray */
35b528cefcSMark Murray
36*ae771770SStanislav Sedov #include "krb5_locl.h"
37b528cefcSMark Murray #include "hdb_locl.h"
38b528cefcSMark Murray
39c19800e8SDoug Rabson #ifdef HAVE_DLFCN_H
40c19800e8SDoug Rabson #include <dlfcn.h>
41c19800e8SDoug Rabson #endif
425e9cd1aeSAssar Westerlund
43*ae771770SStanislav Sedov /*! @mainpage Heimdal database backend library
44*ae771770SStanislav Sedov *
45*ae771770SStanislav Sedov * @section intro Introduction
46*ae771770SStanislav Sedov *
47*ae771770SStanislav Sedov * Heimdal libhdb library provides the backend support for Heimdal kdc
48*ae771770SStanislav Sedov * and kadmind. Its here where plugins for diffrent database engines
49*ae771770SStanislav Sedov * can be pluged in and extend support for here Heimdal get the
50*ae771770SStanislav Sedov * principal and policy data from.
51*ae771770SStanislav Sedov *
52*ae771770SStanislav Sedov * Example of Heimdal backend are:
53*ae771770SStanislav Sedov * - Berkeley DB 1.85
54*ae771770SStanislav Sedov * - Berkeley DB 3.0
55*ae771770SStanislav Sedov * - Berkeley DB 4.0
56*ae771770SStanislav Sedov * - New Berkeley DB
57*ae771770SStanislav Sedov * - LDAP
58*ae771770SStanislav Sedov *
59*ae771770SStanislav Sedov *
60*ae771770SStanislav Sedov * The project web page: http://www.h5l.org/
61*ae771770SStanislav Sedov *
62*ae771770SStanislav Sedov */
63*ae771770SStanislav Sedov
64*ae771770SStanislav Sedov const int hdb_interface_version = HDB_INTERFACE_VERSION;
655e9cd1aeSAssar Westerlund
665e9cd1aeSAssar Westerlund static struct hdb_method methods[] = {
674137ff4cSJacques Vidrine #if HAVE_DB1 || HAVE_DB3
68*ae771770SStanislav Sedov { HDB_INTERFACE_VERSION, "db:", hdb_db_create},
69*ae771770SStanislav Sedov #endif
70*ae771770SStanislav Sedov #if HAVE_DB1
71*ae771770SStanislav Sedov { HDB_INTERFACE_VERSION, "mit-db:", hdb_mdb_create},
725e9cd1aeSAssar Westerlund #endif
734137ff4cSJacques Vidrine #if HAVE_NDBM
74*ae771770SStanislav Sedov { HDB_INTERFACE_VERSION, "ndbm:", hdb_ndbm_create},
755e9cd1aeSAssar Westerlund #endif
76*ae771770SStanislav Sedov { HDB_INTERFACE_VERSION, "keytab:", hdb_keytab_create},
77c19800e8SDoug Rabson #if defined(OPENLDAP) && !defined(OPENLDAP_MODULE)
78*ae771770SStanislav Sedov { HDB_INTERFACE_VERSION, "ldap:", hdb_ldap_create},
79*ae771770SStanislav Sedov { HDB_INTERFACE_VERSION, "ldapi:", hdb_ldapi_create},
805e9cd1aeSAssar Westerlund #endif
81*ae771770SStanislav Sedov #ifdef HAVE_SQLITE3
82*ae771770SStanislav Sedov { HDB_INTERFACE_VERSION, "sqlite:", hdb_sqlite_create},
835e9cd1aeSAssar Westerlund #endif
84*ae771770SStanislav Sedov {0, NULL, NULL}
855e9cd1aeSAssar Westerlund };
86b528cefcSMark Murray
87c19800e8SDoug Rabson #if HAVE_DB1 || HAVE_DB3
88*ae771770SStanislav Sedov static struct hdb_method dbmetod =
89*ae771770SStanislav Sedov { HDB_INTERFACE_VERSION, "", hdb_db_create };
90c19800e8SDoug Rabson #elif defined(HAVE_NDBM)
91*ae771770SStanislav Sedov static struct hdb_method dbmetod =
92*ae771770SStanislav Sedov { HDB_INTERFACE_VERSION, "", hdb_ndbm_create };
93c19800e8SDoug Rabson #endif
94c19800e8SDoug Rabson
95c19800e8SDoug Rabson
96b528cefcSMark Murray krb5_error_code
hdb_next_enctype2key(krb5_context context,const hdb_entry * e,krb5_enctype enctype,Key ** key)97b528cefcSMark Murray hdb_next_enctype2key(krb5_context context,
985e9cd1aeSAssar Westerlund const hdb_entry *e,
99b528cefcSMark Murray krb5_enctype enctype,
100b528cefcSMark Murray Key **key)
101b528cefcSMark Murray {
102b528cefcSMark Murray Key *k;
103b528cefcSMark Murray
1045e9cd1aeSAssar Westerlund for (k = *key ? (*key) + 1 : e->keys.val;
105b528cefcSMark Murray k < e->keys.val + e->keys.len;
106b528cefcSMark Murray k++)
107c19800e8SDoug Rabson {
108b528cefcSMark Murray if(k->key.keytype == enctype){
109b528cefcSMark Murray *key = k;
110b528cefcSMark Murray return 0;
111b528cefcSMark Murray }
112c19800e8SDoug Rabson }
113*ae771770SStanislav Sedov krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
114*ae771770SStanislav Sedov "No next enctype %d for hdb-entry",
115c19800e8SDoug Rabson (int)enctype);
116b528cefcSMark Murray return KRB5_PROG_ETYPE_NOSUPP; /* XXX */
117b528cefcSMark Murray }
118b528cefcSMark Murray
119b528cefcSMark Murray krb5_error_code
hdb_enctype2key(krb5_context context,hdb_entry * e,krb5_enctype enctype,Key ** key)120b528cefcSMark Murray hdb_enctype2key(krb5_context context,
121b528cefcSMark Murray hdb_entry *e,
122b528cefcSMark Murray krb5_enctype enctype,
123b528cefcSMark Murray Key **key)
124b528cefcSMark Murray {
125b528cefcSMark Murray *key = NULL;
126b528cefcSMark Murray return hdb_next_enctype2key(context, e, enctype, key);
127b528cefcSMark Murray }
128b528cefcSMark Murray
129b528cefcSMark Murray void
hdb_free_key(Key * key)130b528cefcSMark Murray hdb_free_key(Key *key)
131b528cefcSMark Murray {
132b528cefcSMark Murray memset(key->key.keyvalue.data,
133b528cefcSMark Murray 0,
134b528cefcSMark Murray key->key.keyvalue.length);
135b528cefcSMark Murray free_Key(key);
136b528cefcSMark Murray free(key);
137b528cefcSMark Murray }
138b528cefcSMark Murray
139b528cefcSMark Murray
140b528cefcSMark Murray krb5_error_code
hdb_lock(int fd,int operation)141b528cefcSMark Murray hdb_lock(int fd, int operation)
142b528cefcSMark Murray {
1435e9cd1aeSAssar Westerlund int i, code = 0;
1445e9cd1aeSAssar Westerlund
145b528cefcSMark Murray for(i = 0; i < 3; i++){
146b528cefcSMark Murray code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB);
147b528cefcSMark Murray if(code == 0 || errno != EWOULDBLOCK)
148b528cefcSMark Murray break;
149b528cefcSMark Murray sleep(1);
150b528cefcSMark Murray }
151b528cefcSMark Murray if(code == 0)
152b528cefcSMark Murray return 0;
153b528cefcSMark Murray if(errno == EWOULDBLOCK)
154b528cefcSMark Murray return HDB_ERR_DB_INUSE;
155b528cefcSMark Murray return HDB_ERR_CANT_LOCK_DB;
156b528cefcSMark Murray }
157b528cefcSMark Murray
158b528cefcSMark Murray krb5_error_code
hdb_unlock(int fd)159b528cefcSMark Murray hdb_unlock(int fd)
160b528cefcSMark Murray {
161b528cefcSMark Murray int code;
162b528cefcSMark Murray code = flock(fd, LOCK_UN);
163b528cefcSMark Murray if(code)
164b528cefcSMark Murray return 4711 /* XXX */;
165b528cefcSMark Murray return 0;
166b528cefcSMark Murray }
167b528cefcSMark Murray
168b528cefcSMark Murray void
hdb_free_entry(krb5_context context,hdb_entry_ex * ent)169c19800e8SDoug Rabson hdb_free_entry(krb5_context context, hdb_entry_ex *ent)
170b528cefcSMark Murray {
171*ae771770SStanislav Sedov size_t i;
172b528cefcSMark Murray
173c19800e8SDoug Rabson if (ent->free_entry)
174c19800e8SDoug Rabson (*ent->free_entry)(context, ent);
175c19800e8SDoug Rabson
176c19800e8SDoug Rabson for(i = 0; i < ent->entry.keys.len; ++i) {
177c19800e8SDoug Rabson Key *k = &ent->entry.keys.val[i];
178b528cefcSMark Murray
179b528cefcSMark Murray memset (k->key.keyvalue.data, 0, k->key.keyvalue.length);
180b528cefcSMark Murray }
181c19800e8SDoug Rabson free_hdb_entry(&ent->entry);
182b528cefcSMark Murray }
183b528cefcSMark Murray
184b528cefcSMark Murray krb5_error_code
hdb_foreach(krb5_context context,HDB * db,unsigned flags,hdb_foreach_func_t func,void * data)185b528cefcSMark Murray hdb_foreach(krb5_context context,
186b528cefcSMark Murray HDB *db,
187b528cefcSMark Murray unsigned flags,
188b528cefcSMark Murray hdb_foreach_func_t func,
189b528cefcSMark Murray void *data)
190b528cefcSMark Murray {
191b528cefcSMark Murray krb5_error_code ret;
192c19800e8SDoug Rabson hdb_entry_ex entry;
193c19800e8SDoug Rabson ret = db->hdb_firstkey(context, db, flags, &entry);
194c19800e8SDoug Rabson if (ret == 0)
195*ae771770SStanislav Sedov krb5_clear_error_message(context);
196b528cefcSMark Murray while(ret == 0){
197b528cefcSMark Murray ret = (*func)(context, db, &entry, data);
198b528cefcSMark Murray hdb_free_entry(context, &entry);
199b528cefcSMark Murray if(ret == 0)
200c19800e8SDoug Rabson ret = db->hdb_nextkey(context, db, flags, &entry);
201b528cefcSMark Murray }
202b528cefcSMark Murray if(ret == HDB_ERR_NOENTRY)
203b528cefcSMark Murray ret = 0;
204b528cefcSMark Murray return ret;
205b528cefcSMark Murray }
206b528cefcSMark Murray
207b528cefcSMark Murray krb5_error_code
hdb_check_db_format(krb5_context context,HDB * db)208b528cefcSMark Murray hdb_check_db_format(krb5_context context, HDB *db)
209b528cefcSMark Murray {
210b528cefcSMark Murray krb5_data tag;
211b528cefcSMark Murray krb5_data version;
212c19800e8SDoug Rabson krb5_error_code ret, ret2;
213b528cefcSMark Murray unsigned ver;
214b528cefcSMark Murray int foo;
215b528cefcSMark Murray
216c19800e8SDoug Rabson ret = db->hdb_lock(context, db, HDB_RLOCK);
217b528cefcSMark Murray if (ret)
218b528cefcSMark Murray return ret;
219c19800e8SDoug Rabson
220*ae771770SStanislav Sedov tag.data = (void *)(intptr_t)HDB_DB_FORMAT_ENTRY;
221c19800e8SDoug Rabson tag.length = strlen(tag.data);
222c19800e8SDoug Rabson ret = (*db->hdb__get)(context, db, tag, &version);
223c19800e8SDoug Rabson ret2 = db->hdb_unlock(context, db);
224c19800e8SDoug Rabson if(ret)
225c19800e8SDoug Rabson return ret;
226c19800e8SDoug Rabson if (ret2)
227c19800e8SDoug Rabson return ret2;
228b528cefcSMark Murray foo = sscanf(version.data, "%u", &ver);
229b528cefcSMark Murray krb5_data_free (&version);
230b528cefcSMark Murray if (foo != 1)
231b528cefcSMark Murray return HDB_ERR_BADVERSION;
232b528cefcSMark Murray if(ver != HDB_DB_FORMAT)
233b528cefcSMark Murray return HDB_ERR_BADVERSION;
234b528cefcSMark Murray return 0;
235b528cefcSMark Murray }
236b528cefcSMark Murray
237b528cefcSMark Murray krb5_error_code
hdb_init_db(krb5_context context,HDB * db)238b528cefcSMark Murray hdb_init_db(krb5_context context, HDB *db)
239b528cefcSMark Murray {
240c19800e8SDoug Rabson krb5_error_code ret, ret2;
241b528cefcSMark Murray krb5_data tag;
242b528cefcSMark Murray krb5_data version;
243b528cefcSMark Murray char ver[32];
244b528cefcSMark Murray
245b528cefcSMark Murray ret = hdb_check_db_format(context, db);
246b528cefcSMark Murray if(ret != HDB_ERR_NOENTRY)
247b528cefcSMark Murray return ret;
248b528cefcSMark Murray
249c19800e8SDoug Rabson ret = db->hdb_lock(context, db, HDB_WLOCK);
250c19800e8SDoug Rabson if (ret)
251c19800e8SDoug Rabson return ret;
252c19800e8SDoug Rabson
253*ae771770SStanislav Sedov tag.data = (void *)(intptr_t)HDB_DB_FORMAT_ENTRY;
254b528cefcSMark Murray tag.length = strlen(tag.data);
255b528cefcSMark Murray snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT);
256b528cefcSMark Murray version.data = ver;
257b528cefcSMark Murray version.length = strlen(version.data) + 1; /* zero terminated */
258c19800e8SDoug Rabson ret = (*db->hdb__put)(context, db, 0, tag, version);
259c19800e8SDoug Rabson ret2 = db->hdb_unlock(context, db);
260c19800e8SDoug Rabson if (ret) {
261c19800e8SDoug Rabson if (ret2)
262*ae771770SStanislav Sedov krb5_clear_error_message(context);
263b528cefcSMark Murray return ret;
264b528cefcSMark Murray }
265c19800e8SDoug Rabson return ret2;
266c19800e8SDoug Rabson }
267c19800e8SDoug Rabson
268c19800e8SDoug Rabson #ifdef HAVE_DLOPEN
269c19800e8SDoug Rabson
270c19800e8SDoug Rabson /*
271c19800e8SDoug Rabson * Load a dynamic backend from /usr/heimdal/lib/hdb_NAME.so,
272c19800e8SDoug Rabson * looking for the hdb_NAME_create symbol.
273c19800e8SDoug Rabson */
274c19800e8SDoug Rabson
275c19800e8SDoug Rabson static const struct hdb_method *
find_dynamic_method(krb5_context context,const char * filename,const char ** rest)276c19800e8SDoug Rabson find_dynamic_method (krb5_context context,
277c19800e8SDoug Rabson const char *filename,
278c19800e8SDoug Rabson const char **rest)
279c19800e8SDoug Rabson {
280c19800e8SDoug Rabson static struct hdb_method method;
281c19800e8SDoug Rabson struct hdb_so_method *mso;
282c19800e8SDoug Rabson char *prefix, *path, *symbol;
283c19800e8SDoug Rabson const char *p;
284c19800e8SDoug Rabson void *dl;
285c19800e8SDoug Rabson size_t len;
286c19800e8SDoug Rabson
287c19800e8SDoug Rabson p = strchr(filename, ':');
288c19800e8SDoug Rabson
289c19800e8SDoug Rabson /* if no prefix, don't know what module to load, just ignore it */
290c19800e8SDoug Rabson if (p == NULL)
291c19800e8SDoug Rabson return NULL;
292c19800e8SDoug Rabson
293c19800e8SDoug Rabson len = p - filename;
294c19800e8SDoug Rabson *rest = filename + len + 1;
295c19800e8SDoug Rabson
296*ae771770SStanislav Sedov prefix = malloc(len + 1);
297c19800e8SDoug Rabson if (prefix == NULL)
298c19800e8SDoug Rabson krb5_errx(context, 1, "out of memory");
299*ae771770SStanislav Sedov strlcpy(prefix, filename, len + 1);
300c19800e8SDoug Rabson
301c19800e8SDoug Rabson if (asprintf(&path, LIBDIR "/hdb_%s.so", prefix) == -1)
302c19800e8SDoug Rabson krb5_errx(context, 1, "out of memory");
303c19800e8SDoug Rabson
304c19800e8SDoug Rabson #ifndef RTLD_NOW
305c19800e8SDoug Rabson #define RTLD_NOW 0
306c19800e8SDoug Rabson #endif
307c19800e8SDoug Rabson #ifndef RTLD_GLOBAL
308c19800e8SDoug Rabson #define RTLD_GLOBAL 0
309c19800e8SDoug Rabson #endif
310c19800e8SDoug Rabson
311c19800e8SDoug Rabson dl = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
312c19800e8SDoug Rabson if (dl == NULL) {
313c19800e8SDoug Rabson krb5_warnx(context, "error trying to load dynamic module %s: %s\n",
314c19800e8SDoug Rabson path, dlerror());
315c19800e8SDoug Rabson free(prefix);
316c19800e8SDoug Rabson free(path);
317c19800e8SDoug Rabson return NULL;
318c19800e8SDoug Rabson }
319c19800e8SDoug Rabson
320c19800e8SDoug Rabson if (asprintf(&symbol, "hdb_%s_interface", prefix) == -1)
321c19800e8SDoug Rabson krb5_errx(context, 1, "out of memory");
322c19800e8SDoug Rabson
323*ae771770SStanislav Sedov mso = (struct hdb_so_method *) dlsym(dl, symbol);
324c19800e8SDoug Rabson if (mso == NULL) {
325c19800e8SDoug Rabson krb5_warnx(context, "error finding symbol %s in %s: %s\n",
326c19800e8SDoug Rabson symbol, path, dlerror());
327c19800e8SDoug Rabson dlclose(dl);
328c19800e8SDoug Rabson free(symbol);
329c19800e8SDoug Rabson free(prefix);
330c19800e8SDoug Rabson free(path);
331c19800e8SDoug Rabson return NULL;
332c19800e8SDoug Rabson }
333c19800e8SDoug Rabson free(path);
334c19800e8SDoug Rabson free(symbol);
335c19800e8SDoug Rabson
336c19800e8SDoug Rabson if (mso->version != HDB_INTERFACE_VERSION) {
337c19800e8SDoug Rabson krb5_warnx(context,
338c19800e8SDoug Rabson "error wrong version in shared module %s "
339c19800e8SDoug Rabson "version: %d should have been %d\n",
340c19800e8SDoug Rabson prefix, mso->version, HDB_INTERFACE_VERSION);
341c19800e8SDoug Rabson dlclose(dl);
342c19800e8SDoug Rabson free(prefix);
343c19800e8SDoug Rabson return NULL;
344c19800e8SDoug Rabson }
345c19800e8SDoug Rabson
346c19800e8SDoug Rabson if (mso->create == NULL) {
347c19800e8SDoug Rabson krb5_errx(context, 1,
348c19800e8SDoug Rabson "no entry point function in shared mod %s ",
349c19800e8SDoug Rabson prefix);
350c19800e8SDoug Rabson dlclose(dl);
351c19800e8SDoug Rabson free(prefix);
352c19800e8SDoug Rabson return NULL;
353c19800e8SDoug Rabson }
354c19800e8SDoug Rabson
355c19800e8SDoug Rabson method.create = mso->create;
356c19800e8SDoug Rabson method.prefix = prefix;
357c19800e8SDoug Rabson
358c19800e8SDoug Rabson return &method;
359c19800e8SDoug Rabson }
360c19800e8SDoug Rabson #endif /* HAVE_DLOPEN */
361b528cefcSMark Murray
3625e9cd1aeSAssar Westerlund /*
3635e9cd1aeSAssar Westerlund * find the relevant method for `filename', returning a pointer to the
3645e9cd1aeSAssar Westerlund * rest in `rest'.
3655e9cd1aeSAssar Westerlund * return NULL if there's no such method.
3665e9cd1aeSAssar Westerlund */
3675e9cd1aeSAssar Westerlund
3685e9cd1aeSAssar Westerlund static const struct hdb_method *
find_method(const char * filename,const char ** rest)3695e9cd1aeSAssar Westerlund find_method (const char *filename, const char **rest)
3705e9cd1aeSAssar Westerlund {
3715e9cd1aeSAssar Westerlund const struct hdb_method *h;
3725e9cd1aeSAssar Westerlund
373c19800e8SDoug Rabson for (h = methods; h->prefix != NULL; ++h) {
3745e9cd1aeSAssar Westerlund if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0) {
3755e9cd1aeSAssar Westerlund *rest = filename + strlen(h->prefix);
3765e9cd1aeSAssar Westerlund return h;
3775e9cd1aeSAssar Westerlund }
378c19800e8SDoug Rabson }
379c19800e8SDoug Rabson #if defined(HAVE_DB1) || defined(HAVE_DB3) || defined(HAVE_NDBM)
380c19800e8SDoug Rabson if (strncmp(filename, "/", 1) == 0
381c19800e8SDoug Rabson || strncmp(filename, "./", 2) == 0
382c19800e8SDoug Rabson || strncmp(filename, "../", 3) == 0)
383c19800e8SDoug Rabson {
384c19800e8SDoug Rabson *rest = filename;
385c19800e8SDoug Rabson return &dbmetod;
386c19800e8SDoug Rabson }
387c19800e8SDoug Rabson #endif
388c19800e8SDoug Rabson
3895e9cd1aeSAssar Westerlund return NULL;
3905e9cd1aeSAssar Westerlund }
3915e9cd1aeSAssar Westerlund
392b528cefcSMark Murray krb5_error_code
hdb_list_builtin(krb5_context context,char ** list)393c19800e8SDoug Rabson hdb_list_builtin(krb5_context context, char **list)
394c19800e8SDoug Rabson {
395c19800e8SDoug Rabson const struct hdb_method *h;
396c19800e8SDoug Rabson size_t len = 0;
397c19800e8SDoug Rabson char *buf = NULL;
398c19800e8SDoug Rabson
399c19800e8SDoug Rabson for (h = methods; h->prefix != NULL; ++h) {
400c19800e8SDoug Rabson if (h->prefix[0] == '\0')
401c19800e8SDoug Rabson continue;
402c19800e8SDoug Rabson len += strlen(h->prefix) + 2;
403c19800e8SDoug Rabson }
404c19800e8SDoug Rabson
405c19800e8SDoug Rabson len += 1;
406c19800e8SDoug Rabson buf = malloc(len);
407c19800e8SDoug Rabson if (buf == NULL) {
408*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
409c19800e8SDoug Rabson return ENOMEM;
410c19800e8SDoug Rabson }
411c19800e8SDoug Rabson buf[0] = '\0';
412c19800e8SDoug Rabson
413c19800e8SDoug Rabson for (h = methods; h->prefix != NULL; ++h) {
414c19800e8SDoug Rabson if (h != methods)
415c19800e8SDoug Rabson strlcat(buf, ", ", len);
416c19800e8SDoug Rabson strlcat(buf, h->prefix, len);
417c19800e8SDoug Rabson }
418c19800e8SDoug Rabson *list = buf;
419c19800e8SDoug Rabson return 0;
420c19800e8SDoug Rabson }
421c19800e8SDoug Rabson
422c19800e8SDoug Rabson krb5_error_code
_hdb_keytab2hdb_entry(krb5_context context,const krb5_keytab_entry * ktentry,hdb_entry_ex * entry)423*ae771770SStanislav Sedov _hdb_keytab2hdb_entry(krb5_context context,
424*ae771770SStanislav Sedov const krb5_keytab_entry *ktentry,
425*ae771770SStanislav Sedov hdb_entry_ex *entry)
426*ae771770SStanislav Sedov {
427*ae771770SStanislav Sedov entry->entry.kvno = ktentry->vno;
428*ae771770SStanislav Sedov entry->entry.created_by.time = ktentry->timestamp;
429*ae771770SStanislav Sedov
430*ae771770SStanislav Sedov entry->entry.keys.val = calloc(1, sizeof(entry->entry.keys.val[0]));
431*ae771770SStanislav Sedov if (entry->entry.keys.val == NULL)
432*ae771770SStanislav Sedov return ENOMEM;
433*ae771770SStanislav Sedov entry->entry.keys.len = 1;
434*ae771770SStanislav Sedov
435*ae771770SStanislav Sedov entry->entry.keys.val[0].mkvno = NULL;
436*ae771770SStanislav Sedov entry->entry.keys.val[0].salt = NULL;
437*ae771770SStanislav Sedov
438*ae771770SStanislav Sedov return krb5_copy_keyblock_contents(context,
439*ae771770SStanislav Sedov &ktentry->keyblock,
440*ae771770SStanislav Sedov &entry->entry.keys.val[0].key);
441*ae771770SStanislav Sedov }
442*ae771770SStanislav Sedov
443*ae771770SStanislav Sedov /**
444*ae771770SStanislav Sedov * Create a handle for a Kerberos database
445*ae771770SStanislav Sedov *
446*ae771770SStanislav Sedov * Create a handle for a Kerberos database backend specified by a
447*ae771770SStanislav Sedov * filename. Doesn't create a file if its doesn't exists, you have to
448*ae771770SStanislav Sedov * use O_CREAT to tell the backend to create the file.
449*ae771770SStanislav Sedov */
450*ae771770SStanislav Sedov
451*ae771770SStanislav Sedov krb5_error_code
hdb_create(krb5_context context,HDB ** db,const char * filename)452b528cefcSMark Murray hdb_create(krb5_context context, HDB **db, const char *filename)
453b528cefcSMark Murray {
4545e9cd1aeSAssar Westerlund const struct hdb_method *h;
4555e9cd1aeSAssar Westerlund const char *residual;
456*ae771770SStanislav Sedov krb5_error_code ret;
457*ae771770SStanislav Sedov struct krb5_plugin *list = NULL, *e;
4585e9cd1aeSAssar Westerlund
459b528cefcSMark Murray if(filename == NULL)
460b528cefcSMark Murray filename = HDB_DEFAULT_DB;
4614137ff4cSJacques Vidrine krb5_add_et_list(context, initialize_hdb_error_table_r);
4625e9cd1aeSAssar Westerlund h = find_method (filename, &residual);
463*ae771770SStanislav Sedov
464*ae771770SStanislav Sedov if (h == NULL) {
465*ae771770SStanislav Sedov ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, "hdb", &list);
466*ae771770SStanislav Sedov if(ret == 0 && list != NULL) {
467*ae771770SStanislav Sedov for (e = list; e != NULL; e = _krb5_plugin_get_next(e)) {
468*ae771770SStanislav Sedov h = _krb5_plugin_get_symbol(e);
469*ae771770SStanislav Sedov if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0
470*ae771770SStanislav Sedov && h->interface_version == HDB_INTERFACE_VERSION) {
471*ae771770SStanislav Sedov residual = filename + strlen(h->prefix);
472*ae771770SStanislav Sedov break;
473*ae771770SStanislav Sedov }
474*ae771770SStanislav Sedov }
475*ae771770SStanislav Sedov if (e == NULL) {
476*ae771770SStanislav Sedov h = NULL;
477*ae771770SStanislav Sedov _krb5_plugin_free(list);
478*ae771770SStanislav Sedov }
479*ae771770SStanislav Sedov }
480*ae771770SStanislav Sedov }
481*ae771770SStanislav Sedov
482c19800e8SDoug Rabson #ifdef HAVE_DLOPEN
4835e9cd1aeSAssar Westerlund if (h == NULL)
484c19800e8SDoug Rabson h = find_dynamic_method (context, filename, &residual);
485c19800e8SDoug Rabson #endif
486c19800e8SDoug Rabson if (h == NULL)
487c19800e8SDoug Rabson krb5_errx(context, 1, "No database support for %s", filename);
4885e9cd1aeSAssar Westerlund return (*h->create)(context, db, residual);
489b528cefcSMark Murray }
490