17c478bd9Sstevel@tonic-gate /* 2*54925bf6Swillf * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 67c478bd9Sstevel@tonic-gate 77c478bd9Sstevel@tonic-gate /* 87c478bd9Sstevel@tonic-gate * lib/kdb/kdb_cpw.c 97c478bd9Sstevel@tonic-gate * 107c478bd9Sstevel@tonic-gate * Copyright 1995 by the Massachusetts Institute of Technology. 117c478bd9Sstevel@tonic-gate * All Rights Reserved. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 147c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 157c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 167c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 177c478bd9Sstevel@tonic-gate * 187c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 197c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 207c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 217c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 227c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 237c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 247c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 257c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 267c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 277c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 287c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 297c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 307c478bd9Sstevel@tonic-gate * or implied warranty. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * All rights reserved. 387c478bd9Sstevel@tonic-gate * 397c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may require 407c478bd9Sstevel@tonic-gate * a specific license from the United States Government. It is the 417c478bd9Sstevel@tonic-gate * responsibility of any person or organization contemplating export to 427c478bd9Sstevel@tonic-gate * obtain such a license before exporting. 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 457c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 467c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 477c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 487c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 497c478bd9Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining 507c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 517c478bd9Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of 527c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 537c478bd9Sstevel@tonic-gate * or implied warranty. 547c478bd9Sstevel@tonic-gate * 557c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 567c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 577c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate #include "k5-int.h" 61*54925bf6Swillf #include <kdb.h> 627c478bd9Sstevel@tonic-gate #include <stdio.h> 637c478bd9Sstevel@tonic-gate #include <errno.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate static int 667c478bd9Sstevel@tonic-gate get_key_data_kvno(context, count, data) 677c478bd9Sstevel@tonic-gate krb5_context context; 687c478bd9Sstevel@tonic-gate int count; 697c478bd9Sstevel@tonic-gate krb5_key_data * data; 707c478bd9Sstevel@tonic-gate { 717c478bd9Sstevel@tonic-gate int i, kvno; 727c478bd9Sstevel@tonic-gate /* Find last key version number */ 737c478bd9Sstevel@tonic-gate for (kvno = i = 0; i < count; i++) { 747c478bd9Sstevel@tonic-gate if (kvno < data[i].key_data_kvno) { 757c478bd9Sstevel@tonic-gate kvno = data[i].key_data_kvno; 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate } 787c478bd9Sstevel@tonic-gate return(kvno); 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate static void 827c478bd9Sstevel@tonic-gate cleanup_key_data(context, count, data) 837c478bd9Sstevel@tonic-gate krb5_context context; 847c478bd9Sstevel@tonic-gate int count; 857c478bd9Sstevel@tonic-gate krb5_key_data * data; 867c478bd9Sstevel@tonic-gate { 877c478bd9Sstevel@tonic-gate int i, j; 887c478bd9Sstevel@tonic-gate 8956a424ccSmp /* If data is NULL, count is always 0 */ 9056a424ccSmp if (data == NULL) return; 9156a424ccSmp 927c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 937c478bd9Sstevel@tonic-gate for (j = 0; j < data[i].key_data_ver; j++) { 947c478bd9Sstevel@tonic-gate if (data[i].key_data_length[j]) { 957c478bd9Sstevel@tonic-gate free(data[i].key_data_contents[j]); 967c478bd9Sstevel@tonic-gate } 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate free(data); 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static krb5_error_code 1037c478bd9Sstevel@tonic-gate add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno) 1047c478bd9Sstevel@tonic-gate krb5_context context; 1057c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 1067c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 1077c478bd9Sstevel@tonic-gate int ks_tuple_count; 1087c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 1097c478bd9Sstevel@tonic-gate int kvno; 1107c478bd9Sstevel@tonic-gate { 1117c478bd9Sstevel@tonic-gate krb5_principal krbtgt_princ; 1127c478bd9Sstevel@tonic-gate krb5_keyblock key; 1137c478bd9Sstevel@tonic-gate krb5_db_entry krbtgt_entry; 1147c478bd9Sstevel@tonic-gate krb5_boolean more; 1157c478bd9Sstevel@tonic-gate int max_kvno, one, i, j; 1167c478bd9Sstevel@tonic-gate krb5_error_code retval; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate retval = krb5_build_principal_ext(context, &krbtgt_princ, 1197c478bd9Sstevel@tonic-gate db_entry->princ->realm.length, 1207c478bd9Sstevel@tonic-gate db_entry->princ->realm.data, 1217c478bd9Sstevel@tonic-gate KRB5_TGS_NAME_SIZE, 1227c478bd9Sstevel@tonic-gate KRB5_TGS_NAME, 1237c478bd9Sstevel@tonic-gate db_entry->princ->realm.length, 1247c478bd9Sstevel@tonic-gate db_entry->princ->realm.data, 1257c478bd9Sstevel@tonic-gate 0); 1267c478bd9Sstevel@tonic-gate if (retval) 1277c478bd9Sstevel@tonic-gate return retval; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* Get tgt from database */ 1307c478bd9Sstevel@tonic-gate retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry, 1317c478bd9Sstevel@tonic-gate &one, &more); 1327c478bd9Sstevel@tonic-gate krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */ 1337c478bd9Sstevel@tonic-gate if (retval) 1347c478bd9Sstevel@tonic-gate return(retval); 1357c478bd9Sstevel@tonic-gate if ((one > 1) || (more)) { 1367c478bd9Sstevel@tonic-gate krb5_db_free_principal(context, &krbtgt_entry, one); 1377c478bd9Sstevel@tonic-gate return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE; 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate if (!one) 1407c478bd9Sstevel@tonic-gate return KRB5_KDB_NOENTRY; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /* Get max kvno */ 1437c478bd9Sstevel@tonic-gate for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) { 1447c478bd9Sstevel@tonic-gate if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) { 1457c478bd9Sstevel@tonic-gate max_kvno = krbtgt_entry.key_data[j].key_data_kvno; 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate for (i = 0; i < ks_tuple_count; i++) { 1507c478bd9Sstevel@tonic-gate krb5_boolean similar; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate similar = 0; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * We could use krb5_keysalt_iterate to replace this loop, or use 1567c478bd9Sstevel@tonic-gate * krb5_keysalt_is_present for the loop below, but we want to avoid 1577c478bd9Sstevel@tonic-gate * circular library dependencies. 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) { 1607c478bd9Sstevel@tonic-gate if ((retval = krb5_c_enctype_compare(context, 1617c478bd9Sstevel@tonic-gate ks_tuple[i].ks_enctype, 1627c478bd9Sstevel@tonic-gate ks_tuple[j].ks_enctype, 1637c478bd9Sstevel@tonic-gate &similar))) 1647c478bd9Sstevel@tonic-gate return(retval); 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate if (similar) 1677c478bd9Sstevel@tonic-gate break; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate if (similar) 1717c478bd9Sstevel@tonic-gate continue; 1727c478bd9Sstevel@tonic-gate 17356a424ccSmp if ((retval = krb5_dbe_create_key_data(context, db_entry))) 1747c478bd9Sstevel@tonic-gate goto add_key_rnd_err; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* there used to be code here to extract the old key, and derive 1777c478bd9Sstevel@tonic-gate a new key from it. Now that there's a unified prng, that isn't 1787c478bd9Sstevel@tonic-gate necessary. */ 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* make new key */ 1817c478bd9Sstevel@tonic-gate if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype, 1827c478bd9Sstevel@tonic-gate &key))) 1837c478bd9Sstevel@tonic-gate goto add_key_rnd_err; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate retval = krb5_dbekd_encrypt_key_data(context, master_key, 1867c478bd9Sstevel@tonic-gate &key, NULL, kvno, 1877c478bd9Sstevel@tonic-gate &db_entry->key_data[db_entry->n_key_data-1]); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &key); 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate if (retval) 1927c478bd9Sstevel@tonic-gate goto add_key_rnd_err; 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate add_key_rnd_err: 1967c478bd9Sstevel@tonic-gate krb5_db_free_principal(context, &krbtgt_entry, one); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate return(retval); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * Change random key for a krb5_db_entry 2037c478bd9Sstevel@tonic-gate * Assumes the max kvno 2047c478bd9Sstevel@tonic-gate * 2057c478bd9Sstevel@tonic-gate * As a side effect all old keys are nuked if keepold is false. 2067c478bd9Sstevel@tonic-gate */ 2077c478bd9Sstevel@tonic-gate krb5_error_code 2087c478bd9Sstevel@tonic-gate krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry) 2097c478bd9Sstevel@tonic-gate krb5_context context; 2107c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 2117c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 2127c478bd9Sstevel@tonic-gate int ks_tuple_count; 2137c478bd9Sstevel@tonic-gate krb5_boolean keepold; 2147c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate int key_data_count; 2177c478bd9Sstevel@tonic-gate int n_new_key_data; 2187c478bd9Sstevel@tonic-gate krb5_key_data * key_data; 2197c478bd9Sstevel@tonic-gate krb5_error_code retval; 2207c478bd9Sstevel@tonic-gate int kvno; 2217c478bd9Sstevel@tonic-gate int i; 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate /* First save the old keydata */ 2247c478bd9Sstevel@tonic-gate kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data); 2257c478bd9Sstevel@tonic-gate key_data_count = db_entry->n_key_data; 2267c478bd9Sstevel@tonic-gate key_data = db_entry->key_data; 2277c478bd9Sstevel@tonic-gate db_entry->key_data = NULL; 2287c478bd9Sstevel@tonic-gate db_entry->n_key_data = 0; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* increment the kvno */ 2317c478bd9Sstevel@tonic-gate kvno++; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate retval = add_key_rnd(context, master_key, ks_tuple, 2347c478bd9Sstevel@tonic-gate ks_tuple_count, db_entry, kvno); 2357c478bd9Sstevel@tonic-gate if (retval) { 2367c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); 2377c478bd9Sstevel@tonic-gate db_entry->n_key_data = key_data_count; 2387c478bd9Sstevel@tonic-gate db_entry->key_data = key_data; 2397c478bd9Sstevel@tonic-gate } else if (keepold) { 2407c478bd9Sstevel@tonic-gate n_new_key_data = db_entry->n_key_data; 2417c478bd9Sstevel@tonic-gate for (i = 0; i < key_data_count; i++) { 2427c478bd9Sstevel@tonic-gate retval = krb5_dbe_create_key_data(context, db_entry); 2437c478bd9Sstevel@tonic-gate if (retval) { 2447c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, 2457c478bd9Sstevel@tonic-gate db_entry->key_data); 2467c478bd9Sstevel@tonic-gate break; 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate db_entry->key_data[i+n_new_key_data] = key_data[i]; 2497c478bd9Sstevel@tonic-gate memset(&key_data[i], 0, sizeof(krb5_key_data)); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate } else { 2527c478bd9Sstevel@tonic-gate cleanup_key_data(context, key_data_count, key_data); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate return(retval); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * Add random key for a krb5_db_entry 2597c478bd9Sstevel@tonic-gate * Assumes the max kvno 2607c478bd9Sstevel@tonic-gate * 2617c478bd9Sstevel@tonic-gate * As a side effect all old keys older than the max kvno are nuked. 2627c478bd9Sstevel@tonic-gate */ 2637c478bd9Sstevel@tonic-gate krb5_error_code 2647c478bd9Sstevel@tonic-gate krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry) 2657c478bd9Sstevel@tonic-gate krb5_context context; 2667c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 2677c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 2687c478bd9Sstevel@tonic-gate int ks_tuple_count; 2697c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 2707c478bd9Sstevel@tonic-gate { 2717c478bd9Sstevel@tonic-gate int key_data_count; 2727c478bd9Sstevel@tonic-gate krb5_key_data * key_data; 2737c478bd9Sstevel@tonic-gate krb5_error_code retval; 2747c478bd9Sstevel@tonic-gate int kvno; 2757c478bd9Sstevel@tonic-gate int i; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate /* First save the old keydata */ 2787c478bd9Sstevel@tonic-gate kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data); 2797c478bd9Sstevel@tonic-gate key_data_count = db_entry->n_key_data; 2807c478bd9Sstevel@tonic-gate key_data = db_entry->key_data; 2817c478bd9Sstevel@tonic-gate db_entry->key_data = NULL; 2827c478bd9Sstevel@tonic-gate db_entry->n_key_data = 0; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* increment the kvno */ 2857c478bd9Sstevel@tonic-gate kvno++; 2867c478bd9Sstevel@tonic-gate 28756a424ccSmp if ((retval = add_key_rnd(context, master_key, ks_tuple, 28856a424ccSmp ks_tuple_count, db_entry, kvno))) { 2897c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); 2907c478bd9Sstevel@tonic-gate db_entry->n_key_data = key_data_count; 2917c478bd9Sstevel@tonic-gate db_entry->key_data = key_data; 2927c478bd9Sstevel@tonic-gate } else { 2937c478bd9Sstevel@tonic-gate /* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */ 2947c478bd9Sstevel@tonic-gate for (i = 0; i < key_data_count; i++) { 2957c478bd9Sstevel@tonic-gate if (key_data[i].key_data_kvno == (kvno - 1)) { 29656a424ccSmp if ((retval = krb5_dbe_create_key_data(context, db_entry))) { 2977c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, 2987c478bd9Sstevel@tonic-gate db_entry->key_data); 2997c478bd9Sstevel@tonic-gate break; 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate /* We should decrypt/re-encrypt the data to use the same mkvno*/ 3027c478bd9Sstevel@tonic-gate db_entry->key_data[db_entry->n_key_data - 1] = key_data[i]; 3037c478bd9Sstevel@tonic-gate memset(&key_data[i], 0, sizeof(krb5_key_data)); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate cleanup_key_data(context, key_data_count, key_data); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate return(retval); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate /* 3127c478bd9Sstevel@tonic-gate * Add key_data for a krb5_db_entry 3137c478bd9Sstevel@tonic-gate * If passwd is NULL the assumes that the caller wants a random password. 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate static krb5_error_code 3167c478bd9Sstevel@tonic-gate add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd, 3177c478bd9Sstevel@tonic-gate db_entry, kvno) 3187c478bd9Sstevel@tonic-gate krb5_context context; 3197c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 3207c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 3217c478bd9Sstevel@tonic-gate int ks_tuple_count; 3227c478bd9Sstevel@tonic-gate char * passwd; 3237c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 3247c478bd9Sstevel@tonic-gate int kvno; 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate krb5_error_code retval; 3277c478bd9Sstevel@tonic-gate krb5_keysalt key_salt; 3287c478bd9Sstevel@tonic-gate krb5_keyblock key; 3297c478bd9Sstevel@tonic-gate krb5_data pwd; 3307c478bd9Sstevel@tonic-gate int i, j; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate retval = 0; 33356a424ccSmp 3347c478bd9Sstevel@tonic-gate for (i = 0; i < ks_tuple_count; i++) { 3357c478bd9Sstevel@tonic-gate krb5_boolean similar; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate similar = 0; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * We could use krb5_keysalt_iterate to replace this loop, or use 3417c478bd9Sstevel@tonic-gate * krb5_keysalt_is_present for the loop below, but we want to avoid 3427c478bd9Sstevel@tonic-gate * circular library dependencies. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) { 3457c478bd9Sstevel@tonic-gate if ((retval = krb5_c_enctype_compare(context, 3467c478bd9Sstevel@tonic-gate ks_tuple[i].ks_enctype, 3477c478bd9Sstevel@tonic-gate ks_tuple[j].ks_enctype, 3487c478bd9Sstevel@tonic-gate &similar))) 3497c478bd9Sstevel@tonic-gate return(retval); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate if (similar && 3527c478bd9Sstevel@tonic-gate (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype)) 3537c478bd9Sstevel@tonic-gate break; 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate if (j < i) 3577c478bd9Sstevel@tonic-gate continue; 3587c478bd9Sstevel@tonic-gate 35956a424ccSmp if ((retval = krb5_dbe_create_key_data(context, db_entry))) 3607c478bd9Sstevel@tonic-gate return(retval); 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* Convert password string to key using appropriate salt */ 3637c478bd9Sstevel@tonic-gate switch (key_salt.type = ks_tuple[i].ks_salttype) { 3647c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_ONLYREALM: { 3657c478bd9Sstevel@tonic-gate krb5_data * saltdata; 36656a424ccSmp if ((retval = krb5_copy_data(context, krb5_princ_realm(context, 36756a424ccSmp db_entry->princ), &saltdata))) 3687c478bd9Sstevel@tonic-gate return(retval); 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate key_salt.data = *saltdata; 3717c478bd9Sstevel@tonic-gate krb5_xfree(saltdata); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate break; 3747c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_NOREALM: 37556a424ccSmp if ((retval=krb5_principal2salt_norealm(context, db_entry->princ, 37656a424ccSmp &key_salt.data))) 3777c478bd9Sstevel@tonic-gate return(retval); 3787c478bd9Sstevel@tonic-gate break; 3797c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_NORMAL: 38056a424ccSmp if ((retval = krb5_principal2salt(context, db_entry->princ, 38156a424ccSmp &key_salt.data))) 3827c478bd9Sstevel@tonic-gate return(retval); 3837c478bd9Sstevel@tonic-gate break; 3847c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_V4: 3857c478bd9Sstevel@tonic-gate key_salt.data.length = 0; 3867c478bd9Sstevel@tonic-gate key_salt.data.data = 0; 3877c478bd9Sstevel@tonic-gate break; 3887c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_AFS3: { 3897c478bd9Sstevel@tonic-gate #if 0 3907c478bd9Sstevel@tonic-gate krb5_data * saltdata; 3917c478bd9Sstevel@tonic-gate if (retval = krb5_copy_data(context, krb5_princ_realm(context, 3927c478bd9Sstevel@tonic-gate db_entry->princ), &saltdata)) 3937c478bd9Sstevel@tonic-gate return(retval); 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate key_salt.data = *saltdata; 39656a424ccSmp key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/ 3977c478bd9Sstevel@tonic-gate krb5_xfree(saltdata); 3987c478bd9Sstevel@tonic-gate #else 3997c478bd9Sstevel@tonic-gate /* Why do we do this? Well, the afs_mit_string_to_key needs to 4007c478bd9Sstevel@tonic-gate use strlen, and the realm is not NULL terminated.... */ 40156a424ccSmp unsigned int slen = 40256a424ccSmp (*krb5_princ_realm(context,db_entry->princ)).length; 4037c478bd9Sstevel@tonic-gate if(!(key_salt.data.data = (char *) malloc(slen+1))) 4047c478bd9Sstevel@tonic-gate return ENOMEM; 4057c478bd9Sstevel@tonic-gate key_salt.data.data[slen] = 0; 4067c478bd9Sstevel@tonic-gate memcpy((char *)key_salt.data.data, 4077c478bd9Sstevel@tonic-gate (char *)(*krb5_princ_realm(context,db_entry->princ)).data, 4087c478bd9Sstevel@tonic-gate slen); 40956a424ccSmp key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/ 4107c478bd9Sstevel@tonic-gate #endif 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate break; 4147c478bd9Sstevel@tonic-gate default: 4157c478bd9Sstevel@tonic-gate return(KRB5_KDB_BAD_SALTTYPE); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate pwd.data = passwd; 4197c478bd9Sstevel@tonic-gate pwd.length = strlen(passwd); 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate memset(&key, 0, sizeof (krb5_keyblock)); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype, 4247c478bd9Sstevel@tonic-gate &pwd, &key_salt.data, &key))) { 4257c478bd9Sstevel@tonic-gate if (key_salt.data.data) 4267c478bd9Sstevel@tonic-gate free(key_salt.data.data); 4277c478bd9Sstevel@tonic-gate return(retval); 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate 43056a424ccSmp if (key_salt.data.length == SALT_TYPE_AFS_LENGTH) 4317c478bd9Sstevel@tonic-gate key_salt.data.length = 4327c478bd9Sstevel@tonic-gate krb5_princ_realm(context, db_entry->princ)->length; 4337c478bd9Sstevel@tonic-gate 43456a424ccSmp if ((retval = krb5_dbekd_encrypt_key_data(context, master_key, &key, 4357c478bd9Sstevel@tonic-gate (const krb5_keysalt *)&key_salt, 43656a424ccSmp kvno, &db_entry->key_data[db_entry->n_key_data-1]))) { 4377c478bd9Sstevel@tonic-gate if (key_salt.data.data) 4387c478bd9Sstevel@tonic-gate free(key_salt.data.data); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &key); 4417c478bd9Sstevel@tonic-gate return(retval); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate if (key_salt.data.data) 4447c478bd9Sstevel@tonic-gate free(key_salt.data.data); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &key); 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate return(retval); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate /* 4527c478bd9Sstevel@tonic-gate * Change password for a krb5_db_entry 4537c478bd9Sstevel@tonic-gate * Assumes the max kvno 4547c478bd9Sstevel@tonic-gate * 4557c478bd9Sstevel@tonic-gate * As a side effect all old keys are nuked if keepold is false. 4567c478bd9Sstevel@tonic-gate */ 4577c478bd9Sstevel@tonic-gate krb5_error_code 458*54925bf6Swillf krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd, 4597c478bd9Sstevel@tonic-gate new_kvno, keepold, db_entry) 4607c478bd9Sstevel@tonic-gate krb5_context context; 4617c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 4627c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 4637c478bd9Sstevel@tonic-gate int ks_tuple_count; 4647c478bd9Sstevel@tonic-gate char * passwd; 4657c478bd9Sstevel@tonic-gate int new_kvno; 4667c478bd9Sstevel@tonic-gate krb5_boolean keepold; 4677c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 4687c478bd9Sstevel@tonic-gate { 4697c478bd9Sstevel@tonic-gate int key_data_count; 4707c478bd9Sstevel@tonic-gate int n_new_key_data; 4717c478bd9Sstevel@tonic-gate krb5_key_data * key_data; 4727c478bd9Sstevel@tonic-gate krb5_error_code retval; 4737c478bd9Sstevel@tonic-gate int old_kvno; 4747c478bd9Sstevel@tonic-gate int i; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /* First save the old keydata */ 4777c478bd9Sstevel@tonic-gate old_kvno = get_key_data_kvno(context, db_entry->n_key_data, 4787c478bd9Sstevel@tonic-gate db_entry->key_data); 4797c478bd9Sstevel@tonic-gate key_data_count = db_entry->n_key_data; 4807c478bd9Sstevel@tonic-gate key_data = db_entry->key_data; 4817c478bd9Sstevel@tonic-gate db_entry->key_data = NULL; 4827c478bd9Sstevel@tonic-gate db_entry->n_key_data = 0; 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* increment the kvno. if the requested kvno is too small, 4857c478bd9Sstevel@tonic-gate increment the old kvno */ 4867c478bd9Sstevel@tonic-gate if (new_kvno < old_kvno+1) 4877c478bd9Sstevel@tonic-gate new_kvno = old_kvno+1; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, 4907c478bd9Sstevel@tonic-gate passwd, db_entry, new_kvno); 4917c478bd9Sstevel@tonic-gate if (retval) { 4927c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); 4937c478bd9Sstevel@tonic-gate db_entry->n_key_data = key_data_count; 4947c478bd9Sstevel@tonic-gate db_entry->key_data = key_data; 4957c478bd9Sstevel@tonic-gate } else if (keepold) { 4967c478bd9Sstevel@tonic-gate n_new_key_data = db_entry->n_key_data; 4977c478bd9Sstevel@tonic-gate for (i = 0; i < key_data_count; i++) { 4987c478bd9Sstevel@tonic-gate retval = krb5_dbe_create_key_data(context, db_entry); 4997c478bd9Sstevel@tonic-gate if (retval) { 5007c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, 5017c478bd9Sstevel@tonic-gate db_entry->key_data); 5027c478bd9Sstevel@tonic-gate break; 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate db_entry->key_data[i+n_new_key_data] = key_data[i]; 5057c478bd9Sstevel@tonic-gate memset(&key_data[i], 0, sizeof(krb5_key_data)); 5067c478bd9Sstevel@tonic-gate } 507*54925bf6Swillf krb5_db_free( context, key_data ); 5087c478bd9Sstevel@tonic-gate } else { 5097c478bd9Sstevel@tonic-gate cleanup_key_data(context, key_data_count, key_data); 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate return(retval); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* 5157c478bd9Sstevel@tonic-gate * Add password for a krb5_db_entry 5167c478bd9Sstevel@tonic-gate * Assumes the max kvno 5177c478bd9Sstevel@tonic-gate * 5187c478bd9Sstevel@tonic-gate * As a side effect all old keys older than the max kvno are nuked. 5197c478bd9Sstevel@tonic-gate */ 5207c478bd9Sstevel@tonic-gate krb5_error_code 5217c478bd9Sstevel@tonic-gate krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry) 5227c478bd9Sstevel@tonic-gate krb5_context context; 5237c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 5247c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 5257c478bd9Sstevel@tonic-gate int ks_tuple_count; 5267c478bd9Sstevel@tonic-gate char * passwd; 5277c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate int key_data_count; 5307c478bd9Sstevel@tonic-gate krb5_key_data * key_data; 5317c478bd9Sstevel@tonic-gate krb5_error_code retval; 5327c478bd9Sstevel@tonic-gate int old_kvno, new_kvno; 5337c478bd9Sstevel@tonic-gate int i; 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* First save the old keydata */ 5367c478bd9Sstevel@tonic-gate old_kvno = get_key_data_kvno(context, db_entry->n_key_data, 5377c478bd9Sstevel@tonic-gate db_entry->key_data); 5387c478bd9Sstevel@tonic-gate key_data_count = db_entry->n_key_data; 5397c478bd9Sstevel@tonic-gate key_data = db_entry->key_data; 5407c478bd9Sstevel@tonic-gate db_entry->key_data = NULL; 5417c478bd9Sstevel@tonic-gate db_entry->n_key_data = 0; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* increment the kvno */ 5447c478bd9Sstevel@tonic-gate new_kvno = old_kvno+1; 5457c478bd9Sstevel@tonic-gate 54656a424ccSmp if ((retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, 54756a424ccSmp passwd, db_entry, new_kvno))) { 5487c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); 5497c478bd9Sstevel@tonic-gate db_entry->n_key_data = key_data_count; 5507c478bd9Sstevel@tonic-gate db_entry->key_data = key_data; 5517c478bd9Sstevel@tonic-gate } else { 5527c478bd9Sstevel@tonic-gate /* Copy keys with key_data_kvno == old_kvno */ 5537c478bd9Sstevel@tonic-gate for (i = 0; i < key_data_count; i++) { 5547c478bd9Sstevel@tonic-gate if (key_data[i].key_data_kvno == old_kvno) { 55556a424ccSmp if ((retval = krb5_dbe_create_key_data(context, db_entry))) { 5567c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, 5577c478bd9Sstevel@tonic-gate db_entry->key_data); 5587c478bd9Sstevel@tonic-gate break; 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate /* We should decrypt/re-encrypt the data to use the same mkvno*/ 5617c478bd9Sstevel@tonic-gate db_entry->key_data[db_entry->n_key_data - 1] = key_data[i]; 5627c478bd9Sstevel@tonic-gate memset(&key_data[i], 0, sizeof(krb5_key_data)); 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate cleanup_key_data(context, key_data_count, key_data); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate return(retval); 5687c478bd9Sstevel@tonic-gate } 569