xref: /minix3/crypto/external/bsd/heimdal/dist/lib/hdb/hdb-mitdb.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: hdb-mitdb.c,v 1.1.1.2 2014/04/24 12:45:28 pettai Exp $	*/
2ebfedea0SLionel Sambuc 
3ebfedea0SLionel Sambuc /*
4ebfedea0SLionel Sambuc  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
5ebfedea0SLionel Sambuc  * (Royal Institute of Technology, Stockholm, Sweden).
6ebfedea0SLionel Sambuc  * All rights reserved.
7ebfedea0SLionel Sambuc  *
8ebfedea0SLionel Sambuc  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9ebfedea0SLionel Sambuc  *
10ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
11ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
12ebfedea0SLionel Sambuc  * are met:
13ebfedea0SLionel Sambuc  *
14ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
15ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
16ebfedea0SLionel Sambuc  *
17ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
18ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
19ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
20ebfedea0SLionel Sambuc  *
21ebfedea0SLionel Sambuc  * 3. Neither the name of the Institute nor the names of its contributors
22ebfedea0SLionel Sambuc  *    may be used to endorse or promote products derived from this software
23ebfedea0SLionel Sambuc  *    without specific prior written permission.
24ebfedea0SLionel Sambuc  *
25ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26ebfedea0SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ebfedea0SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29ebfedea0SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30ebfedea0SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31ebfedea0SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32ebfedea0SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33ebfedea0SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34ebfedea0SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35ebfedea0SLionel Sambuc  * SUCH DAMAGE.
36ebfedea0SLionel Sambuc  */
37ebfedea0SLionel Sambuc 
38ebfedea0SLionel Sambuc #define KRB5_KDB_DISALLOW_POSTDATED	0x00000001
39ebfedea0SLionel Sambuc #define KRB5_KDB_DISALLOW_FORWARDABLE	0x00000002
40ebfedea0SLionel Sambuc #define KRB5_KDB_DISALLOW_TGT_BASED	0x00000004
41ebfedea0SLionel Sambuc #define KRB5_KDB_DISALLOW_RENEWABLE	0x00000008
42ebfedea0SLionel Sambuc #define KRB5_KDB_DISALLOW_PROXIABLE	0x00000010
43ebfedea0SLionel Sambuc #define KRB5_KDB_DISALLOW_DUP_SKEY	0x00000020
44ebfedea0SLionel Sambuc #define KRB5_KDB_DISALLOW_ALL_TIX	0x00000040
45ebfedea0SLionel Sambuc #define KRB5_KDB_REQUIRES_PRE_AUTH	0x00000080
46ebfedea0SLionel Sambuc #define KRB5_KDB_REQUIRES_HW_AUTH	0x00000100
47ebfedea0SLionel Sambuc #define KRB5_KDB_REQUIRES_PWCHANGE	0x00000200
48ebfedea0SLionel Sambuc #define KRB5_KDB_DISALLOW_SVR		0x00001000
49ebfedea0SLionel Sambuc #define KRB5_KDB_PWCHANGE_SERVICE	0x00002000
50ebfedea0SLionel Sambuc #define KRB5_KDB_SUPPORT_DESMD5		0x00004000
51ebfedea0SLionel Sambuc #define KRB5_KDB_NEW_PRINC		0x00008000
52ebfedea0SLionel Sambuc 
53ebfedea0SLionel Sambuc /*
54ebfedea0SLionel Sambuc 
55ebfedea0SLionel Sambuc key: krb5_unparse_name  + NUL
56ebfedea0SLionel Sambuc 
57ebfedea0SLionel Sambuc  16: baselength
58ebfedea0SLionel Sambuc  32: attributes
59ebfedea0SLionel Sambuc  32: max time
60ebfedea0SLionel Sambuc  32: max renewable time
61ebfedea0SLionel Sambuc  32: client expire
62ebfedea0SLionel Sambuc  32: passwd expire
63ebfedea0SLionel Sambuc  32: last successful passwd
64ebfedea0SLionel Sambuc  32: last failed attempt
65ebfedea0SLionel Sambuc  32: num of failed attempts
66ebfedea0SLionel Sambuc  16: num tl data
67ebfedea0SLionel Sambuc  16: num data data
68ebfedea0SLionel Sambuc  16: principal length
69ebfedea0SLionel Sambuc  length: principal
70ebfedea0SLionel Sambuc  for num tl data times
71ebfedea0SLionel Sambuc     16: tl data type
72ebfedea0SLionel Sambuc     16: tl data length
73ebfedea0SLionel Sambuc     length: length
74ebfedea0SLionel Sambuc  for num key data times
75ebfedea0SLionel Sambuc     16: version (num keyblocks)
76ebfedea0SLionel Sambuc     16: kvno
77ebfedea0SLionel Sambuc     for version times:
78ebfedea0SLionel Sambuc         16: type
79ebfedea0SLionel Sambuc         16: length
80ebfedea0SLionel Sambuc         length: keydata
81ebfedea0SLionel Sambuc 
82ebfedea0SLionel Sambuc 
83ebfedea0SLionel Sambuc key_data_contents[0]
84ebfedea0SLionel Sambuc 
85ebfedea0SLionel Sambuc 	int16: length
86ebfedea0SLionel Sambuc 	read-of-data: key-encrypted, key-usage 0, master-key
87ebfedea0SLionel Sambuc 
88ebfedea0SLionel Sambuc salt:
89ebfedea0SLionel Sambuc     version2 = salt in key_data->key_data_contents[1]
90ebfedea0SLionel Sambuc     else default salt.
91ebfedea0SLionel Sambuc 
92ebfedea0SLionel Sambuc */
93ebfedea0SLionel Sambuc 
94ebfedea0SLionel Sambuc #include "hdb_locl.h"
95ebfedea0SLionel Sambuc 
96ebfedea0SLionel Sambuc #define KDB_V1_BASE_LENGTH 38
97ebfedea0SLionel Sambuc 
98ebfedea0SLionel Sambuc #if HAVE_DB1
99ebfedea0SLionel Sambuc 
100ebfedea0SLionel Sambuc #if defined(HAVE_DB_185_H)
101ebfedea0SLionel Sambuc #include <db_185.h>
102ebfedea0SLionel Sambuc #elif defined(HAVE_DB_H)
103ebfedea0SLionel Sambuc #include <db.h>
104ebfedea0SLionel Sambuc #endif
105ebfedea0SLionel Sambuc 
106ebfedea0SLionel Sambuc #define CHECK(x) do { if ((x)) goto out; } while(0)
107ebfedea0SLionel Sambuc 
108ebfedea0SLionel Sambuc static krb5_error_code
mdb_principal2key(krb5_context context,krb5_const_principal principal,krb5_data * key)109ebfedea0SLionel Sambuc mdb_principal2key(krb5_context context,
110ebfedea0SLionel Sambuc 		  krb5_const_principal principal,
111ebfedea0SLionel Sambuc 		  krb5_data *key)
112ebfedea0SLionel Sambuc {
113ebfedea0SLionel Sambuc     krb5_error_code ret;
114ebfedea0SLionel Sambuc     char *str;
115ebfedea0SLionel Sambuc 
116ebfedea0SLionel Sambuc     ret = krb5_unparse_name(context, principal, &str);
117ebfedea0SLionel Sambuc     if (ret)
118ebfedea0SLionel Sambuc 	return ret;
119ebfedea0SLionel Sambuc     key->data = str;
120ebfedea0SLionel Sambuc     key->length = strlen(str) + 1;
121ebfedea0SLionel Sambuc     return 0;
122ebfedea0SLionel Sambuc }
123ebfedea0SLionel Sambuc 
124ebfedea0SLionel Sambuc #define KRB5_KDB_SALTTYPE_NORMAL	0
125ebfedea0SLionel Sambuc #define KRB5_KDB_SALTTYPE_V4		1
126ebfedea0SLionel Sambuc #define KRB5_KDB_SALTTYPE_NOREALM	2
127ebfedea0SLionel Sambuc #define KRB5_KDB_SALTTYPE_ONLYREALM	3
128ebfedea0SLionel Sambuc #define KRB5_KDB_SALTTYPE_SPECIAL	4
129ebfedea0SLionel Sambuc #define KRB5_KDB_SALTTYPE_AFS3		5
130ebfedea0SLionel Sambuc #define KRB5_KDB_SALTTYPE_CERTHASH	6
131ebfedea0SLionel Sambuc 
132ebfedea0SLionel Sambuc static krb5_error_code
fix_salt(krb5_context context,hdb_entry * ent,int key_num)133ebfedea0SLionel Sambuc fix_salt(krb5_context context, hdb_entry *ent, int key_num)
134ebfedea0SLionel Sambuc {
135ebfedea0SLionel Sambuc     krb5_error_code ret;
136ebfedea0SLionel Sambuc     Salt *salt = ent->keys.val[key_num].salt;
137ebfedea0SLionel Sambuc     /* fix salt type */
138ebfedea0SLionel Sambuc     switch((int)salt->type) {
139ebfedea0SLionel Sambuc     case KRB5_KDB_SALTTYPE_NORMAL:
140ebfedea0SLionel Sambuc 	salt->type = KRB5_PADATA_PW_SALT;
141ebfedea0SLionel Sambuc 	break;
142ebfedea0SLionel Sambuc     case KRB5_KDB_SALTTYPE_V4:
143ebfedea0SLionel Sambuc 	krb5_data_free(&salt->salt);
144ebfedea0SLionel Sambuc 	salt->type = KRB5_PADATA_PW_SALT;
145ebfedea0SLionel Sambuc 	break;
146ebfedea0SLionel Sambuc     case KRB5_KDB_SALTTYPE_NOREALM:
147ebfedea0SLionel Sambuc     {
148ebfedea0SLionel Sambuc 	size_t len;
149*0a6a1f1dSLionel Sambuc 	size_t i;
150ebfedea0SLionel Sambuc 	char *p;
151ebfedea0SLionel Sambuc 
152ebfedea0SLionel Sambuc 	len = 0;
153ebfedea0SLionel Sambuc 	for (i = 0; i < ent->principal->name.name_string.len; ++i)
154ebfedea0SLionel Sambuc 	    len += strlen(ent->principal->name.name_string.val[i]);
155ebfedea0SLionel Sambuc 	ret = krb5_data_alloc (&salt->salt, len);
156ebfedea0SLionel Sambuc 	if (ret)
157ebfedea0SLionel Sambuc 	    return ret;
158ebfedea0SLionel Sambuc 	p = salt->salt.data;
159ebfedea0SLionel Sambuc 	for (i = 0; i < ent->principal->name.name_string.len; ++i) {
160ebfedea0SLionel Sambuc 	    memcpy (p,
161ebfedea0SLionel Sambuc 		    ent->principal->name.name_string.val[i],
162ebfedea0SLionel Sambuc 		    strlen(ent->principal->name.name_string.val[i]));
163ebfedea0SLionel Sambuc 	    p += strlen(ent->principal->name.name_string.val[i]);
164ebfedea0SLionel Sambuc 	}
165ebfedea0SLionel Sambuc 
166ebfedea0SLionel Sambuc 	salt->type = KRB5_PADATA_PW_SALT;
167ebfedea0SLionel Sambuc 	break;
168ebfedea0SLionel Sambuc     }
169ebfedea0SLionel Sambuc     case KRB5_KDB_SALTTYPE_ONLYREALM:
170ebfedea0SLionel Sambuc 	krb5_data_free(&salt->salt);
171ebfedea0SLionel Sambuc 	ret = krb5_data_copy(&salt->salt,
172ebfedea0SLionel Sambuc 			     ent->principal->realm,
173ebfedea0SLionel Sambuc 			     strlen(ent->principal->realm));
174ebfedea0SLionel Sambuc 	if(ret)
175ebfedea0SLionel Sambuc 	    return ret;
176ebfedea0SLionel Sambuc 	salt->type = KRB5_PADATA_PW_SALT;
177ebfedea0SLionel Sambuc 	break;
178ebfedea0SLionel Sambuc     case KRB5_KDB_SALTTYPE_SPECIAL:
179ebfedea0SLionel Sambuc 	salt->type = KRB5_PADATA_PW_SALT;
180ebfedea0SLionel Sambuc 	break;
181ebfedea0SLionel Sambuc     case KRB5_KDB_SALTTYPE_AFS3:
182ebfedea0SLionel Sambuc 	krb5_data_free(&salt->salt);
183ebfedea0SLionel Sambuc 	ret = krb5_data_copy(&salt->salt,
184ebfedea0SLionel Sambuc 		       ent->principal->realm,
185ebfedea0SLionel Sambuc 		       strlen(ent->principal->realm));
186ebfedea0SLionel Sambuc 	if(ret)
187ebfedea0SLionel Sambuc 	    return ret;
188ebfedea0SLionel Sambuc 	salt->type = KRB5_PADATA_AFS3_SALT;
189ebfedea0SLionel Sambuc 	break;
190ebfedea0SLionel Sambuc     case KRB5_KDB_SALTTYPE_CERTHASH:
191ebfedea0SLionel Sambuc 	krb5_data_free(&salt->salt);
192ebfedea0SLionel Sambuc 	free(ent->keys.val[key_num].salt);
193ebfedea0SLionel Sambuc 	ent->keys.val[key_num].salt = NULL;
194ebfedea0SLionel Sambuc 	break;
195ebfedea0SLionel Sambuc     default:
196ebfedea0SLionel Sambuc 	abort();
197ebfedea0SLionel Sambuc     }
198ebfedea0SLionel Sambuc     return 0;
199ebfedea0SLionel Sambuc }
200ebfedea0SLionel Sambuc 
201ebfedea0SLionel Sambuc 
202ebfedea0SLionel Sambuc static krb5_error_code
mdb_value2entry(krb5_context context,krb5_data * data,krb5_kvno kvno,hdb_entry * entry)203ebfedea0SLionel Sambuc mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry)
204ebfedea0SLionel Sambuc {
205ebfedea0SLionel Sambuc     krb5_error_code ret;
206ebfedea0SLionel Sambuc     krb5_storage *sp;
207ebfedea0SLionel Sambuc     uint32_t u32;
208ebfedea0SLionel Sambuc     uint16_t u16, num_keys, num_tl;
209ebfedea0SLionel Sambuc     size_t i, j;
210ebfedea0SLionel Sambuc     char *p;
211ebfedea0SLionel Sambuc 
212ebfedea0SLionel Sambuc     sp = krb5_storage_from_data(data);
213ebfedea0SLionel Sambuc     if (sp == NULL) {
214ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM, "out of memory");
215ebfedea0SLionel Sambuc 	return ENOMEM;
216ebfedea0SLionel Sambuc     }
217ebfedea0SLionel Sambuc 
218ebfedea0SLionel Sambuc     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
219ebfedea0SLionel Sambuc 
220ebfedea0SLionel Sambuc     /*
221ebfedea0SLionel Sambuc      * 16: baselength
222ebfedea0SLionel Sambuc      *
223ebfedea0SLionel Sambuc      * The story here is that these 16 bits have to be a constant:
224ebfedea0SLionel Sambuc      * KDB_V1_BASE_LENGTH.  Once upon a time a different value here
225ebfedea0SLionel Sambuc      * would have been used to indicate the presence of "extra data"
226ebfedea0SLionel Sambuc      * between the "base" contents and the {principal name, TL data,
227ebfedea0SLionel Sambuc      * keys} that follow it.  Nothing supports such "extra data"
228ebfedea0SLionel Sambuc      * nowadays, so neither do we here.
229ebfedea0SLionel Sambuc      *
230ebfedea0SLionel Sambuc      * XXX But... surely we ought to log about this extra data, or skip
231ebfedea0SLionel Sambuc      * it, or something, in case anyone has MIT KDBs with ancient
232ebfedea0SLionel Sambuc      * entries in them...  Logging would allow the admin to know which
233ebfedea0SLionel Sambuc      * entries to dump with MIT krb5's kdb5_util.
234ebfedea0SLionel Sambuc      */
235ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint16(sp, &u16));
236ebfedea0SLionel Sambuc     if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; }
237ebfedea0SLionel Sambuc     /* 32: attributes */
238ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint32(sp, &u32));
239ebfedea0SLionel Sambuc     entry->flags.postdate =	 !(u32 & KRB5_KDB_DISALLOW_POSTDATED);
240ebfedea0SLionel Sambuc     entry->flags.forwardable =	 !(u32 & KRB5_KDB_DISALLOW_FORWARDABLE);
241ebfedea0SLionel Sambuc     entry->flags.initial =	!!(u32 & KRB5_KDB_DISALLOW_TGT_BASED);
242ebfedea0SLionel Sambuc     entry->flags.renewable =	 !(u32 & KRB5_KDB_DISALLOW_RENEWABLE);
243ebfedea0SLionel Sambuc     entry->flags.proxiable =	 !(u32 & KRB5_KDB_DISALLOW_PROXIABLE);
244ebfedea0SLionel Sambuc     /* DUP_SKEY */
245ebfedea0SLionel Sambuc     entry->flags.invalid =	!!(u32 & KRB5_KDB_DISALLOW_ALL_TIX);
246ebfedea0SLionel Sambuc     entry->flags.require_preauth =!!(u32 & KRB5_KDB_REQUIRES_PRE_AUTH);
247ebfedea0SLionel Sambuc     entry->flags.require_hwauth =!!(u32 & KRB5_KDB_REQUIRES_HW_AUTH);
248ebfedea0SLionel Sambuc     entry->flags.server =	 !(u32 & KRB5_KDB_DISALLOW_SVR);
249ebfedea0SLionel Sambuc     entry->flags.change_pw = 	!!(u32 & KRB5_KDB_PWCHANGE_SERVICE);
250ebfedea0SLionel Sambuc     entry->flags.client =	   1; /* XXX */
251ebfedea0SLionel Sambuc 
252ebfedea0SLionel Sambuc     /* 32: max time */
253ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint32(sp, &u32));
254ebfedea0SLionel Sambuc     if (u32) {
255ebfedea0SLionel Sambuc 	entry->max_life = malloc(sizeof(*entry->max_life));
256ebfedea0SLionel Sambuc 	*entry->max_life = u32;
257ebfedea0SLionel Sambuc     }
258ebfedea0SLionel Sambuc     /* 32: max renewable time */
259ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint32(sp, &u32));
260ebfedea0SLionel Sambuc     if (u32) {
261ebfedea0SLionel Sambuc 	entry->max_renew = malloc(sizeof(*entry->max_renew));
262ebfedea0SLionel Sambuc 	*entry->max_renew = u32;
263ebfedea0SLionel Sambuc     }
264ebfedea0SLionel Sambuc     /* 32: client expire */
265ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint32(sp, &u32));
266ebfedea0SLionel Sambuc     if (u32) {
267ebfedea0SLionel Sambuc 	entry->valid_end = malloc(sizeof(*entry->valid_end));
268ebfedea0SLionel Sambuc 	*entry->valid_end = u32;
269ebfedea0SLionel Sambuc     }
270ebfedea0SLionel Sambuc     /* 32: passwd expire */
271ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint32(sp, &u32));
272ebfedea0SLionel Sambuc     if (u32) {
273ebfedea0SLionel Sambuc 	entry->pw_end = malloc(sizeof(*entry->pw_end));
274ebfedea0SLionel Sambuc 	*entry->pw_end = u32;
275ebfedea0SLionel Sambuc     }
276ebfedea0SLionel Sambuc     /* 32: last successful passwd */
277ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint32(sp, &u32));
278ebfedea0SLionel Sambuc     /* 32: last failed attempt */
279ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint32(sp, &u32));
280ebfedea0SLionel Sambuc     /* 32: num of failed attempts */
281ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint32(sp, &u32));
282ebfedea0SLionel Sambuc     /* 16: num tl data */
283ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint16(sp, &u16));
284ebfedea0SLionel Sambuc     num_tl = u16;
285ebfedea0SLionel Sambuc     /* 16: num key data */
286ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint16(sp, &u16));
287ebfedea0SLionel Sambuc     num_keys = u16;
288ebfedea0SLionel Sambuc     /* 16: principal length */
289ebfedea0SLionel Sambuc     CHECK(ret = krb5_ret_uint16(sp, &u16));
290ebfedea0SLionel Sambuc     /* length: principal */
291ebfedea0SLionel Sambuc     {
292ebfedea0SLionel Sambuc 	/*
293ebfedea0SLionel Sambuc 	 * Note that the principal name includes the NUL in the entry,
294ebfedea0SLionel Sambuc 	 * but we don't want to take chances, so we add an extra NUL.
295ebfedea0SLionel Sambuc 	 */
296ebfedea0SLionel Sambuc 	p = malloc(u16 + 1);
297ebfedea0SLionel Sambuc 	if (p == NULL) {
298ebfedea0SLionel Sambuc 	    ret = ENOMEM;
299ebfedea0SLionel Sambuc 	    goto out;
300ebfedea0SLionel Sambuc 	}
301ebfedea0SLionel Sambuc 	krb5_storage_read(sp, p, u16);
302ebfedea0SLionel Sambuc 	p[u16] = '\0';
303ebfedea0SLionel Sambuc 	CHECK(ret = krb5_parse_name(context, p, &entry->principal));
304ebfedea0SLionel Sambuc 	free(p);
305ebfedea0SLionel Sambuc     }
306ebfedea0SLionel Sambuc     /* for num tl data times
307ebfedea0SLionel Sambuc            16: tl data type
308ebfedea0SLionel Sambuc            16: tl data length
309ebfedea0SLionel Sambuc            length: length */
310ebfedea0SLionel Sambuc     for (i = 0; i < num_tl; i++) {
311ebfedea0SLionel Sambuc 	/* 16: TL data type */
312ebfedea0SLionel Sambuc 	CHECK(ret = krb5_ret_uint16(sp, &u16));
313ebfedea0SLionel Sambuc 	/* 16: TL data length */
314ebfedea0SLionel Sambuc 	CHECK(ret = krb5_ret_uint16(sp, &u16));
315ebfedea0SLionel Sambuc 	krb5_storage_seek(sp, u16, SEEK_CUR);
316ebfedea0SLionel Sambuc     }
317ebfedea0SLionel Sambuc     /*
318ebfedea0SLionel Sambuc      * for num key data times
319ebfedea0SLionel Sambuc      * 16: "version"
320ebfedea0SLionel Sambuc      * 16: kvno
321ebfedea0SLionel Sambuc      * for version times:
322ebfedea0SLionel Sambuc      *     16: type
323ebfedea0SLionel Sambuc      *     16: length
324ebfedea0SLionel Sambuc      *     length: keydata
325ebfedea0SLionel Sambuc      *
326ebfedea0SLionel Sambuc      * "version" here is really 1 or 2, the first meaning there's only
327ebfedea0SLionel Sambuc      * keys for this kvno, the second meaning there's keys and salt[s?].
328ebfedea0SLionel Sambuc      * That's right... hold that gag reflex, you can do it.
329ebfedea0SLionel Sambuc      */
330ebfedea0SLionel Sambuc     for (i = 0; i < num_keys; i++) {
331ebfedea0SLionel Sambuc 	int keep = 0;
332ebfedea0SLionel Sambuc 	uint16_t version;
333ebfedea0SLionel Sambuc 	void *ptr;
334ebfedea0SLionel Sambuc 
335ebfedea0SLionel Sambuc 	CHECK(ret = krb5_ret_uint16(sp, &u16));
336ebfedea0SLionel Sambuc 	version = u16;
337ebfedea0SLionel Sambuc 	CHECK(ret = krb5_ret_uint16(sp, &u16));
338ebfedea0SLionel Sambuc 
339ebfedea0SLionel Sambuc 	/*
340ebfedea0SLionel Sambuc 	 * First time through, and until we find one matching key,
341ebfedea0SLionel Sambuc 	 * entry->kvno == 0.
342ebfedea0SLionel Sambuc 	 */
343ebfedea0SLionel Sambuc 	if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) {
344ebfedea0SLionel Sambuc 	    keep = 1;
345ebfedea0SLionel Sambuc 	    entry->kvno = u16;
346ebfedea0SLionel Sambuc 	    /*
347ebfedea0SLionel Sambuc 	     * Found a higher kvno than earlier, so free the old highest
348ebfedea0SLionel Sambuc 	     * kvno keys.
349ebfedea0SLionel Sambuc 	     *
350ebfedea0SLionel Sambuc 	     * XXX Of course, we actually want to extract the old kvnos
351ebfedea0SLionel Sambuc 	     * as well, for some of the kadm5 APIs.  We shouldn't free
352ebfedea0SLionel Sambuc 	     * these keys, but keep them elsewhere.
353ebfedea0SLionel Sambuc 	     */
354ebfedea0SLionel Sambuc 	    for (j = 0; j < entry->keys.len; j++)
355ebfedea0SLionel Sambuc 		free_Key(&entry->keys.val[j]);
356ebfedea0SLionel Sambuc 	    free(entry->keys.val);
357ebfedea0SLionel Sambuc 	    entry->keys.len = 0;
358ebfedea0SLionel Sambuc 	    entry->keys.val = NULL;
359ebfedea0SLionel Sambuc 	} else if (entry->kvno == u16)
360ebfedea0SLionel Sambuc 	    /* Accumulate keys */
361ebfedea0SLionel Sambuc 	    keep = 1;
362ebfedea0SLionel Sambuc 
363ebfedea0SLionel Sambuc 	if (keep) {
364ebfedea0SLionel Sambuc 	    Key *k;
365ebfedea0SLionel Sambuc 
366ebfedea0SLionel Sambuc 	    ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1));
367ebfedea0SLionel Sambuc 	    if (ptr == NULL) {
368ebfedea0SLionel Sambuc 		ret = ENOMEM;
369ebfedea0SLionel Sambuc 		goto out;
370ebfedea0SLionel Sambuc 	    }
371ebfedea0SLionel Sambuc 	    entry->keys.val = ptr;
372ebfedea0SLionel Sambuc 
373ebfedea0SLionel Sambuc 	    /* k points to current Key */
374ebfedea0SLionel Sambuc 	    k = &entry->keys.val[entry->keys.len];
375ebfedea0SLionel Sambuc 
376ebfedea0SLionel Sambuc 	    memset(k, 0, sizeof(*k));
377ebfedea0SLionel Sambuc 	    entry->keys.len += 1;
378ebfedea0SLionel Sambuc 
379ebfedea0SLionel Sambuc 	    k->mkvno = malloc(sizeof(*k->mkvno));
380ebfedea0SLionel Sambuc 	    if (k->mkvno == NULL) {
381ebfedea0SLionel Sambuc 		ret = ENOMEM;
382ebfedea0SLionel Sambuc 		goto out;
383ebfedea0SLionel Sambuc 	    }
384ebfedea0SLionel Sambuc 	    *k->mkvno = 1;
385ebfedea0SLionel Sambuc 
386ebfedea0SLionel Sambuc 	    for (j = 0; j < version; j++) {
387ebfedea0SLionel Sambuc 		uint16_t type;
388ebfedea0SLionel Sambuc 		CHECK(ret = krb5_ret_uint16(sp, &type));
389ebfedea0SLionel Sambuc 		CHECK(ret = krb5_ret_uint16(sp, &u16));
390ebfedea0SLionel Sambuc 		if (j == 0) {
391ebfedea0SLionel Sambuc 		    /* This "version" means we have a key */
392ebfedea0SLionel Sambuc 		    k->key.keytype = type;
393ebfedea0SLionel Sambuc 		    if (u16 < 2) {
394ebfedea0SLionel Sambuc 			ret = EINVAL;
395ebfedea0SLionel Sambuc 			goto out;
396ebfedea0SLionel Sambuc 		    }
397ebfedea0SLionel Sambuc 		    /*
398ebfedea0SLionel Sambuc 		     * MIT stores keys encrypted keys as {16-bit length
399ebfedea0SLionel Sambuc 		     * of plaintext key, {encrypted key}}.  The reason
400ebfedea0SLionel Sambuc 		     * for this is that the Kerberos cryptosystem is not
401ebfedea0SLionel Sambuc 		     * length-preserving.  Heimdal's approach is to
402ebfedea0SLionel Sambuc 		     * truncate the plaintext to the expected length of
403ebfedea0SLionel Sambuc 		     * the key given its enctype, so we ignore this
404ebfedea0SLionel Sambuc 		     * 16-bit length-of-plaintext-key field.
405ebfedea0SLionel Sambuc 		     */
406ebfedea0SLionel Sambuc 		    krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */
407ebfedea0SLionel Sambuc 		    k->key.keyvalue.length = u16 - 2;   /* adjust cipher len */
408ebfedea0SLionel Sambuc 		    k->key.keyvalue.data = malloc(k->key.keyvalue.length);
409ebfedea0SLionel Sambuc 		    krb5_storage_read(sp, k->key.keyvalue.data,
410ebfedea0SLionel Sambuc 				      k->key.keyvalue.length);
411ebfedea0SLionel Sambuc 		} else if (j == 1) {
412ebfedea0SLionel Sambuc 		    /* This "version" means we have a salt */
413ebfedea0SLionel Sambuc 		    k->salt = calloc(1, sizeof(*k->salt));
414ebfedea0SLionel Sambuc 		    if (k->salt == NULL) {
415ebfedea0SLionel Sambuc 			ret = ENOMEM;
416ebfedea0SLionel Sambuc 			goto out;
417ebfedea0SLionel Sambuc 		    }
418ebfedea0SLionel Sambuc 		    k->salt->type = type;
419ebfedea0SLionel Sambuc 		    if (u16 != 0) {
420ebfedea0SLionel Sambuc 			k->salt->salt.data = malloc(u16);
421ebfedea0SLionel Sambuc 			if (k->salt->salt.data == NULL) {
422ebfedea0SLionel Sambuc 			    ret = ENOMEM;
423ebfedea0SLionel Sambuc 			    goto out;
424ebfedea0SLionel Sambuc 			}
425ebfedea0SLionel Sambuc 			k->salt->salt.length = u16;
426ebfedea0SLionel Sambuc 			krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length);
427ebfedea0SLionel Sambuc 		    }
428ebfedea0SLionel Sambuc 		    fix_salt(context, entry, entry->keys.len - 1);
429ebfedea0SLionel Sambuc 		} else {
430ebfedea0SLionel Sambuc 		    /*
431ebfedea0SLionel Sambuc 		     * Whatever this "version" might be, we skip it
432ebfedea0SLionel Sambuc 		     *
433ebfedea0SLionel Sambuc 		     * XXX A krb5.conf parameter requesting that we log
434ebfedea0SLionel Sambuc 		     * about strangeness like this, or return an error
435ebfedea0SLionel Sambuc 		     * from here, might be nice.
436ebfedea0SLionel Sambuc 		     */
437ebfedea0SLionel Sambuc 		    krb5_storage_seek(sp, u16, SEEK_CUR);
438ebfedea0SLionel Sambuc 		}
439ebfedea0SLionel Sambuc 	    }
440ebfedea0SLionel Sambuc 	} else {
441ebfedea0SLionel Sambuc 	    /*
442ebfedea0SLionel Sambuc 	     * XXX For now we skip older kvnos, but we should extract
443ebfedea0SLionel Sambuc 	     * them...
444ebfedea0SLionel Sambuc 	     */
445ebfedea0SLionel Sambuc 	    for (j = 0; j < version; j++) {
446ebfedea0SLionel Sambuc 		/* enctype */
447ebfedea0SLionel Sambuc 		CHECK(ret = krb5_ret_uint16(sp, &u16));
448ebfedea0SLionel Sambuc 		/* encrypted key (or plaintext salt) */
449ebfedea0SLionel Sambuc 		CHECK(ret = krb5_ret_uint16(sp, &u16));
450ebfedea0SLionel Sambuc 		krb5_storage_seek(sp, u16, SEEK_CUR);
451ebfedea0SLionel Sambuc 	    }
452ebfedea0SLionel Sambuc 	}
453ebfedea0SLionel Sambuc     }
454ebfedea0SLionel Sambuc 
455ebfedea0SLionel Sambuc     if (entry->kvno == 0 && kvno != 0) {
456ebfedea0SLionel Sambuc 	ret = HDB_ERR_NOT_FOUND_HERE;
457ebfedea0SLionel Sambuc 	goto out;
458ebfedea0SLionel Sambuc     }
459ebfedea0SLionel Sambuc 
460ebfedea0SLionel Sambuc     return 0;
461ebfedea0SLionel Sambuc  out:
462ebfedea0SLionel Sambuc     if (ret == HEIM_ERR_EOF)
463ebfedea0SLionel Sambuc 	/* Better error code than "end of file" */
464ebfedea0SLionel Sambuc 	ret = HEIM_ERR_BAD_HDBENT_ENCODING;
465ebfedea0SLionel Sambuc     return ret;
466ebfedea0SLionel Sambuc }
467ebfedea0SLionel Sambuc 
468ebfedea0SLionel Sambuc #if 0
469ebfedea0SLionel Sambuc static krb5_error_code
470ebfedea0SLionel Sambuc mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data)
471ebfedea0SLionel Sambuc {
472ebfedea0SLionel Sambuc     return EINVAL;
473ebfedea0SLionel Sambuc }
474ebfedea0SLionel Sambuc #endif
475ebfedea0SLionel Sambuc 
476ebfedea0SLionel Sambuc 
477ebfedea0SLionel Sambuc static krb5_error_code
mdb_close(krb5_context context,HDB * db)478ebfedea0SLionel Sambuc mdb_close(krb5_context context, HDB *db)
479ebfedea0SLionel Sambuc {
480ebfedea0SLionel Sambuc     DB *d = (DB*)db->hdb_db;
481ebfedea0SLionel Sambuc     (*d->close)(d);
482ebfedea0SLionel Sambuc     return 0;
483ebfedea0SLionel Sambuc }
484ebfedea0SLionel Sambuc 
485ebfedea0SLionel Sambuc static krb5_error_code
mdb_destroy(krb5_context context,HDB * db)486ebfedea0SLionel Sambuc mdb_destroy(krb5_context context, HDB *db)
487ebfedea0SLionel Sambuc {
488ebfedea0SLionel Sambuc     krb5_error_code ret;
489ebfedea0SLionel Sambuc 
490ebfedea0SLionel Sambuc     ret = hdb_clear_master_key (context, db);
491ebfedea0SLionel Sambuc     free(db->hdb_name);
492ebfedea0SLionel Sambuc     free(db);
493ebfedea0SLionel Sambuc     return ret;
494ebfedea0SLionel Sambuc }
495ebfedea0SLionel Sambuc 
496ebfedea0SLionel Sambuc static krb5_error_code
mdb_lock(krb5_context context,HDB * db,int operation)497ebfedea0SLionel Sambuc mdb_lock(krb5_context context, HDB *db, int operation)
498ebfedea0SLionel Sambuc {
499ebfedea0SLionel Sambuc     DB *d = (DB*)db->hdb_db;
500ebfedea0SLionel Sambuc     int fd = (*d->fd)(d);
501ebfedea0SLionel Sambuc     if(fd < 0) {
502ebfedea0SLionel Sambuc 	krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
503ebfedea0SLionel Sambuc 			       "Can't lock database: %s", db->hdb_name);
504ebfedea0SLionel Sambuc 	return HDB_ERR_CANT_LOCK_DB;
505ebfedea0SLionel Sambuc     }
506ebfedea0SLionel Sambuc     return hdb_lock(fd, operation);
507ebfedea0SLionel Sambuc }
508ebfedea0SLionel Sambuc 
509ebfedea0SLionel Sambuc static krb5_error_code
mdb_unlock(krb5_context context,HDB * db)510ebfedea0SLionel Sambuc mdb_unlock(krb5_context context, HDB *db)
511ebfedea0SLionel Sambuc {
512ebfedea0SLionel Sambuc     DB *d = (DB*)db->hdb_db;
513ebfedea0SLionel Sambuc     int fd = (*d->fd)(d);
514ebfedea0SLionel Sambuc     if(fd < 0) {
515ebfedea0SLionel Sambuc 	krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
516ebfedea0SLionel Sambuc 			       "Can't unlock database: %s", db->hdb_name);
517ebfedea0SLionel Sambuc 	return HDB_ERR_CANT_LOCK_DB;
518ebfedea0SLionel Sambuc     }
519ebfedea0SLionel Sambuc     return hdb_unlock(fd);
520ebfedea0SLionel Sambuc }
521ebfedea0SLionel Sambuc 
522ebfedea0SLionel Sambuc 
523ebfedea0SLionel Sambuc static krb5_error_code
mdb_seq(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry,int flag)524ebfedea0SLionel Sambuc mdb_seq(krb5_context context, HDB *db,
525ebfedea0SLionel Sambuc        unsigned flags, hdb_entry_ex *entry, int flag)
526ebfedea0SLionel Sambuc {
527ebfedea0SLionel Sambuc     DB *d = (DB*)db->hdb_db;
528ebfedea0SLionel Sambuc     DBT key, value;
529ebfedea0SLionel Sambuc     krb5_data key_data, data;
530ebfedea0SLionel Sambuc     int code;
531ebfedea0SLionel Sambuc 
532ebfedea0SLionel Sambuc     code = db->hdb_lock(context, db, HDB_RLOCK);
533ebfedea0SLionel Sambuc     if(code == -1) {
534ebfedea0SLionel Sambuc 	krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name);
535ebfedea0SLionel Sambuc 	return HDB_ERR_DB_INUSE;
536ebfedea0SLionel Sambuc     }
537ebfedea0SLionel Sambuc     code = (*d->seq)(d, &key, &value, flag);
538ebfedea0SLionel Sambuc     db->hdb_unlock(context, db); /* XXX check value */
539ebfedea0SLionel Sambuc     if(code == -1) {
540ebfedea0SLionel Sambuc 	code = errno;
541ebfedea0SLionel Sambuc 	krb5_set_error_message(context, code, "Database %s seq error: %s",
542ebfedea0SLionel Sambuc 			       db->hdb_name, strerror(code));
543ebfedea0SLionel Sambuc 	return code;
544ebfedea0SLionel Sambuc     }
545ebfedea0SLionel Sambuc     if(code == 1) {
546ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
547ebfedea0SLionel Sambuc 	return HDB_ERR_NOENTRY;
548ebfedea0SLionel Sambuc     }
549ebfedea0SLionel Sambuc 
550ebfedea0SLionel Sambuc     key_data.data = key.data;
551ebfedea0SLionel Sambuc     key_data.length = key.size;
552ebfedea0SLionel Sambuc     data.data = value.data;
553ebfedea0SLionel Sambuc     data.length = value.size;
554ebfedea0SLionel Sambuc     memset(entry, 0, sizeof(*entry));
555ebfedea0SLionel Sambuc 
556ebfedea0SLionel Sambuc     if (mdb_value2entry(context, &data, 0, &entry->entry))
557ebfedea0SLionel Sambuc 	return mdb_seq(context, db, flags, entry, R_NEXT);
558ebfedea0SLionel Sambuc 
559ebfedea0SLionel Sambuc     if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
560ebfedea0SLionel Sambuc 	code = hdb_unseal_keys (context, db, &entry->entry);
561ebfedea0SLionel Sambuc 	if (code)
562ebfedea0SLionel Sambuc 	    hdb_free_entry (context, entry);
563ebfedea0SLionel Sambuc     }
564ebfedea0SLionel Sambuc 
565ebfedea0SLionel Sambuc     return code;
566ebfedea0SLionel Sambuc }
567ebfedea0SLionel Sambuc 
568ebfedea0SLionel Sambuc 
569ebfedea0SLionel Sambuc static krb5_error_code
mdb_firstkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)570ebfedea0SLionel Sambuc mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
571ebfedea0SLionel Sambuc {
572ebfedea0SLionel Sambuc     return mdb_seq(context, db, flags, entry, R_FIRST);
573ebfedea0SLionel Sambuc }
574ebfedea0SLionel Sambuc 
575ebfedea0SLionel Sambuc 
576ebfedea0SLionel Sambuc static krb5_error_code
mdb_nextkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)577ebfedea0SLionel Sambuc mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
578ebfedea0SLionel Sambuc {
579ebfedea0SLionel Sambuc     return mdb_seq(context, db, flags, entry, R_NEXT);
580ebfedea0SLionel Sambuc }
581ebfedea0SLionel Sambuc 
582ebfedea0SLionel Sambuc static krb5_error_code
mdb_rename(krb5_context context,HDB * db,const char * new_name)583ebfedea0SLionel Sambuc mdb_rename(krb5_context context, HDB *db, const char *new_name)
584ebfedea0SLionel Sambuc {
585ebfedea0SLionel Sambuc     int ret;
586ebfedea0SLionel Sambuc     char *old, *new;
587ebfedea0SLionel Sambuc 
588ebfedea0SLionel Sambuc     asprintf(&old, "%s.db", db->hdb_name);
589ebfedea0SLionel Sambuc     asprintf(&new, "%s.db", new_name);
590ebfedea0SLionel Sambuc     ret = rename(old, new);
591ebfedea0SLionel Sambuc     free(old);
592ebfedea0SLionel Sambuc     free(new);
593ebfedea0SLionel Sambuc     if(ret)
594ebfedea0SLionel Sambuc 	return errno;
595ebfedea0SLionel Sambuc 
596ebfedea0SLionel Sambuc     free(db->hdb_name);
597ebfedea0SLionel Sambuc     db->hdb_name = strdup(new_name);
598ebfedea0SLionel Sambuc     return 0;
599ebfedea0SLionel Sambuc }
600ebfedea0SLionel Sambuc 
601ebfedea0SLionel Sambuc static krb5_error_code
mdb__get(krb5_context context,HDB * db,krb5_data key,krb5_data * reply)602ebfedea0SLionel Sambuc mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
603ebfedea0SLionel Sambuc {
604ebfedea0SLionel Sambuc     DB *d = (DB*)db->hdb_db;
605ebfedea0SLionel Sambuc     DBT k, v;
606ebfedea0SLionel Sambuc     int code;
607ebfedea0SLionel Sambuc 
608ebfedea0SLionel Sambuc     k.data = key.data;
609ebfedea0SLionel Sambuc     k.size = key.length;
610ebfedea0SLionel Sambuc     code = db->hdb_lock(context, db, HDB_RLOCK);
611ebfedea0SLionel Sambuc     if(code)
612ebfedea0SLionel Sambuc 	return code;
613ebfedea0SLionel Sambuc     code = (*d->get)(d, &k, &v, 0);
614ebfedea0SLionel Sambuc     db->hdb_unlock(context, db);
615ebfedea0SLionel Sambuc     if(code < 0) {
616ebfedea0SLionel Sambuc 	code = errno;
617ebfedea0SLionel Sambuc 	krb5_set_error_message(context, code, "Database %s get error: %s",
618ebfedea0SLionel Sambuc 			       db->hdb_name, strerror(code));
619ebfedea0SLionel Sambuc 	return code;
620ebfedea0SLionel Sambuc     }
621ebfedea0SLionel Sambuc     if(code == 1) {
622ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
623ebfedea0SLionel Sambuc 	return HDB_ERR_NOENTRY;
624ebfedea0SLionel Sambuc     }
625ebfedea0SLionel Sambuc 
626ebfedea0SLionel Sambuc     krb5_data_copy(reply, v.data, v.size);
627ebfedea0SLionel Sambuc     return 0;
628ebfedea0SLionel Sambuc }
629ebfedea0SLionel Sambuc 
630ebfedea0SLionel Sambuc static krb5_error_code
mdb__put(krb5_context context,HDB * db,int replace,krb5_data key,krb5_data value)631ebfedea0SLionel Sambuc mdb__put(krb5_context context, HDB *db, int replace,
632ebfedea0SLionel Sambuc 	krb5_data key, krb5_data value)
633ebfedea0SLionel Sambuc {
634ebfedea0SLionel Sambuc     DB *d = (DB*)db->hdb_db;
635ebfedea0SLionel Sambuc     DBT k, v;
636ebfedea0SLionel Sambuc     int code;
637ebfedea0SLionel Sambuc 
638ebfedea0SLionel Sambuc     k.data = key.data;
639ebfedea0SLionel Sambuc     k.size = key.length;
640ebfedea0SLionel Sambuc     v.data = value.data;
641ebfedea0SLionel Sambuc     v.size = value.length;
642ebfedea0SLionel Sambuc     code = db->hdb_lock(context, db, HDB_WLOCK);
643ebfedea0SLionel Sambuc     if(code)
644ebfedea0SLionel Sambuc 	return code;
645ebfedea0SLionel Sambuc     code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
646ebfedea0SLionel Sambuc     db->hdb_unlock(context, db);
647ebfedea0SLionel Sambuc     if(code < 0) {
648ebfedea0SLionel Sambuc 	code = errno;
649ebfedea0SLionel Sambuc 	krb5_set_error_message(context, code, "Database %s put error: %s",
650ebfedea0SLionel Sambuc 			       db->hdb_name, strerror(code));
651ebfedea0SLionel Sambuc 	return code;
652ebfedea0SLionel Sambuc     }
653ebfedea0SLionel Sambuc     if(code == 1) {
654ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
655ebfedea0SLionel Sambuc 	return HDB_ERR_EXISTS;
656ebfedea0SLionel Sambuc     }
657ebfedea0SLionel Sambuc     return 0;
658ebfedea0SLionel Sambuc }
659ebfedea0SLionel Sambuc 
660ebfedea0SLionel Sambuc static krb5_error_code
mdb__del(krb5_context context,HDB * db,krb5_data key)661ebfedea0SLionel Sambuc mdb__del(krb5_context context, HDB *db, krb5_data key)
662ebfedea0SLionel Sambuc {
663ebfedea0SLionel Sambuc     DB *d = (DB*)db->hdb_db;
664ebfedea0SLionel Sambuc     DBT k;
665ebfedea0SLionel Sambuc     krb5_error_code code;
666ebfedea0SLionel Sambuc     k.data = key.data;
667ebfedea0SLionel Sambuc     k.size = key.length;
668ebfedea0SLionel Sambuc     code = db->hdb_lock(context, db, HDB_WLOCK);
669ebfedea0SLionel Sambuc     if(code)
670ebfedea0SLionel Sambuc 	return code;
671ebfedea0SLionel Sambuc     code = (*d->del)(d, &k, 0);
672ebfedea0SLionel Sambuc     db->hdb_unlock(context, db);
673ebfedea0SLionel Sambuc     if(code == 1) {
674ebfedea0SLionel Sambuc 	code = errno;
675ebfedea0SLionel Sambuc 	krb5_set_error_message(context, code, "Database %s put error: %s",
676ebfedea0SLionel Sambuc 			       db->hdb_name, strerror(code));
677ebfedea0SLionel Sambuc 	return code;
678ebfedea0SLionel Sambuc     }
679ebfedea0SLionel Sambuc     if(code < 0)
680ebfedea0SLionel Sambuc 	return errno;
681ebfedea0SLionel Sambuc     return 0;
682ebfedea0SLionel Sambuc }
683ebfedea0SLionel Sambuc 
684ebfedea0SLionel Sambuc static krb5_error_code
mdb_fetch_kvno(krb5_context context,HDB * db,krb5_const_principal principal,unsigned flags,krb5_kvno kvno,hdb_entry_ex * entry)685ebfedea0SLionel Sambuc mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
686ebfedea0SLionel Sambuc 	       unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
687ebfedea0SLionel Sambuc {
688ebfedea0SLionel Sambuc     krb5_data key, value;
689ebfedea0SLionel Sambuc     krb5_error_code code;
690ebfedea0SLionel Sambuc 
691ebfedea0SLionel Sambuc     code = mdb_principal2key(context, principal, &key);
692ebfedea0SLionel Sambuc     if (code)
693ebfedea0SLionel Sambuc 	return code;
694ebfedea0SLionel Sambuc     code = db->hdb__get(context, db, key, &value);
695ebfedea0SLionel Sambuc     krb5_data_free(&key);
696ebfedea0SLionel Sambuc     if(code)
697ebfedea0SLionel Sambuc 	return code;
698ebfedea0SLionel Sambuc     code = mdb_value2entry(context, &value, kvno, &entry->entry);
699ebfedea0SLionel Sambuc     krb5_data_free(&value);
700ebfedea0SLionel Sambuc     if (code)
701ebfedea0SLionel Sambuc 	return code;
702ebfedea0SLionel Sambuc 
703ebfedea0SLionel Sambuc     if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
704ebfedea0SLionel Sambuc 	code = hdb_unseal_keys (context, db, &entry->entry);
705ebfedea0SLionel Sambuc 	if (code)
706ebfedea0SLionel Sambuc 	    hdb_free_entry(context, entry);
707ebfedea0SLionel Sambuc     }
708ebfedea0SLionel Sambuc 
709ebfedea0SLionel Sambuc     return 0;
710ebfedea0SLionel Sambuc }
711ebfedea0SLionel Sambuc 
712ebfedea0SLionel Sambuc static krb5_error_code
mdb_store(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)713ebfedea0SLionel Sambuc mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
714ebfedea0SLionel Sambuc {
715ebfedea0SLionel Sambuc     krb5_set_error_message(context, EINVAL, "can't set principal in mdb");
716ebfedea0SLionel Sambuc     return EINVAL;
717ebfedea0SLionel Sambuc }
718ebfedea0SLionel Sambuc 
719ebfedea0SLionel Sambuc static krb5_error_code
mdb_remove(krb5_context context,HDB * db,krb5_const_principal principal)720ebfedea0SLionel Sambuc mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)
721ebfedea0SLionel Sambuc {
722ebfedea0SLionel Sambuc     krb5_error_code code;
723ebfedea0SLionel Sambuc     krb5_data key;
724ebfedea0SLionel Sambuc 
725ebfedea0SLionel Sambuc     mdb_principal2key(context, principal, &key);
726ebfedea0SLionel Sambuc     code = db->hdb__del(context, db, key);
727ebfedea0SLionel Sambuc     krb5_data_free(&key);
728ebfedea0SLionel Sambuc     return code;
729ebfedea0SLionel Sambuc }
730ebfedea0SLionel Sambuc 
731ebfedea0SLionel Sambuc static krb5_error_code
mdb_open(krb5_context context,HDB * db,int flags,mode_t mode)732ebfedea0SLionel Sambuc mdb_open(krb5_context context, HDB *db, int flags, mode_t mode)
733ebfedea0SLionel Sambuc {
734ebfedea0SLionel Sambuc     char *fn;
735ebfedea0SLionel Sambuc     krb5_error_code ret;
736ebfedea0SLionel Sambuc 
737ebfedea0SLionel Sambuc     asprintf(&fn, "%s.db", db->hdb_name);
738ebfedea0SLionel Sambuc     if (fn == NULL) {
739ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
740ebfedea0SLionel Sambuc 	return ENOMEM;
741ebfedea0SLionel Sambuc     }
742ebfedea0SLionel Sambuc     db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
743ebfedea0SLionel Sambuc     free(fn);
744ebfedea0SLionel Sambuc 
745ebfedea0SLionel Sambuc     if (db->hdb_db == NULL) {
746ebfedea0SLionel Sambuc 	switch (errno) {
747ebfedea0SLionel Sambuc #ifdef EFTYPE
748ebfedea0SLionel Sambuc 	case EFTYPE:
749ebfedea0SLionel Sambuc #endif
750ebfedea0SLionel Sambuc 	case EINVAL:
751ebfedea0SLionel Sambuc 	    db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
752ebfedea0SLionel Sambuc 	}
753ebfedea0SLionel Sambuc     }
754ebfedea0SLionel Sambuc 
755ebfedea0SLionel Sambuc     /* try to open without .db extension */
756ebfedea0SLionel Sambuc     if(db->hdb_db == NULL && errno == ENOENT)
757ebfedea0SLionel Sambuc 	db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL);
758ebfedea0SLionel Sambuc     if(db->hdb_db == NULL) {
759ebfedea0SLionel Sambuc 	ret = errno;
760ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret, "dbopen (%s): %s",
761ebfedea0SLionel Sambuc 			      db->hdb_name, strerror(ret));
762ebfedea0SLionel Sambuc 	return ret;
763ebfedea0SLionel Sambuc     }
764ebfedea0SLionel Sambuc     if((flags & O_ACCMODE) == O_RDONLY)
765ebfedea0SLionel Sambuc 	ret = hdb_check_db_format(context, db);
766ebfedea0SLionel Sambuc     else
767ebfedea0SLionel Sambuc 	ret = hdb_init_db(context, db);
768ebfedea0SLionel Sambuc     if(ret == HDB_ERR_NOENTRY) {
769ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
770ebfedea0SLionel Sambuc 	return 0;
771ebfedea0SLionel Sambuc     }
772ebfedea0SLionel Sambuc     if (ret) {
773ebfedea0SLionel Sambuc 	mdb_close(context, db);
774ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",
775ebfedea0SLionel Sambuc 			      (flags & O_ACCMODE) == O_RDONLY ?
776ebfedea0SLionel Sambuc 			      "checking format of" : "initialize",
777ebfedea0SLionel Sambuc 			      db->hdb_name);
778ebfedea0SLionel Sambuc     }
779ebfedea0SLionel Sambuc     return ret;
780ebfedea0SLionel Sambuc }
781ebfedea0SLionel Sambuc 
782ebfedea0SLionel Sambuc krb5_error_code
hdb_mdb_create(krb5_context context,HDB ** db,const char * filename)783ebfedea0SLionel Sambuc hdb_mdb_create(krb5_context context, HDB **db,
784ebfedea0SLionel Sambuc 	       const char *filename)
785ebfedea0SLionel Sambuc {
786ebfedea0SLionel Sambuc     *db = calloc(1, sizeof(**db));
787ebfedea0SLionel Sambuc     if (*db == NULL) {
788ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
789ebfedea0SLionel Sambuc 	return ENOMEM;
790ebfedea0SLionel Sambuc     }
791ebfedea0SLionel Sambuc 
792ebfedea0SLionel Sambuc     (*db)->hdb_db = NULL;
793ebfedea0SLionel Sambuc     (*db)->hdb_name = strdup(filename);
794ebfedea0SLionel Sambuc     if ((*db)->hdb_name == NULL) {
795ebfedea0SLionel Sambuc 	free(*db);
796ebfedea0SLionel Sambuc 	*db = NULL;
797ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
798ebfedea0SLionel Sambuc 	return ENOMEM;
799ebfedea0SLionel Sambuc     }
800ebfedea0SLionel Sambuc     (*db)->hdb_master_key_set = 0;
801ebfedea0SLionel Sambuc     (*db)->hdb_openp = 0;
802ebfedea0SLionel Sambuc     (*db)->hdb_capability_flags = 0;
803ebfedea0SLionel Sambuc     (*db)->hdb_open = mdb_open;
804ebfedea0SLionel Sambuc     (*db)->hdb_close = mdb_close;
805ebfedea0SLionel Sambuc     (*db)->hdb_fetch_kvno = mdb_fetch_kvno;
806ebfedea0SLionel Sambuc     (*db)->hdb_store = mdb_store;
807ebfedea0SLionel Sambuc     (*db)->hdb_remove = mdb_remove;
808ebfedea0SLionel Sambuc     (*db)->hdb_firstkey = mdb_firstkey;
809ebfedea0SLionel Sambuc     (*db)->hdb_nextkey= mdb_nextkey;
810ebfedea0SLionel Sambuc     (*db)->hdb_lock = mdb_lock;
811ebfedea0SLionel Sambuc     (*db)->hdb_unlock = mdb_unlock;
812ebfedea0SLionel Sambuc     (*db)->hdb_rename = mdb_rename;
813ebfedea0SLionel Sambuc     (*db)->hdb__get = mdb__get;
814ebfedea0SLionel Sambuc     (*db)->hdb__put = mdb__put;
815ebfedea0SLionel Sambuc     (*db)->hdb__del = mdb__del;
816ebfedea0SLionel Sambuc     (*db)->hdb_destroy = mdb_destroy;
817ebfedea0SLionel Sambuc     return 0;
818ebfedea0SLionel Sambuc }
819ebfedea0SLionel Sambuc 
820ebfedea0SLionel Sambuc #endif /* HAVE_DB1 */
821