xref: /freebsd-src/crypto/heimdal/lib/hdb/hdb.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
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