#include "k5-int.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 i, kvno;
for (kvno = i = 0; i < count; i++) {
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;
{
int i, j;
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]) {
krb5_db_free(context, data[i].key_data_contents[j]);
}
}
}
krb5_db_free(context, data);
}
static krb5_error_code
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 key;
krb5_db_entry krbtgt_entry;
krb5_boolean more;
int max_kvno, one, 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);
if (retval)
return retval;
retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry,
&one, &more);
krb5_free_principal(context, krbtgt_princ);
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;
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++) {
krb5_boolean similar;
similar = 0;
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;
if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
&key)))
goto add_key_rnd_err;
retval = krb5_dbekd_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);
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);
}
krb5_error_code
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;
int n_new_key_data;
krb5_key_data * key_data;
krb5_error_code retval;
int kvno;
int i;
kvno = 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;
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);
} else {
cleanup_key_data(context, key_data_count, key_data);
}
return(retval);
}
krb5_error_code
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;
kvno = 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;
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 {
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;
}
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);
}
static krb5_error_code
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_keysalt key_salt;
krb5_keyblock key;
krb5_data pwd;
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++) {
krb5_boolean similar;
similar = 0;
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);
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);
break;
case KRB5_KDB_SALTTYPE_NORMAL:
if ((retval = krb5_principal2salt(context, db_entry->princ,
&key_salt.data)))
return(retval);
break;
case KRB5_KDB_SALTTYPE_V4:
key_salt.data.length = 0;
key_salt.data.data = 0;
break;
case KRB5_KDB_SALTTYPE_AFS3: {
#if 0
krb5_data * saltdata;
if (retval = krb5_copy_data(context, krb5_princ_realm(context,
db_entry->princ), &saltdata))
return(retval);
key_salt.data = *saltdata;
key_salt.data.length = SALT_TYPE_AFS_LENGTH;
krb5_xfree(saltdata);
#else
unsigned int slen =
(*krb5_princ_realm(context,db_entry->princ)).length;
if(!(key_salt.data.data = (char *) malloc(slen+1)))
return ENOMEM;
key_salt.data.data[slen] = 0;
memcpy((char *)key_salt.data.data,
(char *)(*krb5_princ_realm(context,db_entry->princ)).data,
slen);
key_salt.data.length = SALT_TYPE_AFS_LENGTH;
#endif
}
break;
default:
return(KRB5_KDB_BAD_SALTTYPE);
}
pwd.data = passwd;
pwd.length = strlen(passwd);
if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype,
&pwd, &key_salt.data, &key))) {
if (key_salt.data.data)
free(key_salt.data.data);
return(retval);
}
if (key_salt.data.length == SALT_TYPE_AFS_LENGTH)
key_salt.data.length =
krb5_princ_realm(context, db_entry->princ)->length;
retval = krb5_dbekd_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);
krb5_xfree(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);
}
krb5_error_code
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;
int n_new_key_data;
krb5_key_data * key_data;
krb5_error_code retval;
int old_kvno;
int i;
old_kvno = 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 (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);
}
return(retval);
}
krb5_error_code
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 old_kvno, new_kvno;
int i;
old_kvno = 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;
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 {
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;
}
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);
}