1/*
2 * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "hdb_locl.h"
35
36int
37hdb_principal2key(krb5_context context, krb5_const_principal p, krb5_data *key)
38{
39    Principal new;
40    size_t len = 0;
41    int ret;
42
43    ret = copy_Principal(p, &new);
44    if(ret)
45	return ret;
46    new.name.name_type = 0;
47
48    ASN1_MALLOC_ENCODE(Principal, key->data, key->length, &new, &len, ret);
49    if (ret == 0 && key->length != len)
50	krb5_abortx(context, "internal asn.1 encoder error");
51    free_Principal(&new);
52    return ret;
53}
54
55int
56hdb_key2principal(krb5_context context, krb5_data *key, krb5_principal p)
57{
58    return decode_Principal(key->data, key->length, p, NULL);
59}
60
61int
62hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value)
63{
64    size_t len = 0;
65    int ret;
66
67    ASN1_MALLOC_ENCODE(hdb_entry, value->data, value->length, ent, &len, ret);
68    if (ret == 0 && value->length != len)
69	krb5_abortx(context, "internal asn.1 encoder error");
70    return ret;
71}
72
73int
74hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent)
75{
76    return decode_hdb_entry(value->data, value->length, ent, NULL);
77}
78
79int
80hdb_entry_alias2value(krb5_context context,
81		      const hdb_entry_alias *alias,
82		      krb5_data *value)
83{
84    size_t len = 0;
85    int ret;
86
87    ASN1_MALLOC_ENCODE(hdb_entry_alias, value->data, value->length,
88		       alias, &len, ret);
89    if (ret == 0 && value->length != len)
90	krb5_abortx(context, "internal asn.1 encoder error");
91    return ret;
92}
93
94int
95hdb_value2entry_alias(krb5_context context, krb5_data *value,
96		      hdb_entry_alias *ent)
97{
98    return decode_hdb_entry_alias(value->data, value->length, ent, NULL);
99}
100
101krb5_error_code
102_hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
103		unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
104{
105    krb5_principal enterprise_principal = NULL;
106    krb5_data key, value;
107    krb5_error_code ret;
108
109    if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
110	if (principal->name.name_string.len != 1) {
111	    ret = KRB5_PARSE_MALFORMED;
112	    krb5_set_error_message(context, ret, "malformed principal: "
113				   "enterprise name with %d name components",
114				   principal->name.name_string.len);
115	    return ret;
116	}
117	ret = krb5_parse_name(context, principal->name.name_string.val[0],
118			      &enterprise_principal);
119	if (ret)
120	    return ret;
121	principal = enterprise_principal;
122    }
123
124    ret = hdb_principal2key(context, principal, &key);
125    if (enterprise_principal)
126	krb5_free_principal(context, enterprise_principal);
127    if (ret)
128        return ret;
129    ret = db->hdb__get(context, db, key, &value);
130    krb5_data_free(&key);
131    if(ret)
132	return ret;
133    ret = hdb_value2entry(context, &value, &entry->entry);
134    if (ret == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) {
135	krb5_data_free(&value);
136	return HDB_ERR_NOENTRY;
137    } else if (ret == ASN1_BAD_ID) {
138	hdb_entry_alias alias;
139
140	ret = hdb_value2entry_alias(context, &value, &alias);
141	if (ret) {
142	    krb5_data_free(&value);
143	    return ret;
144	}
145	hdb_principal2key(context, alias.principal, &key);
146	krb5_data_free(&value);
147	free_hdb_entry_alias(&alias);
148
149	ret = db->hdb__get(context, db, key, &value);
150	krb5_data_free(&key);
151	if (ret)
152	    return ret;
153	ret = hdb_value2entry(context, &value, &entry->entry);
154	if (ret) {
155	    krb5_data_free(&value);
156	    return ret;
157	}
158    }
159    krb5_data_free(&value);
160    if ((flags & HDB_F_DECRYPT) && (flags & HDB_F_ALL_KVNOS)) {
161	/* Decrypt the current keys */
162	ret = hdb_unseal_keys(context, db, &entry->entry);
163	if (ret) {
164	    hdb_free_entry(context, entry);
165	    return ret;
166	}
167	/* Decrypt the key history too */
168	ret = hdb_unseal_keys_kvno(context, db, 0, flags, &entry->entry);
169	if (ret) {
170	    hdb_free_entry(context, entry);
171	    return ret;
172	}
173    } else if ((flags & HDB_F_DECRYPT)) {
174	if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->entry.kvno) {
175	    /* Decrypt the current keys */
176	    ret = hdb_unseal_keys(context, db, &entry->entry);
177	    if (ret) {
178		hdb_free_entry(context, entry);
179		return ret;
180	    }
181	} else {
182	    if ((flags & HDB_F_ALL_KVNOS))
183		kvno = 0;
184	    /*
185	     * Find and decrypt the keys from the history that we want,
186	     * and swap them with the current keys
187	     */
188	    ret = hdb_unseal_keys_kvno(context, db, kvno, flags, &entry->entry);
189	    if (ret) {
190		hdb_free_entry(context, entry);
191		return ret;
192	    }
193	}
194    }
195
196    return 0;
197}
198
199static krb5_error_code
200hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key)
201{
202    const HDB_Ext_Aliases *aliases;
203    krb5_error_code code;
204    hdb_entry oldentry;
205    krb5_data value;
206    size_t i;
207
208    code = db->hdb__get(context, db, *key, &value);
209    if (code == HDB_ERR_NOENTRY)
210	return 0;
211    else if (code)
212	return code;
213
214    code = hdb_value2entry(context, &value, &oldentry);
215    krb5_data_free(&value);
216    if (code)
217	return code;
218
219    code = hdb_entry_get_aliases(&oldentry, &aliases);
220    if (code || aliases == NULL) {
221	free_hdb_entry(&oldentry);
222	return code;
223    }
224    for (i = 0; i < aliases->aliases.len; i++) {
225	krb5_data akey;
226
227	code = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
228        if (code) {
229            free_hdb_entry(&oldentry);
230            return code;
231        }
232	code = db->hdb__del(context, db, akey);
233	krb5_data_free(&akey);
234	if (code) {
235	    free_hdb_entry(&oldentry);
236	    return code;
237	}
238    }
239    free_hdb_entry(&oldentry);
240    return 0;
241}
242
243static krb5_error_code
244hdb_add_aliases(krb5_context context, HDB *db,
245		unsigned flags, hdb_entry_ex *entry)
246{
247    const HDB_Ext_Aliases *aliases;
248    krb5_error_code code;
249    krb5_data key, value;
250    size_t i;
251
252    code = hdb_entry_get_aliases(&entry->entry, &aliases);
253    if (code || aliases == NULL)
254	return code;
255
256    for (i = 0; i < aliases->aliases.len; i++) {
257	hdb_entry_alias entryalias;
258	entryalias.principal = entry->entry.principal;
259
260	code = hdb_principal2key(context, &aliases->aliases.val[i], &key);
261    if (code)
262        return code;
263	code = hdb_entry_alias2value(context, &entryalias, &value);
264	if (code) {
265	    krb5_data_free(&key);
266	    return code;
267	}
268	code = db->hdb__put(context, db, flags, key, value);
269	krb5_data_free(&key);
270	krb5_data_free(&value);
271	if (code)
272	    return code;
273    }
274    return 0;
275}
276
277static krb5_error_code
278hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry)
279{
280    const HDB_Ext_Aliases *aliases;
281    int code;
282    size_t i;
283
284    /* check if new aliases already is used */
285
286    code = hdb_entry_get_aliases(&entry->entry, &aliases);
287    if (code)
288	return code;
289
290    for (i = 0; aliases && i < aliases->aliases.len; i++) {
291	hdb_entry_alias alias;
292	krb5_data akey, value;
293
294	code = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
295    if (code)
296        return code;
297	code = db->hdb__get(context, db, akey, &value);
298	krb5_data_free(&akey);
299	if (code == HDB_ERR_NOENTRY)
300	    continue;
301	else if (code)
302	    return code;
303
304	code = hdb_value2entry_alias(context, &value, &alias);
305	krb5_data_free(&value);
306
307	if (code == ASN1_BAD_ID)
308	    return HDB_ERR_EXISTS;
309	else if (code)
310	    return code;
311
312	code = krb5_principal_compare(context, alias.principal,
313				      entry->entry.principal);
314	free_hdb_entry_alias(&alias);
315	if (code == 0)
316	    return HDB_ERR_EXISTS;
317    }
318    return 0;
319}
320
321krb5_error_code
322_hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
323{
324    krb5_data key, value;
325    int code;
326
327    if (entry->entry.flags.do_not_store)
328	return HDB_ERR_MISUSE;
329    /* check if new aliases already is used */
330    code = hdb_check_aliases(context, db, entry);
331    if (code)
332	return code;
333
334    if(entry->entry.generation == NULL) {
335	struct timeval t;
336	entry->entry.generation = malloc(sizeof(*entry->entry.generation));
337	if(entry->entry.generation == NULL) {
338	    krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
339	    return ENOMEM;
340	}
341	gettimeofday(&t, NULL);
342	entry->entry.generation->time = t.tv_sec;
343	entry->entry.generation->usec = t.tv_usec;
344	entry->entry.generation->gen = 0;
345    } else
346	entry->entry.generation->gen++;
347
348    code = hdb_seal_keys(context, db, &entry->entry);
349    if (code)
350	return code;
351
352    hdb_principal2key(context, entry->entry.principal, &key);
353
354    /* remove aliases */
355    code = hdb_remove_aliases(context, db, &key);
356    if (code) {
357	krb5_data_free(&key);
358	return code;
359    }
360    hdb_entry2value(context, &entry->entry, &value);
361    code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value);
362    krb5_data_free(&value);
363    krb5_data_free(&key);
364    if (code)
365	return code;
366
367    code = hdb_add_aliases(context, db, flags, entry);
368
369    return code;
370}
371
372krb5_error_code
373_hdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)
374{
375    krb5_data key;
376    int code;
377
378    hdb_principal2key(context, principal, &key);
379
380    code = hdb_remove_aliases(context, db, &key);
381    if (code) {
382	krb5_data_free(&key);
383	return code;
384    }
385    code = db->hdb__del(context, db, key);
386    krb5_data_free(&key);
387    return code;
388}
389
390