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