/* * $Source$ * $Author$ * * Copyright 1990,1991 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America is assumed * to 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. * * Sandia National Laboratories also makes no representations about the * suitability of the modifications, or additions to this software for * any purpose. It is provided "as is" without express or implied warranty. * * Modify the Kerberos Database */ #if !defined(lint) && !defined(SABER) static char rcsid_adm_funcs[] = "$Id$"; #endif /* !lint & !SABER */ #include #include #include #include #ifndef hpux #include #endif #include #include #include #include #include #include #include #include "adm_extern.h" #include #include #include #include struct saltblock { int salttype; krb5_data saltdata; }; extern krb5_encrypt_block master_encblock; extern krb5_keyblock master_keyblock; #define norealm_salt(princ, retdata) krb5_principal2salt(&(princ)[1], retdata) struct mblock { krb5_deltat max_life; krb5_deltat max_rlife; krb5_timestamp expiration; krb5_flags flags; krb5_kvno mkvno; } mblock = { /* XXX */ KRB5_KDB_MAX_LIFE, KRB5_KDB_MAX_RLIFE, KRB5_KDB_EXPIRATION, KRB5_KDB_DEF_FLAGS, 0 }; typedef unsigned char des_cblock[8]; /* krb5_kvno may be narrow */ #include krb5_error_code adm_get_rnd_key PROTOTYPE((char *, krb5_ticket *, krb5_authenticator *, krb5_principal, int, krb5_db_entry *)); krb5_error_code adm_modify_kdb PROTOTYPE((char const *, char const *, krb5_const_principal, const krb5_keyblock *, const krb5_keyblock *, int, struct saltblock *, struct saltblock *, krb5_db_entry *)); krb5_error_code adm_enter_pwd_key PROTOTYPE((char *, char *, krb5_const_principal, krb5_const_principal, int, int, char *, krb5_db_entry *)); krb5_error_code adm_negotiate_key PROTOTYPE((char const *, krb5_ticket *, char *)); #include krb5_kvno adm_princ_exists(cmdname, principal, entry, nprincs) char *cmdname; krb5_principal principal; krb5_db_entry *entry; int *nprincs; { krb5_boolean more; krb5_error_code retval; if (retval = krb5_db_get_principal(principal, entry, nprincs, &more)) { com_err("adm_princ_exists", retval, "while attempting to verify principal's existence"); return(0); } if (! *nprincs) return(0); return(*nprincs); } krb5_error_code adm_modify_kdb(DECLARG(char const *, cmdname), DECLARG(char const *, newprinc), DECLARG(krb5_const_principal, principal), DECLARG(const krb5_keyblock *, key), DECLARG(const krb5_keyblock *, alt_key), DECLARG(int, req_type), DECLARG(struct saltblock *, salt), DECLARG(struct saltblock *, altsalt), DECLARG(krb5_db_entry *, entry)) OLDDECLARG(char const *, cmdname) OLDDECLARG(char const *, newprinc) OLDDECLARG(krb5_const_principal, principal) OLDDECLARG(const krb5_keyblock *, key) OLDDECLARG(const krb5_keyblock *, alt_key) OLDDECLARG(int, req_type) OLDDECLARG(struct saltblock *, salt) OLDDECLARG(struct saltblock *, altsalt) OLDDECLARG(krb5_db_entry *, entry) { krb5_error_code retval; int one = 1; krb5_kvno KDB5_VERSION_NUM = 1; krb5_deltat KDB5_MAX_TKT_LIFE = KRB5_KDB_MAX_LIFE; krb5_deltat KDB5_MAX_REN_LIFE = KRB5_KDB_MAX_RLIFE; krb5_timestamp KDB5_EXP_DATE = KRB5_KDB_EXPIRATION; extern krb5_flags NEW_ATTRIBUTES; if (key && key->length) { retval = krb5_kdb_encrypt_key(&master_encblock, key, &entry->key); if (retval) { com_err("adm_modify_kdb", retval, "while encrypting key for '%s'", newprinc); return(KADM_NO_ENCRYPT); } } if (alt_key && alt_key->length) { retval = krb5_kdb_encrypt_key(&master_encblock, alt_key, &entry->alt_key); if (retval) { com_err("adm_modify_kdb", retval, "while encrypting alt_key for '%s'", newprinc); return(KADM_NO_ENCRYPT); } } if (!req_type) { /* New entry - initialize */ memset((char *) &entry, 0, sizeof(entry)); entry->principal = (krb5_principal) principal; entry->kvno = KDB5_VERSION_NUM; entry->max_life = KDB5_MAX_TKT_LIFE; entry->max_renewable_life = KDB5_MAX_REN_LIFE; entry->mkvno = mblock.mkvno; entry->expiration = KDB5_EXP_DATE; entry->mod_name = master_princ; } else { /* Modify existing entry */ entry->kvno++; #ifdef SANDIA entry->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; #endif entry->mod_name = (krb5_principal) principal; } if (retval = krb5_timeofday(&entry->mod_date)) { com_err("adm_modify_kdb", retval, "while fetching date"); memset((char *) entry->key.contents, 0, entry->key.length); memset((char *) entry->alt_key.contents, 0, entry->alt_key.length); if (entry->key.contents) xfree(entry->key.contents); if (entry->alt_key.contents) xfree(entry->alt_key.contents); return(KRB_ERR_GENERIC); } if (!req_type) { if (salt->salttype == KRB5_KDB_SALTTYPE_V4) { entry->attributes = (KRB5_KDB_DISALLOW_DUP_SKEY | NEW_ATTRIBUTES) #ifdef SANDIA & ~KRB5_KDB_REQUIRES_PRE_AUTH & ~KRB5_KDB_REQUIRES_HW_AUTH #endif ; } else { entry->attributes = NEW_ATTRIBUTES; } #ifdef SANDIA entry->last_pwd_change = entry->mod_date; entry->last_success = entry->mod_date; entry->fail_auth_count = 0; #endif if (salt) { entry->salt_type = salt->salttype; entry->salt_length = salt->saltdata.length; entry->salt = (krb5_octet *) salt->saltdata.data; } else { entry->salt_type = KRB5_KDB_SALTTYPE_NORMAL; entry->salt_length = 0; entry->salt = 0; } /* Set up version 4 alt key and alt salt info.....*/ if (altsalt) { entry->alt_salt_type = altsalt->salttype; entry->alt_salt_length = altsalt->saltdata.length; entry->alt_salt = (krb5_octet *) altsalt->saltdata.data; } else { entry->alt_salt_type = KRB5_KDB_SALTTYPE_NORMAL; entry->alt_salt_length = 0; entry->alt_salt = 0; } } else { if (retval = krb5_timeofday(&entry->last_pwd_change)) { com_err("adm_modify_kdb", retval, "while fetching date"); memset((char *) entry->key.contents, 0, entry->key.length); memset((char *) entry->alt_key.contents, 0, entry->alt_key.length); if (entry->key.contents) xfree(entry->key.contents); if (entry->alt_key.contents) xfree(entry->alt_key.contents); return(5); } } retval = krb5_db_put_principal(entry, &one); memset((char *) entry->key.contents, 0, entry->key.length); if (entry->key.contents) xfree(entry->key.contents); memset((char *) entry->alt_key.contents, 0, entry->alt_key.length); if (entry->alt_key.contents) xfree(entry->alt_key.contents); if (retval) { com_err("adm_modify_kdb", retval, "while storing entry for '%s'\n", newprinc); return(kdb5_err_base + retval); } if (one != 1) com_err("adm_modify_kdb", 0, "entry not stored in database (unknown failure)"); return(0); } krb5_error_code adm_enter_pwd_key(DECLARG(char *, cmdname), DECLARG(char *, newprinc), DECLARG(krb5_const_principal, princ), DECLARG(krb5_const_principal, string_princ), DECLARG(int, req_type), DECLARG(int, salttype), DECLARG(char *, new_password), DECLARG(krb5_db_entry *, entry)) OLDDECLARG(char *, cmdname) OLDDECLARG(char *, newprinc) OLDDECLARG(krb5_const_principal, princ) OLDDECLARG(krb5_const_principal, string_princ) OLDDECLARG(int, req_type) OLDDECLARG(int, salttype) OLDDECLARG(char *, new_password) OLDDECLARG(krb5_db_entry *, entry) { krb5_error_code retval; krb5_keyblock tempkey; krb5_data pwd; struct saltblock salt; struct saltblock altsalt; krb5_keyblock alttempkey; krb5_octet v4_keyptr[8]; pwd.data = new_password; pwd.length = strlen((char *) new_password); salt.salttype = salttype; switch (salttype) { case KRB5_KDB_SALTTYPE_NORMAL: if (retval = krb5_principal2salt(string_princ, &salt.saltdata)) { com_err("adm_enter_pwd_key", retval, "while converting principal to salt for '%s'", newprinc); return(KRB_ERR_GENERIC); } altsalt.salttype = KRB5_KDB_SALTTYPE_V4; altsalt.saltdata.data = 0; altsalt.saltdata.length = 0; break; case KRB5_KDB_SALTTYPE_V4: salt.saltdata.data = 0; salt.saltdata.length = 0; if (retval = krb5_principal2salt(string_princ, &altsalt.saltdata)) { com_err("adm_enter_pwd_key", retval, "while converting principal to altsalt for '%s'", newprinc); return(KRB_ERR_GENERIC); } altsalt.salttype = KRB5_KDB_SALTTYPE_NORMAL; break; case KRB5_KDB_SALTTYPE_NOREALM: if (retval = norealm_salt(string_princ, &salt.saltdata)) { com_err("adm_enter_pwd_key", retval, "while converting principal to salt for '%s'", newprinc); return(KRB_ERR_GENERIC); } altsalt.salttype = KRB5_KDB_SALTTYPE_V4; altsalt.saltdata.data = 0; altsalt.saltdata.length = 0; break; case KRB5_KDB_SALTTYPE_ONLYREALM: { krb5_data *foo; if (retval = krb5_copy_data(krb5_princ_realm(string_princ), &foo)) { com_err("adm_enter_pwd_key", retval, "while converting principal to salt for '%s'", newprinc); return(KRB_ERR_GENERIC); } salt.saltdata = *foo; xfree(foo); altsalt.salttype = KRB5_KDB_SALTTYPE_V4; altsalt.saltdata.data = 0; altsalt.saltdata.length = 0; break; } default: com_err("adm_enter_pwd_key", 0, "Don't know how to enter salt type %d", salttype); return(KRB_ERR_GENERIC); } if (retval = krb5_string_to_key(&master_encblock, master_keyblock.keytype, &tempkey, &pwd, &salt.saltdata)) { com_err("adm_enter_pwd_key", retval, "while converting password to alt_key for '%s'", newprinc); memset((char *) new_password, 0, sizeof(new_password)); /* erase it */ xfree(salt.saltdata.data); return(retval); } if (retval = krb5_string_to_key(&master_encblock, master_keyblock.keytype, &alttempkey, &pwd, &altsalt.saltdata)) { com_err("adm_enter_pwd_key", retval, "while converting password to alt_key for '%s'", newprinc); xfree(salt.saltdata.data); free(entry->alt_key.contents); memset((char *) new_password, 0, sizeof(new_password)); /* erase it */ return(retval); } memset((char *) new_password, 0, sizeof(new_password)); /* erase it */ retval = adm_modify_kdb("adm_enter_pwd_key", newprinc, princ, &tempkey, &alttempkey, req_type, &salt, &altsalt, entry); memset((char *) tempkey.contents, 0, tempkey.length); memset((char *) alttempkey.contents, 0, alttempkey.length); if (entry->alt_key.contents) free(entry->alt_key.contents); return(retval); } krb5_error_code adm5_change(prog, newprinc, client_creds) char *prog; krb5_principal newprinc; krb5_ticket *client_creds; { krb5_db_entry entry; int nprincs = 1; krb5_error_code retval; char *composite_name; char new_passwd[ADM_MAX_PW_LENGTH + 1]; if (!(adm_princ_exists("adm5_change", newprinc, &entry, &nprincs))) { com_err("adm5_change", 0, "No principal exists!"); krb5_free_principal(newprinc); return(1); } memset((char *) new_passwd, 0, ADM_MAX_PW_LENGTH + 1); /* Negotiate for New Key */ if (retval = adm_negotiate_key("adm5_change", client_creds, new_passwd)) { krb5_db_free_principal(&entry, nprincs); krb5_free_principal(newprinc); return(1); } retval = krb5_unparse_name(newprinc, &composite_name); if (entry.salt_type == KRB5_KDB_SALTTYPE_V4) { entry.salt_type = KRB5_KDB_SALTTYPE_NORMAL; entry.alt_salt_type = KRB5_KDB_SALTTYPE_V4; com_err("adm5_change", 0, "Converting v4user to v5user"); } retval = adm_enter_pwd_key("adm5_change", composite_name, newprinc, newprinc, 1, /* change */ KRB5_KDB_SALTTYPE_NORMAL, new_passwd, &entry); (void) memset(new_passwd, 0, strlen(new_passwd)); krb5_free_principal(newprinc); krb5_db_free_principal(&entry, nprincs); free(composite_name); return(retval); } #ifdef SANDIA krb5_error_code adm5_create_rnd(prog, change_princ, client_auth_data, client_creds) char *prog; krb5_principal change_princ; krb5_authenticator *client_auth_data; krb5_ticket *client_creds; { krb5_db_entry entry; int nprincs = 1; krb5_error_code retval; if (!(adm_princ_exists("adm5_create_rnd", change_princ, &entry, &nprincs))) { com_err("adm5_create_rnd", 0, "No principal exists!"); krb5_free_principal(change_princ); return(1); } if (retval = adm_get_rnd_key("adm5_create_rnd", client_creds, client_auth_data, change_princ, 1, /* change */ &entry)) { krb5_db_free_principal(&entry, nprincs); krb5_free_principal(change_princ); return(retval); } krb5_free_principal(change_princ); krb5_db_free_principal(&entry, nprincs); return(0); } #endif #define MAXMSGSZ 255 krb5_error_code adm_enter_rnd_pwd_key(DECLARG(char *, cmdname), DECLARG(krb5_principal, change_princ), DECLARG(int, req_type), DECLARG(krb5_db_entry *, entry)) OLDDECLARG(char *, cmdname) OLDDECLARG(krb5_principal, change_princ) OLDDECLARG(int, req_type) OLDDECLARG(krb5_db_entry *, entry) { krb5_error_code retval; krb5_keyblock *tempkey; krb5_pointer master_random; int salttype = KRB5_KDB_SALTTYPE_NORMAL; struct saltblock salt; char *principal_name; salt.salttype = salttype; entry->salt_type = salttype; if (retval = krb5_init_random_key(&master_encblock, &master_keyblock, &master_random)) { com_err("adm_enter_rnd_pwd_key", 0, "Unable to Initialize Random Key"); (void) krb5_finish_key(&master_encblock); memset((char *)master_keyblock.contents, 0, master_keyblock.length); xfree(master_keyblock.contents); goto finish; } /* Get Random Key */ if (retval = krb5_random_key(&master_encblock, master_random, &tempkey)) { com_err("adm_enter_rnd_pwd_key", 0, "Unable to Obtain Random Key"); goto finish; } /* Tie the Random Key to the Principal */ if (retval = krb5_principal2salt(change_princ, &salt.saltdata)) { com_err("adm_enter_rnd_pwd_key", 0, "Principal2salt Failure"); goto finish; } retval = krb5_unparse_name(change_princ, &principal_name); if (retval) return retval; /* Modify Database */ retval = adm_modify_kdb("adm_enter_rnd_pwd_key", principal_name, change_princ, tempkey, tempkey, req_type, &salt, &salt, entry); free(principal_name); if (retval) { com_err("adm_enter_rnd_pwd_key", 0, "Database Modification Failure"); retval = 2; goto finish; } finish: if(retval) { memset((char *) tempkey->contents, 0, tempkey->length); return(retval); } memset((char *) tempkey->contents, 0, tempkey->length); return(0); }