diff options
Diffstat (limited to 'crypto/heimdal/lib/hdb/hdb.c')
-rw-r--r-- | crypto/heimdal/lib/hdb/hdb.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/crypto/heimdal/lib/hdb/hdb.c b/crypto/heimdal/lib/hdb/hdb.c new file mode 100644 index 0000000..edf6677 --- /dev/null +++ b/crypto/heimdal/lib/hdb/hdb.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 1997, 1998, 1999 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: hdb.c,v 1.35 1999/12/02 17:05:05 joda Exp $"); + +krb5_error_code +hdb_next_enctype2key(krb5_context context, + hdb_entry *e, + krb5_enctype enctype, + Key **key) +{ + Key *k; + + for (k = *key ? *key : e->keys.val; + k < e->keys.val + e->keys.len; + k++) + if(k->key.keytype == enctype){ + *key = k; + return 0; + } + return KRB5_PROG_ETYPE_NOSUPP; /* XXX */ +} + +krb5_error_code +hdb_enctype2key(krb5_context context, + hdb_entry *e, + krb5_enctype enctype, + Key **key) +{ + *key = NULL; + return hdb_next_enctype2key(context, e, enctype, key); +} + +/* this is a bit ugly, but will get better when the crypto framework + gets fixed */ + +krb5_error_code +hdb_process_master_key(krb5_context context, EncryptionKey key, + krb5_data *schedule) +{ + krb5_error_code ret; + + if(key.keytype != ETYPE_DES_CBC_MD5) + return KRB5_PROG_KEYTYPE_NOSUPP; + + ret = krb5_data_alloc (schedule, sizeof(des_key_schedule)); + if (ret) + return ret; + + des_set_key((des_cblock*)key.keyvalue.data, schedule->data); + return 0; +} + +krb5_error_code +hdb_read_master_key(krb5_context context, const char *filename, + EncryptionKey *key) +{ + FILE *f; + unsigned char buf[256]; + size_t len; + krb5_error_code ret; + if(filename == NULL) + filename = HDB_DB_DIR "/m-key"; + f = fopen(filename, "r"); + if(f == NULL) + return errno; + len = fread(buf, 1, sizeof(buf), f); + if(ferror(f)) + ret = errno; + else + ret = decode_EncryptionKey(buf, len, key, &len); + fclose(f); + memset(buf, 0, sizeof(buf)); + return ret; +} + +void +_hdb_unseal_keys_int(hdb_entry *ent, int key_version, krb5_data schedule) +{ + int i; + for(i = 0; i < ent->keys.len; i++){ + des_cblock iv; + int num = 0; + if(ent->keys.val[i].mkvno == NULL) + continue; + if(*ent->keys.val[i].mkvno != key_version) + ; + memset(&iv, 0, sizeof(iv)); + + des_cfb64_encrypt(ent->keys.val[i].key.keyvalue.data, + ent->keys.val[i].key.keyvalue.data, + ent->keys.val[i].key.keyvalue.length, + schedule.data, &iv, &num, 0); + free(ent->keys.val[i].mkvno); + ent->keys.val[i].mkvno = NULL; + } +} + +void +hdb_unseal_keys(HDB *db, hdb_entry *ent) +{ + if (db->master_key_set == 0) + return; + _hdb_unseal_keys_int(ent, db->master_key_version, db->master_key); +} + +void +_hdb_seal_keys_int(hdb_entry *ent, int key_version, krb5_data schedule) +{ + int i; + for(i = 0; i < ent->keys.len; i++){ + des_cblock iv; + int num = 0; + + if(ent->keys.val[i].mkvno != NULL) + continue; + memset(&iv, 0, sizeof(iv)); + des_cfb64_encrypt(ent->keys.val[i].key.keyvalue.data, + ent->keys.val[i].key.keyvalue.data, + ent->keys.val[i].key.keyvalue.length, + schedule.data, &iv, &num, 1); + ent->keys.val[i].mkvno = malloc(sizeof(*ent->keys.val[i].mkvno)); + *ent->keys.val[i].mkvno = key_version; + } +} + +void +hdb_seal_keys(HDB *db, hdb_entry *ent) +{ + if (db->master_key_set == 0) + return; + + _hdb_seal_keys_int(ent, db->master_key_version, db->master_key); +} + +void +hdb_free_key(Key *key) +{ + memset(key->key.keyvalue.data, + 0, + key->key.keyvalue.length); + free_Key(key); + free(key); +} + + +krb5_error_code +hdb_lock(int fd, int operation) +{ + int i, code; + for(i = 0; i < 3; i++){ + code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB); + if(code == 0 || errno != EWOULDBLOCK) + break; + sleep(1); + } + if(code == 0) + return 0; + if(errno == EWOULDBLOCK) + return HDB_ERR_DB_INUSE; + return HDB_ERR_CANT_LOCK_DB; +} + +krb5_error_code +hdb_unlock(int fd) +{ + int code; + code = flock(fd, LOCK_UN); + if(code) + return 4711 /* XXX */; + return 0; +} + +void +hdb_free_entry(krb5_context context, hdb_entry *ent) +{ + int i; + + for(i = 0; i < ent->keys.len; ++i) { + Key *k = &ent->keys.val[i]; + + memset (k->key.keyvalue.data, 0, k->key.keyvalue.length); + } + free_hdb_entry(ent); +} + +krb5_error_code +hdb_foreach(krb5_context context, + HDB *db, + unsigned flags, + hdb_foreach_func_t func, + void *data) +{ + krb5_error_code ret; + hdb_entry entry; + ret = db->firstkey(context, db, flags, &entry); + while(ret == 0){ + ret = (*func)(context, db, &entry, data); + hdb_free_entry(context, &entry); + if(ret == 0) + ret = db->nextkey(context, db, flags, &entry); + } + if(ret == HDB_ERR_NOENTRY) + ret = 0; + return ret; +} + +krb5_error_code +hdb_check_db_format(krb5_context context, HDB *db) +{ + krb5_data tag; + krb5_data version; + krb5_error_code ret; + unsigned ver; + int foo; + + tag.data = HDB_DB_FORMAT_ENTRY; + tag.length = strlen(tag.data); + ret = (*db->_get)(context, db, tag, &version); + if(ret) + return ret; + foo = sscanf(version.data, "%u", &ver); + krb5_data_free (&version); + if (foo != 1) + return HDB_ERR_BADVERSION; + if(ver != HDB_DB_FORMAT) + return HDB_ERR_BADVERSION; + return 0; +} + +krb5_error_code +hdb_init_db(krb5_context context, HDB *db) +{ + krb5_error_code ret; + krb5_data tag; + krb5_data version; + char ver[32]; + + ret = hdb_check_db_format(context, db); + if(ret != HDB_ERR_NOENTRY) + return ret; + + tag.data = HDB_DB_FORMAT_ENTRY; + tag.length = strlen(tag.data); + snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT); + version.data = ver; + version.length = strlen(version.data) + 1; /* zero terminated */ + ret = (*db->_put)(context, db, 0, tag, version); + return ret; +} + +krb5_error_code +hdb_create(krb5_context context, HDB **db, const char *filename) +{ + krb5_error_code ret = 0; + if(filename == NULL) + filename = HDB_DEFAULT_DB; + initialize_hdb_error_table_r(&context->et_list); +#ifdef HAVE_DB_H + ret = hdb_db_create(context, db, filename); +#elif HAVE_NDBM_H + ret = hdb_ndbm_create(context, db, filename); +#else + krb5_errx(context, 1, "No database support! (hdb_create)"); +#endif + return ret; +} + +krb5_error_code +hdb_set_master_key (krb5_context context, + HDB *db, + EncryptionKey key) +{ + krb5_error_code ret; + + ret = hdb_process_master_key(context, key, &db->master_key); + if (ret) + return ret; +#if 0 /* XXX - why? */ + des_set_random_generator_seed(key.keyvalue.data); +#endif + db->master_key_set = 1; + db->master_key_version = 0; /* XXX */ + return 0; +} + +krb5_error_code +hdb_set_master_keyfile (krb5_context context, + HDB *db, + const char *keyfile) +{ + EncryptionKey key; + krb5_error_code ret; + + ret = hdb_read_master_key(context, keyfile, &key); + if (ret) { + if (ret != ENOENT) + return ret; + return 0; + } + ret = hdb_set_master_key(context, db, key); + memset(key.keyvalue.data, 0, key.keyvalue.length); + free_EncryptionKey(&key); + return ret; +} + +krb5_error_code +hdb_clear_master_key (krb5_context context, + HDB *db) +{ + if (db->master_key_set) { + memset(db->master_key.data, 0, db->master_key.length); + krb5_data_free(&db->master_key); + db->master_key_set = 0; + } + return 0; +} |