diff options
Diffstat (limited to 'lib/hdb/common.c')
-rw-r--r-- | lib/hdb/common.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/lib/hdb/common.c b/lib/hdb/common.c new file mode 100644 index 0000000..680b666 --- /dev/null +++ b/lib/hdb/common.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" + +RCSID("$Id: common.c 20236 2007-02-16 23:52:29Z lha $"); + +int +hdb_principal2key(krb5_context context, krb5_const_principal p, krb5_data *key) +{ + Principal new; + size_t len; + int ret; + + ret = copy_Principal(p, &new); + if(ret) + return ret; + new.name.name_type = 0; + + ASN1_MALLOC_ENCODE(Principal, key->data, key->length, &new, &len, ret); + if (ret == 0 && key->length != len) + krb5_abortx(context, "internal asn.1 encoder error"); + free_Principal(&new); + return ret; +} + +int +hdb_key2principal(krb5_context context, krb5_data *key, krb5_principal p) +{ + return decode_Principal(key->data, key->length, p, NULL); +} + +int +hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value) +{ + size_t len; + int ret; + + ASN1_MALLOC_ENCODE(hdb_entry, value->data, value->length, ent, &len, ret); + if (ret == 0 && value->length != len) + krb5_abortx(context, "internal asn.1 encoder error"); + return ret; +} + +int +hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent) +{ + return decode_hdb_entry(value->data, value->length, ent, NULL); +} + +int +hdb_entry_alias2value(krb5_context context, + const hdb_entry_alias *alias, + krb5_data *value) +{ + size_t len; + int ret; + + ASN1_MALLOC_ENCODE(hdb_entry_alias, value->data, value->length, + alias, &len, ret); + if (ret == 0 && value->length != len) + krb5_abortx(context, "internal asn.1 encoder error"); + return ret; +} + +int +hdb_value2entry_alias(krb5_context context, krb5_data *value, + hdb_entry_alias *ent) +{ + return decode_hdb_entry_alias(value->data, value->length, ent, NULL); +} + +krb5_error_code +_hdb_fetch(krb5_context context, HDB *db, krb5_const_principal principal, + unsigned flags, hdb_entry_ex *entry) +{ + krb5_data key, value; + int code; + + hdb_principal2key(context, principal, &key); + code = db->hdb__get(context, db, key, &value); + krb5_data_free(&key); + if(code) + return code; + code = hdb_value2entry(context, &value, &entry->entry); + if (code == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) { + krb5_data_free(&value); + return HDB_ERR_NOENTRY; + } else if (code == ASN1_BAD_ID) { + hdb_entry_alias alias; + + code = hdb_value2entry_alias(context, &value, &alias); + if (code) { + krb5_data_free(&value); + return code; + } + hdb_principal2key(context, alias.principal, &key); + krb5_data_free(&value); + free_hdb_entry_alias(&alias); + + code = db->hdb__get(context, db, key, &value); + krb5_data_free(&key); + if (code) + return code; + code = hdb_value2entry(context, &value, &entry->entry); + if (code) { + krb5_data_free(&value); + return code; + } + } + krb5_data_free(&value); + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + code = hdb_unseal_keys (context, db, &entry->entry); + if (code) + hdb_free_entry(context, entry); + } + return code; +} + +static krb5_error_code +hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key) +{ + const HDB_Ext_Aliases *aliases; + krb5_error_code code; + hdb_entry oldentry; + krb5_data value; + int i; + + code = db->hdb__get(context, db, *key, &value); + if (code == HDB_ERR_NOENTRY) + return 0; + else if (code) + return code; + + code = hdb_value2entry(context, &value, &oldentry); + krb5_data_free(&value); + if (code) + return code; + + code = hdb_entry_get_aliases(&oldentry, &aliases); + if (code || aliases == NULL) { + free_hdb_entry(&oldentry); + return code; + } + for (i = 0; i < aliases->aliases.len; i++) { + krb5_data akey; + + hdb_principal2key(context, &aliases->aliases.val[i], &akey); + code = db->hdb__del(context, db, akey); + krb5_data_free(&akey); + if (code) { + free_hdb_entry(&oldentry); + return code; + } + } + free_hdb_entry(&oldentry); + return 0; +} + +static krb5_error_code +hdb_add_aliases(krb5_context context, HDB *db, + unsigned flags, hdb_entry_ex *entry) +{ + const HDB_Ext_Aliases *aliases; + krb5_error_code code; + krb5_data key, value; + int i; + + code = hdb_entry_get_aliases(&entry->entry, &aliases); + if (code || aliases == NULL) + return code; + + for (i = 0; i < aliases->aliases.len; i++) { + hdb_entry_alias entryalias; + entryalias.principal = entry->entry.principal; + + hdb_principal2key(context, &aliases->aliases.val[i], &key); + code = hdb_entry_alias2value(context, &entryalias, &value); + if (code) { + krb5_data_free(&key); + return code; + } + code = db->hdb__put(context, db, flags, key, value); + krb5_data_free(&key); + krb5_data_free(&value); + if (code) + return code; + } + return 0; +} + +krb5_error_code +_hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +{ + krb5_data key, value; + int code; + + if(entry->entry.generation == NULL) { + struct timeval t; + entry->entry.generation = malloc(sizeof(*entry->entry.generation)); + if(entry->entry.generation == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + gettimeofday(&t, NULL); + entry->entry.generation->time = t.tv_sec; + entry->entry.generation->usec = t.tv_usec; + entry->entry.generation->gen = 0; + } else + entry->entry.generation->gen++; + hdb_principal2key(context, entry->entry.principal, &key); + code = hdb_seal_keys(context, db, &entry->entry); + if (code) { + krb5_data_free(&key); + return code; + } + + /* remove aliases */ + code = hdb_remove_aliases(context, db, &key); + if (code) { + krb5_data_free(&key); + return code; + } + hdb_entry2value(context, &entry->entry, &value); + code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value); + krb5_data_free(&value); + krb5_data_free(&key); + if (code) + return code; + + code = hdb_add_aliases(context, db, flags, entry); + + return code; +} + +krb5_error_code +_hdb_remove(krb5_context context, HDB *db, krb5_const_principal principal) +{ + krb5_data key; + int code; + + hdb_principal2key(context, principal, &key); + + code = hdb_remove_aliases(context, db, &key); + if (code) { + krb5_data_free(&key); + return code; + } + code = db->hdb__del(context, db, key); + krb5_data_free(&key); + return code; +} + |