155682Smarkm/*
2233294Sstas * Copyright (c) 1997-2002 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "hdb_locl.h"
3555682Smarkm
3655682Smarkmint
37178825Sdfrhdb_principal2key(krb5_context context, krb5_const_principal p, krb5_data *key)
3855682Smarkm{
3955682Smarkm    Principal new;
40233294Sstas    size_t len = 0;
4155682Smarkm    int ret;
4255682Smarkm
4355682Smarkm    ret = copy_Principal(p, &new);
44233294Sstas    if(ret)
45103423Snectar	return ret;
4655682Smarkm    new.name.name_type = 0;
47103423Snectar
48103423Snectar    ASN1_MALLOC_ENCODE(Principal, key->data, key->length, &new, &len, ret);
49178825Sdfr    if (ret == 0 && key->length != len)
50178825Sdfr	krb5_abortx(context, "internal asn.1 encoder error");
5155682Smarkm    free_Principal(&new);
5255682Smarkm    return ret;
5355682Smarkm}
5455682Smarkm
5555682Smarkmint
5655682Smarkmhdb_key2principal(krb5_context context, krb5_data *key, krb5_principal p)
5755682Smarkm{
5855682Smarkm    return decode_Principal(key->data, key->length, p, NULL);
5955682Smarkm}
6055682Smarkm
6155682Smarkmint
62178825Sdfrhdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value)
6355682Smarkm{
64233294Sstas    size_t len = 0;
6555682Smarkm    int ret;
66233294Sstas
67103423Snectar    ASN1_MALLOC_ENCODE(hdb_entry, value->data, value->length, ent, &len, ret);
68178825Sdfr    if (ret == 0 && value->length != len)
69178825Sdfr	krb5_abortx(context, "internal asn.1 encoder error");
70103423Snectar    return ret;
7155682Smarkm}
7255682Smarkm
7355682Smarkmint
7455682Smarkmhdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent)
7555682Smarkm{
7655682Smarkm    return decode_hdb_entry(value->data, value->length, ent, NULL);
7755682Smarkm}
7855682Smarkm
79178825Sdfrint
80233294Sstashdb_entry_alias2value(krb5_context context,
81178825Sdfr		      const hdb_entry_alias *alias,
82178825Sdfr		      krb5_data *value)
83178825Sdfr{
84233294Sstas    size_t len = 0;
85178825Sdfr    int ret;
86233294Sstas
87233294Sstas    ASN1_MALLOC_ENCODE(hdb_entry_alias, value->data, value->length,
88178825Sdfr		       alias, &len, ret);
89178825Sdfr    if (ret == 0 && value->length != len)
90178825Sdfr	krb5_abortx(context, "internal asn.1 encoder error");
91178825Sdfr    return ret;
92178825Sdfr}
93178825Sdfr
94178825Sdfrint
95233294Sstashdb_value2entry_alias(krb5_context context, krb5_data *value,
96178825Sdfr		      hdb_entry_alias *ent)
97178825Sdfr{
98178825Sdfr    return decode_hdb_entry_alias(value->data, value->length, ent, NULL);
99178825Sdfr}
100178825Sdfr
10155682Smarkmkrb5_error_code
102233294Sstas_hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
103233294Sstas		unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
10455682Smarkm{
105233294Sstas    krb5_principal enterprise_principal = NULL;
10655682Smarkm    krb5_data key, value;
107233294Sstas    krb5_error_code ret;
108120945Snectar    int code;
10955682Smarkm
110233294Sstas    if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
111233294Sstas	if (principal->name.name_string.len != 1) {
112233294Sstas	    ret = KRB5_PARSE_MALFORMED;
113233294Sstas	    krb5_set_error_message(context, ret, "malformed principal: "
114233294Sstas				   "enterprise name with %d name components",
115233294Sstas				   principal->name.name_string.len);
116233294Sstas	    return ret;
117233294Sstas	}
118233294Sstas	ret = krb5_parse_name(context, principal->name.name_string.val[0],
119233294Sstas			      &enterprise_principal);
120233294Sstas	if (ret)
121233294Sstas	    return ret;
122233294Sstas	principal = enterprise_principal;
123233294Sstas    }
124233294Sstas
125178825Sdfr    hdb_principal2key(context, principal, &key);
126233294Sstas    if (enterprise_principal)
127233294Sstas	krb5_free_principal(context, enterprise_principal);
128178825Sdfr    code = db->hdb__get(context, db, key, &value);
12955682Smarkm    krb5_data_free(&key);
13055682Smarkm    if(code)
13155682Smarkm	return code;
132178825Sdfr    code = hdb_value2entry(context, &value, &entry->entry);
133178825Sdfr    if (code == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) {
134178825Sdfr	krb5_data_free(&value);
135178825Sdfr	return HDB_ERR_NOENTRY;
136178825Sdfr    } else if (code == ASN1_BAD_ID) {
137178825Sdfr	hdb_entry_alias alias;
138178825Sdfr
139178825Sdfr	code = hdb_value2entry_alias(context, &value, &alias);
140178825Sdfr	if (code) {
141178825Sdfr	    krb5_data_free(&value);
142178825Sdfr	    return code;
143178825Sdfr	}
144178825Sdfr	hdb_principal2key(context, alias.principal, &key);
145178825Sdfr	krb5_data_free(&value);
146178825Sdfr	free_hdb_entry_alias(&alias);
147178825Sdfr
148178825Sdfr	code = db->hdb__get(context, db, key, &value);
149178825Sdfr	krb5_data_free(&key);
150178825Sdfr	if (code)
151178825Sdfr	    return code;
152178825Sdfr	code = hdb_value2entry(context, &value, &entry->entry);
153178825Sdfr	if (code) {
154178825Sdfr	    krb5_data_free(&value);
155178825Sdfr	    return code;
156178825Sdfr	}
157178825Sdfr    }
158120945Snectar    krb5_data_free(&value);
159178825Sdfr    if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
160178825Sdfr	code = hdb_unseal_keys (context, db, &entry->entry);
16172445Sassar	if (code)
16272445Sassar	    hdb_free_entry(context, entry);
16372445Sassar    }
16472445Sassar    return code;
16555682Smarkm}
16655682Smarkm
167178825Sdfrstatic krb5_error_code
168178825Sdfrhdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key)
169178825Sdfr{
170178825Sdfr    const HDB_Ext_Aliases *aliases;
171178825Sdfr    krb5_error_code code;
172178825Sdfr    hdb_entry oldentry;
173178825Sdfr    krb5_data value;
174233294Sstas    size_t i;
175178825Sdfr
176178825Sdfr    code = db->hdb__get(context, db, *key, &value);
177178825Sdfr    if (code == HDB_ERR_NOENTRY)
178178825Sdfr	return 0;
179178825Sdfr    else if (code)
180178825Sdfr	return code;
181233294Sstas
182178825Sdfr    code = hdb_value2entry(context, &value, &oldentry);
183178825Sdfr    krb5_data_free(&value);
184178825Sdfr    if (code)
185178825Sdfr	return code;
186178825Sdfr
187178825Sdfr    code = hdb_entry_get_aliases(&oldentry, &aliases);
188178825Sdfr    if (code || aliases == NULL) {
189178825Sdfr	free_hdb_entry(&oldentry);
190178825Sdfr	return code;
191178825Sdfr    }
192178825Sdfr    for (i = 0; i < aliases->aliases.len; i++) {
193178825Sdfr	krb5_data akey;
194178825Sdfr
195178825Sdfr	hdb_principal2key(context, &aliases->aliases.val[i], &akey);
196178825Sdfr	code = db->hdb__del(context, db, akey);
197178825Sdfr	krb5_data_free(&akey);
198178825Sdfr	if (code) {
199178825Sdfr	    free_hdb_entry(&oldentry);
200178825Sdfr	    return code;
201178825Sdfr	}
202178825Sdfr    }
203178825Sdfr    free_hdb_entry(&oldentry);
204178825Sdfr    return 0;
205178825Sdfr}
206178825Sdfr
207178825Sdfrstatic krb5_error_code
208233294Sstashdb_add_aliases(krb5_context context, HDB *db,
209178825Sdfr		unsigned flags, hdb_entry_ex *entry)
210178825Sdfr{
211178825Sdfr    const HDB_Ext_Aliases *aliases;
212178825Sdfr    krb5_error_code code;
213178825Sdfr    krb5_data key, value;
214233294Sstas    size_t i;
215233294Sstas
216178825Sdfr    code = hdb_entry_get_aliases(&entry->entry, &aliases);
217178825Sdfr    if (code || aliases == NULL)
218178825Sdfr	return code;
219233294Sstas
220178825Sdfr    for (i = 0; i < aliases->aliases.len; i++) {
221178825Sdfr	hdb_entry_alias entryalias;
222178825Sdfr	entryalias.principal = entry->entry.principal;
223233294Sstas
224178825Sdfr	hdb_principal2key(context, &aliases->aliases.val[i], &key);
225178825Sdfr	code = hdb_entry_alias2value(context, &entryalias, &value);
226178825Sdfr	if (code) {
227178825Sdfr	    krb5_data_free(&key);
228178825Sdfr	    return code;
229178825Sdfr	}
230178825Sdfr	code = db->hdb__put(context, db, flags, key, value);
231178825Sdfr	krb5_data_free(&key);
232178825Sdfr	krb5_data_free(&value);
233178825Sdfr	if (code)
234178825Sdfr	    return code;
235178825Sdfr    }
236178825Sdfr    return 0;
237178825Sdfr}
238178825Sdfr
239233294Sstasstatic krb5_error_code
240233294Sstashdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry)
241233294Sstas{
242233294Sstas    const HDB_Ext_Aliases *aliases;
243233294Sstas    int code;
244233294Sstas    size_t i;
245233294Sstas
246233294Sstas    /* check if new aliases already is used */
247233294Sstas
248233294Sstas    code = hdb_entry_get_aliases(&entry->entry, &aliases);
249233294Sstas    if (code)
250233294Sstas	return code;
251233294Sstas
252233294Sstas    for (i = 0; aliases && i < aliases->aliases.len; i++) {
253233294Sstas	hdb_entry_alias alias;
254233294Sstas	krb5_data akey, value;
255233294Sstas
256233294Sstas	hdb_principal2key(context, &aliases->aliases.val[i], &akey);
257233294Sstas	code = db->hdb__get(context, db, akey, &value);
258233294Sstas	krb5_data_free(&akey);
259233294Sstas	if (code == HDB_ERR_NOENTRY)
260233294Sstas	    continue;
261233294Sstas	else if (code)
262233294Sstas	    return code;
263233294Sstas
264233294Sstas	code = hdb_value2entry_alias(context, &value, &alias);
265233294Sstas	krb5_data_free(&value);
266233294Sstas
267233294Sstas	if (code == ASN1_BAD_ID)
268233294Sstas	    return HDB_ERR_EXISTS;
269233294Sstas	else if (code)
270233294Sstas	    return code;
271233294Sstas
272233294Sstas	code = krb5_principal_compare(context, alias.principal,
273233294Sstas				      entry->entry.principal);
274233294Sstas	free_hdb_entry_alias(&alias);
275233294Sstas	if (code == 0)
276233294Sstas	    return HDB_ERR_EXISTS;
277233294Sstas    }
278233294Sstas    return 0;
279233294Sstas}
280233294Sstas
28155682Smarkmkrb5_error_code
282178825Sdfr_hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
28355682Smarkm{
28455682Smarkm    krb5_data key, value;
28555682Smarkm    int code;
28655682Smarkm
287233294Sstas    /* check if new aliases already is used */
288233294Sstas    code = hdb_check_aliases(context, db, entry);
289233294Sstas    if (code)
290233294Sstas	return code;
291233294Sstas
292178825Sdfr    if(entry->entry.generation == NULL) {
29390926Snectar	struct timeval t;
294178825Sdfr	entry->entry.generation = malloc(sizeof(*entry->entry.generation));
295178825Sdfr	if(entry->entry.generation == NULL) {
296233294Sstas	    krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
29790926Snectar	    return ENOMEM;
29890926Snectar	}
29990926Snectar	gettimeofday(&t, NULL);
300178825Sdfr	entry->entry.generation->time = t.tv_sec;
301178825Sdfr	entry->entry.generation->usec = t.tv_usec;
302178825Sdfr	entry->entry.generation->gen = 0;
30390926Snectar    } else
304178825Sdfr	entry->entry.generation->gen++;
305233294Sstas
306178825Sdfr    code = hdb_seal_keys(context, db, &entry->entry);
307233294Sstas    if (code)
30872445Sassar	return code;
309178825Sdfr
310233294Sstas    hdb_principal2key(context, entry->entry.principal, &key);
311233294Sstas
312178825Sdfr    /* remove aliases */
313178825Sdfr    code = hdb_remove_aliases(context, db, &key);
314178825Sdfr    if (code) {
315178825Sdfr	krb5_data_free(&key);
316178825Sdfr	return code;
317178825Sdfr    }
318178825Sdfr    hdb_entry2value(context, &entry->entry, &value);
319178825Sdfr    code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value);
32055682Smarkm    krb5_data_free(&value);
32155682Smarkm    krb5_data_free(&key);
322178825Sdfr    if (code)
323178825Sdfr	return code;
324178825Sdfr
325178825Sdfr    code = hdb_add_aliases(context, db, flags, entry);
326178825Sdfr
32755682Smarkm    return code;
32855682Smarkm}
32955682Smarkm
33055682Smarkmkrb5_error_code
331178825Sdfr_hdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)
33255682Smarkm{
33355682Smarkm    krb5_data key;
33455682Smarkm    int code;
33555682Smarkm
336178825Sdfr    hdb_principal2key(context, principal, &key);
337178825Sdfr
338178825Sdfr    code = hdb_remove_aliases(context, db, &key);
339178825Sdfr    if (code) {
340178825Sdfr	krb5_data_free(&key);
341178825Sdfr	return code;
342178825Sdfr    }
343178825Sdfr    code = db->hdb__del(context, db, key);
34455682Smarkm    krb5_data_free(&key);
34555682Smarkm    return code;
34655682Smarkm}
34755682Smarkm
348