From 4f0debdb553c49e68b36ee4e0ece3d2f32e4ae03 Mon Sep 17 00:00:00 2001 From: Chris Provenzano Date: Thu, 27 Jul 1995 08:44:02 +0000 Subject: [PATCH] * decrypt_key.c, encrypt_key.c, kdb_dbm.c, kdb_xdr.c: Rewritten for new kdb format. * kdb_cpw.c : New password changing routines for new kdb format. * verify_mky.c, t_kdb.c : Use new kdb format. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6328 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/kdb/ChangeLog | 8 + src/lib/kdb/Makefile.in | 2 + src/lib/kdb/decrypt_key.c | 77 +++-- src/lib/kdb/encrypt_key.c | 99 +++--- src/lib/kdb/kdb_cpw.c | 68 ++++ src/lib/kdb/kdb_dbm.c | 498 +++-------------------------- src/lib/kdb/kdb_xdr.c | 652 ++++++++++++++++++++++++++++++++++++++ src/lib/kdb/t_kdb.c | 116 ++++--- src/lib/kdb/verify_mky.c | 4 +- 9 files changed, 936 insertions(+), 588 deletions(-) create mode 100644 src/lib/kdb/kdb_cpw.c create mode 100644 src/lib/kdb/kdb_xdr.c diff --git a/src/lib/kdb/ChangeLog b/src/lib/kdb/ChangeLog index fcebad85d..5cb3bf914 100644 --- a/src/lib/kdb/ChangeLog +++ b/src/lib/kdb/ChangeLog @@ -1,3 +1,11 @@ + +Thu Jul 27 02:59:05 1995 Chris Provenzano (proven@mit.edu) + * decrypt_key.c, encrypt_key.c, kdb_dbm.c, kdb_xdr.c: + Rewritten for new kdb format. + * kdb_cpw.c : New password changing routines for new kdb format. + * verify_mky.c, t_kdb.c : Use new kdb format. + + Tue Jul 25 14:06:50 1995 Tom Yu * kdb_dbm.c, t_kdb.c: Add prototype for dbm_error and dbm_clearerr diff --git a/src/lib/kdb/Makefile.in b/src/lib/kdb/Makefile.in index afb8fe31e..fad482eec 100644 --- a/src/lib/kdb/Makefile.in +++ b/src/lib/kdb/Makefile.in @@ -8,6 +8,7 @@ SRCS= \ $(srcdir)/encrypt_key.c \ $(srcdir)/decrypt_key.c \ $(srcdir)/kdb_dbm.c \ + $(srcdir)/kdb_xdr.c \ $(srcdir)/verify_mky.c \ $(srcdir)/fetch_mkey.c \ $(srcdir)/setup_mkey.c \ @@ -17,6 +18,7 @@ OBJS= \ encrypt_key.o \ decrypt_key.o \ kdb_dbm.o \ + kdb_xdr.o \ verify_mky.o \ fetch_mkey.o \ setup_mkey.o \ diff --git a/src/lib/kdb/decrypt_key.c b/src/lib/kdb/decrypt_key.c index cb901b677..cc0503f8f 100644 --- a/src/lib/kdb/decrypt_key.c +++ b/src/lib/kdb/decrypt_key.c @@ -33,51 +33,50 @@ */ krb5_error_code -krb5_kdb_decrypt_key(context, eblock, in, out) - krb5_context context; - krb5_encrypt_block *eblock; - const krb5_encrypted_keyblock *in; - krb5_keyblock *out; +krb5_dbekd_decrypt_key_data(context, eblock, key_data, keyblock, keysalt) + krb5_context context; + krb5_encrypt_block * eblock; + const krb5_key_data * key_data; + krb5_keyblock * keyblock; + krb5_keysalt * keysalt; { - krb5_error_code retval; + krb5_error_code retval; + krb5_octet * ptr; - /* the encrypted version is stored as the unencrypted key length - (4 bytes, MSB first) followed by the encrypted key. */ - out->magic = KV5M_KEYBLOCK; - out->etype = ETYPE_UNKNOWN; - out->keytype = in->keytype; - out->length = krb5_encrypt_size(in->length-sizeof(in->length), - eblock->crypto_entry); - out->contents = (krb5_octet *)malloc(out->length); - if (!out->contents) { - out->contents = 0; - out->length = 0; - return ENOMEM; - } + keyblock->magic = KV5M_KEYBLOCK; + keyblock->etype = ETYPE_UNKNOWN; + keyblock->keytype = key_data->key_data_type[0]; - /* copy out the real length count */ - out->length = (((unsigned char *)in->contents)[0] << 24) - + (((unsigned char *)in->contents)[1] << 16) - + (((unsigned char *)in->contents)[2] << 8) - + ((unsigned char *)in->contents)[3]; + /* Decrypt key_data_contents */ + if ((keyblock->contents = (krb5_octet *)malloc(krb5_encrypt_size( + key_data->key_data_length[0] - 2, eblock->crypto_entry))) == NULL) + return ENOMEM; - /* remember the contents of the encrypted version has a 4 byte - integer length of the real embedded key, followed by the - encrypted key, so the offset here is needed */ - if (retval = krb5_decrypt(context, (krb5_pointer) ( - (char *) in->contents + 4), - (krb5_pointer) out->contents, - in->length-sizeof(in->length), eblock, 0)) { - krb5_xfree(out->contents); - out->contents = 0; - out->length = 0; + keyblock->length = 0; + ptr = key_data->key_data_contents[0]; + *(((krb5_octet *)(&keyblock->length))) = *ptr++; + *(((krb5_octet *)(&keyblock->length)) + 1) = *ptr++; + if (retval = krb5_decrypt(context, (krb5_pointer) ptr, + (krb5_pointer)keyblock->contents, + key_data->key_data_length[0] - 2, + eblock, 0)) { + krb5_xfree(keyblock->contents); return retval; } - if (out->length < 0) { - krb5_xfree(out->contents); - out->contents = 0; - out->length = 0; - return KRB5_KDB_INVALIDKEYSIZE; + + /* Decode salt data */ + if (keysalt) { + if (key_data->key_data_ver == 2) { + keysalt->type = key_data->key_data_type[1]; + keysalt->data.length = key_data->key_data_length[1]; + if (!(keysalt->data.data = (krb5_octet *)malloc(keysalt->data.length))){ + krb5_xfree(keyblock->contents); + return ENOMEM; + } + } else { + keysalt->type = KRB5_KDB_SALTTYPE_NORMAL; + keysalt->data.length = 0; + } } return retval; } diff --git a/src/lib/kdb/encrypt_key.c b/src/lib/kdb/encrypt_key.c index 277983e34..272280a00 100644 --- a/src/lib/kdb/encrypt_key.c +++ b/src/lib/kdb/encrypt_key.c @@ -33,57 +33,74 @@ */ krb5_error_code -krb5_kdb_encrypt_key(context, eblock, in, out) - krb5_context context; - krb5_encrypt_block *eblock; - const krb5_keyblock *in; - register krb5_encrypted_keyblock *out; +krb5_dbekd_encrypt_key_data(context, eblock, keyblock, keysalt, keyver,key_data) + krb5_context context; + krb5_encrypt_block * eblock; + const krb5_keyblock * keyblock; + const krb5_keysalt * keysalt; + int keyver; + krb5_key_data * key_data; { - /* Encrypted rep has the real (unencrypted) key length stored - along with the encrypted key. The length is stored as a 4 - byte integer, MSB first. */ + krb5_error_code retval; + krb5_keyblock tmp; + krb5_octet * ptr; + krb5_int16 len; + int i; - krb5_error_code retval; - krb5_keyblock tmpin; - unsigned int length; + for (i = 0; i < key_data->key_data_ver; i++) + if (key_data->key_data_contents[i]) + krb5_xfree(key_data->key_data_contents[i]); - out->keytype = in->keytype; - out->length = krb5_encrypt_size(in->length, eblock->crypto_entry); + key_data->key_data_ver = 1; + key_data->key_data_kvno = keyver; - /* because of checksum space requirements imposed by the encryption - interface, we need to copy the input key into a larger area. */ - tmpin.length = in->length; - tmpin.contents = (krb5_octet *)malloc(out->length); - if (!tmpin.contents) { - out->length = 0; + /* + * The First element of the type/length/contents + * fields is the key type/length/contents + */ + key_data->key_data_type[0] = keyblock->keytype; + key_data->key_data_length[0] = krb5_encrypt_size(keyblock->length, + eblock->crypto_entry) + 2; + + /* + * because of checksum space requirements imposed by the encryption + * interface, we need to copy the input key into a larger area. + */ + tmp.contents = (krb5_octet *)malloc(key_data->key_data_length[0] - 2); + len = tmp.length = keyblock->length; + if (tmp.contents == NULL) return ENOMEM; - } - memcpy((char *)tmpin.contents, (const char *)in->contents, tmpin.length); - out->length += sizeof(out->length); - out->contents = (krb5_octet *)malloc(out->length); - if (!out->contents) { - krb5_xfree(tmpin.contents); - out->contents = 0; - out->length = 0; + memcpy((char *)tmp.contents, (const char *)keyblock->contents, tmp.length); + key_data->key_data_contents[0] = ptr = (krb5_octet *)malloc( + key_data->key_data_length[0] - 2); + if (key_data->key_data_contents[0] == NULL) { + krb5_xfree(tmp.contents); return ENOMEM; } - length = tmpin.length; - ((char *)out->contents)[0] = length >> 24; - ((char *)out->contents)[1] = length >> 16; - ((char *)out->contents)[2] = length >> 8; - ((char *)out->contents)[3] = length; - - retval = krb5_encrypt(context, (krb5_pointer) tmpin.contents, - (krb5_pointer) ((char *) out->contents + 4), - tmpin.length, eblock, 0); - krb5_xfree(tmpin.contents); - if (retval) { - krb5_xfree(out->contents); - out->contents = 0; - out->length = 0; + *ptr++ = len & 0xff; + *ptr++ = (len >> 8) & 0xff; + if (retval = krb5_encrypt(context, (krb5_pointer) tmp.contents, + (krb5_pointer)(ptr), tmp.length, eblock, 0)) { + krb5_xfree(key_data->key_data_contents[0]); + krb5_xfree(tmp.contents); + return retval; } + krb5_xfree(tmp.contents); + + /* After key comes the salt in necessary */ + if (keysalt) { + key_data->key_data_contents[1] = + (krb5_octet *)malloc(keysalt->data.length); + if (key_data->key_data_contents[1] == NULL) { + krb5_xfree(key_data->key_data_contents[0]); + return ENOMEM; + } + key_data->key_data_length[1] = keysalt->data.length; + key_data->key_data_type[1] = keysalt->type; + key_data->key_data_ver++; + } return retval; } diff --git a/src/lib/kdb/kdb_cpw.c b/src/lib/kdb/kdb_cpw.c new file mode 100644 index 000000000..7376c22c4 --- /dev/null +++ b/src/lib/kdb/kdb_cpw.c @@ -0,0 +1,68 @@ +/* + * lib/kdb/kdb_cpw.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#include "k5-int.h" +#include +#include + +/* + * Change password for a krb5_db_entry for a specific key version number + */ +krb5_error_code +krb5_kdb_cpw_dbe_for_kvno(context, db_entry, password, kvno) + krb5_context context; + krb5_db_entry * db_entry; + char * password; + int kvno; +{ + krb5_error_code retval; + int key; + + for (key = 0; key < db_entry.n_key_data; key++) { + if (db_entry.key_data[key] == kvno) { + } + } + return retval; +} + +/* + * Change password for a krb5_db_entry + * Assumes the max kvno + */ +krb5_error_code +krb5_kdb_cpw_dbe_for_kvno(context, db_entry, password) + krb5_context context; + krb5_db_entry * db_entry; + char * password; + int kvno; +{ + int key, kvno; + + for (kvno = key = 0; key < db_entry.n_key_data; key++) { + if (kvno < db_entry.key_data[key].key_data_kvno) { + kvno = db_entry.key_data[key].key_data_kvno; + } + } + return(krb5_kdb_cpw_dbe_for_kvno(context, db_entry, password, kvno)); +} diff --git a/src/lib/kdb/kdb_dbm.c b/src/lib/kdb/kdb_dbm.c index 88ebb55b0..9cb02a36e 100644 --- a/src/lib/kdb/kdb_dbm.c +++ b/src/lib/kdb/kdb_dbm.c @@ -87,35 +87,6 @@ static krb5_error_code krb5_dbm_db_start_read static krb5_error_code krb5_dbm_db_end_read PROTOTYPE((krb5_context, time_t )); -static krb5_error_code encode_princ_dbmkey - PROTOTYPE((krb5_context, - datum *, - krb5_principal )); -static void free_encode_princ_dbmkey - PROTOTYPE((krb5_context, - datum * )); -static krb5_error_code encode_princ_contents - PROTOTYPE((krb5_context, - datum *, - krb5_db_entry * )); -static void free_encode_princ_contents - PROTOTYPE((datum * )); -static krb5_error_code decode_princ_contents - PROTOTYPE((krb5_context, - datum *, - krb5_db_entry * )); -static void free_decode_princ_contents - PROTOTYPE((krb5_context, - krb5_db_entry * )); - -#if 0 -/* not used */ -static krb5_error_code decode_princ_dbmkey - PROTOTYPE((datum *, - krb5_principal * )); -static void free_decode_princ_dbmkey - PROTOTYPE((krb5_principal )); -#endif #ifdef BERK_DB_DBM @@ -170,9 +141,8 @@ int dbm_clearerr PROTOTYPE((DBM *)); /* * This module contains all of the code which directly interfaces to * the underlying representation of the Kerberos database; this - * implementation uses a DBM or NDBM indexed "file" (actually - * implemented as two separate files) to store the relations, plus a - * third file as a semaphore to allow the database to be replaced out + * implementation uses the Berkeley hash db to store the relations, plus a + * second file as a semaphore to allow the database to be replaced out * from underneath the KDC server. */ static kdb5_dispatch_table kdb5_default_dispatch = { @@ -693,402 +663,6 @@ krb5_dbm_db_end_read(context, age) return 0; } - -static krb5_error_code -encode_princ_dbmkey(context, key, principal) - krb5_context context; - datum *key; - krb5_principal principal; -{ - char *princ_name; - krb5_error_code retval; - - if (retval = krb5_unparse_name(context, principal, &princ_name)) - return(retval); - key->dptr = princ_name; - key->dsize = strlen(princ_name)+1; /* need to store the NULL for - decoding */ - return 0; -} - -static void -free_encode_princ_dbmkey(context, key) - krb5_context context; - datum *key; -{ - (void) free(key->dptr); - key->dptr = 0; - key->dsize = 0; - return; -} - -#if 0 -/* these aren't used, but if they ever should be... */ -static krb5_error_code -decode_princ_dbmkey(context, key, principal) - datum *key; - krb5_principal *principal; -{ - return(krb5_parse_name(context, key->dptr, principal)); -} - -static void -free_decode_princ_dbmkey(context, principal) - krb5_context context; - krb5_principal principal; -{ - krb5_free_principal(context, principal); - return; -} -#endif - -static krb5_error_code -encode_princ_contents(context, contents, entry) - krb5_context context; - register datum *contents; - krb5_db_entry *entry; -{ - krb5_db_entry copy_princ; - char *unparse_princ, *unparse_mod_princ; - register char *nextloc; - int princ_size, mod_size; - - krb5_error_code retval; - - /* since there is some baggage pointing off of the entry - structure, we'll encode it by writing the structure, with nulled - pointers, followed by the unparsed principal name, then the key, and - then the unparsed mod_princ name, and then the salt (if any). - */ - copy_princ = *entry; - copy_princ.principal = 0; - copy_princ.mod_name = 0; - copy_princ.salt = 0; - copy_princ.alt_salt = 0; - if (!entry->salt) - copy_princ.salt_length = 0; /* Safety measures.... */ - if (!entry->alt_salt) - copy_princ.alt_salt_length = 0; - - if (retval = krb5_unparse_name(context, entry->principal, &unparse_princ)) - return(retval); - if (retval = krb5_unparse_name(context, entry->mod_name, &unparse_mod_princ)) { - free(unparse_princ); - return(retval); - } - princ_size = strlen(unparse_princ)+1; - mod_size = strlen(unparse_mod_princ)+1; - contents->dsize = (2 + sizeof(copy_princ) + princ_size - + sizeof(entry->principal->type) + mod_size - + sizeof(copy_princ.key.length) - + copy_princ.key.length + copy_princ.salt_length - + sizeof(copy_princ.alt_key.length) - + copy_princ.alt_key.length - + copy_princ.alt_salt_length); - contents->dptr = malloc(contents->dsize); - if (!contents->dptr) { - free(unparse_princ); - free(unparse_mod_princ); - contents->dsize = 0; - contents->dptr = 0; - return(ENOMEM); - } - nextloc = contents->dptr; - *nextloc++ = 2; /* Version number 2.0 */ - *nextloc++ = 0; - (void) memcpy(nextloc, (char *)©_princ, sizeof(copy_princ)); - nextloc += sizeof(copy_princ); - - (void) memcpy(nextloc, unparse_princ, princ_size); - nextloc += princ_size; - (void) memcpy(nextloc, (char *)&entry->principal->type, - sizeof(entry->principal->type)); - nextloc += sizeof(entry->principal->type); - (void) memcpy(nextloc, unparse_mod_princ, mod_size); - nextloc += mod_size; - if (copy_princ.key.length) { - (void) memcpy(nextloc, (char *)entry->key.contents, entry->key.length); - nextloc += entry->key.length; - } - if (copy_princ.salt_length) { - (void) memcpy(nextloc, (char *)entry->salt, entry->salt_length); - nextloc += entry->salt_length; - } - if (copy_princ.alt_key.length) { - (void) memcpy(nextloc, (char *)entry->alt_key.contents, - entry->alt_key.length); - nextloc += entry->alt_key.length; - } - if (copy_princ.alt_salt_length) { - (void) memcpy(nextloc, (char *)entry->alt_salt, - entry->alt_salt_length); - nextloc += entry->alt_salt_length; - } - free(unparse_princ); - free(unparse_mod_princ); - return 0; -} - -static void -free_encode_princ_contents(contents) - datum *contents; -{ - free(contents->dptr); - contents->dsize = 0; - contents->dptr = 0; - return; -} - -static krb5_error_code -decode_princ_contents(context, contents, entry) - krb5_context context; - datum *contents; - krb5_db_entry *entry; -{ - register char *nextloc; - krb5_principal princ, mod_princ; - krb5_error_code retval; - int sizeleft; - int major_version = 0, minor_version = 0; - - /* - * undo the effects of encode_princ_contents. - */ - sizeleft = contents->dsize; - nextloc = contents->dptr; - if (sizeleft <= 0) - return KRB5_KDB_TRUNCATED_RECORD; - - /* - * First, check the version number. If the major version number is - * greater than zero, then the version number is explicitly - * allocated; otherwise, it is part of the zeroed principal pointer. - */ - major_version = *nextloc; - if (major_version) { - nextloc++; sizeleft--; - minor_version = *nextloc; - nextloc++; sizeleft--; - } -#ifdef OLD_COMPAT_VERSION_1 - if (major_version == 0 || major_version == 1) { - old_krb5_db_entry old_entry; - - /* - * Copy in structure to old-style structure, and then copy it - * to the new structure. - */ - sizeleft -= sizeof(old_entry); - if (sizeleft < 0) - return KRB5_KDB_TRUNCATED_RECORD; - - memcpy((char *) &old_entry, nextloc, sizeof(old_entry)); - nextloc += sizeof(old_entry); /* Skip past structure */ - - entry->key.keytype = old_entry.key.keytype; - entry->key.length = old_entry.key.length; - - entry->kvno = old_entry.kvno; - entry->max_life = old_entry.max_life; - entry->max_renewable_life = old_entry.max_renewable_life; - entry->mkvno = old_entry.mkvno; - - entry->expiration = old_entry.expiration; - entry->pw_expiration = old_entry.pw_expiration; - entry->last_pwd_change = old_entry.last_pwd_change; - entry->last_success = old_entry.last_success; - - entry->last_failed = old_entry.last_failed; - entry->fail_auth_count = old_entry.fail_auth_count; - - entry->mod_date = old_entry.mod_date; - entry->attributes = old_entry.attributes; - entry->salt_type = old_entry.salt_type; - entry->salt_length = old_entry.salt_length; - - entry->alt_key.keytype = old_entry.alt_key.keytype; - entry->alt_key.length = old_entry.alt_key.length; - entry->alt_salt_type = old_entry.alt_salt_type; - entry->alt_salt_length = old_entry.alt_salt_length; - - goto resume_processing; - } -#endif - if (major_version != 2) - return KRB5_KDB_BAD_VERSION; - - sizeleft -= sizeof(*entry); - if (sizeleft < 0) - return KRB5_KDB_TRUNCATED_RECORD; - - memcpy((char *) entry, nextloc, sizeof(*entry)); - nextloc += sizeof(*entry); /* Skip past structure */ - -#ifdef OLD_COMPAT_VERSION_1 -resume_processing: -#endif - - /* - * These values should be zero if they are not in use, but just in - * case, we clear them to make sure nothing bad happens if we need - * to call free_decode_princ_contents(). (What me, paranoid?) - */ - entry->principal = 0; - entry->mod_name = 0; - entry->salt = 0; - entry->alt_salt = 0; - entry->key.contents = 0; - entry->alt_key.contents = 0; - - /* - * Get the principal name for the entry (stored as a string which - * gets unparsed.) - */ - sizeleft -= strlen(nextloc)+1; - if (sizeleft < 0) { - retval = KRB5_KDB_TRUNCATED_RECORD; - goto error_out; - } - retval = krb5_parse_name(context, nextloc, &princ); - if (retval) - goto error_out; - entry->principal = princ; - nextloc += strlen(nextloc)+1; /* advance past 1st string */ - - if (major_version >= 1) { /* Get principal type */ - sizeleft -= sizeof(entry->principal->type); - if (sizeleft < 0) { - retval = KRB5_KDB_TRUNCATED_RECORD; - goto error_out; - } - memcpy((char *)&entry->principal->type,nextloc, - sizeof(entry->principal->type)); - nextloc += sizeof(princ->type); - } - - /* - * Get the last modified principal for the entry (again stored as - * string which gets unparased.) - */ - sizeleft -= strlen(nextloc)+1; /* check size for 2nd string */ - if (sizeleft < 0) { - retval = KRB5_KDB_TRUNCATED_RECORD; - goto error_out; - } - retval = krb5_parse_name(context, nextloc, &mod_princ); - if (retval) - goto error_out; - entry->mod_name = mod_princ; - nextloc += strlen(nextloc)+1; /* advance past 2nd string */ - - /* - * Get the primary key... - */ - if (entry->key.length) { - sizeleft -= entry->key.length; /* check size for key */ - if (sizeleft < 0) { - retval = KRB5_KDB_TRUNCATED_RECORD; - goto error_out; - } - entry->key.contents = (unsigned char *)malloc(entry->key.length); - if (!entry->key.contents) { - retval = ENOMEM; - goto error_out; - } - (void) memcpy((char *)entry->key.contents, nextloc, entry->key.length); - nextloc += entry->key.length; /* advance past key */ - } - - /* - * ...and the salt, if present... - */ - if (entry->salt_length) { - sizeleft -= entry->salt_length; - if (sizeleft < 0) { - retval = KRB5_KDB_TRUNCATED_RECORD; - goto error_out; - } - entry->salt = (krb5_octet *)malloc(entry->salt_length); - if (!entry->salt) { - retval = KRB5_KDB_TRUNCATED_RECORD; - goto error_out; - } - (void) memcpy((char *)entry->salt, nextloc, entry->salt_length); - nextloc += entry->salt_length; /* advance past salt */ - } - - /* - * ... and the alternate key, if present... - */ - if (entry->alt_key.length) { - sizeleft -= entry->alt_key.length; /* check size for alt_key */ - if (sizeleft < 0) { - retval = KRB5_KDB_TRUNCATED_RECORD; - goto error_out; - } - entry->alt_key.contents = (unsigned char *) malloc(entry->alt_key.length); - if (!entry->alt_key.contents) { - retval = ENOMEM; - goto error_out; - } - (void) memcpy((char *)entry->alt_key.contents, nextloc, - entry->alt_key.length); - nextloc += entry->alt_key.length; /* advance past alt_key */ - } - - /* - * ...and the alternate key's salt, if present. - */ - if (entry->alt_salt_length) { - sizeleft -= entry->alt_salt_length; - if (sizeleft < 0) { - retval = KRB5_KDB_TRUNCATED_RECORD; - goto error_out; - } - entry->alt_salt = (krb5_octet *)malloc(entry->alt_salt_length); - if (!entry->alt_salt) { - retval = KRB5_KDB_TRUNCATED_RECORD; - goto error_out; - } - (void) memcpy((char *)entry->alt_salt, nextloc, - entry->alt_salt_length); - nextloc += entry->alt_salt_length; /* advance past salt */ - } - - return 0; -error_out: - free_decode_princ_contents(context, entry); - return retval; -} - -static void -free_decode_princ_contents(context, entry) - krb5_context context; - krb5_db_entry *entry; -{ - /* erase the key */ - if (entry->key.contents) { - memset((char *)entry->key.contents, 0, entry->key.length); - krb5_xfree(entry->key.contents); - } - if (entry->salt) - krb5_xfree(entry->salt); - - if (entry->alt_key.contents) { - memset((char *)entry->alt_key.contents, 0, entry->alt_key.length); - krb5_xfree(entry->alt_key.contents); - } - if (entry->alt_salt) - krb5_xfree(entry->alt_salt); - - if (entry->principal) - krb5_free_principal(context, entry->principal); - if (entry->mod_name) - krb5_free_principal(context, entry->mod_name); - (void) memset((char *)entry, 0, sizeof(*entry)); - return; -} - krb5_error_code krb5_dbm_db_lock(context, mode) krb5_context context; @@ -1431,7 +1005,7 @@ errout: free_dbsuffix (fromdir); if (retval == 0) - retval = krb5_dbm_db_end_update(context, to, trans); + return krb5_dbm_db_end_update(context, to, trans); if (tmpcontext) { k5dbm_clear_context((db_context_t *) context->db_context); @@ -1488,15 +1062,15 @@ krb5_boolean *more; /* are there more? */ *more = FALSE; /* XXX deal with wildcard lookups */ - if (retval = encode_princ_dbmkey(context, &key, searchfor)) + if (retval = krb5_encode_princ_dbmkey(context, &key, searchfor)) goto cleanup; contents = KDBM_FETCH(db_ctx, db, key); - free_encode_princ_dbmkey(context, &key); + krb5_free_princ_dbmkey(context, &key); if (contents.dptr == NULL) found = 0; - else if (retval = decode_princ_contents(context, &contents, entries)) + else if (retval = krb5_decode_princ_contents(context,&contents,entries)) goto cleanup; else found = 1; @@ -1534,7 +1108,7 @@ krb5_dbm_db_free_principal(context, entries, nentries) { register int i; for (i = 0; i < nentries; i++) - free_decode_princ_contents(context, &entries[i]); + krb5_dbe_free_contents(context, &entries[i]); return; } @@ -1587,19 +1161,19 @@ krb5_dbm_db_put_principal(context, entries, nentries) /* for each one, stuff temps, and do replace/append */ for (i = 0; i < *nentries; i++) { - if (retval = encode_princ_contents(context, &contents, entries)) + if (retval = krb5_encode_princ_contents(context, &contents, entries)) break; - if (retval = encode_princ_dbmkey(context, &key, entries->principal)) { - free_encode_princ_contents(&contents); + if (retval = krb5_encode_princ_dbmkey(context, &key, entries->princ)) { + krb5_free_princ_contents(context, &contents); break; } if (KDBM_STORE(db_ctx, db, key, contents, DBM_REPLACE)) retval = errno; else retval = 0; - free_encode_princ_contents(&contents); - free_encode_princ_dbmkey(context, &key); + krb5_free_princ_contents(context, &contents); + krb5_free_princ_dbmkey(context, &key); if (retval) break; entries++; /* bump to next struct */ @@ -1619,16 +1193,16 @@ krb5_dbm_db_put_principal(context, entries, nentries) krb5_error_code krb5_dbm_db_delete_principal(context, searchfor, nentries) - krb5_context context; -krb5_principal searchfor; -int *nentries; /* how many found & deleted */ + krb5_context context; + krb5_principal searchfor; + int * nentries; /* how many found & deleted */ { - int found = 0; - datum key, contents, contents2; - krb5_db_entry entry; - DBM *db; - krb5_error_code retval; - db_context_t *db_ctx; + krb5_error_code retval; + krb5_db_entry entry; + db_context_t * db_ctx; + datum key, contents, contents2; + DBM * db; + int i; if (!k5dbm_inited(context)) return KRB5_KDB_DBNOTINITED; @@ -1648,19 +1222,26 @@ int *nentries; /* how many found & deleted */ } } - if (retval = encode_princ_dbmkey(context, &key, searchfor)) + if (retval = krb5_encode_princ_dbmkey(context, &key, searchfor)) goto cleanup; contents = KDBM_FETCH(db_ctx, db, key); if (contents.dptr == NULL) { - found = 0; retval = KRB5_KDB_NOENTRY; + *nentries = 0; } else { - if (retval = decode_princ_contents(context, &contents, &entry)) + memset((char *)&entry, 0, sizeof(entry)); + if (retval = krb5_decode_princ_contents(context, &contents, &entry)) goto cleankey; - found = 1; - memset((char *)entry.key.contents, 0, entry.key.length); - if (retval = encode_princ_contents(context, &contents2, &entry)) + *nentries = 1; + /* Clear encrypted key contents */ + for (i = 0; i < entry.n_key_data; i++) { + if (entry.key_data[i].key_data_length[0]) { + memset((char *)entry.key_data[i].key_data_contents[0], 0, + entry.key_data[i].key_data_length[0]); + } + } + if (retval = krb5_encode_princ_contents(context, &contents2, &entry)) goto cleancontents; if (KDBM_STORE(db_ctx, db, key, contents2, DBM_REPLACE)) @@ -1671,18 +1252,17 @@ int *nentries; /* how many found & deleted */ else retval = 0; } - free_encode_princ_contents(&contents2); + krb5_free_princ_contents(context, &contents2); cleancontents: - free_decode_princ_contents(context, &entry); + krb5_dbe_free_contents(context, &entry); cleankey: - free_encode_princ_dbmkey(context, &key); + krb5_free_princ_dbmkey(context, &key); } cleanup: if (db_ctx->db_dbm_ctx == 0) KDBM_CLOSE(db_ctx, db); (void) krb5_dbm_db_unlock(context); /* unlock write lock */ - *nentries = found; return retval; } @@ -1719,10 +1299,10 @@ krb5_dbm_db_iterate (context, func, func_arg) for (key = KDBM_FIRSTKEY (db_ctx, db); key.dptr != NULL; key = KDBM_NEXTKEY(db_ctx, db)) { contents = KDBM_FETCH (db_ctx, db, key); - if (retval = decode_princ_contents(context, &contents, &entries)) + if (retval = krb5_decode_princ_contents(context, &contents, &entries)) break; retval = (*func)(func_arg, &entries); - free_decode_princ_contents(context, &entries); + krb5_dbe_free_contents(context, &entries); if (retval) break; } diff --git a/src/lib/kdb/kdb_xdr.c b/src/lib/kdb/kdb_xdr.c new file mode 100644 index 000000000..84ad28d48 --- /dev/null +++ b/src/lib/kdb/kdb_xdr.c @@ -0,0 +1,652 @@ +/* + * lib/kdb/kdb_xdr.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#include "k5-int.h" +#include +#include + +krb5_error_code +krb5_dbe_create_key_data(context, entry) + krb5_context context; + krb5_db_entry * entry; +{ + if (entry->n_key_data) { + if (entry->key_data = (krb5_key_data *)realloc(entry->key_data, + sizeof(krb5_key_data) * entry->n_key_data + 1)) + memset(entry->key_data + entry->n_key_data,0,sizeof(krb5_key_data)); + else + return ENOMEM; + } else { + if (entry->key_data = (krb5_key_data *)malloc(sizeof(krb5_key_data))) + memset(entry->key_data, 0, sizeof(krb5_key_data)); + else + return ENOMEM; + } + entry->n_key_data++; + return 0; +} + +krb5_dbe_encode_mod_princ_data(context, mod_princ, entry) + krb5_context context; + krb5_tl_mod_princ * mod_princ; + krb5_db_entry * entry; +{ + krb5_error_code retval; + krb5_tl_data ** tl_data; + krb5_octet * nextloc; + char * unparse_mod_princ; + int unparse_mod_princ_size; + + /* + * Allocate *tl_data if necessary otherwise reuse it + * Need 04 bytes for date + * Need XX bytes for string + */ + if (retval = krb5_unparse_name(context, mod_princ->mod_princ, + &unparse_mod_princ)) + return(retval); + + if ((nextloc = malloc(unparse_mod_princ_size + 4)) == NULL) + return ENOMEM; + + /* Find any old versions and delete them. */ + for (tl_data = &(entry->tl_data); *tl_data; + tl_data = &((*tl_data)->tl_data_next)) { + if ((*tl_data)->tl_data_type == KRB5_TL_MOD_PRINC) { + free((*tl_data)->tl_data_contents); + entry->n_tl_data--; + break; + } + } + + unparse_mod_princ_size = strlen(unparse_mod_princ) + 1; + + if ((*tl_data) || + /* Only zero data if it is freshly allocated */ + ((*tl_data) = (krb5_tl_data *)calloc(1, sizeof(krb5_tl_data)))) { + entry->n_tl_data++; + (*tl_data)->tl_data_type = KRB5_TL_MOD_PRINC; + (*tl_data)->tl_data_length = unparse_mod_princ_size + 4; + (*tl_data)->tl_data_contents = nextloc; + + /* Mod Date */ + *nextloc++ = (krb5_octet)(mod_princ->mod_date & 0xff); + *nextloc++ = (krb5_octet)((mod_princ->mod_date >> 8) & 0xff); + *nextloc++ = (krb5_octet)((mod_princ->mod_date >> 16) & 0xff); + *nextloc++ = (krb5_octet)((mod_princ->mod_date >> 24) & 0xff); + + /* Mod Princ */ + memcpy(nextloc, unparse_mod_princ, unparse_mod_princ_size); + return 0; + } + + free(nextloc); + return ENOMEM; +} + +krb5_dbe_decode_mod_princ_data(context, entry, mod_princ) + krb5_context context; + krb5_db_entry * entry; + krb5_tl_mod_princ ** mod_princ; +{ + krb5_error_code retval; + krb5_tl_data * tl_data; + krb5_octet * nextloc; + + for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { + if (tl_data->tl_data_type == KRB5_TL_MOD_PRINC) { + if ((*mod_princ = malloc(sizeof(krb5_tl_mod_princ))) == NULL) + return ENOMEM; + + nextloc = tl_data->tl_data_contents; + + /* Mod Date */ + *(((krb5_octet *)(&(*mod_princ)->mod_date))) = *nextloc++; + *(((krb5_octet *)(&(*mod_princ)->mod_date)) + 1) = *nextloc++; + *(((krb5_octet *)(&(*mod_princ)->mod_date)) + 2) = *nextloc++; + *(((krb5_octet *)(&(*mod_princ)->mod_date)) + 3) = *nextloc++; + + /* Mod Princ */ + if (retval = krb5_parse_name(context, nextloc, + &((*mod_princ)->mod_princ))) + break; + if ((strlen(nextloc) + 1 + 4) != tl_data->tl_data_length) { + retval = KRB5_KDB_TRUNCATED_RECORD; + break; + } + } + } + + if (retval) + free(*mod_princ); + return retval; +} + +krb5_encode_princ_dbmkey(context, key, principal) + krb5_context context; + datum *key; + krb5_principal principal; +{ + char *princ_name; + krb5_error_code retval; + + if (!(retval = krb5_unparse_name(context, principal, &princ_name))) { + /* need to store the NULL for decoding */ + key->dsize = strlen(princ_name)+1; + key->dptr = princ_name; + } + return(retval); +} + +void +krb5_free_princ_dbmkey(context, key) + krb5_context context; + datum *key; +{ + (void) free(key->dptr); + key->dsize = 0; + key->dptr = 0; + return; +} + +krb5_error_code +krb5_encode_princ_contents(context, content, entry) + krb5_context context; + datum * content; + krb5_db_entry * entry; +{ + int unparse_princ_size, i, j; + char * unparse_princ; + char * nextloc; + krb5_tl_data * tl_data; + krb5_error_code retval; + + krb5_db_entry copy_princ; + + /* + * Generate one lump of data from the krb5_db_entry. + * This data must be independent of byte order of the machine, + * compact and extensible. + */ + + /* + * First allocate enough space for all the data. + * Need 2 bytes for the length of the base structure + * then 40 [9 * 4 + 2 * 2] bytes for the base information + * [ mkvno, attributes, max_life, max_renewable_life, expiration, + * pw_expiration, last_success, last_failed, fail_auth_count ] + * [ n_key_data, n_tl_data ] + * then XX bytes [ e_length ] for the extra data [ e_data ] + * then XX bytes [ 2 for length + length for string ] for the principal, + * then (4 [type + length] + tl_data_length) bytes per tl_data + * then (4 + (4 + key_data_length) per key_data_contents) bytes per key_data + */ + content->dsize = entry->len + entry->e_length; + + if (retval = krb5_unparse_name(context, entry->princ, &unparse_princ)) + return(retval); + + unparse_princ_size = strlen(unparse_princ) + 1; + content->dsize += unparse_princ_size; + content->dsize += 2; + + i = 0; + /* tl_data is a linked list */ + for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { + content->dsize += tl_data->tl_data_length; + content->dsize += 4; /* type, length */ + i++; + } + + if (i != entry->n_tl_data) { + retval = KRB5_KDB_TRUNCATED_RECORD; + goto epc_error; + } + + /* key_data is an array */ + for (i = 0; i < entry->n_key_data; i++) { + content->dsize += 4; /* Version, KVNO */ + for (j = 0; j < entry->key_data[i].key_data_ver; j++) { + content->dsize += entry->key_data[i].key_data_length[j]; + content->dsize += 4; /* type + length */ + } + } + + if ((content->dptr = malloc(content->dsize)) == NULL) { + retval = ENOMEM; + goto epc_error; + } + + /* + * Now we go through entry again, this time copying data + * These first entries are always saved regaurdless of version + */ + nextloc = content->dptr; + + /* Base Length */ + *nextloc++ = (krb5_octet)(entry->len & 0xff); + *nextloc++ = (krb5_octet)((entry->len >> 8) & 0xff); + + /* Master Key Version */ + *nextloc++ = (krb5_octet)(entry->mkvno & 0xff); + *nextloc++ = (krb5_octet)((entry->mkvno >> 8) & 0xff); + *nextloc++ = (krb5_octet)((entry->mkvno >> 16) & 0xff); + *nextloc++ = (krb5_octet)((entry->mkvno >> 24) & 0xff); + + /* Attributes */ + *nextloc++ = (krb5_octet)(entry->attributes & 0xff); + *nextloc++ = (krb5_octet)((entry->attributes >> 8) & 0xff); + *nextloc++ = (krb5_octet)((entry->attributes >> 16) & 0xff); + *nextloc++ = (krb5_octet)((entry->attributes >> 24) & 0xff); + + /* Max Life */ + *nextloc++ = (krb5_octet)(entry->max_life & 0xff); + *nextloc++ = (krb5_octet)((entry->max_life >> 8) & 0xff); + *nextloc++ = (krb5_octet)((entry->max_life >> 16) & 0xff); + *nextloc++ = (krb5_octet)((entry->max_life >> 24) & 0xff); + + /* Max Renewable Life */ + *nextloc++ = (krb5_octet)(entry->max_renewable_life & 0xff); + *nextloc++ = (krb5_octet)((entry->max_renewable_life >> 8) & 0xff); + *nextloc++ = (krb5_octet)((entry->max_renewable_life >> 16) & 0xff); + *nextloc++ = (krb5_octet)((entry->max_renewable_life >> 24) & 0xff); + + /* When the client expires */ + *nextloc++ = (krb5_octet)(entry->expiration & 0xff); + *nextloc++ = (krb5_octet)((entry->expiration >> 8) & 0xff); + *nextloc++ = (krb5_octet)((entry->expiration >> 16) & 0xff); + *nextloc++ = (krb5_octet)((entry->expiration >> 24) & 0xff); + + /* When its passwd expires */ + *nextloc++ = (krb5_octet)(entry->pw_expiration & 0xff); + *nextloc++ = (krb5_octet)((entry->pw_expiration >> 8) & 0xff); + *nextloc++ = (krb5_octet)((entry->pw_expiration >> 16) & 0xff); + *nextloc++ = (krb5_octet)((entry->pw_expiration >> 24) & 0xff); + + /* Last successful passwd */ + *nextloc++ = (krb5_octet)(entry->last_success & 0xff); + *nextloc++ = (krb5_octet)((entry->last_success >> 8) & 0xff); + *nextloc++ = (krb5_octet)((entry->last_success >> 16) & 0xff); + *nextloc++ = (krb5_octet)((entry->last_success >> 24) & 0xff); + + /* Last failed passwd attempt */ + *nextloc++ = (krb5_octet)(entry->last_failed & 0xff); + *nextloc++ = (krb5_octet)((entry->last_failed >> 8) & 0xff); + *nextloc++ = (krb5_octet)((entry->last_failed >> 16) & 0xff); + *nextloc++ = (krb5_octet)((entry->last_failed >> 24) & 0xff); + + /* # of failed passwd attempt */ + *nextloc++ = (krb5_octet)(entry->fail_auth_count & 0xff); + *nextloc++ = (krb5_octet)((entry->fail_auth_count >> 8) & 0xff); + *nextloc++ = (krb5_octet)((entry->fail_auth_count >> 16) & 0xff); + *nextloc++ = (krb5_octet)((entry->fail_auth_count >> 24) & 0xff); + + /* # tl_data strutures */ + *nextloc++ = (krb5_octet)(entry->n_tl_data & 0xff); + *nextloc++ = (krb5_octet)((entry->n_tl_data >> 8) & 0xff); + + /* # key_data strutures */ + *nextloc++ = (krb5_octet)(entry->n_key_data & 0xff); + *nextloc++ = (krb5_octet)((entry->n_key_data >> 8) & 0xff); + + /* Put extended fields here */ + if (entry->len != KRB5_KDB_V1_BASE_LENGTH) + abort(); + + /* Any extra data that this version doesn't understand. */ + if (entry->e_length) { + memcpy(nextloc, entry->e_data, entry->e_length); + nextloc += entry->e_length; + } + + /* + * Now we get to the principal. + * To squeze a few extra bytes out it is always assumed to come + * after the base type. + */ + *nextloc++ = (krb5_octet)(unparse_princ_size & 0xff); + *nextloc++ = (krb5_octet)((unparse_princ_size >> 8) & 0xff); + (void) memcpy(nextloc, unparse_princ, unparse_princ_size); + nextloc += unparse_princ_size; + + /* tl_data is a linked list, of type, legth, contents */ + for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { + *nextloc++ = (krb5_octet)(tl_data->tl_data_type & 0xff); + *nextloc++ = (krb5_octet)((tl_data->tl_data_type >> 8) & 0xff); + + *nextloc++ = (krb5_octet)(tl_data->tl_data_length & 0xff); + *nextloc++ = (krb5_octet)((tl_data->tl_data_length >> 8) & 0xff); + + memcpy(nextloc, tl_data->tl_data_contents, tl_data->tl_data_length); + nextloc += tl_data->tl_data_length; + } + + /* key_data is an array */ + for (i = 0; i < entry->n_key_data; i++) { + *nextloc++ = (krb5_octet)(entry->key_data[i].key_data_ver & 0xff); + *nextloc++ = (krb5_octet)((entry->key_data[i].key_data_ver >> 8)&0xff); + *nextloc++ = (krb5_octet)(entry->key_data[i].key_data_kvno & 0xff); + *nextloc++ = (krb5_octet)((entry->key_data[i].key_data_kvno >> 8)&0xff); + + for (j = 0; j < entry->key_data[i].key_data_ver; j++) { + krb5_int16 type = entry->key_data[i].key_data_type[j]; + krb5_int16 length = entry->key_data[i].key_data_length[j]; + + *nextloc++ = (krb5_octet)(type & 0xff); + *nextloc++ = (krb5_octet)((type >> 8) & 0xff); + + *nextloc++ = (krb5_octet)(length & 0xff); + *nextloc++ = (krb5_octet)((length >> 8) & 0xff); + + if (length) { + memcpy(nextloc, entry->key_data[i].key_data_contents[j],length); + nextloc += length; + } + } + } + +epc_error:; + free(unparse_princ); + return retval; +} + +void +krb5_free_princ_contents(context, contents) + krb5_context context; + datum *contents; +{ + free(contents->dptr); + contents->dsize = 0; + contents->dptr = 0; + return; +} + +krb5_error_code +krb5_decode_princ_contents(context, content, entry) + krb5_context context; + datum * content; + krb5_db_entry * entry; +{ + int sizeleft, i; + char * nextloc; + krb5_tl_data ** tl_data; + + krb5_principal princ; + krb5_error_code retval; + int major_version = 0, minor_version = 0; + + /* Zero out entry and NULL pointers */ + memset(entry, 0, sizeof(krb5_db_entry)); + + /* + * undo the effects of encode_princ_contents. + * + * The first part is decoding the base type. If the base type is + * bigger than the original base type then the additional fields + * need to be filled in. If the base type is larger than any + * known base type the additional data goes in e_data. + */ + + /* First do the easy stuff */ + nextloc = content->dptr; + sizeleft = content->dsize; + if ((sizeleft -= KRB5_KDB_V1_BASE_LENGTH) < 0) + return KRB5_KDB_TRUNCATED_RECORD; + + /* Base Length */ + *(((krb5_octet *)(&entry->len))) = *nextloc++; + *(((krb5_octet *)(&entry->len)) + 1) = *nextloc++; + + /* Master Key Version */ + *(((krb5_octet *)(&entry->mkvno))) = *nextloc++; + *(((krb5_octet *)(&entry->mkvno)) + 1) = *nextloc++; + *(((krb5_octet *)(&entry->mkvno)) + 2) = *nextloc++; + *(((krb5_octet *)(&entry->mkvno)) + 3) = *nextloc++; + + /* Attributes */ + *(((krb5_octet *)(&entry->attributes))) = *nextloc++; + *(((krb5_octet *)(&entry->attributes)) + 1) = *nextloc++; + *(((krb5_octet *)(&entry->attributes)) + 2) = *nextloc++; + *(((krb5_octet *)(&entry->attributes)) + 3) = *nextloc++; + + /* Max Life */ + *(((krb5_octet *)(&entry->max_life))) = *nextloc++; + *(((krb5_octet *)(&entry->max_life)) + 1) = *nextloc++; + *(((krb5_octet *)(&entry->max_life)) + 2) = *nextloc++; + *(((krb5_octet *)(&entry->max_life)) + 3) = *nextloc++; + + /* Max Renewable Life */ + *(((krb5_octet *)(&entry->max_renewable_life))) = *nextloc++; + *(((krb5_octet *)(&entry->max_renewable_life)) + 1) = *nextloc++; + *(((krb5_octet *)(&entry->max_renewable_life)) + 2) = *nextloc++; + *(((krb5_octet *)(&entry->max_renewable_life)) + 3) = *nextloc++; + + /* When the client expires */ + *(((krb5_octet *)(&entry->expiration))) = *nextloc++; + *(((krb5_octet *)(&entry->expiration)) + 1) = *nextloc++; + *(((krb5_octet *)(&entry->expiration)) + 2) = *nextloc++; + *(((krb5_octet *)(&entry->expiration)) + 3) = *nextloc++; + + /* When its passwd expires */ + *(((krb5_octet *)(&entry->pw_expiration))) = *nextloc++; + *(((krb5_octet *)(&entry->pw_expiration)) + 1) = *nextloc++; + *(((krb5_octet *)(&entry->pw_expiration)) + 2) = *nextloc++; + *(((krb5_octet *)(&entry->pw_expiration)) + 3) = *nextloc++; + + /* Last successful passwd */ + *(((krb5_octet *)(&entry->last_success))) = *nextloc++; + *(((krb5_octet *)(&entry->last_success)) + 1) = *nextloc++; + *(((krb5_octet *)(&entry->last_success)) + 2) = *nextloc++; + *(((krb5_octet *)(&entry->last_success)) + 3) = *nextloc++; + + /* Last failed passwd attempt */ + *(((krb5_octet *)(&entry->last_failed))) = *nextloc++; + *(((krb5_octet *)(&entry->last_failed)) + 1) = *nextloc++; + *(((krb5_octet *)(&entry->last_failed)) + 2) = *nextloc++; + *(((krb5_octet *)(&entry->last_failed)) + 3) = *nextloc++; + + /* # of failed passwd attempt */ + *(((krb5_octet *)(&entry->fail_auth_count))) = *nextloc++; + *(((krb5_octet *)(&entry->fail_auth_count)) + 1) = *nextloc++; + *(((krb5_octet *)(&entry->fail_auth_count)) + 2) = *nextloc++; + *(((krb5_octet *)(&entry->fail_auth_count)) + 3) = *nextloc++; + + /* # tl_data strutures */ + *(((krb5_octet *)(&entry->n_tl_data))) = *nextloc++; + *(((krb5_octet *)(&entry->n_tl_data)) + 1) = *nextloc++; + + if (entry->n_tl_data < 0) + return KRB5_KDB_TRUNCATED_RECORD; + + /* # key_data strutures */ + *(((krb5_octet *)(&entry->n_key_data))) = *nextloc++; + *(((krb5_octet *)(&entry->n_key_data)) + 1) = *nextloc++; + + if (entry->n_key_data < 0) + return KRB5_KDB_TRUNCATED_RECORD; + + /* Check for extra data */ + if (entry->len > KRB5_KDB_V1_BASE_LENGTH) { + entry->e_length = entry->len - KRB5_KDB_V1_BASE_LENGTH; + if (entry->e_data = (krb5_octet *)malloc(entry->e_length)) { + memcpy(entry->e_data, nextloc, entry->e_length); + nextloc += entry->e_length; + } else { + return ENOMEM; + } + } + + /* + * Get the principal name for the entry + * (stored as a string which gets unparsed.) + */ + if ((sizeleft -= 2) < 0) { + retval = KRB5_KDB_TRUNCATED_RECORD; + goto error_out; + } + + i = 0; + *(((krb5_octet *)(&i))) = *nextloc++; + *(((krb5_octet *)(&i)) + 1) = *nextloc++; + + if (retval = krb5_parse_name(context, nextloc, &(entry->princ))) + goto error_out; + if ((i != (strlen(nextloc) + 1)) || (sizeleft < i)) { + retval = KRB5_KDB_TRUNCATED_RECORD; + goto error_out; + } + sizeleft -= i; + nextloc += i; + + /* tl_data is a linked list */ + tl_data = &entry->tl_data; + for (i = 0; i < entry->n_tl_data; i++) { + if ((sizeleft -= 4) < 0) { + retval = KRB5_KDB_TRUNCATED_RECORD; + goto error_out; + } + if ((*tl_data = (krb5_tl_data *) + malloc(sizeof(krb5_tl_data))) == NULL) { + retval = ENOMEM; + goto error_out; + } + (*tl_data)->tl_data_next = NULL; + (*tl_data)->tl_data_contents = NULL; + *(((krb5_octet *)(&(*tl_data)->tl_data_type))) = *nextloc++; + *(((krb5_octet *)(&(*tl_data)->tl_data_type)) + 1) = *nextloc++; + *(((krb5_octet *)(&(*tl_data)->tl_data_length))) = *nextloc++; + *(((krb5_octet *)(&(*tl_data)->tl_data_length)) + 1) = *nextloc++; + + if ((sizeleft -= (*tl_data)->tl_data_length) < 0) { + retval = KRB5_KDB_TRUNCATED_RECORD; + goto error_out; + } + if (((*tl_data)->tl_data_contents = (krb5_octet *) + malloc((*tl_data)->tl_data_length)) == NULL) { + retval = ENOMEM; + goto error_out; + } + memcpy((*tl_data)->tl_data_contents,nextloc,(*tl_data)->tl_data_length); + nextloc += (*tl_data)->tl_data_length; + } + + /* key_data is an array */ + if ((entry->key_data = (krb5_key_data *) + malloc(sizeof(krb5_key_data) * entry->n_key_data)) == NULL) { + retval = ENOMEM; + goto error_out; + } + for (i = 0; i < entry->n_key_data; i++) { + krb5_key_data * key_data; + int j; + + if ((sizeleft -= 4) < 0) { + retval = KRB5_KDB_TRUNCATED_RECORD; + goto error_out; + } + key_data = entry->key_data + i; + *(((krb5_octet *)(&key_data->key_data_ver))) = *nextloc++; + *(((krb5_octet *)(&key_data->key_data_ver)) + 1) = *nextloc++; + *(((krb5_octet *)(&key_data->key_data_kvno))) = *nextloc++; + *(((krb5_octet *)(&key_data->key_data_kvno)) + 1) = *nextloc++; + + /* key_data_ver determins number of elements and how to unparse them. */ + if (key_data->key_data_ver < KRB5_KDB_V1_KEY_DATA_ARRAY) { + for (j = 0; j < key_data->key_data_ver; j++) { + if ((sizeleft -= 4) < 0) { + retval = KRB5_KDB_TRUNCATED_RECORD; + goto error_out; + } + *(((krb5_octet *)(&key_data->key_data_type[j]))) = *nextloc++; + *(((krb5_octet *)(&key_data->key_data_type[j]))+1) = *nextloc++; + *(((krb5_octet *)(&key_data->key_data_length[j]))) = *nextloc++; + *(((krb5_octet *)(&key_data->key_data_length[j]))+1)=*nextloc++; + + if ((sizeleft -= key_data->key_data_length[j]) < 0) { + retval = KRB5_KDB_TRUNCATED_RECORD; + goto error_out; + } + if (key_data->key_data_length[j]) { + if ((key_data->key_data_contents[j] = (krb5_octet *) + malloc(key_data->key_data_length[j])) == NULL) { + retval = ENOMEM; + goto error_out; + } + memcpy(key_data->key_data_contents[j], nextloc, + key_data->key_data_length[j]); + nextloc += key_data->key_data_length[j]; + } + } + } else { + /* This isn't right. I'll fix it later */ + abort(); + } + } + return 0; + +error_out:; + krb5_dbe_free_contents(context, entry); + return retval; +} + +void +krb5_dbe_free_contents(context, entry) + krb5_context context; + krb5_db_entry * entry; +{ + krb5_tl_data * tl_data_next; + krb5_tl_data * tl_data; + int i, j; + + if (entry->e_data) + free(entry->e_data); + if (entry->princ) + krb5_free_principal(context, entry->princ); + for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) { + tl_data_next = tl_data->tl_data_next; + if (tl_data->tl_data_contents) + free(tl_data->tl_data_contents); + free(tl_data); + } + if (entry->key_data) { + for (i = 0; i < entry->n_key_data; i++) { + for (j = 0; j < entry->key_data[i].key_data_ver; j++) { + if (entry->key_data[i].key_data_length[j]) { + if (entry->key_data[i].key_data_contents[j]) { + memset(entry->key_data[i].key_data_contents[j], + 0, entry->key_data[i].key_data_length[j]); + free (entry->key_data[i].key_data_contents[j]); + } + } + entry->key_data[i].key_data_contents[j] = NULL; + entry->key_data[i].key_data_length[j] = 0; + entry->key_data[i].key_data_type[j] = 0; + } + } + free(entry->key_data); + } + memset(entry, 0, sizeof(*entry)); + return; +} + diff --git a/src/lib/kdb/t_kdb.c b/src/lib/kdb/t_kdb.c index 1010b65dd..f067f58dc 100644 --- a/src/lib/kdb/t_kdb.c +++ b/src/lib/kdb/t_kdb.c @@ -137,12 +137,20 @@ static kdb5_dispatch_table dbm_dispatch = { #ifdef dbm_error (int (*)()) NULL, /* Get Database Error */ #else /* dbm_error */ +#ifdef HAVE_DBM_ERROR dbm_error, /* Get Database Error */ +#else + (int (*)()) NULL, /* Get Database Error */ +#endif #endif /* dbm_error */ #ifdef dbm_clearerr (int (*)()) NULL, /* Clear Database Error */ #else /* dbm_clearerr */ +#ifdef HAVE_DBM_CLEARERR dbm_clearerr, /* Clear Database Error */ +#else + (int (*)()) NULL, /* Clear Database Error */ +#endif #endif /* dbm_clearerr */ #ifdef dbm_dirfno (int (*)()) NULL, /* Get Database FD num */ @@ -255,54 +263,56 @@ principal_found(nvalid, pname) */ krb5_error_code add_principal(kcontext, principal, eblock, key, rseed) - krb5_context kcontext; - krb5_principal principal; - krb5_encrypt_block *eblock; - krb5_keyblock *key; - krb5_pointer rseed; + krb5_context kcontext; + krb5_principal principal; + krb5_encrypt_block * eblock; + krb5_keyblock * key; + krb5_pointer rseed; { - krb5_error_code kret; - krb5_db_entry dbent; - krb5_keyblock *rkey; - krb5_keyblock *kp; - int nentries = 1; + krb5_error_code kret; + krb5_db_entry dbent; + krb5_tl_mod_princ mod_princ; + krb5_keyblock * rkey = NULL; + int nentries = 1; memset((char *) &dbent, 0, sizeof(dbent)); - rkey = (krb5_keyblock *) NULL; - dbent.principal = principal; - dbent.kvno = 1; - dbent.max_life = KRB5_KDB_MAX_LIFE; - dbent.max_renewable_life = KRB5_KDB_MAX_RLIFE; - dbent.mkvno = 1; - dbent.expiration = KRB5_KDB_EXPIRATION; - dbent.mod_name = principal; - dbent.attributes = KRB5_KDB_DEF_FLAGS; - if (kret = krb5_timeofday(kcontext, &dbent.mod_date)) - return(kret); + dbent.len = KRB5_KDB_V1_BASE_LENGTH; + + dbent.mkvno = 1; + dbent.attributes = KRB5_KDB_DEF_FLAGS; + dbent.max_life = KRB5_KDB_MAX_LIFE; + dbent.expiration = KRB5_KDB_EXPIRATION; + dbent.max_renewable_life = KRB5_KDB_MAX_RLIFE; + + if (kret = krb5_copy_principal(kcontext, principal, &dbent.princ)) + goto out; + + mod_princ.mod_princ = principal; + if (kret = krb5_timeofday(kcontext, &mod_princ.mod_date)) + goto out; + if (kret = krb5_dbe_encode_mod_princ_data(kcontext, &mod_princ, &dbent)) + goto out; if (!key) { if (kret = krb5_random_key(kcontext, eblock, rseed, &rkey)) - return(kret); - kp = rkey; - } - else - kp = key; + goto out; + } else + rkey = key; - if (kret = krb5_kdb_encrypt_key(kcontext, eblock, kp, &dbent.key)) + if (kret = krb5_dbe_create_key_data(kcontext, &dbent)) + goto out; + if (kret = krb5_dbekd_encrypt_key_data(kcontext, eblock, rkey, NULL, 1, + &dbent.key_data[0])) goto out; - if (rkey) + if (!key) krb5_free_keyblock(kcontext, rkey); - dbent.salt_type = KRB5_KDB_SALTTYPE_NORMAL; - dbent.salt_length = 0; - dbent.salt = (krb5_octet *) NULL; kret = krb5_db_put_principal(kcontext, &dbent, &nentries); - if (!kret && (nentries != 1)) + if ((!kret) && (nentries != 1)) kret = KRB5KRB_ERR_GENERIC; out: - if (dbent.key.contents) - free(dbent.key.contents); + krb5_dbe_free_contents(kcontext, &dbent); return(kret); } @@ -369,32 +379,42 @@ find_principal(kcontext, principal, docompare) { krb5_error_code kret; krb5_db_entry dbent; + krb5_tl_mod_princ * mod_princ; int how_many; krb5_boolean more; - how_many = 1; more = 0; - if (kret = krb5_db_get_principal(kcontext, - principal, - &dbent, - &how_many, - &more)) + how_many = 1; + if (kret = krb5_db_get_principal(kcontext, principal, &dbent, + &how_many, &more)) + return(kret); + if (how_many == 0) + return(KRB5KRB_ERR_GENERIC); + + if (kret = krb5_dbe_decode_mod_princ_data(kcontext, &dbent, &mod_princ)) { + krb5_db_free_principal(kcontext, &dbent, how_many); return(kret); + } + if (docompare) { - if ((dbent.kvno != 1) || + if ((dbent.mkvno != 1) || (dbent.max_life != KRB5_KDB_MAX_LIFE) || (dbent.max_renewable_life != KRB5_KDB_MAX_RLIFE) || - (dbent.mkvno != 1) || (dbent.expiration != KRB5_KDB_EXPIRATION) || (dbent.attributes != KRB5_KDB_DEF_FLAGS) || - !krb5_principal_compare(kcontext, principal, dbent.principal) || - !krb5_principal_compare(kcontext, principal, dbent.mod_name)) + !krb5_principal_compare(kcontext, principal, dbent.princ) || + !krb5_principal_compare(kcontext, principal, mod_princ->mod_princ)) kret = KRB5_PRINC_NOMATCH; - krb5_db_free_principal(kcontext, &dbent, how_many); } - if (!kret && how_many) - krb5_db_free_principal(kcontext, &dbent, how_many); - return(((how_many == 1) && (more == 0)) ? 0 : KRB5KRB_ERR_GENERIC); + + krb5_db_free_principal(kcontext, &dbent, how_many); + krb5_free_principal(kcontext, mod_princ->mod_princ); + krb5_xfree(mod_princ); + if (!kret) + return(((how_many == 1) && (more == 0)) ? 0 : KRB5KRB_ERR_GENERIC); + else + return(kret); + } /* diff --git a/src/lib/kdb/verify_mky.c b/src/lib/kdb/verify_mky.c index 4ef8304e3..dbac6ff35 100644 --- a/src/lib/kdb/verify_mky.c +++ b/src/lib/kdb/verify_mky.c @@ -64,7 +64,9 @@ krb5_db_verify_master_key(context, mprinc, mkey, eblock) krb5_db_free_principal(context, &master_entry, nprinc); return(retval); } - if (retval = krb5_kdb_decrypt_key(context, eblock, &master_entry.key, &tempkey)) { + if (retval = krb5_dbekd_decrypt_key_data(context, eblock, + &master_entry.key_data[0], + &tempkey, NULL)) { (void) krb5_finish_key(context, eblock); krb5_db_free_principal(context, &master_entry, nprinc); return retval; -- 2.26.2