+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/kdb/kdb_cpw.c */
/*
- * lib/kdb/kdb_cpw.c
- *
- * Copyright 1995 by the Massachusetts Institute of Technology.
+ * Copyright 1995, 2009 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
* 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
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * 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.
+ */
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
- *
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "k5-int.h"
-#include "krb5/adm.h"
+#include "kdb.h"
#include <stdio.h>
#include <errno.h>
-static int
-get_key_data_kvno(context, count, data)
- krb5_context context;
- int count;
- krb5_key_data * data;
+int
+krb5_db_get_key_data_kvno(context, count, data)
+ krb5_context context;
+ int count;
+ krb5_key_data * data;
{
int i, kvno;
/* Find last key version number */
for (kvno = i = 0; i < count; i++) {
- if (kvno < data[i].key_data_kvno) {
- kvno = data[i].key_data_kvno;
- }
+ if (kvno < data[i].key_data_kvno) {
+ kvno = data[i].key_data_kvno;
+ }
}
return(kvno);
}
static void
cleanup_key_data(context, count, data)
- krb5_context context;
- int count;
- krb5_key_data * data;
+ krb5_context context;
+ int count;
+ krb5_key_data * data;
{
int i, j;
+ /* If data is NULL, count is always 0 */
+ if (data == NULL) return;
+
for (i = 0; i < count; i++) {
- for (j = 0; j < data[i].key_data_ver; j++) {
- if (data[i].key_data_length[j]) {
- free(data[i].key_data_contents[j]);
- }
- }
+ for (j = 0; j < data[i].key_data_ver; j++) {
+ if (data[i].key_data_length[j]) {
+ krb5_db_free(context, data[i].key_data_contents[j]);
+ }
+ }
}
+ krb5_db_free(context, data);
}
-/*
- * Currently we can only generate random keys for preinitialized
- * krb5_encrypt_block with a seed. This is bogus but currently
- * necessary to insure that we don't generate two keys with the
- * same data.
- */
static krb5_error_code
-add_key_rnd(context, master_eblock, ks_tuple, ks_tuple_count, db_entry, kvno)
- krb5_context context;
- krb5_encrypt_block * master_eblock;
- krb5_key_salt_tuple * ks_tuple;
- int ks_tuple_count;
- krb5_db_entry * db_entry;
- int kvno;
+add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
+ krb5_context context;
+ krb5_keyblock * master_key;
+ krb5_key_salt_tuple * ks_tuple;
+ int ks_tuple_count;
+ krb5_db_entry * db_entry;
+ int kvno;
{
- krb5_principal krbtgt_princ;
- krb5_keyblock krbtgt_keyblock, * key;
- krb5_pointer krbtgt_seed;
- krb5_encrypt_block krbtgt_eblock;
- krb5_db_entry krbtgt_entry;
- krb5_boolean more, found;
- int max_kvno, one, i, j;
- krb5_error_code retval;
-
- memset(&krbtgt_keyblock, 0, sizeof(krbtgt_keyblock));
+ krb5_principal krbtgt_princ;
+ krb5_keyblock key;
+ krb5_db_entry *krbtgt_entry;
+ int max_kvno, i, j, k;
+ krb5_error_code retval;
+ krb5_key_data tmp_key_data;
+ krb5_key_data *tptr;
+
+ memset( &tmp_key_data, 0, sizeof(tmp_key_data));
+
+
retval = krb5_build_principal_ext(context, &krbtgt_princ,
- db_entry->princ->realm.length,
- db_entry->princ->realm.data,
- KRB5_TGS_NAME_SIZE,
- KRB5_TGS_NAME,
- db_entry->princ->realm.length,
- db_entry->princ->realm.data,
- 0);
+ db_entry->princ->realm.length,
+ db_entry->princ->realm.data,
+ KRB5_TGS_NAME_SIZE,
+ KRB5_TGS_NAME,
+ db_entry->princ->realm.length,
+ db_entry->princ->realm.data,
+ 0);
if (retval)
- return retval;
+ return retval;
/* Get tgt from database */
- retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry,
- &one, &more);
+ retval = krb5_db_get_principal(context, krbtgt_princ, 0, &krbtgt_entry);
krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */
if (retval)
- return(retval);
- if ((one > 1) || (more)) {
- krb5_db_free_principal(context, &krbtgt_entry, one);
- return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
- }
- if (!one)
- return KRB5_KDB_NOENTRY;
+ return(retval);
/* Get max kvno */
- for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
- if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
- max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
- }
+ for (max_kvno = j = 0; j < krbtgt_entry->n_key_data; j++) {
+ if (max_kvno < krbtgt_entry->key_data[j].key_data_kvno) {
+ max_kvno = krbtgt_entry->key_data[j].key_data_kvno;
+ }
}
for (i = 0; i < ks_tuple_count; i++) {
- /*
- * We could use krb5_keysalt_iterate to replace this loop, or use
- * krb5_keysalt_is_present for the loop below, but we want to avoid
- * circular library dependencies.
- */
- found = 0;
- for (j = 0; j < i; j++) {
- if (ks_tuple[j].ks_keytype == ks_tuple[i].ks_keytype) {
- found = 1;
- break;
- }
- }
- if (found)
- continue;
- if (retval = krb5_dbe_create_key_data(context, db_entry))
- goto add_key_rnd_err;
-
- for (j = 0; j < krbtgt_entry.n_key_data; j++) {
- if ((krbtgt_entry.key_data[j].key_data_kvno == max_kvno) &&
- (krbtgt_entry.key_data[j].key_data_type[0] ==
- ks_tuple[i].ks_keytype)) {
- break;
- }
- }
-
- if (j == krbtgt_entry.n_key_data) {
- retval = KRB5_KDB_BAD_KEYTYPE;
- goto add_key_rnd_err;
- }
-
- /* Decrypt key */
- if (retval = krb5_dbekd_decrypt_key_data(context, master_eblock,
- &krbtgt_entry.key_data[j],
- &krbtgt_keyblock, NULL)) {
- goto add_key_rnd_err;
- }
-
- /* Init key */
- krb5_use_keytype(context, &krbtgt_eblock, ks_tuple[i].ks_keytype);
- if (retval = krb5_process_key(context,&krbtgt_eblock,&krbtgt_keyblock)){
- goto add_key_rnd_err;
- }
-
- /* Init random generator */
- if (retval = krb5_init_random_key(context, &krbtgt_eblock,
- &krbtgt_keyblock, &krbtgt_seed)) {
- krb5_finish_key(context, &krbtgt_eblock);
- goto add_key_rnd_err;
- }
-
- if (retval = krb5_random_key(context,&krbtgt_eblock,krbtgt_seed,&key)) {
- krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed);
- krb5_finish_key(context, &krbtgt_eblock);
- goto add_key_rnd_err;
- }
-
- krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed);
- krb5_finish_key(context, &krbtgt_eblock);
-
- if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock,
- key, NULL, kvno + 1,
- &db_entry->key_data[db_entry->n_key_data-1])) {
- krb5_free_keyblock(context, key);
- goto add_key_rnd_err;
- }
-
- /* Finish random key */
- krb5_free_keyblock(context, key);
+ krb5_boolean similar;
+
+ similar = 0;
+
+ /*
+ * We could use krb5_keysalt_iterate to replace this loop, or use
+ * krb5_keysalt_is_present for the loop below, but we want to avoid
+ * circular library dependencies.
+ */
+ for (j = 0; j < i; j++) {
+ if ((retval = krb5_c_enctype_compare(context,
+ ks_tuple[i].ks_enctype,
+ ks_tuple[j].ks_enctype,
+ &similar)))
+ return(retval);
+
+ if (similar)
+ break;
+ }
+
+ if (similar)
+ continue;
+
+ if ((retval = krb5_dbe_create_key_data(context, db_entry)))
+ goto add_key_rnd_err;
+
+ /* there used to be code here to extract the old key, and derive
+ a new key from it. Now that there's a unified prng, that isn't
+ necessary. */
+
+ /* make new key */
+ if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
+ &key)))
+ goto add_key_rnd_err;
+
+
+ /* db library will free this. Since, its a so, it could actually be using different memory management
+ function. So, its better if the memory is allocated by the db's malloc. So, a temporary memory is used
+ here which will later be copied to the db_entry */
+ retval = krb5_dbe_encrypt_key_data(context, master_key, &key, NULL,
+ kvno, &tmp_key_data);
+
+ krb5_free_keyblock_contents(context, &key);
+ if( retval )
+ goto add_key_rnd_err;
+
+ tptr = &db_entry->key_data[db_entry->n_key_data-1];
+
+ tptr->key_data_ver = tmp_key_data.key_data_ver;
+ tptr->key_data_kvno = tmp_key_data.key_data_kvno;
+
+ for( k = 0; k < tmp_key_data.key_data_ver; k++ )
+ {
+ tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
+ tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
+ if( tmp_key_data.key_data_contents[k] )
+ {
+ tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
+ if( tptr->key_data_contents[k] == NULL )
+ {
+ cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+ db_entry->key_data = NULL;
+ db_entry->n_key_data = 0;
+ retval = ENOMEM;
+ goto add_key_rnd_err;
+ }
+ memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
+
+ memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
+ free( tmp_key_data.key_data_contents[k] );
+ tmp_key_data.key_data_contents[k] = NULL;
+ }
+ }
+
}
-add_key_rnd_err:;
- krb5_db_free_principal(context, &krbtgt_entry, one);
- if (krbtgt_keyblock.contents && krbtgt_keyblock.length) {
- memset(krbtgt_keyblock.contents, 0, krbtgt_keyblock.length);
- krb5_xfree(krbtgt_keyblock.contents);
+add_key_rnd_err:
+ krb5_db_free_principal(context, krbtgt_entry);
+
+ for( i = 0; i < tmp_key_data.key_data_ver; i++ )
+ {
+ if( tmp_key_data.key_data_contents[i] )
+ {
+ memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
+ free( tmp_key_data.key_data_contents[i] );
+ }
}
return(retval);
}
/*
- * Change random key for a krb5_db_entry
+ * Change random key for a krb5_db_entry
* Assumes the max kvno
*
- * As a side effect all old keys are nuked.
+ * As a side effect all old keys are nuked if keepold is false.
*/
krb5_error_code
-krb5_dbe_crk(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
- krb5_context context;
- krb5_encrypt_block * master_eblock;
- krb5_key_salt_tuple * ks_tuple;
- int ks_tuple_count;
- krb5_db_entry * db_entry;
+krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry)
+ krb5_context context;
+ krb5_keyblock * master_key;
+ krb5_key_salt_tuple * ks_tuple;
+ int ks_tuple_count;
+ krb5_boolean keepold;
+ krb5_db_entry * db_entry;
{
- int key_data_count;
- krb5_key_data * key_data;
- krb5_error_code retval;
- int kvno;
+ int key_data_count;
+ int n_new_key_data;
+ krb5_key_data * key_data;
+ krb5_error_code retval;
+ int kvno;
+ int i;
/* First save the old keydata */
- kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
+ kvno = krb5_db_get_key_data_kvno(context, db_entry->n_key_data,
+ db_entry->key_data);
key_data_count = db_entry->n_key_data;
key_data = db_entry->key_data;
db_entry->key_data = NULL;
db_entry->n_key_data = 0;
- if (retval = add_key_rnd(context, master_eblock, ks_tuple,
- ks_tuple_count, db_entry, kvno)) {
- cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
- db_entry->n_key_data = key_data_count;
- db_entry->key_data = key_data;
+ /* increment the kvno */
+ kvno++;
+
+ retval = add_key_rnd(context, master_key, ks_tuple,
+ ks_tuple_count, db_entry, kvno);
+ if (retval) {
+ cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+ db_entry->n_key_data = key_data_count;
+ db_entry->key_data = key_data;
+ } else if (keepold) {
+ n_new_key_data = db_entry->n_key_data;
+ for (i = 0; i < key_data_count; i++) {
+ retval = krb5_dbe_create_key_data(context, db_entry);
+ if (retval) {
+ cleanup_key_data(context, db_entry->n_key_data,
+ db_entry->key_data);
+ break;
+ }
+ db_entry->key_data[i+n_new_key_data] = key_data[i];
+ memset(&key_data[i], 0, sizeof(krb5_key_data));
+ }
+ krb5_db_free(context, key_data); /* we moved the cotents to new memory. But, the original block which contained the data */
} else {
- cleanup_key_data(context, key_data_count, key_data);
+ cleanup_key_data(context, key_data_count, key_data);
}
return(retval);
}
/*
- * Add random key for a krb5_db_entry
+ * Add random key for a krb5_db_entry
* Assumes the max kvno
*
* As a side effect all old keys older than the max kvno are nuked.
*/
krb5_error_code
-krb5_dbe_ark(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
- krb5_context context;
- krb5_encrypt_block * master_eblock;
- krb5_key_salt_tuple * ks_tuple;
- int ks_tuple_count;
- krb5_db_entry * db_entry;
+krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry)
+ krb5_context context;
+ krb5_keyblock * master_key;
+ krb5_key_salt_tuple * ks_tuple;
+ int ks_tuple_count;
+ krb5_db_entry * db_entry;
{
- int key_data_count;
- krb5_key_data * key_data;
- krb5_error_code retval;
- int kvno;
- int i;
+ int key_data_count;
+ krb5_key_data * key_data;
+ krb5_error_code retval;
+ int kvno;
+ int i;
/* First save the old keydata */
- kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
+ kvno = krb5_db_get_key_data_kvno(context, db_entry->n_key_data,
+ db_entry->key_data);
key_data_count = db_entry->n_key_data;
key_data = db_entry->key_data;
db_entry->key_data = NULL;
db_entry->n_key_data = 0;
- if (retval = add_key_rnd(context, master_eblock, ks_tuple,
- ks_tuple_count, db_entry, kvno)) {
- cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
- db_entry->n_key_data = key_data_count;
- db_entry->key_data = key_data;
+ /* increment the kvno */
+ kvno++;
+
+ if ((retval = add_key_rnd(context, master_key, ks_tuple,
+ ks_tuple_count, db_entry, kvno))) {
+ cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+ db_entry->n_key_data = key_data_count;
+ db_entry->key_data = key_data;
} else {
- /* Copy keys with key_data_kvno = kvno */
- for (i = 0; i < key_data_count; i++) {
- if (key_data[i].key_data_kvno = kvno) {
- if (retval = krb5_dbe_create_key_data(context, db_entry)) {
- cleanup_key_data(context, db_entry->n_key_data,
- db_entry->key_data);
- break;
- }
- /* We should decrypt/re-encrypt the data to use the same mkvno*/
- db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
- memset(&key_data[i], 0, sizeof(krb5_key_data));
- }
- }
- cleanup_key_data(context, key_data_count, key_data);
+ /* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */
+ for (i = 0; i < key_data_count; i++) {
+ if (key_data[i].key_data_kvno == (kvno - 1)) {
+ if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
+ cleanup_key_data(context, db_entry->n_key_data,
+ db_entry->key_data);
+ break;
+ }
+ /* We should decrypt/re-encrypt the data to use the same mkvno*/
+ db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
+ memset(&key_data[i], 0, sizeof(krb5_key_data));
+ }
+ }
+ cleanup_key_data(context, key_data_count, key_data);
}
return(retval);
}
+/* Construct a random explicit salt. */
+static krb5_error_code
+make_random_salt(krb5_context context, krb5_keysalt *salt_out)
+{
+ krb5_error_code retval;
+ unsigned char rndbuf[8];
+ krb5_data salt, rnd = make_data(rndbuf, sizeof(rndbuf));
+ unsigned int i;
+
+ /*
+ * Salts are limited by RFC 4120 to 7-bit ASCII. For ease of examination
+ * and to avoid certain folding issues for older enctypes, we use printable
+ * characters with four fixed bits and four random bits, encoding 64
+ * psuedo-random bits into 16 bytes.
+ */
+ retval = krb5_c_random_make_octets(context, &rnd);
+ if (retval)
+ return retval;
+ retval = alloc_data(&salt, sizeof(rndbuf) * 2);
+ if (retval)
+ return retval;
+ for (i = 0; i < sizeof(rndbuf); i++) {
+ salt.data[i * 2] = 0x40 | (rndbuf[i] >> 4);
+ salt.data[i * 2 + 1] = 0x40 | (rndbuf[i] & 0xf);
+ }
+
+ salt_out->type = KRB5_KDB_SALTTYPE_SPECIAL;
+ salt_out->data = salt;
+ return 0;
+}
+
/*
- * Add key_data for a krb5_db_entry
+ * Add key_data for a krb5_db_entry
* If passwd is NULL the assumes that the caller wants a random password.
*/
static krb5_error_code
-add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd,
- db_entry, kvno)
- krb5_context context;
- krb5_encrypt_block * master_eblock;
- krb5_key_salt_tuple * ks_tuple;
- int ks_tuple_count;
- char * passwd;
- krb5_db_entry * db_entry;
- int kvno;
+add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
+ db_entry, kvno)
+ krb5_context context;
+ krb5_keyblock * master_key;
+ krb5_key_salt_tuple * ks_tuple;
+ int ks_tuple_count;
+ char * passwd;
+ krb5_db_entry * db_entry;
+ int kvno;
{
- krb5_error_code retval;
- krb5_encrypt_block key_eblock;
- krb5_keysalt key_salt;
- krb5_keyblock key;
- krb5_data pwd;
- krb5_boolean found;
- int i, j;
+ krb5_error_code retval;
+ krb5_keysalt key_salt;
+ krb5_keyblock key;
+ krb5_data pwd;
+ krb5_data afs_params = string2data("\1"), *s2k_params = NULL;
+ int i, j, k;
+ krb5_key_data tmp_key_data;
+ krb5_key_data *tptr;
+
+ memset( &tmp_key_data, 0, sizeof(tmp_key_data));
+
+ retval = 0;
for (i = 0; i < ks_tuple_count; i++) {
- /*
- * We could use krb5_keysalt_iterate to replace this loop, or use
- * krb5_keysalt_is_present for the loop below, but we want to avoid
- * circular library dependencies.
- */
- found = 0;
- for (j = 0; j < i; j++) {
- if ((ks_tuple[j].ks_keytype == ks_tuple[i].ks_keytype) &&
- (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype)) {
- found = 1;
- break;
- }
- }
- if (found)
- continue;
- krb5_use_keytype(context, &key_eblock, ks_tuple[i].ks_keytype);
- if (retval = krb5_dbe_create_key_data(context, db_entry))
- return(retval);
-
- /* Convert password string to key using appropriate salt */
- switch (key_salt.type = ks_tuple[i].ks_salttype) {
- case KRB5_KDB_SALTTYPE_ONLYREALM: {
+ krb5_boolean similar;
+
+ similar = 0;
+
+ /*
+ * We could use krb5_keysalt_iterate to replace this loop, or use
+ * krb5_keysalt_is_present for the loop below, but we want to avoid
+ * circular library dependencies.
+ */
+ for (j = 0; j < i; j++) {
+ if ((retval = krb5_c_enctype_compare(context,
+ ks_tuple[i].ks_enctype,
+ ks_tuple[j].ks_enctype,
+ &similar)))
+ return(retval);
+
+ if (similar &&
+ (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype))
+ break;
+ }
+
+ if (j < i)
+ continue;
+
+ if ((retval = krb5_dbe_create_key_data(context, db_entry)))
+ return(retval);
+
+ /* Convert password string to key using appropriate salt */
+ switch (key_salt.type = ks_tuple[i].ks_salttype) {
+ case KRB5_KDB_SALTTYPE_ONLYREALM: {
krb5_data * saltdata;
- if (retval = krb5_copy_data(context, krb5_princ_realm(context,
- db_entry->princ), &saltdata))
- return(retval);
-
- key_salt.data = *saltdata;
- krb5_xfree(saltdata);
- }
- break;
- case KRB5_KDB_SALTTYPE_NOREALM:
- if (retval=krb5_principal2salt_norealm(context, db_entry->princ,
- &key_salt.data))
- return(retval);
+ if ((retval = krb5_copy_data(context, krb5_princ_realm(context,
+ db_entry->princ), &saltdata)))
+ return(retval);
+
+ key_salt.data = *saltdata;
+ free(saltdata);
+ }
+ break;
+ case KRB5_KDB_SALTTYPE_NOREALM:
+ if ((retval=krb5_principal2salt_norealm(context, db_entry->princ,
+ &key_salt.data)))
+ return(retval);
break;
- case KRB5_KDB_SALTTYPE_NORMAL:
- if (retval = krb5_principal2salt(context, db_entry->princ,
- &key_salt.data))
- return(retval);
+ case KRB5_KDB_SALTTYPE_NORMAL:
+ if ((retval = krb5_principal2salt(context, db_entry->princ,
+ &key_salt.data)))
+ return(retval);
break;
- case KRB5_KDB_SALTTYPE_V4:
+ case KRB5_KDB_SALTTYPE_V4:
key_salt.data.length = 0;
key_salt.data.data = 0;
break;
- default:
- return(KRB5_KDB_BAD_SALTTYPE);
- }
-
- pwd.data = passwd;
- pwd.length = strlen(passwd);
- if (retval = krb5_string_to_key(context, &key_eblock,
- ks_tuple[i].ks_keytype, &key,
- &pwd, &key_salt.data))
- return(retval);
-
- if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, &key,
- (const krb5_keysalt *)&key_salt,
- kvno + 1, &db_entry->key_data[db_entry->n_key_data-1])) {
- krb5_xfree(key.contents);
- return(retval);
- }
- krb5_xfree(key.contents);
+ case KRB5_KDB_SALTTYPE_AFS3:
+ retval = krb5int_copy_data_contents(context,
+ &db_entry->princ->realm,
+ &key_salt.data);
+ if (retval)
+ return retval;
+ s2k_params = &afs_params;
+ break;
+ case KRB5_KDB_SALTTYPE_SPECIAL:
+ retval = make_random_salt(context, &key_salt);
+ if (retval)
+ return retval;
+ break;
+ default:
+ return(KRB5_KDB_BAD_SALTTYPE);
+ }
+
+ pwd.data = passwd;
+ pwd.length = strlen(passwd);
+
+ retval = krb5_c_string_to_key_with_params(context,
+ ks_tuple[i].ks_enctype,
+ &pwd, &key_salt.data,
+ s2k_params, &key);
+ if (retval) {
+ free(key_salt.data.data);
+ return retval;
+ }
+
+ /* memory allocation to be done by db. So, use temporary block and later copy
+ it to the memory allocated by db */
+ retval = krb5_dbe_encrypt_key_data(context, master_key, &key,
+ (const krb5_keysalt *)&key_salt,
+ kvno, &tmp_key_data);
+ if (key_salt.data.data)
+ free(key_salt.data.data);
+ free(key.contents);
+
+ if( retval )
+ return retval;
+
+ tptr = &db_entry->key_data[db_entry->n_key_data-1];
+
+ tptr->key_data_ver = tmp_key_data.key_data_ver;
+ tptr->key_data_kvno = tmp_key_data.key_data_kvno;
+
+ for( k = 0; k < tmp_key_data.key_data_ver; k++ )
+ {
+ tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
+ tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
+ if( tmp_key_data.key_data_contents[k] )
+ {
+ tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
+ if( tptr->key_data_contents[k] == NULL )
+ {
+ cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+ db_entry->key_data = NULL;
+ db_entry->n_key_data = 0;
+ retval = ENOMEM;
+ goto add_key_pwd_err;
+ }
+ memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
+
+ memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
+ free( tmp_key_data.key_data_contents[k] );
+ tmp_key_data.key_data_contents[k] = NULL;
+ }
+ }
+ }
+add_key_pwd_err:
+ for( i = 0; i < tmp_key_data.key_data_ver; i++ )
+ {
+ if( tmp_key_data.key_data_contents[i] )
+ {
+ memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
+ free( tmp_key_data.key_data_contents[i] );
+ }
}
+
return(retval);
}
/*
- * Change password for a krb5_db_entry
+ * Change password for a krb5_db_entry
* Assumes the max kvno
*
- * As a side effect all old keys are nuked.
+ * As a side effect all old keys are nuked if keepold is false.
*/
krb5_error_code
-krb5_dbe_cpw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
- krb5_context context;
- krb5_encrypt_block * master_eblock;
- krb5_key_salt_tuple * ks_tuple;
- int ks_tuple_count;
- char * passwd;
- krb5_db_entry * db_entry;
+krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
+ new_kvno, keepold, db_entry)
+ krb5_context context;
+ krb5_keyblock * master_key;
+ krb5_key_salt_tuple * ks_tuple;
+ int ks_tuple_count;
+ char * passwd;
+ int new_kvno;
+ krb5_boolean keepold;
+ krb5_db_entry * db_entry;
{
- int key_data_count;
- krb5_key_data * key_data;
- krb5_error_code retval;
- int kvno;
+ int key_data_count;
+ int n_new_key_data;
+ krb5_key_data * key_data;
+ krb5_error_code retval;
+ int old_kvno;
+ int i;
/* First save the old keydata */
- kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
+ old_kvno = krb5_db_get_key_data_kvno(context, db_entry->n_key_data,
+ db_entry->key_data);
key_data_count = db_entry->n_key_data;
key_data = db_entry->key_data;
db_entry->key_data = NULL;
db_entry->n_key_data = 0;
- if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
- passwd, db_entry, kvno)) {
- cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
- db_entry->n_key_data = key_data_count;
- db_entry->key_data = key_data;
+ /* increment the kvno. if the requested kvno is too small,
+ increment the old kvno */
+ if (new_kvno < old_kvno+1)
+ new_kvno = old_kvno+1;
+
+ retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
+ passwd, db_entry, new_kvno);
+ if (retval) {
+ cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+ db_entry->n_key_data = key_data_count;
+ db_entry->key_data = key_data;
+ } else if (keepold) {
+ n_new_key_data = db_entry->n_key_data;
+ for (i = 0; i < key_data_count; i++) {
+ retval = krb5_dbe_create_key_data(context, db_entry);
+ if (retval) {
+ cleanup_key_data(context, db_entry->n_key_data,
+ db_entry->key_data);
+ break;
+ }
+ db_entry->key_data[i+n_new_key_data] = key_data[i];
+ memset(&key_data[i], 0, sizeof(krb5_key_data));
+ }
+ krb5_db_free( context, key_data );
} else {
- cleanup_key_data(context, key_data_count, key_data);
+ cleanup_key_data(context, key_data_count, key_data);
}
return(retval);
}
/*
- * Add password for a krb5_db_entry
+ * Add password for a krb5_db_entry
* Assumes the max kvno
*
* As a side effect all old keys older than the max kvno are nuked.
*/
krb5_error_code
-krb5_dbe_apw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
- krb5_context context;
- krb5_encrypt_block * master_eblock;
- krb5_key_salt_tuple * ks_tuple;
- int ks_tuple_count;
- char * passwd;
- krb5_db_entry * db_entry;
+krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry)
+ krb5_context context;
+ krb5_keyblock * master_key;
+ krb5_key_salt_tuple * ks_tuple;
+ int ks_tuple_count;
+ char * passwd;
+ krb5_db_entry * db_entry;
{
- int key_data_count;
- krb5_key_data * key_data;
- krb5_error_code retval;
- int kvno;
- int i;
+ int key_data_count;
+ krb5_key_data * key_data;
+ krb5_error_code retval;
+ int old_kvno, new_kvno;
+ int i;
/* First save the old keydata */
- kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
+ old_kvno = krb5_db_get_key_data_kvno(context, db_entry->n_key_data,
+ db_entry->key_data);
key_data_count = db_entry->n_key_data;
key_data = db_entry->key_data;
db_entry->key_data = NULL;
db_entry->n_key_data = 0;
- if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
- passwd, db_entry, kvno)) {
- cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
- db_entry->n_key_data = key_data_count;
- db_entry->key_data = key_data;
+ /* increment the kvno */
+ new_kvno = old_kvno+1;
+
+ if ((retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
+ passwd, db_entry, new_kvno))) {
+ cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+ db_entry->n_key_data = key_data_count;
+ db_entry->key_data = key_data;
} else {
- /* Copy keys with key_data_kvno = kvno */
- for (i = 0; i < key_data_count; i++) {
- if (key_data[i].key_data_kvno = kvno) {
- if (retval = krb5_dbe_create_key_data(context, db_entry)) {
- cleanup_key_data(context, db_entry->n_key_data,
- db_entry->key_data);
- break;
- }
- /* We should decrypt/re-encrypt the data to use the same mkvno*/
- db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
- memset(&key_data[i], 0, sizeof(krb5_key_data));
- }
- }
- cleanup_key_data(context, key_data_count, key_data);
+ /* Copy keys with key_data_kvno == old_kvno */
+ for (i = 0; i < key_data_count; i++) {
+ if (key_data[i].key_data_kvno == old_kvno) {
+ if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
+ cleanup_key_data(context, db_entry->n_key_data,
+ db_entry->key_data);
+ break;
+ }
+ /* We should decrypt/re-encrypt the data to use the same mkvno*/
+ db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
+ memset(&key_data[i], 0, sizeof(krb5_key_data));
+ }
+ }
+ cleanup_key_data(context, key_data_count, key_data);
}
return(retval);
}