xref: /freebsd-src/crypto/heimdal/lib/hdb/keytab.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov  * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #include "hdb_locl.h"
35b528cefcSMark Murray 
36b528cefcSMark Murray /* keytab backend for HDB databases */
37b528cefcSMark Murray 
38b528cefcSMark Murray struct hdb_data {
39b528cefcSMark Murray     char *dbname;
40b528cefcSMark Murray     char *mkey;
41b528cefcSMark Murray };
42b528cefcSMark Murray 
43*ae771770SStanislav Sedov struct hdb_cursor {
44*ae771770SStanislav Sedov     HDB *db;
45*ae771770SStanislav Sedov     hdb_entry_ex hdb_entry;
46*ae771770SStanislav Sedov     int first, next;
47*ae771770SStanislav Sedov     int key_idx;
48*ae771770SStanislav Sedov };
49*ae771770SStanislav Sedov 
505e9cd1aeSAssar Westerlund /*
515e9cd1aeSAssar Westerlund  * the format for HDB keytabs is:
52*ae771770SStanislav Sedov  * HDB:[HDBFORMAT:database-specific-data[:mkey=mkey-file]]
535e9cd1aeSAssar Westerlund  */
545e9cd1aeSAssar Westerlund 
55*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
hdb_resolve(krb5_context context,const char * name,krb5_keytab id)56b528cefcSMark Murray hdb_resolve(krb5_context context, const char *name, krb5_keytab id)
57b528cefcSMark Murray {
58b528cefcSMark Murray     struct hdb_data *d;
59b528cefcSMark Murray     const char *db, *mkey;
605e9cd1aeSAssar Westerlund 
61b528cefcSMark Murray     d = malloc(sizeof(*d));
624137ff4cSJacques Vidrine     if(d == NULL) {
63*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
64b528cefcSMark Murray 	return ENOMEM;
654137ff4cSJacques Vidrine     }
66b528cefcSMark Murray     db = name;
67*ae771770SStanislav Sedov     mkey = strstr(name, ":mkey=");
68*ae771770SStanislav Sedov     if(mkey == NULL || mkey[5] == '\0') {
69b528cefcSMark Murray 	if(*name == '\0')
70b528cefcSMark Murray 	    d->dbname = NULL;
71b528cefcSMark Murray 	else {
72b528cefcSMark Murray 	    d->dbname = strdup(name);
73b528cefcSMark Murray 	    if(d->dbname == NULL) {
74b528cefcSMark Murray 		free(d);
75*ae771770SStanislav Sedov 		krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
76b528cefcSMark Murray 		return ENOMEM;
77b528cefcSMark Murray 	    }
78b528cefcSMark Murray 	}
79b528cefcSMark Murray 	d->mkey = NULL;
80b528cefcSMark Murray     } else {
81c19800e8SDoug Rabson 	d->dbname = malloc(mkey - db + 1);
82b528cefcSMark Murray 	if(d->dbname == NULL) {
83b528cefcSMark Murray 	    free(d);
84*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
85b528cefcSMark Murray 	    return ENOMEM;
86b528cefcSMark Murray 	}
875e9cd1aeSAssar Westerlund 	memmove(d->dbname, db, mkey - db);
88b528cefcSMark Murray 	d->dbname[mkey - db] = '\0';
89*ae771770SStanislav Sedov 
90*ae771770SStanislav Sedov 	d->mkey = strdup(mkey + 5);
91b528cefcSMark Murray 	if(d->mkey == NULL) {
92b528cefcSMark Murray 	    free(d->dbname);
93b528cefcSMark Murray 	    free(d);
94*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
95b528cefcSMark Murray 	    return ENOMEM;
96b528cefcSMark Murray 	}
97b528cefcSMark Murray     }
98b528cefcSMark Murray     id->data = d;
99b528cefcSMark Murray     return 0;
100b528cefcSMark Murray }
101b528cefcSMark Murray 
102*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
hdb_close(krb5_context context,krb5_keytab id)103b528cefcSMark Murray hdb_close(krb5_context context, krb5_keytab id)
104b528cefcSMark Murray {
105b528cefcSMark Murray     struct hdb_data *d = id->data;
1065e9cd1aeSAssar Westerlund 
1075e9cd1aeSAssar Westerlund     free(d->dbname);
1085e9cd1aeSAssar Westerlund     free(d->mkey);
109b528cefcSMark Murray     free(d);
110b528cefcSMark Murray     return 0;
111b528cefcSMark Murray }
112b528cefcSMark Murray 
113*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
hdb_get_name(krb5_context context,krb5_keytab id,char * name,size_t namesize)114b528cefcSMark Murray hdb_get_name(krb5_context context,
115b528cefcSMark Murray 	     krb5_keytab id,
116b528cefcSMark Murray 	     char *name,
117b528cefcSMark Murray 	     size_t namesize)
118b528cefcSMark Murray {
119b528cefcSMark Murray     struct hdb_data *d = id->data;
1205e9cd1aeSAssar Westerlund 
121b528cefcSMark Murray     snprintf(name, namesize, "%s%s%s",
122b528cefcSMark Murray 	     d->dbname ? d->dbname : "",
123b528cefcSMark Murray 	     (d->dbname || d->mkey) ? ":" : "",
124b528cefcSMark Murray 	     d->mkey ? d->mkey : "");
125b528cefcSMark Murray     return 0;
126b528cefcSMark Murray }
127b528cefcSMark Murray 
1285e9cd1aeSAssar Westerlund /*
1295e9cd1aeSAssar Westerlund  * try to figure out the database (`dbname') and master-key (`mkey')
1305e9cd1aeSAssar Westerlund  * that should be used for `principal'.
1315e9cd1aeSAssar Westerlund  */
1325e9cd1aeSAssar Westerlund 
133*ae771770SStanislav Sedov static krb5_error_code
find_db(krb5_context context,char ** dbname,char ** mkey,krb5_const_principal principal)1345e9cd1aeSAssar Westerlund find_db (krb5_context context,
135*ae771770SStanislav Sedov 	 char **dbname,
136*ae771770SStanislav Sedov 	 char **mkey,
1375e9cd1aeSAssar Westerlund 	 krb5_const_principal principal)
1385e9cd1aeSAssar Westerlund {
139*ae771770SStanislav Sedov     krb5_const_realm realm = krb5_principal_get_realm(context, principal);
140*ae771770SStanislav Sedov     krb5_error_code ret;
141*ae771770SStanislav Sedov     struct hdb_dbinfo *head, *dbinfo = NULL;
1425e9cd1aeSAssar Westerlund 
1435e9cd1aeSAssar Westerlund     *dbname = *mkey = NULL;
1445e9cd1aeSAssar Westerlund 
145*ae771770SStanislav Sedov     ret = hdb_get_dbinfo(context, &head);
146*ae771770SStanislav Sedov     if (ret)
147*ae771770SStanislav Sedov 	return ret;
1485e9cd1aeSAssar Westerlund 
149*ae771770SStanislav Sedov     while ((dbinfo = hdb_dbinfo_get_next(head, dbinfo)) != NULL) {
150*ae771770SStanislav Sedov 	const char *p = hdb_dbinfo_get_realm(context, dbinfo);
151*ae771770SStanislav Sedov 	if (p && strcmp (realm, p) == 0) {
152*ae771770SStanislav Sedov 	    p = hdb_dbinfo_get_dbname(context, dbinfo);
153*ae771770SStanislav Sedov 	    if (p)
154*ae771770SStanislav Sedov 		*dbname = strdup(p);
155*ae771770SStanislav Sedov 	    p = hdb_dbinfo_get_mkey_file(context, dbinfo);
156*ae771770SStanislav Sedov 	    if (p)
157*ae771770SStanislav Sedov 		*mkey = strdup(p);
1585e9cd1aeSAssar Westerlund 	    break;
1595e9cd1aeSAssar Westerlund 	}
1605e9cd1aeSAssar Westerlund     }
161*ae771770SStanislav Sedov     hdb_free_dbinfo(context, &head);
1625e9cd1aeSAssar Westerlund     if (*dbname == NULL)
163*ae771770SStanislav Sedov 	*dbname = strdup(HDB_DEFAULT_DB);
164*ae771770SStanislav Sedov     return 0;
1655e9cd1aeSAssar Westerlund }
1665e9cd1aeSAssar Westerlund 
1675e9cd1aeSAssar Westerlund /*
1685e9cd1aeSAssar Westerlund  * find the keytab entry in `id' for `principal, kvno, enctype' and return
1695e9cd1aeSAssar Westerlund  * it in `entry'.  return 0 or an error code
1705e9cd1aeSAssar Westerlund  */
1715e9cd1aeSAssar Westerlund 
172*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
hdb_get_entry(krb5_context context,krb5_keytab id,krb5_const_principal principal,krb5_kvno kvno,krb5_enctype enctype,krb5_keytab_entry * entry)173b528cefcSMark Murray hdb_get_entry(krb5_context context,
174b528cefcSMark Murray 	      krb5_keytab id,
175b528cefcSMark Murray 	      krb5_const_principal principal,
176b528cefcSMark Murray 	      krb5_kvno kvno,
177b528cefcSMark Murray 	      krb5_enctype enctype,
178b528cefcSMark Murray 	      krb5_keytab_entry *entry)
179b528cefcSMark Murray {
180c19800e8SDoug Rabson     hdb_entry_ex ent;
181b528cefcSMark Murray     krb5_error_code ret;
182b528cefcSMark Murray     struct hdb_data *d = id->data;
1835e9cd1aeSAssar Westerlund     const char *dbname = d->dbname;
1845e9cd1aeSAssar Westerlund     const char *mkey   = d->mkey;
185*ae771770SStanislav Sedov     char *fdbname = NULL, *fmkey = NULL;
186*ae771770SStanislav Sedov     HDB *db;
187*ae771770SStanislav Sedov     size_t i;
188b528cefcSMark Murray 
189c19800e8SDoug Rabson     memset(&ent, 0, sizeof(ent));
190c19800e8SDoug Rabson 
191*ae771770SStanislav Sedov     if (dbname == NULL) {
192*ae771770SStanislav Sedov 	ret = find_db(context, &fdbname, &fmkey, principal);
193*ae771770SStanislav Sedov 	if (ret)
194*ae771770SStanislav Sedov 	    return ret;
195*ae771770SStanislav Sedov 	dbname = fdbname;
196*ae771770SStanislav Sedov 	mkey = fmkey;
197*ae771770SStanislav Sedov     }
1985e9cd1aeSAssar Westerlund 
1995e9cd1aeSAssar Westerlund     ret = hdb_create (context, &db, dbname);
200b528cefcSMark Murray     if (ret)
201*ae771770SStanislav Sedov 	goto out2;
2025e9cd1aeSAssar Westerlund     ret = hdb_set_master_keyfile (context, db, mkey);
2035e9cd1aeSAssar Westerlund     if (ret) {
204c19800e8SDoug Rabson 	(*db->hdb_destroy)(context, db);
205*ae771770SStanislav Sedov 	goto out2;
2065e9cd1aeSAssar Westerlund     }
2075e9cd1aeSAssar Westerlund 
208c19800e8SDoug Rabson     ret = (*db->hdb_open)(context, db, O_RDONLY, 0);
2095e9cd1aeSAssar Westerlund     if (ret) {
210c19800e8SDoug Rabson 	(*db->hdb_destroy)(context, db);
211*ae771770SStanislav Sedov 	goto out2;
2125e9cd1aeSAssar Westerlund     }
213*ae771770SStanislav Sedov 
214*ae771770SStanislav Sedov     ret = (*db->hdb_fetch_kvno)(context, db, principal,
215*ae771770SStanislav Sedov 				HDB_F_DECRYPT|HDB_F_KVNO_SPECIFIED|
216c19800e8SDoug Rabson 				HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
217*ae771770SStanislav Sedov 				kvno, &ent);
2185e9cd1aeSAssar Westerlund 
219c19800e8SDoug Rabson     if(ret == HDB_ERR_NOENTRY) {
220c19800e8SDoug Rabson 	ret = KRB5_KT_NOTFOUND;
221c19800e8SDoug Rabson 	goto out;
222c19800e8SDoug Rabson     }else if(ret)
223c19800e8SDoug Rabson 	goto out;
224c19800e8SDoug Rabson 
225*ae771770SStanislav Sedov     if(kvno && (krb5_kvno)ent.entry.kvno != kvno) {
226b528cefcSMark Murray 	hdb_free_entry(context, &ent);
227c19800e8SDoug Rabson  	ret = KRB5_KT_NOTFOUND;
228c19800e8SDoug Rabson 	goto out;
229b528cefcSMark Murray     }
230b528cefcSMark Murray     if(enctype == 0)
231c19800e8SDoug Rabson 	if(ent.entry.keys.len > 0)
232c19800e8SDoug Rabson 	    enctype = ent.entry.keys.val[0].key.keytype;
233b528cefcSMark Murray     ret = KRB5_KT_NOTFOUND;
234c19800e8SDoug Rabson     for(i = 0; i < ent.entry.keys.len; i++) {
235c19800e8SDoug Rabson 	if(ent.entry.keys.val[i].key.keytype == enctype) {
236b528cefcSMark Murray 	    krb5_copy_principal(context, principal, &entry->principal);
237c19800e8SDoug Rabson 	    entry->vno = ent.entry.kvno;
238b528cefcSMark Murray 	    krb5_copy_keyblock_contents(context,
239c19800e8SDoug Rabson 					&ent.entry.keys.val[i].key,
240b528cefcSMark Murray 					&entry->keyblock);
241b528cefcSMark Murray 	    ret = 0;
242b528cefcSMark Murray 	    break;
243b528cefcSMark Murray 	}
244b528cefcSMark Murray     }
245b528cefcSMark Murray     hdb_free_entry(context, &ent);
246c19800e8SDoug Rabson  out:
247c19800e8SDoug Rabson     (*db->hdb_close)(context, db);
248c19800e8SDoug Rabson     (*db->hdb_destroy)(context, db);
249*ae771770SStanislav Sedov  out2:
250*ae771770SStanislav Sedov     free(fdbname);
251*ae771770SStanislav Sedov     free(fmkey);
252b528cefcSMark Murray     return ret;
253b528cefcSMark Murray }
254b528cefcSMark Murray 
255*ae771770SStanislav Sedov /*
256*ae771770SStanislav Sedov  * find the keytab entry in `id' for `principal, kvno, enctype' and return
257*ae771770SStanislav Sedov  * it in `entry'.  return 0 or an error code
258*ae771770SStanislav Sedov  */
259*ae771770SStanislav Sedov 
260*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
hdb_start_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursor)261*ae771770SStanislav Sedov hdb_start_seq_get(krb5_context context,
262*ae771770SStanislav Sedov 		  krb5_keytab id,
263*ae771770SStanislav Sedov 		  krb5_kt_cursor *cursor)
264*ae771770SStanislav Sedov {
265*ae771770SStanislav Sedov     krb5_error_code ret;
266*ae771770SStanislav Sedov     struct hdb_cursor *c;
267*ae771770SStanislav Sedov     struct hdb_data *d = id->data;
268*ae771770SStanislav Sedov     const char *dbname = d->dbname;
269*ae771770SStanislav Sedov     const char *mkey   = d->mkey;
270*ae771770SStanislav Sedov     HDB *db;
271*ae771770SStanislav Sedov 
272*ae771770SStanislav Sedov     if (dbname == NULL) {
273*ae771770SStanislav Sedov 	/*
274*ae771770SStanislav Sedov 	 * We don't support enumerating without being told what
275*ae771770SStanislav Sedov 	 * backend to enumerate on
276*ae771770SStanislav Sedov 	 */
277*ae771770SStanislav Sedov   	ret = KRB5_KT_NOTFOUND;
278*ae771770SStanislav Sedov 	return ret;
279*ae771770SStanislav Sedov     }
280*ae771770SStanislav Sedov 
281*ae771770SStanislav Sedov     ret = hdb_create (context, &db, dbname);
282*ae771770SStanislav Sedov     if (ret)
283*ae771770SStanislav Sedov 	return ret;
284*ae771770SStanislav Sedov     ret = hdb_set_master_keyfile (context, db, mkey);
285*ae771770SStanislav Sedov     if (ret) {
286*ae771770SStanislav Sedov 	(*db->hdb_destroy)(context, db);
287*ae771770SStanislav Sedov 	return ret;
288*ae771770SStanislav Sedov     }
289*ae771770SStanislav Sedov 
290*ae771770SStanislav Sedov     ret = (*db->hdb_open)(context, db, O_RDONLY, 0);
291*ae771770SStanislav Sedov     if (ret) {
292*ae771770SStanislav Sedov 	(*db->hdb_destroy)(context, db);
293*ae771770SStanislav Sedov 	return ret;
294*ae771770SStanislav Sedov     }
295*ae771770SStanislav Sedov 
296*ae771770SStanislav Sedov     cursor->data = c = malloc (sizeof(*c));
297*ae771770SStanislav Sedov     if(c == NULL){
298*ae771770SStanislav Sedov 	(*db->hdb_close)(context, db);
299*ae771770SStanislav Sedov 	(*db->hdb_destroy)(context, db);
300*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
301*ae771770SStanislav Sedov 	return ENOMEM;
302*ae771770SStanislav Sedov     }
303*ae771770SStanislav Sedov 
304*ae771770SStanislav Sedov     c->db = db;
305*ae771770SStanislav Sedov     c->first = TRUE;
306*ae771770SStanislav Sedov     c->next = TRUE;
307*ae771770SStanislav Sedov     c->key_idx = 0;
308*ae771770SStanislav Sedov 
309*ae771770SStanislav Sedov     cursor->data = c;
310*ae771770SStanislav Sedov     return ret;
311*ae771770SStanislav Sedov }
312*ae771770SStanislav Sedov 
313*ae771770SStanislav Sedov static int KRB5_CALLCONV
hdb_next_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * cursor)314*ae771770SStanislav Sedov hdb_next_entry(krb5_context context,
315*ae771770SStanislav Sedov 	       krb5_keytab id,
316*ae771770SStanislav Sedov 	       krb5_keytab_entry *entry,
317*ae771770SStanislav Sedov 	       krb5_kt_cursor *cursor)
318*ae771770SStanislav Sedov {
319*ae771770SStanislav Sedov     struct hdb_cursor *c = cursor->data;
320*ae771770SStanislav Sedov     krb5_error_code ret;
321*ae771770SStanislav Sedov 
322*ae771770SStanislav Sedov     memset(entry, 0, sizeof(*entry));
323*ae771770SStanislav Sedov 
324*ae771770SStanislav Sedov     if (c->first) {
325*ae771770SStanislav Sedov 	c->first = FALSE;
326*ae771770SStanislav Sedov 	ret = (c->db->hdb_firstkey)(context, c->db,
327*ae771770SStanislav Sedov 				    HDB_F_DECRYPT|
328*ae771770SStanislav Sedov 				    HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
329*ae771770SStanislav Sedov 				    &c->hdb_entry);
330*ae771770SStanislav Sedov 	if (ret == HDB_ERR_NOENTRY)
331*ae771770SStanislav Sedov 	    return KRB5_KT_END;
332*ae771770SStanislav Sedov 	else if (ret)
333*ae771770SStanislav Sedov 	    return ret;
334*ae771770SStanislav Sedov 
335*ae771770SStanislav Sedov 	if (c->hdb_entry.entry.keys.len == 0)
336*ae771770SStanislav Sedov 	    hdb_free_entry(context, &c->hdb_entry);
337*ae771770SStanislav Sedov 	else
338*ae771770SStanislav Sedov 	    c->next = FALSE;
339*ae771770SStanislav Sedov     }
340*ae771770SStanislav Sedov 
341*ae771770SStanislav Sedov     while (c->next) {
342*ae771770SStanislav Sedov 	ret = (c->db->hdb_nextkey)(context, c->db,
343*ae771770SStanislav Sedov 				   HDB_F_DECRYPT|
344*ae771770SStanislav Sedov 				   HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
345*ae771770SStanislav Sedov 				   &c->hdb_entry);
346*ae771770SStanislav Sedov 	if (ret == HDB_ERR_NOENTRY)
347*ae771770SStanislav Sedov 	    return KRB5_KT_END;
348*ae771770SStanislav Sedov 	else if (ret)
349*ae771770SStanislav Sedov 	    return ret;
350*ae771770SStanislav Sedov 
351*ae771770SStanislav Sedov 	/* If no keys on this entry, try again */
352*ae771770SStanislav Sedov 	if (c->hdb_entry.entry.keys.len == 0)
353*ae771770SStanislav Sedov 	    hdb_free_entry(context, &c->hdb_entry);
354*ae771770SStanislav Sedov 	else
355*ae771770SStanislav Sedov 	    c->next = FALSE;
356*ae771770SStanislav Sedov     }
357*ae771770SStanislav Sedov 
358*ae771770SStanislav Sedov     /*
359*ae771770SStanislav Sedov      * Return next enc type (keytabs are one slot per key, while
360*ae771770SStanislav Sedov      * hdb is one record per principal.
361*ae771770SStanislav Sedov      */
362*ae771770SStanislav Sedov 
363*ae771770SStanislav Sedov     ret = krb5_copy_principal(context,
364*ae771770SStanislav Sedov 			      c->hdb_entry.entry.principal,
365*ae771770SStanislav Sedov 			      &entry->principal);
366*ae771770SStanislav Sedov     if (ret)
367*ae771770SStanislav Sedov 	return ret;
368*ae771770SStanislav Sedov 
369*ae771770SStanislav Sedov     entry->vno = c->hdb_entry.entry.kvno;
370*ae771770SStanislav Sedov     ret = krb5_copy_keyblock_contents(context,
371*ae771770SStanislav Sedov 				      &c->hdb_entry.entry.keys.val[c->key_idx].key,
372*ae771770SStanislav Sedov 				      &entry->keyblock);
373*ae771770SStanislav Sedov     if (ret) {
374*ae771770SStanislav Sedov 	krb5_free_principal(context, entry->principal);
375*ae771770SStanislav Sedov 	memset(entry, 0, sizeof(*entry));
376*ae771770SStanislav Sedov 	return ret;
377*ae771770SStanislav Sedov     }
378*ae771770SStanislav Sedov     c->key_idx++;
379*ae771770SStanislav Sedov 
380*ae771770SStanislav Sedov     /*
381*ae771770SStanislav Sedov      * Once we get to the end of the list, signal that we want the
382*ae771770SStanislav Sedov      * next entry
383*ae771770SStanislav Sedov      */
384*ae771770SStanislav Sedov 
385*ae771770SStanislav Sedov     if ((size_t)c->key_idx == c->hdb_entry.entry.keys.len) {
386*ae771770SStanislav Sedov 	hdb_free_entry(context, &c->hdb_entry);
387*ae771770SStanislav Sedov 	c->next = TRUE;
388*ae771770SStanislav Sedov 	c->key_idx = 0;
389*ae771770SStanislav Sedov     }
390*ae771770SStanislav Sedov 
391*ae771770SStanislav Sedov     return 0;
392*ae771770SStanislav Sedov }
393*ae771770SStanislav Sedov 
394*ae771770SStanislav Sedov 
395*ae771770SStanislav Sedov static int KRB5_CALLCONV
hdb_end_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursor)396*ae771770SStanislav Sedov hdb_end_seq_get(krb5_context context,
397*ae771770SStanislav Sedov 		krb5_keytab id,
398*ae771770SStanislav Sedov 		krb5_kt_cursor *cursor)
399*ae771770SStanislav Sedov {
400*ae771770SStanislav Sedov     struct hdb_cursor *c = cursor->data;
401*ae771770SStanislav Sedov 
402*ae771770SStanislav Sedov     if (!c->next)
403*ae771770SStanislav Sedov 	hdb_free_entry(context, &c->hdb_entry);
404*ae771770SStanislav Sedov 
405*ae771770SStanislav Sedov     (c->db->hdb_close)(context, c->db);
406*ae771770SStanislav Sedov     (c->db->hdb_destroy)(context, c->db);
407*ae771770SStanislav Sedov 
408*ae771770SStanislav Sedov     free(c);
409*ae771770SStanislav Sedov     return 0;
410*ae771770SStanislav Sedov }
411*ae771770SStanislav Sedov 
412b528cefcSMark Murray krb5_kt_ops hdb_kt_ops = {
413b528cefcSMark Murray     "HDB",
414b528cefcSMark Murray     hdb_resolve,
415b528cefcSMark Murray     hdb_get_name,
416b528cefcSMark Murray     hdb_close,
417*ae771770SStanislav Sedov     NULL,		/* destroy */
418b528cefcSMark Murray     hdb_get_entry,
419*ae771770SStanislav Sedov     hdb_start_seq_get,
420*ae771770SStanislav Sedov     hdb_next_entry,
421*ae771770SStanislav Sedov     hdb_end_seq_get,
422b528cefcSMark Murray     NULL,		/* add */
423b528cefcSMark Murray     NULL		/* remove */
424b528cefcSMark Murray };
425