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