17c478bd9Sstevel@tonic-gate /* 2*159d09a2SMark Phalan * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* 77c478bd9Sstevel@tonic-gate * lib/kdb/kdb_cpw.c 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * Copyright 1995 by the Massachusetts Institute of Technology. 107c478bd9Sstevel@tonic-gate * All Rights Reserved. 117c478bd9Sstevel@tonic-gate * 127c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 137c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 147c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 157c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 167c478bd9Sstevel@tonic-gate * 177c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 187c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 197c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 207c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 217c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 227c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 237c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 247c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 257c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 267c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 277c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 287c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 297c478bd9Sstevel@tonic-gate * or implied warranty. 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate /* 347c478bd9Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC. 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * All rights reserved. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may require 397c478bd9Sstevel@tonic-gate * a specific license from the United States Government. It is the 407c478bd9Sstevel@tonic-gate * responsibility of any person or organization contemplating export to 417c478bd9Sstevel@tonic-gate * obtain such a license before exporting. 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 447c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 457c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 467c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 477c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 487c478bd9Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining 497c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 507c478bd9Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of 517c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 527c478bd9Sstevel@tonic-gate * or implied warranty. 537c478bd9Sstevel@tonic-gate * 547c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 557c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 567c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #include "k5-int.h" 60*159d09a2SMark Phalan #include "kdb.h" 617c478bd9Sstevel@tonic-gate #include <stdio.h> 627c478bd9Sstevel@tonic-gate #include <errno.h> 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate static int 657c478bd9Sstevel@tonic-gate get_key_data_kvno(context, count, data) 667c478bd9Sstevel@tonic-gate krb5_context context; 677c478bd9Sstevel@tonic-gate int count; 687c478bd9Sstevel@tonic-gate krb5_key_data * data; 697c478bd9Sstevel@tonic-gate { 707c478bd9Sstevel@tonic-gate int i, kvno; 717c478bd9Sstevel@tonic-gate /* Find last key version number */ 727c478bd9Sstevel@tonic-gate for (kvno = i = 0; i < count; i++) { 737c478bd9Sstevel@tonic-gate if (kvno < data[i].key_data_kvno) { 747c478bd9Sstevel@tonic-gate kvno = data[i].key_data_kvno; 757c478bd9Sstevel@tonic-gate } 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate return(kvno); 787c478bd9Sstevel@tonic-gate } 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate static void 817c478bd9Sstevel@tonic-gate cleanup_key_data(context, count, data) 827c478bd9Sstevel@tonic-gate krb5_context context; 837c478bd9Sstevel@tonic-gate int count; 847c478bd9Sstevel@tonic-gate krb5_key_data * data; 857c478bd9Sstevel@tonic-gate { 867c478bd9Sstevel@tonic-gate int i, j; 877c478bd9Sstevel@tonic-gate 8856a424ccSmp /* If data is NULL, count is always 0 */ 8956a424ccSmp if (data == NULL) return; 9056a424ccSmp 917c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 927c478bd9Sstevel@tonic-gate for (j = 0; j < data[i].key_data_ver; j++) { 937c478bd9Sstevel@tonic-gate if (data[i].key_data_length[j]) { 94*159d09a2SMark Phalan krb5_db_free(context, data[i].key_data_contents[j]); 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate } 977c478bd9Sstevel@tonic-gate } 98*159d09a2SMark Phalan krb5_db_free(context, data); 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate static krb5_error_code 1027c478bd9Sstevel@tonic-gate add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno) 1037c478bd9Sstevel@tonic-gate krb5_context context; 1047c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 1057c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 1067c478bd9Sstevel@tonic-gate int ks_tuple_count; 1077c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 1087c478bd9Sstevel@tonic-gate int kvno; 1097c478bd9Sstevel@tonic-gate { 1107c478bd9Sstevel@tonic-gate krb5_principal krbtgt_princ; 1117c478bd9Sstevel@tonic-gate krb5_keyblock key; 1127c478bd9Sstevel@tonic-gate krb5_db_entry krbtgt_entry; 1137c478bd9Sstevel@tonic-gate krb5_boolean more; 114*159d09a2SMark Phalan int max_kvno, one, i, j, k; 1157c478bd9Sstevel@tonic-gate krb5_error_code retval; 116*159d09a2SMark Phalan krb5_key_data tmp_key_data; 117*159d09a2SMark Phalan krb5_key_data *tptr; 118*159d09a2SMark Phalan 119*159d09a2SMark Phalan memset( &tmp_key_data, 0, sizeof(tmp_key_data)); 120*159d09a2SMark Phalan 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate retval = krb5_build_principal_ext(context, &krbtgt_princ, 1237c478bd9Sstevel@tonic-gate db_entry->princ->realm.length, 1247c478bd9Sstevel@tonic-gate db_entry->princ->realm.data, 1257c478bd9Sstevel@tonic-gate KRB5_TGS_NAME_SIZE, 1267c478bd9Sstevel@tonic-gate KRB5_TGS_NAME, 1277c478bd9Sstevel@tonic-gate db_entry->princ->realm.length, 1287c478bd9Sstevel@tonic-gate db_entry->princ->realm.data, 1297c478bd9Sstevel@tonic-gate 0); 1307c478bd9Sstevel@tonic-gate if (retval) 1317c478bd9Sstevel@tonic-gate return retval; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* Get tgt from database */ 1347c478bd9Sstevel@tonic-gate retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry, 1357c478bd9Sstevel@tonic-gate &one, &more); 1367c478bd9Sstevel@tonic-gate krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */ 1377c478bd9Sstevel@tonic-gate if (retval) 1387c478bd9Sstevel@tonic-gate return(retval); 1397c478bd9Sstevel@tonic-gate if ((one > 1) || (more)) { 1407c478bd9Sstevel@tonic-gate krb5_db_free_principal(context, &krbtgt_entry, one); 1417c478bd9Sstevel@tonic-gate return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE; 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate if (!one) 1447c478bd9Sstevel@tonic-gate return KRB5_KDB_NOENTRY; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* Get max kvno */ 1477c478bd9Sstevel@tonic-gate for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) { 1487c478bd9Sstevel@tonic-gate if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) { 1497c478bd9Sstevel@tonic-gate max_kvno = krbtgt_entry.key_data[j].key_data_kvno; 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate for (i = 0; i < ks_tuple_count; i++) { 1547c478bd9Sstevel@tonic-gate krb5_boolean similar; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate similar = 0; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* 1597c478bd9Sstevel@tonic-gate * We could use krb5_keysalt_iterate to replace this loop, or use 1607c478bd9Sstevel@tonic-gate * krb5_keysalt_is_present for the loop below, but we want to avoid 1617c478bd9Sstevel@tonic-gate * circular library dependencies. 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) { 1647c478bd9Sstevel@tonic-gate if ((retval = krb5_c_enctype_compare(context, 1657c478bd9Sstevel@tonic-gate ks_tuple[i].ks_enctype, 1667c478bd9Sstevel@tonic-gate ks_tuple[j].ks_enctype, 1677c478bd9Sstevel@tonic-gate &similar))) 1687c478bd9Sstevel@tonic-gate return(retval); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate if (similar) 1717c478bd9Sstevel@tonic-gate break; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (similar) 1757c478bd9Sstevel@tonic-gate continue; 1767c478bd9Sstevel@tonic-gate 17756a424ccSmp if ((retval = krb5_dbe_create_key_data(context, db_entry))) 1787c478bd9Sstevel@tonic-gate goto add_key_rnd_err; 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* there used to be code here to extract the old key, and derive 1817c478bd9Sstevel@tonic-gate a new key from it. Now that there's a unified prng, that isn't 1827c478bd9Sstevel@tonic-gate necessary. */ 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* make new key */ 1857c478bd9Sstevel@tonic-gate if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype, 1867c478bd9Sstevel@tonic-gate &key))) 1877c478bd9Sstevel@tonic-gate goto add_key_rnd_err; 1887c478bd9Sstevel@tonic-gate 189*159d09a2SMark Phalan 190*159d09a2SMark Phalan /* db library will free this. Since, its a so, it could actually be using different memory management 191*159d09a2SMark Phalan function. So, its better if the memory is allocated by the db's malloc. So, a temporary memory is used 192*159d09a2SMark Phalan here which will later be copied to the db_entry */ 1937c478bd9Sstevel@tonic-gate retval = krb5_dbekd_encrypt_key_data(context, master_key, 1947c478bd9Sstevel@tonic-gate &key, NULL, kvno, 195*159d09a2SMark Phalan &tmp_key_data); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &key); 198*159d09a2SMark Phalan if( retval ) 1997c478bd9Sstevel@tonic-gate goto add_key_rnd_err; 200*159d09a2SMark Phalan 201*159d09a2SMark Phalan tptr = &db_entry->key_data[db_entry->n_key_data-1]; 202*159d09a2SMark Phalan 203*159d09a2SMark Phalan tptr->key_data_ver = tmp_key_data.key_data_ver; 204*159d09a2SMark Phalan tptr->key_data_kvno = tmp_key_data.key_data_kvno; 205*159d09a2SMark Phalan 206*159d09a2SMark Phalan for( k = 0; k < tmp_key_data.key_data_ver; k++ ) 207*159d09a2SMark Phalan { 208*159d09a2SMark Phalan tptr->key_data_type[k] = tmp_key_data.key_data_type[k]; 209*159d09a2SMark Phalan tptr->key_data_length[k] = tmp_key_data.key_data_length[k]; 210*159d09a2SMark Phalan if( tmp_key_data.key_data_contents[k] ) 211*159d09a2SMark Phalan { 212*159d09a2SMark Phalan tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]); 213*159d09a2SMark Phalan if( tptr->key_data_contents[k] == NULL ) 214*159d09a2SMark Phalan { 215*159d09a2SMark Phalan cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); 216*159d09a2SMark Phalan db_entry->key_data = NULL; 217*159d09a2SMark Phalan db_entry->n_key_data = 0; 218*159d09a2SMark Phalan retval = ENOMEM; 219*159d09a2SMark Phalan goto add_key_rnd_err; 220*159d09a2SMark Phalan } 221*159d09a2SMark Phalan memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); 222*159d09a2SMark Phalan 223*159d09a2SMark Phalan memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); 224*159d09a2SMark Phalan free( tmp_key_data.key_data_contents[k] ); 225*159d09a2SMark Phalan tmp_key_data.key_data_contents[k] = NULL; 226*159d09a2SMark Phalan } 227*159d09a2SMark Phalan } 228*159d09a2SMark Phalan 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate add_key_rnd_err: 2327c478bd9Sstevel@tonic-gate krb5_db_free_principal(context, &krbtgt_entry, one); 2337c478bd9Sstevel@tonic-gate 234*159d09a2SMark Phalan for( i = 0; i < tmp_key_data.key_data_ver; i++ ) 235*159d09a2SMark Phalan { 236*159d09a2SMark Phalan if( tmp_key_data.key_data_contents[i] ) 237*159d09a2SMark Phalan { 238*159d09a2SMark Phalan memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]); 239*159d09a2SMark Phalan free( tmp_key_data.key_data_contents[i] ); 240*159d09a2SMark Phalan } 241*159d09a2SMark Phalan } 2427c478bd9Sstevel@tonic-gate return(retval); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* 2467c478bd9Sstevel@tonic-gate * Change random key for a krb5_db_entry 2477c478bd9Sstevel@tonic-gate * Assumes the max kvno 2487c478bd9Sstevel@tonic-gate * 2497c478bd9Sstevel@tonic-gate * As a side effect all old keys are nuked if keepold is false. 2507c478bd9Sstevel@tonic-gate */ 2517c478bd9Sstevel@tonic-gate krb5_error_code 2527c478bd9Sstevel@tonic-gate krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry) 2537c478bd9Sstevel@tonic-gate krb5_context context; 2547c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 2557c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 2567c478bd9Sstevel@tonic-gate int ks_tuple_count; 2577c478bd9Sstevel@tonic-gate krb5_boolean keepold; 2587c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 2597c478bd9Sstevel@tonic-gate { 2607c478bd9Sstevel@tonic-gate int key_data_count; 2617c478bd9Sstevel@tonic-gate int n_new_key_data; 2627c478bd9Sstevel@tonic-gate krb5_key_data * key_data; 2637c478bd9Sstevel@tonic-gate krb5_error_code retval; 2647c478bd9Sstevel@tonic-gate int kvno; 2657c478bd9Sstevel@tonic-gate int i; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate /* First save the old keydata */ 2687c478bd9Sstevel@tonic-gate kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data); 2697c478bd9Sstevel@tonic-gate key_data_count = db_entry->n_key_data; 2707c478bd9Sstevel@tonic-gate key_data = db_entry->key_data; 2717c478bd9Sstevel@tonic-gate db_entry->key_data = NULL; 2727c478bd9Sstevel@tonic-gate db_entry->n_key_data = 0; 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* increment the kvno */ 2757c478bd9Sstevel@tonic-gate kvno++; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate retval = add_key_rnd(context, master_key, ks_tuple, 2787c478bd9Sstevel@tonic-gate ks_tuple_count, db_entry, kvno); 2797c478bd9Sstevel@tonic-gate if (retval) { 2807c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); 2817c478bd9Sstevel@tonic-gate db_entry->n_key_data = key_data_count; 2827c478bd9Sstevel@tonic-gate db_entry->key_data = key_data; 2837c478bd9Sstevel@tonic-gate } else if (keepold) { 2847c478bd9Sstevel@tonic-gate n_new_key_data = db_entry->n_key_data; 2857c478bd9Sstevel@tonic-gate for (i = 0; i < key_data_count; i++) { 2867c478bd9Sstevel@tonic-gate retval = krb5_dbe_create_key_data(context, db_entry); 2877c478bd9Sstevel@tonic-gate if (retval) { 2887c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, 2897c478bd9Sstevel@tonic-gate db_entry->key_data); 2907c478bd9Sstevel@tonic-gate break; 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate db_entry->key_data[i+n_new_key_data] = key_data[i]; 2937c478bd9Sstevel@tonic-gate memset(&key_data[i], 0, sizeof(krb5_key_data)); 2947c478bd9Sstevel@tonic-gate } 295*159d09a2SMark Phalan krb5_db_free(context, key_data); /* we moved the cotents to new memory. But, the original block which contained the data */ 2967c478bd9Sstevel@tonic-gate } else { 2977c478bd9Sstevel@tonic-gate cleanup_key_data(context, key_data_count, key_data); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate return(retval); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* 3037c478bd9Sstevel@tonic-gate * Add random key for a krb5_db_entry 3047c478bd9Sstevel@tonic-gate * Assumes the max kvno 3057c478bd9Sstevel@tonic-gate * 3067c478bd9Sstevel@tonic-gate * As a side effect all old keys older than the max kvno are nuked. 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate krb5_error_code 3097c478bd9Sstevel@tonic-gate krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry) 3107c478bd9Sstevel@tonic-gate krb5_context context; 3117c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 3127c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 3137c478bd9Sstevel@tonic-gate int ks_tuple_count; 3147c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 3157c478bd9Sstevel@tonic-gate { 3167c478bd9Sstevel@tonic-gate int key_data_count; 3177c478bd9Sstevel@tonic-gate krb5_key_data * key_data; 3187c478bd9Sstevel@tonic-gate krb5_error_code retval; 3197c478bd9Sstevel@tonic-gate int kvno; 3207c478bd9Sstevel@tonic-gate int i; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /* First save the old keydata */ 3237c478bd9Sstevel@tonic-gate kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data); 3247c478bd9Sstevel@tonic-gate key_data_count = db_entry->n_key_data; 3257c478bd9Sstevel@tonic-gate key_data = db_entry->key_data; 3267c478bd9Sstevel@tonic-gate db_entry->key_data = NULL; 3277c478bd9Sstevel@tonic-gate db_entry->n_key_data = 0; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* increment the kvno */ 3307c478bd9Sstevel@tonic-gate kvno++; 3317c478bd9Sstevel@tonic-gate 33256a424ccSmp if ((retval = add_key_rnd(context, master_key, ks_tuple, 33356a424ccSmp ks_tuple_count, db_entry, kvno))) { 3347c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); 3357c478bd9Sstevel@tonic-gate db_entry->n_key_data = key_data_count; 3367c478bd9Sstevel@tonic-gate db_entry->key_data = key_data; 3377c478bd9Sstevel@tonic-gate } else { 3387c478bd9Sstevel@tonic-gate /* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */ 3397c478bd9Sstevel@tonic-gate for (i = 0; i < key_data_count; i++) { 3407c478bd9Sstevel@tonic-gate if (key_data[i].key_data_kvno == (kvno - 1)) { 34156a424ccSmp if ((retval = krb5_dbe_create_key_data(context, db_entry))) { 3427c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, 3437c478bd9Sstevel@tonic-gate db_entry->key_data); 3447c478bd9Sstevel@tonic-gate break; 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate /* We should decrypt/re-encrypt the data to use the same mkvno*/ 3477c478bd9Sstevel@tonic-gate db_entry->key_data[db_entry->n_key_data - 1] = key_data[i]; 3487c478bd9Sstevel@tonic-gate memset(&key_data[i], 0, sizeof(krb5_key_data)); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate cleanup_key_data(context, key_data_count, key_data); 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate return(retval); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * Add key_data for a krb5_db_entry 3587c478bd9Sstevel@tonic-gate * If passwd is NULL the assumes that the caller wants a random password. 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate static krb5_error_code 3617c478bd9Sstevel@tonic-gate add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd, 3627c478bd9Sstevel@tonic-gate db_entry, kvno) 3637c478bd9Sstevel@tonic-gate krb5_context context; 3647c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 3657c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 3667c478bd9Sstevel@tonic-gate int ks_tuple_count; 3677c478bd9Sstevel@tonic-gate char * passwd; 3687c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 3697c478bd9Sstevel@tonic-gate int kvno; 3707c478bd9Sstevel@tonic-gate { 3717c478bd9Sstevel@tonic-gate krb5_error_code retval; 3727c478bd9Sstevel@tonic-gate krb5_keysalt key_salt; 3737c478bd9Sstevel@tonic-gate krb5_keyblock key; 3747c478bd9Sstevel@tonic-gate krb5_data pwd; 375*159d09a2SMark Phalan int i, j, k; 376*159d09a2SMark Phalan krb5_key_data tmp_key_data; 377*159d09a2SMark Phalan krb5_key_data *tptr; 378*159d09a2SMark Phalan 379*159d09a2SMark Phalan memset( &tmp_key_data, 0, sizeof(tmp_key_data)); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate retval = 0; 38256a424ccSmp 3837c478bd9Sstevel@tonic-gate for (i = 0; i < ks_tuple_count; i++) { 3847c478bd9Sstevel@tonic-gate krb5_boolean similar; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate similar = 0; 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* 3897c478bd9Sstevel@tonic-gate * We could use krb5_keysalt_iterate to replace this loop, or use 3907c478bd9Sstevel@tonic-gate * krb5_keysalt_is_present for the loop below, but we want to avoid 3917c478bd9Sstevel@tonic-gate * circular library dependencies. 3927c478bd9Sstevel@tonic-gate */ 3937c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) { 3947c478bd9Sstevel@tonic-gate if ((retval = krb5_c_enctype_compare(context, 3957c478bd9Sstevel@tonic-gate ks_tuple[i].ks_enctype, 3967c478bd9Sstevel@tonic-gate ks_tuple[j].ks_enctype, 3977c478bd9Sstevel@tonic-gate &similar))) 3987c478bd9Sstevel@tonic-gate return(retval); 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate if (similar && 4017c478bd9Sstevel@tonic-gate (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype)) 4027c478bd9Sstevel@tonic-gate break; 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate if (j < i) 4067c478bd9Sstevel@tonic-gate continue; 4077c478bd9Sstevel@tonic-gate 40856a424ccSmp if ((retval = krb5_dbe_create_key_data(context, db_entry))) 4097c478bd9Sstevel@tonic-gate return(retval); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* Convert password string to key using appropriate salt */ 4127c478bd9Sstevel@tonic-gate switch (key_salt.type = ks_tuple[i].ks_salttype) { 4137c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_ONLYREALM: { 4147c478bd9Sstevel@tonic-gate krb5_data * saltdata; 41556a424ccSmp if ((retval = krb5_copy_data(context, krb5_princ_realm(context, 41656a424ccSmp db_entry->princ), &saltdata))) 4177c478bd9Sstevel@tonic-gate return(retval); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate key_salt.data = *saltdata; 4207c478bd9Sstevel@tonic-gate krb5_xfree(saltdata); 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate break; 4237c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_NOREALM: 42456a424ccSmp if ((retval=krb5_principal2salt_norealm(context, db_entry->princ, 42556a424ccSmp &key_salt.data))) 4267c478bd9Sstevel@tonic-gate return(retval); 4277c478bd9Sstevel@tonic-gate break; 4287c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_NORMAL: 42956a424ccSmp if ((retval = krb5_principal2salt(context, db_entry->princ, 43056a424ccSmp &key_salt.data))) 4317c478bd9Sstevel@tonic-gate return(retval); 4327c478bd9Sstevel@tonic-gate break; 4337c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_V4: 4347c478bd9Sstevel@tonic-gate key_salt.data.length = 0; 4357c478bd9Sstevel@tonic-gate key_salt.data.data = 0; 4367c478bd9Sstevel@tonic-gate break; 4377c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_AFS3: { 4387c478bd9Sstevel@tonic-gate #if 0 4397c478bd9Sstevel@tonic-gate krb5_data * saltdata; 4407c478bd9Sstevel@tonic-gate if (retval = krb5_copy_data(context, krb5_princ_realm(context, 4417c478bd9Sstevel@tonic-gate db_entry->princ), &saltdata)) 4427c478bd9Sstevel@tonic-gate return(retval); 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate key_salt.data = *saltdata; 44556a424ccSmp key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/ 4467c478bd9Sstevel@tonic-gate krb5_xfree(saltdata); 4477c478bd9Sstevel@tonic-gate #else 4487c478bd9Sstevel@tonic-gate /* Why do we do this? Well, the afs_mit_string_to_key needs to 4497c478bd9Sstevel@tonic-gate use strlen, and the realm is not NULL terminated.... */ 45056a424ccSmp unsigned int slen = 45156a424ccSmp (*krb5_princ_realm(context,db_entry->princ)).length; 4527c478bd9Sstevel@tonic-gate if(!(key_salt.data.data = (char *) malloc(slen+1))) 4537c478bd9Sstevel@tonic-gate return ENOMEM; 4547c478bd9Sstevel@tonic-gate key_salt.data.data[slen] = 0; 4557c478bd9Sstevel@tonic-gate memcpy((char *)key_salt.data.data, 4567c478bd9Sstevel@tonic-gate (char *)(*krb5_princ_realm(context,db_entry->princ)).data, 4577c478bd9Sstevel@tonic-gate slen); 45856a424ccSmp key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/ 4597c478bd9Sstevel@tonic-gate #endif 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate break; 4637c478bd9Sstevel@tonic-gate default: 4647c478bd9Sstevel@tonic-gate return(KRB5_KDB_BAD_SALTTYPE); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate pwd.data = passwd; 4687c478bd9Sstevel@tonic-gate pwd.length = strlen(passwd); 4697c478bd9Sstevel@tonic-gate 470*159d09a2SMark Phalan /* Solaris Kerberos */ 4717c478bd9Sstevel@tonic-gate memset(&key, 0, sizeof (krb5_keyblock)); 472*159d09a2SMark Phalan 473*159d09a2SMark Phalan /* AFS string to key will happen here */ 4747c478bd9Sstevel@tonic-gate if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype, 4757c478bd9Sstevel@tonic-gate &pwd, &key_salt.data, &key))) { 4767c478bd9Sstevel@tonic-gate if (key_salt.data.data) 4777c478bd9Sstevel@tonic-gate free(key_salt.data.data); 4787c478bd9Sstevel@tonic-gate return(retval); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 48156a424ccSmp if (key_salt.data.length == SALT_TYPE_AFS_LENGTH) 4827c478bd9Sstevel@tonic-gate key_salt.data.length = 4837c478bd9Sstevel@tonic-gate krb5_princ_realm(context, db_entry->princ)->length; 4847c478bd9Sstevel@tonic-gate 485*159d09a2SMark Phalan /* memory allocation to be done by db. So, use temporary block and later copy 486*159d09a2SMark Phalan it to the memory allocated by db */ 487*159d09a2SMark Phalan retval = krb5_dbekd_encrypt_key_data(context, master_key, &key, 488*159d09a2SMark Phalan (const krb5_keysalt *)&key_salt, 489*159d09a2SMark Phalan kvno, &tmp_key_data); 4907c478bd9Sstevel@tonic-gate if (key_salt.data.data) 491*159d09a2SMark Phalan free(key_salt.data.data); 4927c478bd9Sstevel@tonic-gate 493*159d09a2SMark Phalan /* Solaris Kerberos */ 4947c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &key); 495*159d09a2SMark Phalan 496*159d09a2SMark Phalan if( retval ) 497*159d09a2SMark Phalan return retval; 498*159d09a2SMark Phalan 499*159d09a2SMark Phalan tptr = &db_entry->key_data[db_entry->n_key_data-1]; 500*159d09a2SMark Phalan 501*159d09a2SMark Phalan tptr->key_data_ver = tmp_key_data.key_data_ver; 502*159d09a2SMark Phalan tptr->key_data_kvno = tmp_key_data.key_data_kvno; 503*159d09a2SMark Phalan 504*159d09a2SMark Phalan for( k = 0; k < tmp_key_data.key_data_ver; k++ ) 505*159d09a2SMark Phalan { 506*159d09a2SMark Phalan tptr->key_data_type[k] = tmp_key_data.key_data_type[k]; 507*159d09a2SMark Phalan tptr->key_data_length[k] = tmp_key_data.key_data_length[k]; 508*159d09a2SMark Phalan if( tmp_key_data.key_data_contents[k] ) 509*159d09a2SMark Phalan { 510*159d09a2SMark Phalan tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]); 511*159d09a2SMark Phalan if( tptr->key_data_contents[k] == NULL ) 512*159d09a2SMark Phalan { 513*159d09a2SMark Phalan cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); 514*159d09a2SMark Phalan db_entry->key_data = NULL; 515*159d09a2SMark Phalan db_entry->n_key_data = 0; 516*159d09a2SMark Phalan retval = ENOMEM; 517*159d09a2SMark Phalan goto add_key_pwd_err; 518*159d09a2SMark Phalan } 519*159d09a2SMark Phalan memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); 520*159d09a2SMark Phalan 521*159d09a2SMark Phalan memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); 522*159d09a2SMark Phalan free( tmp_key_data.key_data_contents[k] ); 523*159d09a2SMark Phalan tmp_key_data.key_data_contents[k] = NULL; 524*159d09a2SMark Phalan } 525*159d09a2SMark Phalan } 526*159d09a2SMark Phalan } 527*159d09a2SMark Phalan add_key_pwd_err: 528*159d09a2SMark Phalan for( i = 0; i < tmp_key_data.key_data_ver; i++ ) 529*159d09a2SMark Phalan { 530*159d09a2SMark Phalan if( tmp_key_data.key_data_contents[i] ) 531*159d09a2SMark Phalan { 532*159d09a2SMark Phalan memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]); 533*159d09a2SMark Phalan free( tmp_key_data.key_data_contents[i] ); 534*159d09a2SMark Phalan } 5357c478bd9Sstevel@tonic-gate } 536*159d09a2SMark Phalan 5377c478bd9Sstevel@tonic-gate return(retval); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* 5417c478bd9Sstevel@tonic-gate * Change password for a krb5_db_entry 5427c478bd9Sstevel@tonic-gate * Assumes the max kvno 5437c478bd9Sstevel@tonic-gate * 5447c478bd9Sstevel@tonic-gate * As a side effect all old keys are nuked if keepold is false. 5457c478bd9Sstevel@tonic-gate */ 5467c478bd9Sstevel@tonic-gate krb5_error_code 54754925bf6Swillf krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd, 5487c478bd9Sstevel@tonic-gate new_kvno, keepold, db_entry) 5497c478bd9Sstevel@tonic-gate krb5_context context; 5507c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 5517c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 5527c478bd9Sstevel@tonic-gate int ks_tuple_count; 5537c478bd9Sstevel@tonic-gate char * passwd; 5547c478bd9Sstevel@tonic-gate int new_kvno; 5557c478bd9Sstevel@tonic-gate krb5_boolean keepold; 5567c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 5577c478bd9Sstevel@tonic-gate { 5587c478bd9Sstevel@tonic-gate int key_data_count; 5597c478bd9Sstevel@tonic-gate int n_new_key_data; 5607c478bd9Sstevel@tonic-gate krb5_key_data * key_data; 5617c478bd9Sstevel@tonic-gate krb5_error_code retval; 5627c478bd9Sstevel@tonic-gate int old_kvno; 5637c478bd9Sstevel@tonic-gate int i; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate /* First save the old keydata */ 5667c478bd9Sstevel@tonic-gate old_kvno = get_key_data_kvno(context, db_entry->n_key_data, 5677c478bd9Sstevel@tonic-gate db_entry->key_data); 5687c478bd9Sstevel@tonic-gate key_data_count = db_entry->n_key_data; 5697c478bd9Sstevel@tonic-gate key_data = db_entry->key_data; 5707c478bd9Sstevel@tonic-gate db_entry->key_data = NULL; 5717c478bd9Sstevel@tonic-gate db_entry->n_key_data = 0; 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* increment the kvno. if the requested kvno is too small, 5747c478bd9Sstevel@tonic-gate increment the old kvno */ 5757c478bd9Sstevel@tonic-gate if (new_kvno < old_kvno+1) 5767c478bd9Sstevel@tonic-gate new_kvno = old_kvno+1; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, 5797c478bd9Sstevel@tonic-gate passwd, db_entry, new_kvno); 5807c478bd9Sstevel@tonic-gate if (retval) { 5817c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); 5827c478bd9Sstevel@tonic-gate db_entry->n_key_data = key_data_count; 5837c478bd9Sstevel@tonic-gate db_entry->key_data = key_data; 5847c478bd9Sstevel@tonic-gate } else if (keepold) { 5857c478bd9Sstevel@tonic-gate n_new_key_data = db_entry->n_key_data; 5867c478bd9Sstevel@tonic-gate for (i = 0; i < key_data_count; i++) { 5877c478bd9Sstevel@tonic-gate retval = krb5_dbe_create_key_data(context, db_entry); 5887c478bd9Sstevel@tonic-gate if (retval) { 5897c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, 5907c478bd9Sstevel@tonic-gate db_entry->key_data); 5917c478bd9Sstevel@tonic-gate break; 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate db_entry->key_data[i+n_new_key_data] = key_data[i]; 5947c478bd9Sstevel@tonic-gate memset(&key_data[i], 0, sizeof(krb5_key_data)); 5957c478bd9Sstevel@tonic-gate } 59654925bf6Swillf krb5_db_free( context, key_data ); 5977c478bd9Sstevel@tonic-gate } else { 5987c478bd9Sstevel@tonic-gate cleanup_key_data(context, key_data_count, key_data); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate return(retval); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * Add password for a krb5_db_entry 6057c478bd9Sstevel@tonic-gate * Assumes the max kvno 6067c478bd9Sstevel@tonic-gate * 6077c478bd9Sstevel@tonic-gate * As a side effect all old keys older than the max kvno are nuked. 6087c478bd9Sstevel@tonic-gate */ 6097c478bd9Sstevel@tonic-gate krb5_error_code 6107c478bd9Sstevel@tonic-gate krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry) 6117c478bd9Sstevel@tonic-gate krb5_context context; 6127c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 6137c478bd9Sstevel@tonic-gate krb5_key_salt_tuple * ks_tuple; 6147c478bd9Sstevel@tonic-gate int ks_tuple_count; 6157c478bd9Sstevel@tonic-gate char * passwd; 6167c478bd9Sstevel@tonic-gate krb5_db_entry * db_entry; 6177c478bd9Sstevel@tonic-gate { 6187c478bd9Sstevel@tonic-gate int key_data_count; 6197c478bd9Sstevel@tonic-gate krb5_key_data * key_data; 6207c478bd9Sstevel@tonic-gate krb5_error_code retval; 6217c478bd9Sstevel@tonic-gate int old_kvno, new_kvno; 6227c478bd9Sstevel@tonic-gate int i; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* First save the old keydata */ 6257c478bd9Sstevel@tonic-gate old_kvno = get_key_data_kvno(context, db_entry->n_key_data, 6267c478bd9Sstevel@tonic-gate db_entry->key_data); 6277c478bd9Sstevel@tonic-gate key_data_count = db_entry->n_key_data; 6287c478bd9Sstevel@tonic-gate key_data = db_entry->key_data; 6297c478bd9Sstevel@tonic-gate db_entry->key_data = NULL; 6307c478bd9Sstevel@tonic-gate db_entry->n_key_data = 0; 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* increment the kvno */ 6337c478bd9Sstevel@tonic-gate new_kvno = old_kvno+1; 6347c478bd9Sstevel@tonic-gate 63556a424ccSmp if ((retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, 63656a424ccSmp passwd, db_entry, new_kvno))) { 6377c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); 6387c478bd9Sstevel@tonic-gate db_entry->n_key_data = key_data_count; 6397c478bd9Sstevel@tonic-gate db_entry->key_data = key_data; 6407c478bd9Sstevel@tonic-gate } else { 6417c478bd9Sstevel@tonic-gate /* Copy keys with key_data_kvno == old_kvno */ 6427c478bd9Sstevel@tonic-gate for (i = 0; i < key_data_count; i++) { 6437c478bd9Sstevel@tonic-gate if (key_data[i].key_data_kvno == old_kvno) { 64456a424ccSmp if ((retval = krb5_dbe_create_key_data(context, db_entry))) { 6457c478bd9Sstevel@tonic-gate cleanup_key_data(context, db_entry->n_key_data, 6467c478bd9Sstevel@tonic-gate db_entry->key_data); 6477c478bd9Sstevel@tonic-gate break; 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate /* We should decrypt/re-encrypt the data to use the same mkvno*/ 6507c478bd9Sstevel@tonic-gate db_entry->key_data[db_entry->n_key_data - 1] = key_data[i]; 6517c478bd9Sstevel@tonic-gate memset(&key_data[i], 0, sizeof(krb5_key_data)); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate cleanup_key_data(context, key_data_count, key_data); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate return(retval); 6577c478bd9Sstevel@tonic-gate } 658*159d09a2SMark Phalan 659*159d09a2SMark Phalan 660