17c478bd9Sstevel@tonic-gate /* 2*661b8ac7SPeter Shoults * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 37c478bd9Sstevel@tonic-gate */ 47c478bd9Sstevel@tonic-gate 57c478bd9Sstevel@tonic-gate /* 67c478bd9Sstevel@tonic-gate * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * Openvision retains the copyright to derivative works of 97c478bd9Sstevel@tonic-gate * this source code. Do *NOT* create a derivative of this 107c478bd9Sstevel@tonic-gate * source code before consulting with your legal department. 117c478bd9Sstevel@tonic-gate * Do *NOT* integrate *ANY* of this source code into another 127c478bd9Sstevel@tonic-gate * product before consulting with your legal department. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * For further information, read the top-level Openvision 157c478bd9Sstevel@tonic-gate * copyright which is contained in the top-level MIT Kerberos 167c478bd9Sstevel@tonic-gate * copyright. 177c478bd9Sstevel@tonic-gate * 187c478bd9Sstevel@tonic-gate * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 247c478bd9Sstevel@tonic-gate * 25159d09a2SMark Phalan * $Header$ 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #if !defined(lint) && !defined(__CODECENTER__) 29159d09a2SMark Phalan static char *rcsid = "$Header$"; 307c478bd9Sstevel@tonic-gate #endif 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/time.h> 34159d09a2SMark Phalan #include <errno.h> 35159d09a2SMark Phalan #include "server_internal.h" 367c478bd9Sstevel@tonic-gate #include <kadm5/admin.h> 3754925bf6Swillf #include <kdb.h> 387c478bd9Sstevel@tonic-gate #include <stdio.h> 397c478bd9Sstevel@tonic-gate #include <string.h> 407c478bd9Sstevel@tonic-gate #include <stdarg.h> 417c478bd9Sstevel@tonic-gate #include <stdlib.h> 42*661b8ac7SPeter Shoults #include <k5-int.h> 43*661b8ac7SPeter Shoults #include <kadm5/server_internal.h> 44*661b8ac7SPeter Shoults #include <kadm5/admin.h> 4556a424ccSmp153739 #ifdef USE_PASSWORD_SERVER 4656a424ccSmp153739 #include <sys/wait.h> 4756a424ccSmp153739 #endif 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate extern krb5_principal master_princ; 507c478bd9Sstevel@tonic-gate extern krb5_principal hist_princ; 517c478bd9Sstevel@tonic-gate extern krb5_keyblock hist_key; 527c478bd9Sstevel@tonic-gate extern krb5_db_entry master_db; 537c478bd9Sstevel@tonic-gate extern krb5_db_entry hist_db; 547c478bd9Sstevel@tonic-gate extern krb5_kvno hist_kvno; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate static int decrypt_key_data(krb5_context context, 577c478bd9Sstevel@tonic-gate krb5_keyblock *, int n_key_data, krb5_key_data *key_data, 587c478bd9Sstevel@tonic-gate krb5_keyblock **keyblocks, int *n_keys); 597c478bd9Sstevel@tonic-gate 6054925bf6Swillf static krb5_error_code 6154925bf6Swillf kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc) 6254925bf6Swillf { 6354925bf6Swillf register krb5_principal tempprinc; 6454925bf6Swillf register int i, nelems; 6554925bf6Swillf 6654925bf6Swillf tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data)); 6754925bf6Swillf 6854925bf6Swillf if (tempprinc == 0) 6954925bf6Swillf return ENOMEM; 7054925bf6Swillf 7154925bf6Swillf memcpy(tempprinc, inprinc, sizeof(krb5_principal_data)); 7254925bf6Swillf 7354925bf6Swillf nelems = (int) krb5_princ_size(context, inprinc); 7454925bf6Swillf tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data)); 7554925bf6Swillf 7654925bf6Swillf if (tempprinc->data == 0) { 7754925bf6Swillf krb5_db_free(context, (char *)tempprinc); 7854925bf6Swillf return ENOMEM; 7954925bf6Swillf } 8054925bf6Swillf 8154925bf6Swillf for (i = 0; i < nelems; i++) { 8254925bf6Swillf unsigned int len = krb5_princ_component(context, inprinc, i)->length; 8354925bf6Swillf krb5_princ_component(context, tempprinc, i)->length = len; 8454925bf6Swillf if (((krb5_princ_component(context, tempprinc, i)->data = 8554925bf6Swillf krb5_db_alloc(context, NULL, len)) == 0) && len) { 8654925bf6Swillf while (--i >= 0) 8754925bf6Swillf krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data); 8854925bf6Swillf krb5_db_free (context, tempprinc->data); 8954925bf6Swillf krb5_db_free (context, tempprinc); 9054925bf6Swillf return ENOMEM; 9154925bf6Swillf } 9254925bf6Swillf if (len) 9354925bf6Swillf memcpy(krb5_princ_component(context, tempprinc, i)->data, 9454925bf6Swillf krb5_princ_component(context, inprinc, i)->data, len); 9554925bf6Swillf } 9654925bf6Swillf 9754925bf6Swillf tempprinc->realm.data = 9854925bf6Swillf krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length); 9954925bf6Swillf if (!tempprinc->realm.data && tempprinc->realm.length) { 10054925bf6Swillf for (i = 0; i < nelems; i++) 10154925bf6Swillf krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data); 10254925bf6Swillf krb5_db_free(context, tempprinc->data); 10354925bf6Swillf krb5_db_free(context, tempprinc); 10454925bf6Swillf return ENOMEM; 10554925bf6Swillf } 10654925bf6Swillf if (tempprinc->realm.length) 10754925bf6Swillf memcpy(tempprinc->realm.data, inprinc->realm.data, 10854925bf6Swillf inprinc->realm.length); 10954925bf6Swillf 11054925bf6Swillf *outprinc = tempprinc; 11154925bf6Swillf return 0; 11254925bf6Swillf } 11354925bf6Swillf 11454925bf6Swillf static void 11554925bf6Swillf kadm5_free_principal(krb5_context context, krb5_principal val) 11654925bf6Swillf { 11754925bf6Swillf register krb5_int32 i; 11854925bf6Swillf 11954925bf6Swillf if (!val) 12054925bf6Swillf return; 12154925bf6Swillf 12254925bf6Swillf if (val->data) { 12354925bf6Swillf i = krb5_princ_size(context, val); 12454925bf6Swillf while(--i >= 0) 12554925bf6Swillf krb5_db_free(context, krb5_princ_component(context, val, i)->data); 12654925bf6Swillf krb5_db_free(context, val->data); 12754925bf6Swillf } 12854925bf6Swillf if (val->realm.data) 12954925bf6Swillf krb5_db_free(context, val->realm.data); 13054925bf6Swillf krb5_db_free(context, val); 13154925bf6Swillf } 13254925bf6Swillf 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * XXX Functions that ought to be in libkrb5.a, but aren't. 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate kadm5_ret_t krb5_copy_key_data_contents(context, from, to) 1377c478bd9Sstevel@tonic-gate krb5_context context; 1387c478bd9Sstevel@tonic-gate krb5_key_data *from, *to; 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate int i, idx; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate *to = *from; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate idx = (from->key_data_ver == 1 ? 1 : 2); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate for (i = 0; i < idx; i++) { 1477c478bd9Sstevel@tonic-gate if ( from->key_data_length[i] ) { 1487c478bd9Sstevel@tonic-gate to->key_data_contents[i] = malloc(from->key_data_length[i]); 1497c478bd9Sstevel@tonic-gate if (to->key_data_contents[i] == NULL) { 1507c478bd9Sstevel@tonic-gate for (i = 0; i < idx; i++) { 1517c478bd9Sstevel@tonic-gate if (to->key_data_contents[i]) { 1527c478bd9Sstevel@tonic-gate memset(to->key_data_contents[i], 0, 1537c478bd9Sstevel@tonic-gate to->key_data_length[i]); 1547c478bd9Sstevel@tonic-gate free(to->key_data_contents[i]); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate return ENOMEM; 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate memcpy(to->key_data_contents[i], from->key_data_contents[i], 1607c478bd9Sstevel@tonic-gate from->key_data_length[i]); 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate return 0; 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate static krb5_tl_data *dup_tl_data(krb5_tl_data *tl) 1677c478bd9Sstevel@tonic-gate { 1687c478bd9Sstevel@tonic-gate krb5_tl_data *n; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)); 1717c478bd9Sstevel@tonic-gate if (n == NULL) 1727c478bd9Sstevel@tonic-gate return NULL; 1737c478bd9Sstevel@tonic-gate n->tl_data_contents = malloc(tl->tl_data_length); 1747c478bd9Sstevel@tonic-gate if (n->tl_data_contents == NULL) { 1757c478bd9Sstevel@tonic-gate free(n); 1767c478bd9Sstevel@tonic-gate return NULL; 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length); 1797c478bd9Sstevel@tonic-gate n->tl_data_type = tl->tl_data_type; 1807c478bd9Sstevel@tonic-gate n->tl_data_length = tl->tl_data_length; 1817c478bd9Sstevel@tonic-gate n->tl_data_next = NULL; 1827c478bd9Sstevel@tonic-gate return n; 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* This is in lib/kdb/kdb_cpw.c, but is static */ 1867c478bd9Sstevel@tonic-gate static void cleanup_key_data(context, count, data) 1877c478bd9Sstevel@tonic-gate krb5_context context; 1887c478bd9Sstevel@tonic-gate int count; 1897c478bd9Sstevel@tonic-gate krb5_key_data * data; 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate int i, j; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) 1947c478bd9Sstevel@tonic-gate for (j = 0; j < data[i].key_data_ver; j++) 1957c478bd9Sstevel@tonic-gate if (data[i].key_data_length[j]) 19654925bf6Swillf krb5_db_free(context, data[i].key_data_contents[j]); 19754925bf6Swillf krb5_db_free(context, data); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate kadm5_ret_t 2017c478bd9Sstevel@tonic-gate kadm5_create_principal(void *server_handle, 2027c478bd9Sstevel@tonic-gate kadm5_principal_ent_t entry, long mask, 2037c478bd9Sstevel@tonic-gate char *password) 2047c478bd9Sstevel@tonic-gate { 20556a424ccSmp153739 return 20656a424ccSmp153739 kadm5_create_principal_3(server_handle, entry, mask, 20756a424ccSmp153739 0, NULL, password); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate kadm5_ret_t 2107c478bd9Sstevel@tonic-gate kadm5_create_principal_3(void *server_handle, 2117c478bd9Sstevel@tonic-gate kadm5_principal_ent_t entry, long mask, 2127c478bd9Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 2137c478bd9Sstevel@tonic-gate char *password) 2147c478bd9Sstevel@tonic-gate { 2157c478bd9Sstevel@tonic-gate krb5_db_entry kdb; 2167c478bd9Sstevel@tonic-gate osa_princ_ent_rec adb; 2177c478bd9Sstevel@tonic-gate kadm5_policy_ent_rec polent; 2187c478bd9Sstevel@tonic-gate krb5_int32 now; 2197c478bd9Sstevel@tonic-gate krb5_tl_data *tl_data_orig, *tl_data_tail; 2207c478bd9Sstevel@tonic-gate unsigned int ret; 2217c478bd9Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate CHECK_HANDLE(server_handle); 2247c478bd9Sstevel@tonic-gate 22554925bf6Swillf krb5_clear_error_message(handle->context); 22654925bf6Swillf 2277c478bd9Sstevel@tonic-gate /* 2287c478bd9Sstevel@tonic-gate * Argument sanity checking, and opening up the DB 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) || 2317c478bd9Sstevel@tonic-gate (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) || 2327c478bd9Sstevel@tonic-gate (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) || 2337c478bd9Sstevel@tonic-gate (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) || 2347c478bd9Sstevel@tonic-gate (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) || 2357c478bd9Sstevel@tonic-gate (mask & KADM5_FAIL_AUTH_COUNT)) 2367c478bd9Sstevel@tonic-gate return KADM5_BAD_MASK; 2377c478bd9Sstevel@tonic-gate if((mask & ~ALL_PRINC_MASK)) 2387c478bd9Sstevel@tonic-gate return KADM5_BAD_MASK; 2397c478bd9Sstevel@tonic-gate if (entry == (kadm5_principal_ent_t) NULL || password == NULL) 2407c478bd9Sstevel@tonic-gate return EINVAL; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* 2437c478bd9Sstevel@tonic-gate * Check to see if the principal exists 2447c478bd9Sstevel@tonic-gate */ 2457c478bd9Sstevel@tonic-gate ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate switch(ret) { 2487c478bd9Sstevel@tonic-gate case KADM5_UNK_PRINC: 249159d09a2SMark Phalan /* Solaris Kerberos */ 25054925bf6Swillf memset(&kdb, 0, sizeof(krb5_db_entry)); 25154925bf6Swillf memset(&adb, 0, sizeof(osa_princ_ent_rec)); 2527c478bd9Sstevel@tonic-gate break; 2537c478bd9Sstevel@tonic-gate case 0: 25454925bf6Swillf /* 25554925bf6Swillf * Solaris Kerberos: this allows an addprinc to be done on a mix-in 25654925bf6Swillf * princ which has no keys initially. 25754925bf6Swillf */ 25854925bf6Swillf if (kdb.n_key_data != 0) { 25954925bf6Swillf /* have a princ with keys, return dupe princ error */ 2607c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 2617c478bd9Sstevel@tonic-gate return KADM5_DUP; 26254925bf6Swillf } else { 26354925bf6Swillf /* 26454925bf6Swillf * have a princ with no keys, let's replace it. Note, want to 26554925bf6Swillf * keep the existing kdb tl_data (specifically the LDAP plugin 26654925bf6Swillf * adds the DN to the tl_data which is needed to locate the dir. 26754925bf6Swillf * entry). 26854925bf6Swillf */ 26954925bf6Swillf kdb_free_entry(handle, NULL, &adb); 27054925bf6Swillf memset(&adb, 0, sizeof(osa_princ_ent_rec)); 27154925bf6Swillf } 27254925bf6Swillf break; 2737c478bd9Sstevel@tonic-gate default: 2747c478bd9Sstevel@tonic-gate return ret; 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate /* 2787c478bd9Sstevel@tonic-gate * If a policy was specified, load it. 2797c478bd9Sstevel@tonic-gate * If we can not find the one specified return an error 2807c478bd9Sstevel@tonic-gate */ 2817c478bd9Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 2827c478bd9Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, entry->policy, 2837c478bd9Sstevel@tonic-gate &polent)) != KADM5_OK) { 2847c478bd9Sstevel@tonic-gate if(ret == EINVAL) 2857c478bd9Sstevel@tonic-gate return KADM5_BAD_POLICY; 2867c478bd9Sstevel@tonic-gate else 2877c478bd9Sstevel@tonic-gate return ret; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate } 29056a424ccSmp153739 if ((ret = passwd_check(handle, password, (mask & KADM5_POLICY), 29156a424ccSmp153739 &polent, entry->principal))) { 2927c478bd9Sstevel@tonic-gate if (mask & KADM5_POLICY) 2937c478bd9Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 2947c478bd9Sstevel@tonic-gate return ret; 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Start populating the various DB fields, using the 2987c478bd9Sstevel@tonic-gate * "defaults" for fields that were not specified by the 2997c478bd9Sstevel@tonic-gate * mask. 3007c478bd9Sstevel@tonic-gate */ 30156a424ccSmp153739 if ((ret = krb5_timeofday(handle->context, &now))) { 3027c478bd9Sstevel@tonic-gate if (mask & KADM5_POLICY) 3037c478bd9Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 3047c478bd9Sstevel@tonic-gate return ret; 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate kdb.magic = KRB5_KDB_MAGIC_NUMBER; 3087c478bd9Sstevel@tonic-gate kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */ 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 311159d09a2SMark Phalan * Solaris Kerberos: 3127c478bd9Sstevel@tonic-gate * If KADM5_ATTRIBUTES is set, we want to rope in not only 3137c478bd9Sstevel@tonic-gate * entry->attributes, but also the generic params.flags 3147c478bd9Sstevel@tonic-gate * obtained previously via kadm5_get_config_params. 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate if ((mask & KADM5_ATTRIBUTES)) { 3177c478bd9Sstevel@tonic-gate kdb.attributes = handle->params.flags; 3187c478bd9Sstevel@tonic-gate kdb.attributes |= entry->attributes; 3197c478bd9Sstevel@tonic-gate } else { 3207c478bd9Sstevel@tonic-gate kdb.attributes = handle->params.flags; 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate if ((mask & KADM5_MAX_LIFE)) 3247c478bd9Sstevel@tonic-gate kdb.max_life = entry->max_life; 3257c478bd9Sstevel@tonic-gate else 3267c478bd9Sstevel@tonic-gate kdb.max_life = handle->params.max_life; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate if (mask & KADM5_MAX_RLIFE) 3297c478bd9Sstevel@tonic-gate kdb.max_renewable_life = entry->max_renewable_life; 3307c478bd9Sstevel@tonic-gate else 3317c478bd9Sstevel@tonic-gate kdb.max_renewable_life = handle->params.max_rlife; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate if ((mask & KADM5_PRINC_EXPIRE_TIME)) 3347c478bd9Sstevel@tonic-gate kdb.expiration = entry->princ_expire_time; 3357c478bd9Sstevel@tonic-gate else 3367c478bd9Sstevel@tonic-gate kdb.expiration = handle->params.expiration; 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate kdb.pw_expiration = 0; 3397c478bd9Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 3407c478bd9Sstevel@tonic-gate if(polent.pw_max_life) 3417c478bd9Sstevel@tonic-gate kdb.pw_expiration = now + polent.pw_max_life; 3427c478bd9Sstevel@tonic-gate else 3437c478bd9Sstevel@tonic-gate kdb.pw_expiration = 0; 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate if ((mask & KADM5_PW_EXPIRATION)) 3467c478bd9Sstevel@tonic-gate kdb.pw_expiration = entry->pw_expiration; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate kdb.last_success = 0; 3497c478bd9Sstevel@tonic-gate kdb.last_failed = 0; 3507c478bd9Sstevel@tonic-gate kdb.fail_auth_count = 0; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* this is kind of gross, but in order to free the tl data, I need 3537c478bd9Sstevel@tonic-gate to free the entire kdb entry, and that will try to free the 3547c478bd9Sstevel@tonic-gate principal. */ 3557c478bd9Sstevel@tonic-gate 35654925bf6Swillf if ((ret = kadm5_copy_principal(handle->context, 35756a424ccSmp153739 entry->principal, &(kdb.princ)))) { 3587c478bd9Sstevel@tonic-gate if (mask & KADM5_POLICY) 3597c478bd9Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 3607c478bd9Sstevel@tonic-gate return(ret); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 36356a424ccSmp153739 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) { 36454925bf6Swillf krb5_db_free_principal(handle->context, &kdb, 1); 3657c478bd9Sstevel@tonic-gate if (mask & KADM5_POLICY) 3667c478bd9Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 3677c478bd9Sstevel@tonic-gate return(ret); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 37054925bf6Swillf if (mask & KADM5_TL_DATA) { 37154925bf6Swillf /* splice entry->tl_data onto the front of kdb.tl_data */ 37254925bf6Swillf tl_data_orig = kdb.tl_data; 37354925bf6Swillf for (tl_data_tail = entry->tl_data; tl_data_tail; 37454925bf6Swillf tl_data_tail = tl_data_tail->tl_data_next) 37554925bf6Swillf { 37654925bf6Swillf ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl_data_tail); 37754925bf6Swillf if( ret ) 37854925bf6Swillf { 37954925bf6Swillf krb5_db_free_principal(handle->context, &kdb, 1); 38054925bf6Swillf if (mask & KADM5_POLICY) 38154925bf6Swillf (void) kadm5_free_policy_ent(handle->lhandle, &polent); 38254925bf6Swillf return ret; 38354925bf6Swillf } 38454925bf6Swillf } 38554925bf6Swillf } 38654925bf6Swillf 3877c478bd9Sstevel@tonic-gate /* initialize the keys */ 3887c478bd9Sstevel@tonic-gate 38956a424ccSmp153739 if ((ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, 3907c478bd9Sstevel@tonic-gate n_ks_tuple?ks_tuple:handle->params.keysalts, 3917c478bd9Sstevel@tonic-gate n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 3927c478bd9Sstevel@tonic-gate password, 3937c478bd9Sstevel@tonic-gate (mask & KADM5_KVNO)?entry->kvno:1, 39456a424ccSmp153739 FALSE, &kdb))) { 39554925bf6Swillf krb5_db_free_principal(handle->context, &kdb, 1); 3967c478bd9Sstevel@tonic-gate if (mask & KADM5_POLICY) 3977c478bd9Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 3987c478bd9Sstevel@tonic-gate return(ret); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* populate the admin-server-specific fields. In the OV server, 4027c478bd9Sstevel@tonic-gate this used to be in a separate database. Since there's already 4037c478bd9Sstevel@tonic-gate marshalling code for the admin fields, to keep things simple, 4047c478bd9Sstevel@tonic-gate I'm going to keep it, and make all the admin stuff occupy a 4057c478bd9Sstevel@tonic-gate single tl_data record, */ 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate adb.admin_history_kvno = hist_kvno; 4087c478bd9Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 4097c478bd9Sstevel@tonic-gate adb.aux_attributes = KADM5_POLICY; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* this does *not* need to be strdup'ed, because adb is xdr */ 4127c478bd9Sstevel@tonic-gate /* encoded in osa_adb_create_princ, and not ever freed */ 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate adb.policy = entry->policy; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* increment the policy ref count, if any */ 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 4207c478bd9Sstevel@tonic-gate polent.policy_refcnt++; 4217c478bd9Sstevel@tonic-gate if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, 4227c478bd9Sstevel@tonic-gate KADM5_REF_COUNT)) 4237c478bd9Sstevel@tonic-gate != KADM5_OK) { 42454925bf6Swillf krb5_db_free_principal(handle->context, &kdb, 1); 4257c478bd9Sstevel@tonic-gate if (mask & KADM5_POLICY) 4267c478bd9Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 4277c478bd9Sstevel@tonic-gate return(ret); 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate 43154925bf6Swillf /* In all cases key and the principal data is set, let the database provider know */ 43254925bf6Swillf kdb.mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL ; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* store the new db entry */ 4357c478bd9Sstevel@tonic-gate ret = kdb_put_entry(handle, &kdb, &adb); 4367c478bd9Sstevel@tonic-gate 43754925bf6Swillf krb5_db_free_principal(handle->context, &kdb, 1); 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate if (ret) { 4407c478bd9Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 4417c478bd9Sstevel@tonic-gate /* decrement the policy ref count */ 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate polent.policy_refcnt--; 4447c478bd9Sstevel@tonic-gate /* 4457c478bd9Sstevel@tonic-gate * if this fails, there's nothing we can do anyway. the 4467c478bd9Sstevel@tonic-gate * policy refcount wil be too high. 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate (void) kadm5_modify_policy_internal(handle->lhandle, &polent, 4497c478bd9Sstevel@tonic-gate KADM5_REF_COUNT); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate if (mask & KADM5_POLICY) 4537c478bd9Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 4547c478bd9Sstevel@tonic-gate return(ret); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate if (mask & KADM5_POLICY) 4587c478bd9Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate return KADM5_OK; 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate kadm5_ret_t 4657c478bd9Sstevel@tonic-gate kadm5_delete_principal(void *server_handle, krb5_principal principal) 4667c478bd9Sstevel@tonic-gate { 4677c478bd9Sstevel@tonic-gate unsigned int ret; 4687c478bd9Sstevel@tonic-gate kadm5_policy_ent_rec polent; 4697c478bd9Sstevel@tonic-gate krb5_db_entry kdb; 4707c478bd9Sstevel@tonic-gate osa_princ_ent_rec adb; 4717c478bd9Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate CHECK_HANDLE(server_handle); 4747c478bd9Sstevel@tonic-gate 47554925bf6Swillf krb5_clear_error_message(handle->context); 47654925bf6Swillf 4777c478bd9Sstevel@tonic-gate if (principal == NULL) 4787c478bd9Sstevel@tonic-gate return EINVAL; 4797c478bd9Sstevel@tonic-gate 48056a424ccSmp153739 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 4817c478bd9Sstevel@tonic-gate return(ret); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 4847c478bd9Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, 4857c478bd9Sstevel@tonic-gate adb.policy, &polent)) 4867c478bd9Sstevel@tonic-gate == KADM5_OK) { 4877c478bd9Sstevel@tonic-gate polent.policy_refcnt--; 4887c478bd9Sstevel@tonic-gate if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, 4897c478bd9Sstevel@tonic-gate KADM5_REF_COUNT)) 4907c478bd9Sstevel@tonic-gate != KADM5_OK) { 4917c478bd9Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 4927c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 4937c478bd9Sstevel@tonic-gate return(ret); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate } 49656a424ccSmp153739 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) { 4977c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 4987c478bd9Sstevel@tonic-gate return ret; 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate ret = kdb_delete_entry(handle, principal); 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate return ret; 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate kadm5_ret_t 5107c478bd9Sstevel@tonic-gate kadm5_modify_principal(void *server_handle, 5117c478bd9Sstevel@tonic-gate kadm5_principal_ent_t entry, long mask) 5127c478bd9Sstevel@tonic-gate { 5137c478bd9Sstevel@tonic-gate int ret, ret2, i; 5147c478bd9Sstevel@tonic-gate kadm5_policy_ent_rec npol, opol; 5157c478bd9Sstevel@tonic-gate int have_npol = 0, have_opol = 0; 5167c478bd9Sstevel@tonic-gate krb5_db_entry kdb; 51756a424ccSmp153739 krb5_tl_data *tl_data_orig; 5187c478bd9Sstevel@tonic-gate osa_princ_ent_rec adb; 5197c478bd9Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate CHECK_HANDLE(server_handle); 5227c478bd9Sstevel@tonic-gate 52354925bf6Swillf krb5_clear_error_message(handle->context); 52454925bf6Swillf 5257c478bd9Sstevel@tonic-gate if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) || 5267c478bd9Sstevel@tonic-gate (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) || 5277c478bd9Sstevel@tonic-gate (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) || 5287c478bd9Sstevel@tonic-gate (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) || 5297c478bd9Sstevel@tonic-gate (mask & KADM5_LAST_FAILED)) 5307c478bd9Sstevel@tonic-gate return KADM5_BAD_MASK; 5317c478bd9Sstevel@tonic-gate if((mask & ~ALL_PRINC_MASK)) 5327c478bd9Sstevel@tonic-gate return KADM5_BAD_MASK; 5337c478bd9Sstevel@tonic-gate if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR)) 5347c478bd9Sstevel@tonic-gate return KADM5_BAD_MASK; 5357c478bd9Sstevel@tonic-gate if(entry == (kadm5_principal_ent_t) NULL) 5367c478bd9Sstevel@tonic-gate return EINVAL; 5377c478bd9Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 5387c478bd9Sstevel@tonic-gate tl_data_orig = entry->tl_data; 5397c478bd9Sstevel@tonic-gate while (tl_data_orig) { 5407c478bd9Sstevel@tonic-gate if (tl_data_orig->tl_data_type < 256) 5417c478bd9Sstevel@tonic-gate return KADM5_BAD_TL_TYPE; 5427c478bd9Sstevel@tonic-gate tl_data_orig = tl_data_orig->tl_data_next; 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 54656a424ccSmp153739 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); 54756a424ccSmp153739 if (ret) 5487c478bd9Sstevel@tonic-gate return(ret); 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate /* 5517c478bd9Sstevel@tonic-gate * This is pretty much the same as create ... 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 5557c478bd9Sstevel@tonic-gate /* get the new policy */ 5567c478bd9Sstevel@tonic-gate ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol); 5577c478bd9Sstevel@tonic-gate if (ret) { 5587c478bd9Sstevel@tonic-gate switch (ret) { 5597c478bd9Sstevel@tonic-gate case EINVAL: 5607c478bd9Sstevel@tonic-gate ret = KADM5_BAD_POLICY; 5617c478bd9Sstevel@tonic-gate break; 5627c478bd9Sstevel@tonic-gate case KADM5_UNK_POLICY: 5637c478bd9Sstevel@tonic-gate case KADM5_BAD_POLICY: 5647c478bd9Sstevel@tonic-gate ret = KADM5_UNK_POLICY; 5657c478bd9Sstevel@tonic-gate break; 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate goto done; 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate have_npol = 1; 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate /* if we already have a policy, get it to decrement the refcnt */ 5727c478bd9Sstevel@tonic-gate if(adb.aux_attributes & KADM5_POLICY) { 5737c478bd9Sstevel@tonic-gate /* ... but not if the old and new are the same */ 5747c478bd9Sstevel@tonic-gate if(strcmp(adb.policy, entry->policy)) { 5757c478bd9Sstevel@tonic-gate ret = kadm5_get_policy(handle->lhandle, 5767c478bd9Sstevel@tonic-gate adb.policy, &opol); 5777c478bd9Sstevel@tonic-gate switch(ret) { 5787c478bd9Sstevel@tonic-gate case EINVAL: 5797c478bd9Sstevel@tonic-gate case KADM5_BAD_POLICY: 5807c478bd9Sstevel@tonic-gate case KADM5_UNK_POLICY: 5817c478bd9Sstevel@tonic-gate break; 5827c478bd9Sstevel@tonic-gate case KADM5_OK: 5837c478bd9Sstevel@tonic-gate have_opol = 1; 5847c478bd9Sstevel@tonic-gate opol.policy_refcnt--; 5857c478bd9Sstevel@tonic-gate break; 5867c478bd9Sstevel@tonic-gate default: 5877c478bd9Sstevel@tonic-gate goto done; 58856a424ccSmp153739 break; 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate npol.policy_refcnt++; 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate } else npol.policy_refcnt++; 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate /* set us up to use the new policy */ 5957c478bd9Sstevel@tonic-gate adb.aux_attributes |= KADM5_POLICY; 5967c478bd9Sstevel@tonic-gate if (adb.policy) 5977c478bd9Sstevel@tonic-gate free(adb.policy); 5987c478bd9Sstevel@tonic-gate adb.policy = strdup(entry->policy); 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* set pw_max_life based on new policy */ 6017c478bd9Sstevel@tonic-gate if (npol.pw_max_life) { 60256a424ccSmp153739 ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, 60356a424ccSmp153739 &(kdb.pw_expiration)); 60456a424ccSmp153739 if (ret) 6057c478bd9Sstevel@tonic-gate goto done; 6067c478bd9Sstevel@tonic-gate kdb.pw_expiration += npol.pw_max_life; 6077c478bd9Sstevel@tonic-gate } else { 6087c478bd9Sstevel@tonic-gate kdb.pw_expiration = 0; 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate if ((mask & KADM5_POLICY_CLR) && 6137c478bd9Sstevel@tonic-gate (adb.aux_attributes & KADM5_POLICY)) { 6147c478bd9Sstevel@tonic-gate ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol); 6157c478bd9Sstevel@tonic-gate switch(ret) { 6167c478bd9Sstevel@tonic-gate case EINVAL: 6177c478bd9Sstevel@tonic-gate case KADM5_BAD_POLICY: 6187c478bd9Sstevel@tonic-gate case KADM5_UNK_POLICY: 6197c478bd9Sstevel@tonic-gate ret = KADM5_BAD_DB; 6207c478bd9Sstevel@tonic-gate goto done; 62156a424ccSmp153739 break; 6227c478bd9Sstevel@tonic-gate case KADM5_OK: 6237c478bd9Sstevel@tonic-gate have_opol = 1; 6247c478bd9Sstevel@tonic-gate if (adb.policy) 6257c478bd9Sstevel@tonic-gate free(adb.policy); 6267c478bd9Sstevel@tonic-gate adb.policy = NULL; 6277c478bd9Sstevel@tonic-gate adb.aux_attributes &= ~KADM5_POLICY; 6287c478bd9Sstevel@tonic-gate kdb.pw_expiration = 0; 6297c478bd9Sstevel@tonic-gate opol.policy_refcnt--; 6307c478bd9Sstevel@tonic-gate break; 6317c478bd9Sstevel@tonic-gate default: 6327c478bd9Sstevel@tonic-gate goto done; 63356a424ccSmp153739 break; 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) && 6387c478bd9Sstevel@tonic-gate (((have_opol) && 6397c478bd9Sstevel@tonic-gate (ret = 6407c478bd9Sstevel@tonic-gate kadm5_modify_policy_internal(handle->lhandle, &opol, 6417c478bd9Sstevel@tonic-gate KADM5_REF_COUNT))) || 6427c478bd9Sstevel@tonic-gate ((have_npol) && 6437c478bd9Sstevel@tonic-gate (ret = 6447c478bd9Sstevel@tonic-gate kadm5_modify_policy_internal(handle->lhandle, &npol, 6457c478bd9Sstevel@tonic-gate KADM5_REF_COUNT))))) 6467c478bd9Sstevel@tonic-gate goto done; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if ((mask & KADM5_ATTRIBUTES)) 6497c478bd9Sstevel@tonic-gate kdb.attributes = entry->attributes; 6507c478bd9Sstevel@tonic-gate if ((mask & KADM5_MAX_LIFE)) 6517c478bd9Sstevel@tonic-gate kdb.max_life = entry->max_life; 6527c478bd9Sstevel@tonic-gate if ((mask & KADM5_PRINC_EXPIRE_TIME)) 6537c478bd9Sstevel@tonic-gate kdb.expiration = entry->princ_expire_time; 6547c478bd9Sstevel@tonic-gate if (mask & KADM5_PW_EXPIRATION) 6557c478bd9Sstevel@tonic-gate kdb.pw_expiration = entry->pw_expiration; 6567c478bd9Sstevel@tonic-gate if (mask & KADM5_MAX_RLIFE) 6577c478bd9Sstevel@tonic-gate kdb.max_renewable_life = entry->max_renewable_life; 6587c478bd9Sstevel@tonic-gate if (mask & KADM5_FAIL_AUTH_COUNT) 6597c478bd9Sstevel@tonic-gate kdb.fail_auth_count = entry->fail_auth_count; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if((mask & KADM5_KVNO)) { 6627c478bd9Sstevel@tonic-gate for (i = 0; i < kdb.n_key_data; i++) 6637c478bd9Sstevel@tonic-gate kdb.key_data[i].key_data_kvno = entry->kvno; 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 66754925bf6Swillf krb5_tl_data *tl; 66854925bf6Swillf 66954925bf6Swillf /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */ 67054925bf6Swillf 67154925bf6Swillf for (tl = entry->tl_data; tl; 67254925bf6Swillf tl = tl->tl_data_next) 67354925bf6Swillf { 67454925bf6Swillf ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl); 67554925bf6Swillf if( ret ) 67654925bf6Swillf { 67754925bf6Swillf goto done; 67854925bf6Swillf } 67954925bf6Swillf } 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate 68254925bf6Swillf /* let the mask propagate to the database provider */ 68354925bf6Swillf kdb.mask = mask; 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate ret = kdb_put_entry(handle, &kdb, &adb); 6867c478bd9Sstevel@tonic-gate if (ret) goto done; 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate ret = KADM5_OK; 6897c478bd9Sstevel@tonic-gate done: 6907c478bd9Sstevel@tonic-gate if (have_opol) { 6917c478bd9Sstevel@tonic-gate ret2 = kadm5_free_policy_ent(handle->lhandle, &opol); 6927c478bd9Sstevel@tonic-gate ret = ret ? ret : ret2; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate if (have_npol) { 6957c478bd9Sstevel@tonic-gate ret2 = kadm5_free_policy_ent(handle->lhandle, &npol); 6967c478bd9Sstevel@tonic-gate ret = ret ? ret : ret2; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 6997c478bd9Sstevel@tonic-gate return ret; 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate kadm5_ret_t 7037c478bd9Sstevel@tonic-gate kadm5_rename_principal(void *server_handle, 7047c478bd9Sstevel@tonic-gate krb5_principal source, krb5_principal target) 7057c478bd9Sstevel@tonic-gate { 7067c478bd9Sstevel@tonic-gate krb5_db_entry kdb; 7077c478bd9Sstevel@tonic-gate osa_princ_ent_rec adb; 7087c478bd9Sstevel@tonic-gate int ret, i; 7097c478bd9Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate CHECK_HANDLE(server_handle); 7127c478bd9Sstevel@tonic-gate 71354925bf6Swillf krb5_clear_error_message(handle->context); 71454925bf6Swillf 7157c478bd9Sstevel@tonic-gate if (source == NULL || target == NULL) 7167c478bd9Sstevel@tonic-gate return EINVAL; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) { 7197c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 7207c478bd9Sstevel@tonic-gate return(KADM5_DUP); 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, source, &kdb, &adb))) 7247c478bd9Sstevel@tonic-gate return ret; 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate /* this is kinda gross, but unavoidable */ 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate for (i=0; i<kdb.n_key_data; i++) { 7297c478bd9Sstevel@tonic-gate if ((kdb.key_data[i].key_data_ver == 1) || 7307c478bd9Sstevel@tonic-gate (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) { 7317c478bd9Sstevel@tonic-gate ret = KADM5_NO_RENAME_SALT; 7327c478bd9Sstevel@tonic-gate goto done; 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate 73654925bf6Swillf kadm5_free_principal(handle->context, kdb.princ); 73754925bf6Swillf ret = kadm5_copy_principal(handle->context, target, &kdb.princ); 73856a424ccSmp153739 if (ret) { 7397c478bd9Sstevel@tonic-gate kdb.princ = NULL; /* so freeing the dbe doesn't lose */ 7407c478bd9Sstevel@tonic-gate goto done; 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 7447c478bd9Sstevel@tonic-gate goto done; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate ret = kdb_delete_entry(handle, source); 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate done: 7497c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 7507c478bd9Sstevel@tonic-gate return ret; 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate kadm5_ret_t 7547c478bd9Sstevel@tonic-gate kadm5_get_principal(void *server_handle, krb5_principal principal, 7557c478bd9Sstevel@tonic-gate kadm5_principal_ent_t entry, 7567c478bd9Sstevel@tonic-gate long in_mask) 7577c478bd9Sstevel@tonic-gate { 7587c478bd9Sstevel@tonic-gate krb5_db_entry kdb; 7597c478bd9Sstevel@tonic-gate osa_princ_ent_rec adb; 76054925bf6Swillf krb5_error_code ret = 0; 7617c478bd9Sstevel@tonic-gate long mask; 7627c478bd9Sstevel@tonic-gate int i; 7637c478bd9Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 7647c478bd9Sstevel@tonic-gate kadm5_principal_ent_rec entry_local, *entry_orig; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate CHECK_HANDLE(server_handle); 7677c478bd9Sstevel@tonic-gate 76854925bf6Swillf krb5_clear_error_message(handle->context); 76954925bf6Swillf 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * In version 1, all the defined fields are always returned. 7727c478bd9Sstevel@tonic-gate * entry is a pointer to a kadm5_principal_ent_t_v1 that should be 7737c478bd9Sstevel@tonic-gate * filled with allocated memory. 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_1) { 7767c478bd9Sstevel@tonic-gate mask = KADM5_PRINCIPAL_NORMAL_MASK; 7777c478bd9Sstevel@tonic-gate entry_orig = entry; 7787c478bd9Sstevel@tonic-gate entry = &entry_local; 7797c478bd9Sstevel@tonic-gate } else { 7807c478bd9Sstevel@tonic-gate mask = in_mask; 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate memset((char *) entry, 0, sizeof(*entry)); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate if (principal == NULL) 7867c478bd9Sstevel@tonic-gate return EINVAL; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 7897c478bd9Sstevel@tonic-gate return ret; 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate if ((mask & KADM5_POLICY) && 7927c478bd9Sstevel@tonic-gate adb.policy && (adb.aux_attributes & KADM5_POLICY)) { 7937c478bd9Sstevel@tonic-gate if ((entry->policy = (char *) malloc(strlen(adb.policy) + 1)) == NULL) { 7947c478bd9Sstevel@tonic-gate ret = ENOMEM; 7957c478bd9Sstevel@tonic-gate goto done; 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate strcpy(entry->policy, adb.policy); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate if (mask & KADM5_AUX_ATTRIBUTES) 8017c478bd9Sstevel@tonic-gate entry->aux_attributes = adb.aux_attributes; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate if ((mask & KADM5_PRINCIPAL) && 8047c478bd9Sstevel@tonic-gate (ret = krb5_copy_principal(handle->context, principal, 8057c478bd9Sstevel@tonic-gate &entry->principal))) { 8067c478bd9Sstevel@tonic-gate goto done; 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate if (mask & KADM5_PRINC_EXPIRE_TIME) 8107c478bd9Sstevel@tonic-gate entry->princ_expire_time = kdb.expiration; 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate if ((mask & KADM5_LAST_PWD_CHANGE) && 8137c478bd9Sstevel@tonic-gate (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, 8147c478bd9Sstevel@tonic-gate &(entry->last_pwd_change)))) { 8157c478bd9Sstevel@tonic-gate goto done; 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate if (mask & KADM5_PW_EXPIRATION) 8197c478bd9Sstevel@tonic-gate entry->pw_expiration = kdb.pw_expiration; 8207c478bd9Sstevel@tonic-gate if (mask & KADM5_MAX_LIFE) 8217c478bd9Sstevel@tonic-gate entry->max_life = kdb.max_life; 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* this is a little non-sensical because the function returns two */ 8247c478bd9Sstevel@tonic-gate /* values that must be checked separately against the mask */ 8257c478bd9Sstevel@tonic-gate if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) { 82656a424ccSmp153739 ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb, 8277c478bd9Sstevel@tonic-gate &(entry->mod_date), 82856a424ccSmp153739 &(entry->mod_name)); 82956a424ccSmp153739 if (ret) { 8307c478bd9Sstevel@tonic-gate goto done; 8317c478bd9Sstevel@tonic-gate } 83256a424ccSmp153739 8337c478bd9Sstevel@tonic-gate if (! (mask & KADM5_MOD_TIME)) 8347c478bd9Sstevel@tonic-gate entry->mod_date = 0; 8357c478bd9Sstevel@tonic-gate if (! (mask & KADM5_MOD_NAME)) { 8367c478bd9Sstevel@tonic-gate krb5_free_principal(handle->context, entry->principal); 8377c478bd9Sstevel@tonic-gate entry->principal = NULL; 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate if (mask & KADM5_ATTRIBUTES) 8427c478bd9Sstevel@tonic-gate entry->attributes = kdb.attributes; 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate if (mask & KADM5_KVNO) 8457c478bd9Sstevel@tonic-gate for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++) 8467c478bd9Sstevel@tonic-gate if (kdb.key_data[i].key_data_kvno > entry->kvno) 8477c478bd9Sstevel@tonic-gate entry->kvno = kdb.key_data[i].key_data_kvno; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_2) 8507c478bd9Sstevel@tonic-gate entry->mkvno = 0; 8517c478bd9Sstevel@tonic-gate else { 8527c478bd9Sstevel@tonic-gate /* XXX I'll be damned if I know how to deal with this one --marc */ 8537c478bd9Sstevel@tonic-gate entry->mkvno = 1; 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate /* 8577c478bd9Sstevel@tonic-gate * The new fields that only exist in version 2 start here 8587c478bd9Sstevel@tonic-gate */ 8597c478bd9Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_2) { 8607c478bd9Sstevel@tonic-gate if (mask & KADM5_MAX_RLIFE) 8617c478bd9Sstevel@tonic-gate entry->max_renewable_life = kdb.max_renewable_life; 8627c478bd9Sstevel@tonic-gate if (mask & KADM5_LAST_SUCCESS) 8637c478bd9Sstevel@tonic-gate entry->last_success = kdb.last_success; 8647c478bd9Sstevel@tonic-gate if (mask & KADM5_LAST_FAILED) 8657c478bd9Sstevel@tonic-gate entry->last_failed = kdb.last_failed; 8667c478bd9Sstevel@tonic-gate if (mask & KADM5_FAIL_AUTH_COUNT) 8677c478bd9Sstevel@tonic-gate entry->fail_auth_count = kdb.fail_auth_count; 8687c478bd9Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 86956a424ccSmp153739 krb5_tl_data *tl, *tl2; 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate entry->tl_data = NULL; 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate tl = kdb.tl_data; 8747c478bd9Sstevel@tonic-gate while (tl) { 8757c478bd9Sstevel@tonic-gate if (tl->tl_data_type > 255) { 8767c478bd9Sstevel@tonic-gate if ((tl2 = dup_tl_data(tl)) == NULL) { 8777c478bd9Sstevel@tonic-gate ret = ENOMEM; 8787c478bd9Sstevel@tonic-gate goto done; 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate tl2->tl_data_next = entry->tl_data; 8817c478bd9Sstevel@tonic-gate entry->tl_data = tl2; 8827c478bd9Sstevel@tonic-gate entry->n_tl_data++; 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate tl = tl->tl_data_next; 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate if (mask & KADM5_KEY_DATA) { 8897c478bd9Sstevel@tonic-gate entry->n_key_data = kdb.n_key_data; 8907c478bd9Sstevel@tonic-gate if(entry->n_key_data) { 8917c478bd9Sstevel@tonic-gate entry->key_data = (krb5_key_data *) 8927c478bd9Sstevel@tonic-gate malloc(entry->n_key_data*sizeof(krb5_key_data)); 8937c478bd9Sstevel@tonic-gate if (entry->key_data == NULL) { 8947c478bd9Sstevel@tonic-gate ret = ENOMEM; 8957c478bd9Sstevel@tonic-gate goto done; 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate } else 8987c478bd9Sstevel@tonic-gate entry->key_data = NULL; 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate for (i = 0; i < entry->n_key_data; i++) 90156a424ccSmp153739 ret = krb5_copy_key_data_contents(handle->context, 9027c478bd9Sstevel@tonic-gate &kdb.key_data[i], 90356a424ccSmp153739 &entry->key_data[i]); 90456a424ccSmp153739 if (ret) 9057c478bd9Sstevel@tonic-gate goto done; 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * If KADM5_API_VERSION_1, we return an allocated structure, and 9117c478bd9Sstevel@tonic-gate * we need to convert the new structure back into the format the 9127c478bd9Sstevel@tonic-gate * caller is expecting. 9137c478bd9Sstevel@tonic-gate */ 9147c478bd9Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_1) { 9157c478bd9Sstevel@tonic-gate kadm5_principal_ent_t_v1 newv1; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1))); 9187c478bd9Sstevel@tonic-gate if (newv1 == NULL) { 9197c478bd9Sstevel@tonic-gate ret = ENOMEM; 9207c478bd9Sstevel@tonic-gate goto done; 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate newv1->principal = entry->principal; 9247c478bd9Sstevel@tonic-gate newv1->princ_expire_time = entry->princ_expire_time; 9257c478bd9Sstevel@tonic-gate newv1->last_pwd_change = entry->last_pwd_change; 9267c478bd9Sstevel@tonic-gate newv1->pw_expiration = entry->pw_expiration; 9277c478bd9Sstevel@tonic-gate newv1->max_life = entry->max_life; 9287c478bd9Sstevel@tonic-gate newv1->mod_name = entry->mod_name; 9297c478bd9Sstevel@tonic-gate newv1->mod_date = entry->mod_date; 9307c478bd9Sstevel@tonic-gate newv1->attributes = entry->attributes; 9317c478bd9Sstevel@tonic-gate newv1->kvno = entry->kvno; 9327c478bd9Sstevel@tonic-gate newv1->mkvno = entry->mkvno; 9337c478bd9Sstevel@tonic-gate newv1->policy = entry->policy; 9347c478bd9Sstevel@tonic-gate newv1->aux_attributes = entry->aux_attributes; 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1; 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate ret = KADM5_OK; 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate done: 9427c478bd9Sstevel@tonic-gate if (ret && entry->principal) 9437c478bd9Sstevel@tonic-gate krb5_free_principal(handle->context, entry->principal); 9447c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate return ret; 9477c478bd9Sstevel@tonic-gate } 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate /* 9507c478bd9Sstevel@tonic-gate * Function: check_pw_reuse 9517c478bd9Sstevel@tonic-gate * 9527c478bd9Sstevel@tonic-gate * Purpose: Check if a key appears in a list of keys, in order to 9537c478bd9Sstevel@tonic-gate * enforce password history. 9547c478bd9Sstevel@tonic-gate * 9557c478bd9Sstevel@tonic-gate * Arguments: 9567c478bd9Sstevel@tonic-gate * 9577c478bd9Sstevel@tonic-gate * context (r) the krb5 context 9587c478bd9Sstevel@tonic-gate * hist_keyblock (r) the key that hist_key_data is 9597c478bd9Sstevel@tonic-gate * encrypted in 9607c478bd9Sstevel@tonic-gate * n_new_key_data (r) length of new_key_data 9617c478bd9Sstevel@tonic-gate * new_key_data (r) keys to check against 9627c478bd9Sstevel@tonic-gate * pw_hist_data, encrypted in hist_keyblock 9637c478bd9Sstevel@tonic-gate * n_pw_hist_data (r) length of pw_hist_data 9647c478bd9Sstevel@tonic-gate * pw_hist_data (r) passwords to check new_key_data against 9657c478bd9Sstevel@tonic-gate * 9667c478bd9Sstevel@tonic-gate * Effects: 9677c478bd9Sstevel@tonic-gate * For each new_key in new_key_data: 9687c478bd9Sstevel@tonic-gate * decrypt new_key with the master_keyblock 9697c478bd9Sstevel@tonic-gate * for each password in pw_hist_data: 9707c478bd9Sstevel@tonic-gate * for each hist_key in password: 9717c478bd9Sstevel@tonic-gate * decrypt hist_key with hist_keyblock 9727c478bd9Sstevel@tonic-gate * compare the new_key and hist_key 9737c478bd9Sstevel@tonic-gate * 9747c478bd9Sstevel@tonic-gate * Returns krb5 errors, KADM5_PASS_RESUSE if a key in 9757c478bd9Sstevel@tonic-gate * new_key_data is the same as a key in pw_hist_data, or 0. 9767c478bd9Sstevel@tonic-gate */ 9777c478bd9Sstevel@tonic-gate static kadm5_ret_t 9787c478bd9Sstevel@tonic-gate check_pw_reuse(krb5_context context, 9797c478bd9Sstevel@tonic-gate krb5_keyblock *master_keyblock, 9807c478bd9Sstevel@tonic-gate krb5_keyblock *hist_keyblock, 9817c478bd9Sstevel@tonic-gate int n_new_key_data, krb5_key_data *new_key_data, 98256a424ccSmp153739 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data) 9837c478bd9Sstevel@tonic-gate { 9847c478bd9Sstevel@tonic-gate int x, y, z; 9857c478bd9Sstevel@tonic-gate krb5_keyblock newkey, histkey; 9867c478bd9Sstevel@tonic-gate krb5_error_code ret; 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate for (x = 0; x < n_new_key_data; x++) { 98956a424ccSmp153739 ret = krb5_dbekd_decrypt_key_data(context, 9907c478bd9Sstevel@tonic-gate master_keyblock, 9917c478bd9Sstevel@tonic-gate &(new_key_data[x]), 99256a424ccSmp153739 &newkey, NULL); 99356a424ccSmp153739 if (ret) 9947c478bd9Sstevel@tonic-gate return(ret); 9957c478bd9Sstevel@tonic-gate for (y = 0; y < n_pw_hist_data; y++) { 9967c478bd9Sstevel@tonic-gate for (z = 0; z < pw_hist_data[y].n_key_data; z++) { 99756a424ccSmp153739 ret = krb5_dbekd_decrypt_key_data(context, 9987c478bd9Sstevel@tonic-gate hist_keyblock, 9997c478bd9Sstevel@tonic-gate &pw_hist_data[y].key_data[z], 100056a424ccSmp153739 &histkey, NULL); 100156a424ccSmp153739 if (ret) 10027c478bd9Sstevel@tonic-gate return(ret); 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate if ((newkey.length == histkey.length) && 10057c478bd9Sstevel@tonic-gate (newkey.enctype == histkey.enctype) && 10067c478bd9Sstevel@tonic-gate (memcmp(newkey.contents, histkey.contents, 10077c478bd9Sstevel@tonic-gate histkey.length) == 0)) { 10087c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &histkey); 10097c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &newkey); 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate return(KADM5_PASS_REUSE); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &histkey); 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate } 10167c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &newkey); 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate return(0); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * Function: create_history_entry 10247c478bd9Sstevel@tonic-gate * 10257c478bd9Sstevel@tonic-gate * Purpose: Creates a password history entry from an array of 10267c478bd9Sstevel@tonic-gate * key_data. 10277c478bd9Sstevel@tonic-gate * 10287c478bd9Sstevel@tonic-gate * Arguments: 10297c478bd9Sstevel@tonic-gate * 10307c478bd9Sstevel@tonic-gate * context (r) krb5_context to use 10317c478bd9Sstevel@tonic-gate * master_keyblcok (r) master key block 10327c478bd9Sstevel@tonic-gate * n_key_data (r) number of elements in key_data 10337c478bd9Sstevel@tonic-gate * key_data (r) keys to add to the history entry 10347c478bd9Sstevel@tonic-gate * hist (w) history entry to fill in 10357c478bd9Sstevel@tonic-gate * 10367c478bd9Sstevel@tonic-gate * Effects: 10377c478bd9Sstevel@tonic-gate * 10387c478bd9Sstevel@tonic-gate * hist->key_data is allocated to store n_key_data key_datas. Each 10397c478bd9Sstevel@tonic-gate * element of key_data is decrypted with master_keyblock, re-encrypted 10407c478bd9Sstevel@tonic-gate * in hist_key, and added to hist->key_data. hist->n_key_data is 10417c478bd9Sstevel@tonic-gate * set to n_key_data. 10427c478bd9Sstevel@tonic-gate */ 10437c478bd9Sstevel@tonic-gate static 10447c478bd9Sstevel@tonic-gate int create_history_entry(krb5_context context, 10457c478bd9Sstevel@tonic-gate krb5_keyblock *master_keyblock, int n_key_data, 10467c478bd9Sstevel@tonic-gate krb5_key_data *key_data, osa_pw_hist_ent *hist) 10477c478bd9Sstevel@tonic-gate { 10487c478bd9Sstevel@tonic-gate int i, ret; 10497c478bd9Sstevel@tonic-gate krb5_keyblock key; 10507c478bd9Sstevel@tonic-gate krb5_keysalt salt; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data)); 10537c478bd9Sstevel@tonic-gate if (hist->key_data == NULL) 10547c478bd9Sstevel@tonic-gate return ENOMEM; 10557c478bd9Sstevel@tonic-gate memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data)); 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate for (i = 0; i < n_key_data; i++) { 105856a424ccSmp153739 ret = krb5_dbekd_decrypt_key_data(context, 10597c478bd9Sstevel@tonic-gate master_keyblock, 10607c478bd9Sstevel@tonic-gate &key_data[i], 106156a424ccSmp153739 &key, &salt); 106256a424ccSmp153739 if (ret) 10637c478bd9Sstevel@tonic-gate return ret; 106456a424ccSmp153739 106556a424ccSmp153739 ret = krb5_dbekd_encrypt_key_data(context, &hist_key, 10667c478bd9Sstevel@tonic-gate &key, &salt, 10677c478bd9Sstevel@tonic-gate key_data[i].key_data_kvno, 106856a424ccSmp153739 &hist->key_data[i]); 106956a424ccSmp153739 if (ret) 10707c478bd9Sstevel@tonic-gate return ret; 107156a424ccSmp153739 10727c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &key); 10737c478bd9Sstevel@tonic-gate /* krb5_free_keysalt(context, &salt); */ 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate hist->n_key_data = n_key_data; 10777c478bd9Sstevel@tonic-gate return 0; 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate 108056a424ccSmp153739 static 10817c478bd9Sstevel@tonic-gate void free_history_entry(krb5_context context, osa_pw_hist_ent *hist) 10827c478bd9Sstevel@tonic-gate { 10837c478bd9Sstevel@tonic-gate int i; 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate for (i = 0; i < hist->n_key_data; i++) 10867c478bd9Sstevel@tonic-gate krb5_free_key_data_contents(context, &hist->key_data[i]); 10877c478bd9Sstevel@tonic-gate free(hist->key_data); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate /* 10917c478bd9Sstevel@tonic-gate * Function: add_to_history 10927c478bd9Sstevel@tonic-gate * 10937c478bd9Sstevel@tonic-gate * Purpose: Adds a password to a principal's password history. 10947c478bd9Sstevel@tonic-gate * 10957c478bd9Sstevel@tonic-gate * Arguments: 10967c478bd9Sstevel@tonic-gate * 10977c478bd9Sstevel@tonic-gate * context (r) krb5_context to use 10987c478bd9Sstevel@tonic-gate * adb (r/w) admin principal entry to add keys to 10997c478bd9Sstevel@tonic-gate * pol (r) adb's policy 11007c478bd9Sstevel@tonic-gate * pw (r) keys for the password to add to adb's key history 11017c478bd9Sstevel@tonic-gate * 11027c478bd9Sstevel@tonic-gate * Effects: 11037c478bd9Sstevel@tonic-gate * 11047c478bd9Sstevel@tonic-gate * add_to_history adds a single password to adb's password history. 11057c478bd9Sstevel@tonic-gate * pw contains n_key_data keys in its key_data, in storage should be 11067c478bd9Sstevel@tonic-gate * allocated but not freed by the caller (XXX blech!). 11077c478bd9Sstevel@tonic-gate * 11087c478bd9Sstevel@tonic-gate * This function maintains adb->old_keys as a circular queue. It 11097c478bd9Sstevel@tonic-gate * starts empty, and grows each time this function is called until it 11107c478bd9Sstevel@tonic-gate * is pol->pw_history_num items long. adb->old_key_len holds the 11117c478bd9Sstevel@tonic-gate * number of allocated entries in the array, and must therefore be [0, 11127c478bd9Sstevel@tonic-gate * pol->pw_history_num). adb->old_key_next is the index into the 11137c478bd9Sstevel@tonic-gate * array where the next element should be written, and must be [0, 11147c478bd9Sstevel@tonic-gate * adb->old_key_len). 11157c478bd9Sstevel@tonic-gate */ 11167c478bd9Sstevel@tonic-gate #define KADM_MOD(x) (x + adb->old_key_next) % adb->old_key_len 111756a424ccSmp153739 static kadm5_ret_t add_to_history(krb5_context context, 11187c478bd9Sstevel@tonic-gate osa_princ_ent_t adb, 11197c478bd9Sstevel@tonic-gate kadm5_policy_ent_t pol, 11207c478bd9Sstevel@tonic-gate osa_pw_hist_ent *pw) 11217c478bd9Sstevel@tonic-gate { 11227c478bd9Sstevel@tonic-gate osa_pw_hist_ent *histp; 1123159d09a2SMark Phalan uint32_t nhist; 1124159d09a2SMark Phalan unsigned int i, knext, nkeys; 11257c478bd9Sstevel@tonic-gate 1126159d09a2SMark Phalan nhist = pol->pw_history_num; 11277c478bd9Sstevel@tonic-gate /* A history of 1 means just check the current password */ 1128159d09a2SMark Phalan if (nhist <= 1) 1129159d09a2SMark Phalan return 0; 11307c478bd9Sstevel@tonic-gate 1131159d09a2SMark Phalan nkeys = adb->old_key_len; 1132159d09a2SMark Phalan knext = adb->old_key_next; 11337c478bd9Sstevel@tonic-gate /* resize the adb->old_keys array if necessary */ 1134159d09a2SMark Phalan if (nkeys + 1 < nhist) { 11357c478bd9Sstevel@tonic-gate if (adb->old_keys == NULL) { 11367c478bd9Sstevel@tonic-gate adb->old_keys = (osa_pw_hist_ent *) 1137159d09a2SMark Phalan malloc((nkeys + 1) * sizeof (osa_pw_hist_ent)); 11387c478bd9Sstevel@tonic-gate } else { 11397c478bd9Sstevel@tonic-gate adb->old_keys = (osa_pw_hist_ent *) 11407c478bd9Sstevel@tonic-gate realloc(adb->old_keys, 1141159d09a2SMark Phalan (nkeys + 1) * sizeof (osa_pw_hist_ent)); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate if (adb->old_keys == NULL) 11447c478bd9Sstevel@tonic-gate return(ENOMEM); 11457c478bd9Sstevel@tonic-gate 1146159d09a2SMark Phalan memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent)); 1147159d09a2SMark Phalan nkeys = ++adb->old_key_len; 1148159d09a2SMark Phalan /* 1149159d09a2SMark Phalan * To avoid losing old keys, shift forward each entry after 1150159d09a2SMark Phalan * knext. 1151159d09a2SMark Phalan */ 1152159d09a2SMark Phalan for (i = nkeys - 1; i > knext; i--) { 11537c478bd9Sstevel@tonic-gate adb->old_keys[i] = adb->old_keys[i - 1]; 1154159d09a2SMark Phalan } 1155159d09a2SMark Phalan memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent)); 1156159d09a2SMark Phalan } else if (nkeys + 1 > nhist) { 11577c478bd9Sstevel@tonic-gate /* 11587c478bd9Sstevel@tonic-gate * The policy must have changed! Shrink the array. 11597c478bd9Sstevel@tonic-gate * Can't simply realloc() down, since it might be wrapped. 11607c478bd9Sstevel@tonic-gate * To understand the arithmetic below, note that we are 11617c478bd9Sstevel@tonic-gate * copying into new positions 0 .. N-1 from old positions 11627c478bd9Sstevel@tonic-gate * old_key_next-N .. old_key_next-1, modulo old_key_len, 11637c478bd9Sstevel@tonic-gate * where N = pw_history_num - 1 is the length of the 11647c478bd9Sstevel@tonic-gate * shortened list. Matt Crawford, FNAL 11657c478bd9Sstevel@tonic-gate */ 11667c478bd9Sstevel@tonic-gate /* 1167159d09a2SMark Phalan * M = adb->old_key_len, N = pol->pw_history_num - 1 1168159d09a2SMark Phalan * 1169159d09a2SMark Phalan * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M] 11707c478bd9Sstevel@tonic-gate */ 1171159d09a2SMark Phalan int j; 1172159d09a2SMark Phalan osa_pw_hist_t tmp; 1173159d09a2SMark Phalan 1174159d09a2SMark Phalan tmp = (osa_pw_hist_ent *) 1175159d09a2SMark Phalan malloc((nhist - 1) * sizeof (osa_pw_hist_ent)); 1176159d09a2SMark Phalan if (tmp == NULL) 1177159d09a2SMark Phalan return ENOMEM; 1178159d09a2SMark Phalan for (i = 0; i < nhist - 1; i++) { 1179159d09a2SMark Phalan /* 1180159d09a2SMark Phalan * Add nkeys once before taking remainder to avoid 1181159d09a2SMark Phalan * negative values. 1182159d09a2SMark Phalan */ 1183159d09a2SMark Phalan j = (i + nkeys + knext - (nhist - 1)) % nkeys; 1184159d09a2SMark Phalan tmp[i] = adb->old_keys[j]; 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate /* Now free the ones we don't keep (the oldest ones) */ 1187159d09a2SMark Phalan for (i = 0; i < nkeys - (nhist - 1); i++) { 1188159d09a2SMark Phalan j = (i + nkeys + knext) % nkeys; 1189159d09a2SMark Phalan histp = &adb->old_keys[j]; 1190159d09a2SMark Phalan for (j = 0; j < histp->n_key_data; j++) { 1191159d09a2SMark Phalan krb5_free_key_data_contents(context, &histp->key_data[j]); 1192159d09a2SMark Phalan } 1193159d09a2SMark Phalan free(histp->key_data); 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate free((void *)adb->old_keys); 1196159d09a2SMark Phalan adb->old_keys = tmp; 1197159d09a2SMark Phalan nkeys = adb->old_key_len = nhist - 1; 1198159d09a2SMark Phalan knext = adb->old_key_next = 0; 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate 1201159d09a2SMark Phalan /* 1202159d09a2SMark Phalan * If nhist decreased since the last password change, and nkeys+1 1203159d09a2SMark Phalan * is less than the previous nhist, it is possible for knext to 1204159d09a2SMark Phalan * index into unallocated space. This condition would not be 1205159d09a2SMark Phalan * caught by the resizing code above. 1206159d09a2SMark Phalan */ 1207159d09a2SMark Phalan if (knext + 1 > nkeys) 1208159d09a2SMark Phalan knext = adb->old_key_next = 0; 12097c478bd9Sstevel@tonic-gate /* free the old pw history entry if it contains data */ 1210159d09a2SMark Phalan histp = &adb->old_keys[knext]; 12117c478bd9Sstevel@tonic-gate for (i = 0; i < histp->n_key_data; i++) 12127c478bd9Sstevel@tonic-gate krb5_free_key_data_contents(context, &histp->key_data[i]); 12137c478bd9Sstevel@tonic-gate free(histp->key_data); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate /* store the new entry */ 1216159d09a2SMark Phalan adb->old_keys[knext] = *pw; 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate /* update the next pointer */ 1219159d09a2SMark Phalan if (++adb->old_key_next == nhist - 1) 12207c478bd9Sstevel@tonic-gate adb->old_key_next = 0; 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate return(0); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate #undef KADM_MOD 12257c478bd9Sstevel@tonic-gate 1226159d09a2SMark Phalan #ifdef USE_PASSWORD_SERVER 1227159d09a2SMark Phalan /* FIXME: don't use global variable for this */ 1228159d09a2SMark Phalan krb5_boolean use_password_server = 0; 1229159d09a2SMark Phalan 1230159d09a2SMark Phalan static krb5_boolean 1231159d09a2SMark Phalan kadm5_use_password_server (void) 1232159d09a2SMark Phalan { 1233159d09a2SMark Phalan return use_password_server; 1234159d09a2SMark Phalan } 1235159d09a2SMark Phalan 1236159d09a2SMark Phalan void 1237159d09a2SMark Phalan kadm5_set_use_password_server (void) 1238159d09a2SMark Phalan { 1239159d09a2SMark Phalan use_password_server = 1; 1240159d09a2SMark Phalan } 1241159d09a2SMark Phalan #endif 1242159d09a2SMark Phalan 1243159d09a2SMark Phalan #ifdef USE_PASSWORD_SERVER 1244159d09a2SMark Phalan 1245159d09a2SMark Phalan /* 1246159d09a2SMark Phalan * kadm5_launch_task () runs a program (task_path) to synchronize the 1247159d09a2SMark Phalan * Apple password server with the Kerberos database. Password server 1248159d09a2SMark Phalan * programs can receive arguments on the command line (task_argv) 1249159d09a2SMark Phalan * and a block of data via stdin (data_buffer). 1250159d09a2SMark Phalan * 1251159d09a2SMark Phalan * Because a failure to communicate with the tool results in the 1252159d09a2SMark Phalan * password server falling out of sync with the database, 1253159d09a2SMark Phalan * kadm5_launch_task() always fails if it can't talk to the tool. 1254159d09a2SMark Phalan */ 1255159d09a2SMark Phalan 1256159d09a2SMark Phalan static kadm5_ret_t 1257159d09a2SMark Phalan kadm5_launch_task (krb5_context context, 1258159d09a2SMark Phalan const char *task_path, char * const task_argv[], 1259159d09a2SMark Phalan const char *data_buffer) 1260159d09a2SMark Phalan { 1261159d09a2SMark Phalan kadm5_ret_t ret = 0; 1262159d09a2SMark Phalan int data_pipe[2]; 1263159d09a2SMark Phalan 1264159d09a2SMark Phalan if (data_buffer != NULL) { 1265159d09a2SMark Phalan ret = pipe (data_pipe); 1266159d09a2SMark Phalan if (ret) { ret = errno; } 1267159d09a2SMark Phalan } 1268159d09a2SMark Phalan 1269159d09a2SMark Phalan if (!ret) { 1270159d09a2SMark Phalan pid_t pid = fork (); 1271159d09a2SMark Phalan if (pid == -1) { 1272159d09a2SMark Phalan ret = errno; 1273159d09a2SMark Phalan } else if (pid == 0) { 1274159d09a2SMark Phalan /* The child: */ 1275159d09a2SMark Phalan 1276159d09a2SMark Phalan if (data_buffer != NULL) { 1277159d09a2SMark Phalan if (dup2 (data_pipe[0], STDIN_FILENO) == -1) { 1278159d09a2SMark Phalan _exit (1); 1279159d09a2SMark Phalan } 1280159d09a2SMark Phalan } else { 1281159d09a2SMark Phalan close (data_pipe[0]); 1282159d09a2SMark Phalan } 1283159d09a2SMark Phalan 1284159d09a2SMark Phalan close (data_pipe[1]); 1285159d09a2SMark Phalan 1286159d09a2SMark Phalan execv (task_path, task_argv); 1287159d09a2SMark Phalan 1288159d09a2SMark Phalan _exit (1); /* Fail if execv fails */ 1289159d09a2SMark Phalan } else { 1290159d09a2SMark Phalan /* The parent: */ 1291159d09a2SMark Phalan int status; 1292159d09a2SMark Phalan 1293159d09a2SMark Phalan if (data_buffer != NULL) { 1294159d09a2SMark Phalan /* Write out the buffer to the child */ 1295159d09a2SMark Phalan if (krb5_net_write (context, data_pipe[1], 1296159d09a2SMark Phalan data_buffer, strlen (data_buffer)) < 0) { 1297159d09a2SMark Phalan /* kill the child to make sure waitpid() won't hang later */ 1298159d09a2SMark Phalan ret = errno; 1299159d09a2SMark Phalan kill (pid, SIGKILL); 1300159d09a2SMark Phalan } 1301159d09a2SMark Phalan } 1302159d09a2SMark Phalan 1303159d09a2SMark Phalan close (data_buffer[0]); 1304159d09a2SMark Phalan close (data_buffer[1]); 1305159d09a2SMark Phalan 1306159d09a2SMark Phalan waitpid (pid, &status, 0); 1307159d09a2SMark Phalan 1308159d09a2SMark Phalan if (!ret) { 1309159d09a2SMark Phalan if (WIFEXITED (status)) { 1310159d09a2SMark Phalan /* child read password and exited. Check the return value. */ 1311159d09a2SMark Phalan if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) { 1312159d09a2SMark Phalan ret = KRB5KDC_ERR_POLICY; /* password change rejected */ 1313159d09a2SMark Phalan } 1314159d09a2SMark Phalan } else { 1315159d09a2SMark Phalan /* child read password but crashed or was killed */ 1316159d09a2SMark Phalan ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */ 1317159d09a2SMark Phalan } 1318159d09a2SMark Phalan } 1319159d09a2SMark Phalan } 1320159d09a2SMark Phalan } 1321159d09a2SMark Phalan 1322159d09a2SMark Phalan return ret; 1323159d09a2SMark Phalan } 1324159d09a2SMark Phalan 1325159d09a2SMark Phalan #endif 1326159d09a2SMark Phalan 13277c478bd9Sstevel@tonic-gate kadm5_ret_t 13287c478bd9Sstevel@tonic-gate kadm5_chpass_principal(void *server_handle, 13297c478bd9Sstevel@tonic-gate krb5_principal principal, char *password) 13307c478bd9Sstevel@tonic-gate { 133156a424ccSmp153739 return 133256a424ccSmp153739 kadm5_chpass_principal_3(server_handle, principal, FALSE, 133356a424ccSmp153739 0, NULL, password); 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate kadm5_ret_t 13377c478bd9Sstevel@tonic-gate kadm5_chpass_principal_3(void *server_handle, 13387c478bd9Sstevel@tonic-gate krb5_principal principal, krb5_boolean keepold, 13397c478bd9Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 13407c478bd9Sstevel@tonic-gate char *password) 13417c478bd9Sstevel@tonic-gate { 13427c478bd9Sstevel@tonic-gate krb5_int32 now; 13437c478bd9Sstevel@tonic-gate kadm5_policy_ent_rec pol; 13447c478bd9Sstevel@tonic-gate osa_princ_ent_rec adb; 13457c478bd9Sstevel@tonic-gate krb5_db_entry kdb, kdb_save; 134656a424ccSmp153739 int ret, ret2, last_pwd, hist_added; 13477c478bd9Sstevel@tonic-gate int have_pol = 0; 13487c478bd9Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 13497c478bd9Sstevel@tonic-gate osa_pw_hist_ent hist; 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate CHECK_HANDLE(server_handle); 13527c478bd9Sstevel@tonic-gate 1353*661b8ac7SPeter Shoults /* Solaris Kerberos - kadm5_check_min_life checks for null principal. */ 1354*661b8ac7SPeter Shoults ret = kadm5_check_min_life(server_handle,principal,NULL,0); 1355*661b8ac7SPeter Shoults if (ret) 1356*661b8ac7SPeter Shoults return (ret); 135754925bf6Swillf krb5_clear_error_message(handle->context); 135854925bf6Swillf 13597c478bd9Sstevel@tonic-gate hist_added = 0; 13607c478bd9Sstevel@tonic-gate memset(&hist, 0, sizeof(hist)); 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate if (principal == NULL || password == NULL) 13637c478bd9Sstevel@tonic-gate return EINVAL; 13647c478bd9Sstevel@tonic-gate if ((krb5_principal_compare(handle->context, 13657c478bd9Sstevel@tonic-gate principal, hist_princ)) == TRUE) 13667c478bd9Sstevel@tonic-gate return KADM5_PROTECT_PRINCIPAL; 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 13697c478bd9Sstevel@tonic-gate return(ret); 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* we are going to need the current keys after the new keys are set */ 13727c478bd9Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) { 13737c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 13747c478bd9Sstevel@tonic-gate return(ret); 13757c478bd9Sstevel@tonic-gate } 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 13787c478bd9Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol))) 13797c478bd9Sstevel@tonic-gate goto done; 13807c478bd9Sstevel@tonic-gate have_pol = 1; 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate if ((ret = passwd_check(handle, password, adb.aux_attributes & 13847c478bd9Sstevel@tonic-gate KADM5_POLICY, &pol, principal))) 13857c478bd9Sstevel@tonic-gate goto done; 13867c478bd9Sstevel@tonic-gate 138756a424ccSmp153739 ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, 13887c478bd9Sstevel@tonic-gate n_ks_tuple?ks_tuple:handle->params.keysalts, 13897c478bd9Sstevel@tonic-gate n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 13907c478bd9Sstevel@tonic-gate password, 0 /* increment kvno */, 139156a424ccSmp153739 keepold, &kdb); 139256a424ccSmp153739 if (ret) 13937c478bd9Sstevel@tonic-gate goto done; 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 13967c478bd9Sstevel@tonic-gate 139756a424ccSmp153739 ret = krb5_timeofday(handle->context, &now); 139856a424ccSmp153739 if (ret) 13997c478bd9Sstevel@tonic-gate goto done; 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 14027c478bd9Sstevel@tonic-gate /* the policy was loaded before */ 14037c478bd9Sstevel@tonic-gate 140456a424ccSmp153739 ret = krb5_dbe_lookup_last_pwd_change(handle->context, 140556a424ccSmp153739 &kdb, &last_pwd); 140656a424ccSmp153739 if (ret) 14077c478bd9Sstevel@tonic-gate goto done; 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate #if 0 14107c478bd9Sstevel@tonic-gate /* 14117c478bd9Sstevel@tonic-gate * The spec says this check is overridden if the caller has 14127c478bd9Sstevel@tonic-gate * modify privilege. The admin server therefore makes this 14137c478bd9Sstevel@tonic-gate * check itself (in chpass_principal_wrapper, misc.c). A 14147c478bd9Sstevel@tonic-gate * local caller implicitly has all authorization bits. 14157c478bd9Sstevel@tonic-gate */ 14167c478bd9Sstevel@tonic-gate if ((now - last_pwd) < pol.pw_min_life && 14177c478bd9Sstevel@tonic-gate !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 14187c478bd9Sstevel@tonic-gate ret = KADM5_PASS_TOOSOON; 14197c478bd9Sstevel@tonic-gate goto done; 14207c478bd9Sstevel@tonic-gate } 14217c478bd9Sstevel@tonic-gate #endif 14227c478bd9Sstevel@tonic-gate 142356a424ccSmp153739 ret = create_history_entry(handle->context, 14247c478bd9Sstevel@tonic-gate &handle->master_keyblock, kdb_save.n_key_data, 142556a424ccSmp153739 kdb_save.key_data, &hist); 142656a424ccSmp153739 if (ret) 14277c478bd9Sstevel@tonic-gate goto done; 14287c478bd9Sstevel@tonic-gate 142956a424ccSmp153739 ret = check_pw_reuse(handle->context, 14307c478bd9Sstevel@tonic-gate &handle->master_keyblock, 14317c478bd9Sstevel@tonic-gate &hist_key, 14327c478bd9Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 143356a424ccSmp153739 1, &hist); 143456a424ccSmp153739 if (ret) 14357c478bd9Sstevel@tonic-gate goto done; 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate if (pol.pw_history_num > 1) { 14387c478bd9Sstevel@tonic-gate if (adb.admin_history_kvno != hist_kvno) { 14397c478bd9Sstevel@tonic-gate ret = KADM5_BAD_HIST_KEY; 14407c478bd9Sstevel@tonic-gate goto done; 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 144356a424ccSmp153739 ret = check_pw_reuse(handle->context, 14447c478bd9Sstevel@tonic-gate &handle->master_keyblock, 14457c478bd9Sstevel@tonic-gate &hist_key, 14467c478bd9Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 144756a424ccSmp153739 adb.old_key_len, adb.old_keys); 144856a424ccSmp153739 if (ret) 14497c478bd9Sstevel@tonic-gate goto done; 14507c478bd9Sstevel@tonic-gate 145156a424ccSmp153739 ret = add_to_history(handle->context, &adb, &pol, &hist); 145256a424ccSmp153739 if (ret) 14537c478bd9Sstevel@tonic-gate goto done; 14547c478bd9Sstevel@tonic-gate hist_added = 1; 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate if (pol.pw_max_life) 14587c478bd9Sstevel@tonic-gate kdb.pw_expiration = now + pol.pw_max_life; 14597c478bd9Sstevel@tonic-gate else 14607c478bd9Sstevel@tonic-gate kdb.pw_expiration = 0; 14617c478bd9Sstevel@tonic-gate } else { 14627c478bd9Sstevel@tonic-gate kdb.pw_expiration = 0; 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate 1465159d09a2SMark Phalan #ifdef USE_PASSWORD_SERVER 1466159d09a2SMark Phalan if (kadm5_use_password_server () && 1467159d09a2SMark Phalan (krb5_princ_size (handle->context, principal) == 1)) { 1468159d09a2SMark Phalan krb5_data *princ = krb5_princ_component (handle->context, principal, 0); 1469159d09a2SMark Phalan const char *path = "/usr/sbin/mkpassdb"; 1470159d09a2SMark Phalan char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL }; 1471159d09a2SMark Phalan char *pstring = NULL; 1472159d09a2SMark Phalan char pwbuf[256]; 1473159d09a2SMark Phalan int pwlen = strlen (password); 1474159d09a2SMark Phalan 1475159d09a2SMark Phalan if (pwlen > 254) pwlen = 254; 1476159d09a2SMark Phalan strncpy (pwbuf, password, pwlen); 1477159d09a2SMark Phalan pwbuf[pwlen] = '\n'; 1478159d09a2SMark Phalan pwbuf[pwlen + 1] = '\0'; 1479159d09a2SMark Phalan 1480159d09a2SMark Phalan if (!ret) { 1481159d09a2SMark Phalan pstring = malloc ((princ->length + 1) * sizeof (char)); 1482159d09a2SMark Phalan if (pstring == NULL) { ret = errno; } 1483159d09a2SMark Phalan } 1484159d09a2SMark Phalan 1485159d09a2SMark Phalan if (!ret) { 1486159d09a2SMark Phalan memcpy (pstring, princ->data, princ->length); 1487159d09a2SMark Phalan pstring [princ->length] = '\0'; 1488159d09a2SMark Phalan argv[2] = pstring; 1489159d09a2SMark Phalan 1490159d09a2SMark Phalan ret = kadm5_launch_task (handle->context, path, argv, pwbuf); 1491159d09a2SMark Phalan } 1492159d09a2SMark Phalan 1493159d09a2SMark Phalan if (pstring != NULL) 1494159d09a2SMark Phalan free (pstring); 1495159d09a2SMark Phalan 1496159d09a2SMark Phalan if (ret) 1497159d09a2SMark Phalan goto done; 1498159d09a2SMark Phalan } 1499159d09a2SMark Phalan #endif 1500159d09a2SMark Phalan 150156a424ccSmp153739 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 150256a424ccSmp153739 if (ret) 15037c478bd9Sstevel@tonic-gate goto done; 15047c478bd9Sstevel@tonic-gate 150554925bf6Swillf /* key data and attributes changed, let the database provider know */ 15062dd2efa5Swillf /* Solaris Kerberos: adding support for key history in LDAP KDB */ 15072dd2efa5Swillf if (hist_added == 1) 15082dd2efa5Swillf kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES | KADM5_KEY_HIST 15092dd2efa5Swillf /* | KADM5_CPW_FUNCTION */; 15102dd2efa5Swillf else 151154925bf6Swillf kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES /* | KADM5_CPW_FUNCTION */; 151254925bf6Swillf 15137c478bd9Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 15147c478bd9Sstevel@tonic-gate goto done; 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate ret = KADM5_OK; 15177c478bd9Sstevel@tonic-gate done: 15187c478bd9Sstevel@tonic-gate if (!hist_added && hist.key_data) 15197c478bd9Sstevel@tonic-gate free_history_entry(handle->context, &hist); 15207c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 15217c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb_save, NULL); 152254925bf6Swillf krb5_db_free_principal(handle->context, &kdb, 1); 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol)) 15257c478bd9Sstevel@tonic-gate && !ret) 15267c478bd9Sstevel@tonic-gate ret = ret2; 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate return ret; 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate kadm5_ret_t 15327c478bd9Sstevel@tonic-gate kadm5_randkey_principal(void *server_handle, 15337c478bd9Sstevel@tonic-gate krb5_principal principal, 15347c478bd9Sstevel@tonic-gate krb5_keyblock **keyblocks, 15357c478bd9Sstevel@tonic-gate int *n_keys) 15367c478bd9Sstevel@tonic-gate { 1537159d09a2SMark Phalan /* Solaris Kerberos: */ 15387c478bd9Sstevel@tonic-gate krb5_key_salt_tuple keysalts[2]; 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* 15417c478bd9Sstevel@tonic-gate * Anyone calling this routine is forced to use only DES 15427c478bd9Sstevel@tonic-gate * enctypes to be compatible with earlier releases that 15437c478bd9Sstevel@tonic-gate * did not support stronger crypto. 15447c478bd9Sstevel@tonic-gate * 15457c478bd9Sstevel@tonic-gate * S10 (and later) kadmin clients will not use this API, 15467c478bd9Sstevel@tonic-gate * so we can assume the request is from an older version. 15477c478bd9Sstevel@tonic-gate */ 15487c478bd9Sstevel@tonic-gate keysalts[0].ks_enctype = ENCTYPE_DES_CBC_MD5; 15497c478bd9Sstevel@tonic-gate keysalts[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 15507c478bd9Sstevel@tonic-gate keysalts[1].ks_enctype = ENCTYPE_DES_CBC_CRC; 15517c478bd9Sstevel@tonic-gate keysalts[1].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate return (kadm5_randkey_principal_3(server_handle, principal, 15547c478bd9Sstevel@tonic-gate FALSE, 2, keysalts, keyblocks, n_keys)); 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate kadm5_ret_t 15577c478bd9Sstevel@tonic-gate kadm5_randkey_principal_3(void *server_handle, 15587c478bd9Sstevel@tonic-gate krb5_principal principal, 15597c478bd9Sstevel@tonic-gate krb5_boolean keepold, 15607c478bd9Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 15617c478bd9Sstevel@tonic-gate krb5_keyblock **keyblocks, 15627c478bd9Sstevel@tonic-gate int *n_keys) 15637c478bd9Sstevel@tonic-gate { 15647c478bd9Sstevel@tonic-gate krb5_db_entry kdb; 15657c478bd9Sstevel@tonic-gate osa_princ_ent_rec adb; 15667c478bd9Sstevel@tonic-gate krb5_int32 now; 15677c478bd9Sstevel@tonic-gate kadm5_policy_ent_rec pol; 15687c478bd9Sstevel@tonic-gate krb5_key_data *key_data; 15697c478bd9Sstevel@tonic-gate int ret, last_pwd, have_pol = 0; 15707c478bd9Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate if (keyblocks) 15737c478bd9Sstevel@tonic-gate *keyblocks = NULL; 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate CHECK_HANDLE(server_handle); 15767c478bd9Sstevel@tonic-gate 157754925bf6Swillf krb5_clear_error_message(handle->context); 157854925bf6Swillf 15797c478bd9Sstevel@tonic-gate if (principal == NULL) 15807c478bd9Sstevel@tonic-gate return EINVAL; 15817c478bd9Sstevel@tonic-gate if (hist_princ && /* this will be NULL when initializing the databse */ 15827c478bd9Sstevel@tonic-gate ((krb5_principal_compare(handle->context, 15837c478bd9Sstevel@tonic-gate principal, hist_princ)) == TRUE)) 15847c478bd9Sstevel@tonic-gate return KADM5_PROTECT_PRINCIPAL; 15857c478bd9Sstevel@tonic-gate 15867c478bd9Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 15877c478bd9Sstevel@tonic-gate return(ret); 15887c478bd9Sstevel@tonic-gate 158956a424ccSmp153739 ret = krb5_dbe_crk(handle->context, &handle->master_keyblock, 15907c478bd9Sstevel@tonic-gate n_ks_tuple?ks_tuple:handle->params.keysalts, 15917c478bd9Sstevel@tonic-gate n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 15927c478bd9Sstevel@tonic-gate keepold, 159356a424ccSmp153739 &kdb); 159456a424ccSmp153739 if (ret) 15957c478bd9Sstevel@tonic-gate goto done; 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 15987c478bd9Sstevel@tonic-gate 159956a424ccSmp153739 ret = krb5_timeofday(handle->context, &now); 160056a424ccSmp153739 if (ret) 16017c478bd9Sstevel@tonic-gate goto done; 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 16047c478bd9Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 16057c478bd9Sstevel@tonic-gate &pol)) != KADM5_OK) 16067c478bd9Sstevel@tonic-gate goto done; 16077c478bd9Sstevel@tonic-gate have_pol = 1; 16087c478bd9Sstevel@tonic-gate 160956a424ccSmp153739 ret = krb5_dbe_lookup_last_pwd_change(handle->context, 161056a424ccSmp153739 &kdb, &last_pwd); 161156a424ccSmp153739 if (ret) 16127c478bd9Sstevel@tonic-gate goto done; 16137c478bd9Sstevel@tonic-gate 16147c478bd9Sstevel@tonic-gate #if 0 16157c478bd9Sstevel@tonic-gate /* 16167c478bd9Sstevel@tonic-gate * The spec says this check is overridden if the caller has 16177c478bd9Sstevel@tonic-gate * modify privilege. The admin server therefore makes this 16187c478bd9Sstevel@tonic-gate * check itself (in chpass_principal_wrapper, misc.c). A 16197c478bd9Sstevel@tonic-gate * local caller implicitly has all authorization bits. 16207c478bd9Sstevel@tonic-gate */ 16217c478bd9Sstevel@tonic-gate if((now - last_pwd) < pol.pw_min_life && 16227c478bd9Sstevel@tonic-gate !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 16237c478bd9Sstevel@tonic-gate ret = KADM5_PASS_TOOSOON; 16247c478bd9Sstevel@tonic-gate goto done; 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate #endif 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate if(pol.pw_history_num > 1) { 16297c478bd9Sstevel@tonic-gate if(adb.admin_history_kvno != hist_kvno) { 16307c478bd9Sstevel@tonic-gate ret = KADM5_BAD_HIST_KEY; 16317c478bd9Sstevel@tonic-gate goto done; 16327c478bd9Sstevel@tonic-gate } 16337c478bd9Sstevel@tonic-gate 163456a424ccSmp153739 ret = check_pw_reuse(handle->context, 16357c478bd9Sstevel@tonic-gate &handle->master_keyblock, 16367c478bd9Sstevel@tonic-gate &hist_key, 16377c478bd9Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 163856a424ccSmp153739 adb.old_key_len, adb.old_keys); 163956a424ccSmp153739 if (ret) 16407c478bd9Sstevel@tonic-gate goto done; 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate if (pol.pw_max_life) 16437c478bd9Sstevel@tonic-gate kdb.pw_expiration = now + pol.pw_max_life; 16447c478bd9Sstevel@tonic-gate else 16457c478bd9Sstevel@tonic-gate kdb.pw_expiration = 0; 16467c478bd9Sstevel@tonic-gate } else { 16477c478bd9Sstevel@tonic-gate kdb.pw_expiration = 0; 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate 165056a424ccSmp153739 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 165156a424ccSmp153739 if (ret) 16527c478bd9Sstevel@tonic-gate goto done; 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate if (keyblocks) { 16557c478bd9Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_1) { 16567c478bd9Sstevel@tonic-gate /* Version 1 clients will expect to see a DES_CRC enctype. */ 165756a424ccSmp153739 ret = krb5_dbe_find_enctype(handle->context, &kdb, 16587c478bd9Sstevel@tonic-gate ENCTYPE_DES_CBC_CRC, 165956a424ccSmp153739 -1, -1, &key_data); 166056a424ccSmp153739 if (ret) 16617c478bd9Sstevel@tonic-gate goto done; 16627c478bd9Sstevel@tonic-gate 166356a424ccSmp153739 ret = decrypt_key_data(handle->context, 16647c478bd9Sstevel@tonic-gate &handle->master_keyblock, 1, key_data, 166556a424ccSmp153739 keyblocks, NULL); 166656a424ccSmp153739 if (ret) 16677c478bd9Sstevel@tonic-gate goto done; 16687c478bd9Sstevel@tonic-gate } else { 16697c478bd9Sstevel@tonic-gate ret = decrypt_key_data(handle->context, 16707c478bd9Sstevel@tonic-gate &handle->master_keyblock, 16717c478bd9Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 16727c478bd9Sstevel@tonic-gate keyblocks, n_keys); 16737c478bd9Sstevel@tonic-gate if (ret) 16747c478bd9Sstevel@tonic-gate goto done; 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate 167854925bf6Swillf /* key data changed, let the database provider know */ 167954925bf6Swillf kdb.mask = KADM5_KEY_DATA /* | KADM5_RANDKEY_USED */; 168054925bf6Swillf 16817c478bd9Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 16827c478bd9Sstevel@tonic-gate goto done; 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate ret = KADM5_OK; 16857c478bd9Sstevel@tonic-gate done: 16867c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 16877c478bd9Sstevel@tonic-gate if (have_pol) 16887c478bd9Sstevel@tonic-gate kadm5_free_policy_ent(handle->lhandle, &pol); 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate return ret; 16917c478bd9Sstevel@tonic-gate } 16927c478bd9Sstevel@tonic-gate 1693159d09a2SMark Phalan #if 0 /* Solaris Kerberos */ 1694159d09a2SMark Phalan /* 1695159d09a2SMark Phalan * kadm5_setv4key_principal: 1696159d09a2SMark Phalan * 1697159d09a2SMark Phalan * Set only ONE key of the principal, removing all others. This key 1698159d09a2SMark Phalan * must have the DES_CBC_CRC enctype and is entered as having the 1699159d09a2SMark Phalan * krb4 salttype. This is to enable things like kadmind4 to work. 1700159d09a2SMark Phalan */ 1701159d09a2SMark Phalan kadm5_ret_t 1702159d09a2SMark Phalan kadm5_setv4key_principal(void *server_handle, 1703159d09a2SMark Phalan krb5_principal principal, 1704159d09a2SMark Phalan krb5_keyblock *keyblock) 1705159d09a2SMark Phalan { 1706159d09a2SMark Phalan krb5_db_entry kdb; 1707159d09a2SMark Phalan osa_princ_ent_rec adb; 1708159d09a2SMark Phalan krb5_int32 now; 1709159d09a2SMark Phalan kadm5_policy_ent_rec pol; 1710159d09a2SMark Phalan krb5_keysalt keysalt; 1711159d09a2SMark Phalan int i, k, kvno, ret, have_pol = 0; 1712159d09a2SMark Phalan #if 0 1713159d09a2SMark Phalan int last_pwd; 1714159d09a2SMark Phalan #endif 1715159d09a2SMark Phalan kadm5_server_handle_t handle = server_handle; 1716159d09a2SMark Phalan krb5_key_data tmp_key_data; 1717159d09a2SMark Phalan 1718159d09a2SMark Phalan memset( &tmp_key_data, 0, sizeof(tmp_key_data)); 1719159d09a2SMark Phalan 1720159d09a2SMark Phalan CHECK_HANDLE(server_handle); 1721159d09a2SMark Phalan 1722159d09a2SMark Phalan krb5_clear_error_message(handle->context); 1723159d09a2SMark Phalan 1724159d09a2SMark Phalan if (principal == NULL || keyblock == NULL) 1725159d09a2SMark Phalan return EINVAL; 1726159d09a2SMark Phalan if (hist_princ && /* this will be NULL when initializing the databse */ 1727159d09a2SMark Phalan ((krb5_principal_compare(handle->context, 1728159d09a2SMark Phalan principal, hist_princ)) == TRUE)) 1729159d09a2SMark Phalan return KADM5_PROTECT_PRINCIPAL; 1730159d09a2SMark Phalan 1731159d09a2SMark Phalan if (keyblock->enctype != ENCTYPE_DES_CBC_CRC) 1732159d09a2SMark Phalan return KADM5_SETV4KEY_INVAL_ENCTYPE; 1733159d09a2SMark Phalan 1734159d09a2SMark Phalan if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1735159d09a2SMark Phalan return(ret); 1736159d09a2SMark Phalan 1737159d09a2SMark Phalan for (kvno = 0, i=0; i<kdb.n_key_data; i++) 1738159d09a2SMark Phalan if (kdb.key_data[i].key_data_kvno > kvno) 1739159d09a2SMark Phalan kvno = kdb.key_data[i].key_data_kvno; 1740159d09a2SMark Phalan 1741159d09a2SMark Phalan if (kdb.key_data != NULL) 1742159d09a2SMark Phalan cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 1743159d09a2SMark Phalan 1744159d09a2SMark Phalan kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data)); 1745159d09a2SMark Phalan if (kdb.key_data == NULL) 1746159d09a2SMark Phalan return ENOMEM; 1747159d09a2SMark Phalan memset(kdb.key_data, 0, sizeof(krb5_key_data)); 1748159d09a2SMark Phalan kdb.n_key_data = 1; 1749159d09a2SMark Phalan keysalt.type = KRB5_KDB_SALTTYPE_V4; 1750159d09a2SMark Phalan /* XXX data.magic? */ 1751159d09a2SMark Phalan keysalt.data.length = 0; 1752159d09a2SMark Phalan keysalt.data.data = NULL; 1753159d09a2SMark Phalan 1754159d09a2SMark Phalan /* use tmp_key_data as temporary location and reallocate later */ 1755159d09a2SMark Phalan ret = krb5_dbekd_encrypt_key_data(handle->context, &master_keyblock, 1756159d09a2SMark Phalan keyblock, &keysalt, kvno + 1, 1757159d09a2SMark Phalan &tmp_key_data); 1758159d09a2SMark Phalan if (ret) { 1759159d09a2SMark Phalan goto done; 1760159d09a2SMark Phalan } 1761159d09a2SMark Phalan 1762159d09a2SMark Phalan for (k = 0; k < tmp_key_data.key_data_ver; k++) { 1763159d09a2SMark Phalan kdb.key_data->key_data_type[k] = tmp_key_data.key_data_type[k]; 1764159d09a2SMark Phalan kdb.key_data->key_data_length[k] = tmp_key_data.key_data_length[k]; 1765159d09a2SMark Phalan if (tmp_key_data.key_data_contents[k]) { 1766159d09a2SMark Phalan kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]); 1767159d09a2SMark Phalan if (kdb.key_data->key_data_contents[k] == NULL) { 1768159d09a2SMark Phalan cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 1769159d09a2SMark Phalan kdb.key_data = NULL; 1770159d09a2SMark Phalan kdb.n_key_data = 0; 1771159d09a2SMark Phalan ret = ENOMEM; 1772159d09a2SMark Phalan goto done; 1773159d09a2SMark Phalan } 1774159d09a2SMark Phalan memcpy (kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); 1775159d09a2SMark Phalan 1776159d09a2SMark Phalan memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); 1777159d09a2SMark Phalan free (tmp_key_data.key_data_contents[k]); 1778159d09a2SMark Phalan tmp_key_data.key_data_contents[k] = NULL; 1779159d09a2SMark Phalan } 1780159d09a2SMark Phalan } 1781159d09a2SMark Phalan 1782159d09a2SMark Phalan 1783159d09a2SMark Phalan 1784159d09a2SMark Phalan kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 1785159d09a2SMark Phalan 1786159d09a2SMark Phalan ret = krb5_timeofday(handle->context, &now); 1787159d09a2SMark Phalan if (ret) 1788159d09a2SMark Phalan goto done; 1789159d09a2SMark Phalan 1790159d09a2SMark Phalan if ((adb.aux_attributes & KADM5_POLICY)) { 1791159d09a2SMark Phalan if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 1792159d09a2SMark Phalan &pol)) != KADM5_OK) 1793159d09a2SMark Phalan goto done; 1794159d09a2SMark Phalan have_pol = 1; 1795159d09a2SMark Phalan 1796159d09a2SMark Phalan #if 0 1797159d09a2SMark Phalan /* 1798159d09a2SMark Phalan * The spec says this check is overridden if the caller has 1799159d09a2SMark Phalan * modify privilege. The admin server therefore makes this 1800159d09a2SMark Phalan * check itself (in chpass_principal_wrapper, misc.c). A 1801159d09a2SMark Phalan * local caller implicitly has all authorization bits. 1802159d09a2SMark Phalan */ 1803159d09a2SMark Phalan if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1804159d09a2SMark Phalan &kdb, &last_pwd)) 1805159d09a2SMark Phalan goto done; 1806159d09a2SMark Phalan if((now - last_pwd) < pol.pw_min_life && 1807159d09a2SMark Phalan !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 1808159d09a2SMark Phalan ret = KADM5_PASS_TOOSOON; 1809159d09a2SMark Phalan goto done; 1810159d09a2SMark Phalan } 1811159d09a2SMark Phalan #endif 1812159d09a2SMark Phalan #if 0 1813159d09a2SMark Phalan /* 1814159d09a2SMark Phalan * Should we be checking/updating pw history here? 1815159d09a2SMark Phalan */ 1816159d09a2SMark Phalan if(pol.pw_history_num > 1) { 1817159d09a2SMark Phalan if(adb.admin_history_kvno != hist_kvno) { 1818159d09a2SMark Phalan ret = KADM5_BAD_HIST_KEY; 1819159d09a2SMark Phalan goto done; 1820159d09a2SMark Phalan } 1821159d09a2SMark Phalan 1822159d09a2SMark Phalan if (ret = check_pw_reuse(handle->context, 1823159d09a2SMark Phalan &hist_key, 1824159d09a2SMark Phalan kdb.n_key_data, kdb.key_data, 1825159d09a2SMark Phalan adb.old_key_len, adb.old_keys)) 1826159d09a2SMark Phalan goto done; 1827159d09a2SMark Phalan } 1828159d09a2SMark Phalan #endif 1829159d09a2SMark Phalan 1830159d09a2SMark Phalan if (pol.pw_max_life) 1831159d09a2SMark Phalan kdb.pw_expiration = now + pol.pw_max_life; 1832159d09a2SMark Phalan else 1833159d09a2SMark Phalan kdb.pw_expiration = 0; 1834159d09a2SMark Phalan } else { 1835159d09a2SMark Phalan kdb.pw_expiration = 0; 1836159d09a2SMark Phalan } 1837159d09a2SMark Phalan 1838159d09a2SMark Phalan ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 1839159d09a2SMark Phalan if (ret) 1840159d09a2SMark Phalan goto done; 1841159d09a2SMark Phalan 1842159d09a2SMark Phalan if ((ret = kdb_put_entry(handle, &kdb, &adb))) 1843159d09a2SMark Phalan goto done; 1844159d09a2SMark Phalan 1845159d09a2SMark Phalan ret = KADM5_OK; 1846159d09a2SMark Phalan done: 1847159d09a2SMark Phalan for (i = 0; i < tmp_key_data.key_data_ver; i++) { 1848159d09a2SMark Phalan if (tmp_key_data.key_data_contents[i]) { 1849159d09a2SMark Phalan memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]); 1850159d09a2SMark Phalan free (tmp_key_data.key_data_contents[i]); 1851159d09a2SMark Phalan } 1852159d09a2SMark Phalan } 1853159d09a2SMark Phalan 1854159d09a2SMark Phalan kdb_free_entry(handle, &kdb, &adb); 1855159d09a2SMark Phalan if (have_pol) 1856159d09a2SMark Phalan kadm5_free_policy_ent(handle->lhandle, &pol); 1857159d09a2SMark Phalan 1858159d09a2SMark Phalan return ret; 1859159d09a2SMark Phalan } 1860159d09a2SMark Phalan #endif 1861159d09a2SMark Phalan 18627c478bd9Sstevel@tonic-gate kadm5_ret_t 18637c478bd9Sstevel@tonic-gate kadm5_setkey_principal(void *server_handle, 18647c478bd9Sstevel@tonic-gate krb5_principal principal, 18657c478bd9Sstevel@tonic-gate krb5_keyblock *keyblocks, 18667c478bd9Sstevel@tonic-gate int n_keys) 18677c478bd9Sstevel@tonic-gate { 186856a424ccSmp153739 return 186956a424ccSmp153739 kadm5_setkey_principal_3(server_handle, principal, 187056a424ccSmp153739 FALSE, 0, NULL, 187156a424ccSmp153739 keyblocks, n_keys); 18727c478bd9Sstevel@tonic-gate } 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate kadm5_ret_t 18757c478bd9Sstevel@tonic-gate kadm5_setkey_principal_3(void *server_handle, 18767c478bd9Sstevel@tonic-gate krb5_principal principal, 18777c478bd9Sstevel@tonic-gate krb5_boolean keepold, 18787c478bd9Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 18797c478bd9Sstevel@tonic-gate krb5_keyblock *keyblocks, 18807c478bd9Sstevel@tonic-gate int n_keys) 18817c478bd9Sstevel@tonic-gate { 18827c478bd9Sstevel@tonic-gate krb5_db_entry kdb; 18837c478bd9Sstevel@tonic-gate osa_princ_ent_rec adb; 18847c478bd9Sstevel@tonic-gate krb5_int32 now; 18857c478bd9Sstevel@tonic-gate kadm5_policy_ent_rec pol; 18867c478bd9Sstevel@tonic-gate krb5_key_data *old_key_data; 18877c478bd9Sstevel@tonic-gate int n_old_keys; 188854925bf6Swillf int i, j, k, kvno, ret, have_pol = 0; 188954925bf6Swillf #if 0 189054925bf6Swillf int last_pwd; 189154925bf6Swillf #endif 18927c478bd9Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 18937c478bd9Sstevel@tonic-gate krb5_boolean similar; 18947c478bd9Sstevel@tonic-gate krb5_keysalt keysalt; 189554925bf6Swillf krb5_key_data tmp_key_data; 189654925bf6Swillf krb5_key_data *tptr; 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate CHECK_HANDLE(server_handle); 18997c478bd9Sstevel@tonic-gate 190054925bf6Swillf krb5_clear_error_message(handle->context); 190154925bf6Swillf 19027c478bd9Sstevel@tonic-gate if (principal == NULL || keyblocks == NULL) 19037c478bd9Sstevel@tonic-gate return EINVAL; 19047c478bd9Sstevel@tonic-gate if (hist_princ && /* this will be NULL when initializing the databse */ 19057c478bd9Sstevel@tonic-gate ((krb5_principal_compare(handle->context, 19067c478bd9Sstevel@tonic-gate principal, hist_princ)) == TRUE)) 19077c478bd9Sstevel@tonic-gate return KADM5_PROTECT_PRINCIPAL; 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate for (i = 0; i < n_keys; i++) { 19107c478bd9Sstevel@tonic-gate for (j = i+1; j < n_keys; j++) { 191156a424ccSmp153739 if ((ret = krb5_c_enctype_compare(handle->context, 19127c478bd9Sstevel@tonic-gate keyblocks[i].enctype, 19137c478bd9Sstevel@tonic-gate keyblocks[j].enctype, 191456a424ccSmp153739 &similar))) 19157c478bd9Sstevel@tonic-gate return(ret); 191656a424ccSmp153739 if (similar) { 19177c478bd9Sstevel@tonic-gate if (n_ks_tuple) { 19187c478bd9Sstevel@tonic-gate if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype) 19197c478bd9Sstevel@tonic-gate return KADM5_SETKEY_DUP_ENCTYPES; 19207c478bd9Sstevel@tonic-gate } else 19217c478bd9Sstevel@tonic-gate return KADM5_SETKEY_DUP_ENCTYPES; 19227c478bd9Sstevel@tonic-gate } 19237c478bd9Sstevel@tonic-gate } 192456a424ccSmp153739 } 19257c478bd9Sstevel@tonic-gate 192656a424ccSmp153739 if (n_ks_tuple && n_ks_tuple != n_keys) 19277c478bd9Sstevel@tonic-gate return KADM5_SETKEY3_ETYPE_MISMATCH; 19287c478bd9Sstevel@tonic-gate 19297c478bd9Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 19307c478bd9Sstevel@tonic-gate return(ret); 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate for (kvno = 0, i=0; i<kdb.n_key_data; i++) 19337c478bd9Sstevel@tonic-gate if (kdb.key_data[i].key_data_kvno > kvno) 19347c478bd9Sstevel@tonic-gate kvno = kdb.key_data[i].key_data_kvno; 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate if (keepold) { 19377c478bd9Sstevel@tonic-gate old_key_data = kdb.key_data; 19387c478bd9Sstevel@tonic-gate n_old_keys = kdb.n_key_data; 19397c478bd9Sstevel@tonic-gate } else { 19407c478bd9Sstevel@tonic-gate if (kdb.key_data != NULL) 19417c478bd9Sstevel@tonic-gate cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 19427c478bd9Sstevel@tonic-gate n_old_keys = 0; 19437c478bd9Sstevel@tonic-gate old_key_data = NULL; 19447c478bd9Sstevel@tonic-gate } 19457c478bd9Sstevel@tonic-gate 194654925bf6Swillf kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys) 19477c478bd9Sstevel@tonic-gate *sizeof(krb5_key_data)); 194854925bf6Swillf if (kdb.key_data == NULL) { 194954925bf6Swillf ret = ENOMEM; 195054925bf6Swillf goto done; 195154925bf6Swillf } 195254925bf6Swillf 19537c478bd9Sstevel@tonic-gate memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data)); 19547c478bd9Sstevel@tonic-gate kdb.n_key_data = 0; 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gate for (i = 0; i < n_keys; i++) { 19577c478bd9Sstevel@tonic-gate if (n_ks_tuple) { 19587c478bd9Sstevel@tonic-gate keysalt.type = ks_tuple[i].ks_salttype; 19597c478bd9Sstevel@tonic-gate keysalt.data.length = 0; 19607c478bd9Sstevel@tonic-gate keysalt.data.data = NULL; 19617c478bd9Sstevel@tonic-gate if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) { 196254925bf6Swillf ret = KADM5_SETKEY3_ETYPE_MISMATCH; 196354925bf6Swillf goto done; 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate } 196654925bf6Swillf memset (&tmp_key_data, 0, sizeof(tmp_key_data)); 196754925bf6Swillf 19687c478bd9Sstevel@tonic-gate ret = krb5_dbekd_encrypt_key_data(handle->context, 19697c478bd9Sstevel@tonic-gate &handle->master_keyblock, 19707c478bd9Sstevel@tonic-gate &keyblocks[i], 19717c478bd9Sstevel@tonic-gate n_ks_tuple ? &keysalt : NULL, 19727c478bd9Sstevel@tonic-gate kvno + 1, 197354925bf6Swillf &tmp_key_data); 19747c478bd9Sstevel@tonic-gate if (ret) { 197554925bf6Swillf goto done; 197654925bf6Swillf } 197754925bf6Swillf tptr = &kdb.key_data[i]; 197854925bf6Swillf for (k = 0; k < tmp_key_data.key_data_ver; k++) { 197954925bf6Swillf tptr->key_data_type[k] = tmp_key_data.key_data_type[k]; 198054925bf6Swillf tptr->key_data_length[k] = tmp_key_data.key_data_length[k]; 198154925bf6Swillf if (tmp_key_data.key_data_contents[k]) { 198254925bf6Swillf tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]); 198354925bf6Swillf if (tptr->key_data_contents[k] == NULL) { 198454925bf6Swillf int i1; 198554925bf6Swillf for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) { 198654925bf6Swillf if (tmp_key_data.key_data_contents[i1]) { 198754925bf6Swillf memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]); 198854925bf6Swillf free (tmp_key_data.key_data_contents[i1]); 198954925bf6Swillf } 199054925bf6Swillf } 199154925bf6Swillf 199254925bf6Swillf ret = ENOMEM; 199354925bf6Swillf goto done; 199454925bf6Swillf } 199554925bf6Swillf memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); 199654925bf6Swillf 199754925bf6Swillf memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); 199854925bf6Swillf free (tmp_key_data.key_data_contents[k]); 199954925bf6Swillf tmp_key_data.key_data_contents[k] = NULL; 200054925bf6Swillf } 20017c478bd9Sstevel@tonic-gate } 20027c478bd9Sstevel@tonic-gate kdb.n_key_data++; 20037c478bd9Sstevel@tonic-gate } 20047c478bd9Sstevel@tonic-gate 20057c478bd9Sstevel@tonic-gate /* copy old key data if necessary */ 20067c478bd9Sstevel@tonic-gate for (i = 0; i < n_old_keys; i++) { 20077c478bd9Sstevel@tonic-gate kdb.key_data[i+n_keys] = old_key_data[i]; 20087c478bd9Sstevel@tonic-gate memset(&old_key_data[i], 0, sizeof (krb5_key_data)); 20097c478bd9Sstevel@tonic-gate kdb.n_key_data++; 20107c478bd9Sstevel@tonic-gate } 201154925bf6Swillf 201254925bf6Swillf if (old_key_data) 201354925bf6Swillf krb5_db_free(handle->context, old_key_data); 201454925bf6Swillf 20157c478bd9Sstevel@tonic-gate /* assert(kdb.n_key_data == n_keys + n_old_keys) */ 20167c478bd9Sstevel@tonic-gate kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 20177c478bd9Sstevel@tonic-gate 201856a424ccSmp153739 if ((ret = krb5_timeofday(handle->context, &now))) 20197c478bd9Sstevel@tonic-gate goto done; 20207c478bd9Sstevel@tonic-gate 20217c478bd9Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 20227c478bd9Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 20237c478bd9Sstevel@tonic-gate &pol)) != KADM5_OK) 20247c478bd9Sstevel@tonic-gate goto done; 20257c478bd9Sstevel@tonic-gate have_pol = 1; 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate #if 0 20287c478bd9Sstevel@tonic-gate /* 20297c478bd9Sstevel@tonic-gate * The spec says this check is overridden if the caller has 20307c478bd9Sstevel@tonic-gate * modify privilege. The admin server therefore makes this 20317c478bd9Sstevel@tonic-gate * check itself (in chpass_principal_wrapper, misc.c). A 20327c478bd9Sstevel@tonic-gate * local caller implicitly has all authorization bits. 20337c478bd9Sstevel@tonic-gate */ 20347c478bd9Sstevel@tonic-gate if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, 20357c478bd9Sstevel@tonic-gate &kdb, &last_pwd)) 20367c478bd9Sstevel@tonic-gate goto done; 20377c478bd9Sstevel@tonic-gate if((now - last_pwd) < pol.pw_min_life && 20387c478bd9Sstevel@tonic-gate !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 20397c478bd9Sstevel@tonic-gate ret = KADM5_PASS_TOOSOON; 20407c478bd9Sstevel@tonic-gate goto done; 20417c478bd9Sstevel@tonic-gate } 20427c478bd9Sstevel@tonic-gate #endif 20437c478bd9Sstevel@tonic-gate #if 0 20447c478bd9Sstevel@tonic-gate /* 20457c478bd9Sstevel@tonic-gate * Should we be checking/updating pw history here? 20467c478bd9Sstevel@tonic-gate */ 20477c478bd9Sstevel@tonic-gate if (pol.pw_history_num > 1) { 20487c478bd9Sstevel@tonic-gate if(adb.admin_history_kvno != hist_kvno) { 20497c478bd9Sstevel@tonic-gate ret = KADM5_BAD_HIST_KEY; 20507c478bd9Sstevel@tonic-gate goto done; 20517c478bd9Sstevel@tonic-gate } 20527c478bd9Sstevel@tonic-gate 20537c478bd9Sstevel@tonic-gate if (ret = check_pw_reuse(handle->context, 20547c478bd9Sstevel@tonic-gate &handle->master_keyblock, 20557c478bd9Sstevel@tonic-gate &hist_key, 20567c478bd9Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 20577c478bd9Sstevel@tonic-gate adb.old_key_len, adb.old_keys)) 20587c478bd9Sstevel@tonic-gate goto done; 20597c478bd9Sstevel@tonic-gate } 20607c478bd9Sstevel@tonic-gate #endif 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate if (pol.pw_max_life) 20637c478bd9Sstevel@tonic-gate kdb.pw_expiration = now + pol.pw_max_life; 20647c478bd9Sstevel@tonic-gate else 20657c478bd9Sstevel@tonic-gate kdb.pw_expiration = 0; 20667c478bd9Sstevel@tonic-gate } else { 20677c478bd9Sstevel@tonic-gate kdb.pw_expiration = 0; 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate 207056a424ccSmp153739 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) 20717c478bd9Sstevel@tonic-gate goto done; 20727c478bd9Sstevel@tonic-gate 20737c478bd9Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 20747c478bd9Sstevel@tonic-gate goto done; 20757c478bd9Sstevel@tonic-gate 20767c478bd9Sstevel@tonic-gate ret = KADM5_OK; 20777c478bd9Sstevel@tonic-gate done: 20787c478bd9Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 20797c478bd9Sstevel@tonic-gate if (have_pol) 20807c478bd9Sstevel@tonic-gate kadm5_free_policy_ent(handle->lhandle, &pol); 20817c478bd9Sstevel@tonic-gate 20827c478bd9Sstevel@tonic-gate return ret; 20837c478bd9Sstevel@tonic-gate } 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate /* 20867c478bd9Sstevel@tonic-gate * Allocate an array of n_key_data krb5_keyblocks, fill in each 20877c478bd9Sstevel@tonic-gate * element with the results of decrypting the nth key in key_data with 20887c478bd9Sstevel@tonic-gate * master_keyblock, and if n_keys is not NULL fill it in with the 20897c478bd9Sstevel@tonic-gate * number of keys decrypted. 20907c478bd9Sstevel@tonic-gate */ 20917c478bd9Sstevel@tonic-gate static int decrypt_key_data(krb5_context context, 20927c478bd9Sstevel@tonic-gate krb5_keyblock *master_keyblock, 20937c478bd9Sstevel@tonic-gate int n_key_data, krb5_key_data *key_data, 20947c478bd9Sstevel@tonic-gate krb5_keyblock **keyblocks, int *n_keys) 20957c478bd9Sstevel@tonic-gate { 20967c478bd9Sstevel@tonic-gate krb5_keyblock *keys; 20977c478bd9Sstevel@tonic-gate int ret, i; 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock)); 21007c478bd9Sstevel@tonic-gate if (keys == NULL) 21017c478bd9Sstevel@tonic-gate return ENOMEM; 21027c478bd9Sstevel@tonic-gate memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate for (i = 0; i < n_key_data; i++) { 210556a424ccSmp153739 ret = krb5_dbekd_decrypt_key_data(context, 210656a424ccSmp153739 master_keyblock, 210756a424ccSmp153739 &key_data[i], 210856a424ccSmp153739 &keys[i], NULL); 210956a424ccSmp153739 if (ret) { 211054925bf6Swillf for (; i >= 0; i--) { 211154925bf6Swillf if (keys[i].contents) { 211254925bf6Swillf memset (keys[i].contents, 0, keys[i].length); 211354925bf6Swillf free( keys[i].contents ); 211454925bf6Swillf } 211554925bf6Swillf } 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); 21187c478bd9Sstevel@tonic-gate free(keys); 21197c478bd9Sstevel@tonic-gate return ret; 21207c478bd9Sstevel@tonic-gate } 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate *keyblocks = keys; 21247c478bd9Sstevel@tonic-gate if (n_keys) 21257c478bd9Sstevel@tonic-gate *n_keys = n_key_data; 21267c478bd9Sstevel@tonic-gate 21277c478bd9Sstevel@tonic-gate return 0; 21287c478bd9Sstevel@tonic-gate } 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate /* 21317c478bd9Sstevel@tonic-gate * Function: kadm5_decrypt_key 21327c478bd9Sstevel@tonic-gate * 21337c478bd9Sstevel@tonic-gate * Purpose: Retrieves and decrypts a principal key. 21347c478bd9Sstevel@tonic-gate * 21357c478bd9Sstevel@tonic-gate * Arguments: 21367c478bd9Sstevel@tonic-gate * 21377c478bd9Sstevel@tonic-gate * server_handle (r) kadm5 handle 21387c478bd9Sstevel@tonic-gate * entry (r) principal retrieved with kadm5_get_principal 21397c478bd9Sstevel@tonic-gate * ktype (r) enctype to search for, or -1 to ignore 21407c478bd9Sstevel@tonic-gate * stype (r) salt type to search for, or -1 to ignore 21417c478bd9Sstevel@tonic-gate * kvno (r) kvno to search for, -1 for max, 0 for max 21427c478bd9Sstevel@tonic-gate * only if it also matches ktype and stype 21437c478bd9Sstevel@tonic-gate * keyblock (w) keyblock to fill in 21447c478bd9Sstevel@tonic-gate * keysalt (w) keysalt to fill in, or NULL 21457c478bd9Sstevel@tonic-gate * kvnop (w) kvno to fill in, or NULL 21467c478bd9Sstevel@tonic-gate * 21477c478bd9Sstevel@tonic-gate * Effects: Searches the key_data array of entry, which must have been 21487c478bd9Sstevel@tonic-gate * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to 21497c478bd9Sstevel@tonic-gate * find a key with a specified enctype, salt type, and kvno in a 21507c478bd9Sstevel@tonic-gate * principal entry. If not found, return ENOENT. Otherwise, decrypt 21517c478bd9Sstevel@tonic-gate * it with the master key, and return the key in keyblock, the salt 21527c478bd9Sstevel@tonic-gate * in salttype, and the key version number in kvno. 21537c478bd9Sstevel@tonic-gate * 21547c478bd9Sstevel@tonic-gate * If ktype or stype is -1, it is ignored for the search. If kvno is 21557c478bd9Sstevel@tonic-gate * -1, ktype and stype are ignored and the key with the max kvno is 21567c478bd9Sstevel@tonic-gate * returned. If kvno is 0, only the key with the max kvno is returned 21577c478bd9Sstevel@tonic-gate * and only if it matches the ktype and stype; otherwise, ENOENT is 21587c478bd9Sstevel@tonic-gate * returned. 21597c478bd9Sstevel@tonic-gate */ 21607c478bd9Sstevel@tonic-gate kadm5_ret_t kadm5_decrypt_key(void *server_handle, 21617c478bd9Sstevel@tonic-gate kadm5_principal_ent_t entry, krb5_int32 21627c478bd9Sstevel@tonic-gate ktype, krb5_int32 stype, krb5_int32 21637c478bd9Sstevel@tonic-gate kvno, krb5_keyblock *keyblock, 21647c478bd9Sstevel@tonic-gate krb5_keysalt *keysalt, int *kvnop) 21657c478bd9Sstevel@tonic-gate { 21667c478bd9Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 21677c478bd9Sstevel@tonic-gate krb5_db_entry dbent; 21687c478bd9Sstevel@tonic-gate krb5_key_data *key_data; 21697c478bd9Sstevel@tonic-gate int ret; 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate CHECK_HANDLE(server_handle); 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate if (entry->n_key_data == 0 || entry->key_data == NULL) 21747c478bd9Sstevel@tonic-gate return EINVAL; 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate /* find_enctype only uses these two fields */ 21777c478bd9Sstevel@tonic-gate dbent.n_key_data = entry->n_key_data; 21787c478bd9Sstevel@tonic-gate dbent.key_data = entry->key_data; 217956a424ccSmp153739 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype, 218056a424ccSmp153739 stype, kvno, &key_data))) 21817c478bd9Sstevel@tonic-gate return ret; 21827c478bd9Sstevel@tonic-gate 218356a424ccSmp153739 if ((ret = krb5_dbekd_decrypt_key_data(handle->context, 21847c478bd9Sstevel@tonic-gate &handle->master_keyblock, key_data, 218556a424ccSmp153739 keyblock, keysalt))) 21867c478bd9Sstevel@tonic-gate return ret; 21877c478bd9Sstevel@tonic-gate 2188159d09a2SMark Phalan /* 2189159d09a2SMark Phalan * Coerce the enctype of the output keyblock in case we got an 2190159d09a2SMark Phalan * inexact match on the enctype; this behavior will go away when 2191159d09a2SMark Phalan * the key storage architecture gets redesigned for 1.3. 2192159d09a2SMark Phalan */ 2193159d09a2SMark Phalan keyblock->enctype = ktype; 2194159d09a2SMark Phalan 21957c478bd9Sstevel@tonic-gate if (kvnop) 21967c478bd9Sstevel@tonic-gate *kvnop = key_data->key_data_kvno; 21977c478bd9Sstevel@tonic-gate 21987c478bd9Sstevel@tonic-gate return KADM5_OK; 21997c478bd9Sstevel@tonic-gate } 220054925bf6Swillf 2201*661b8ac7SPeter Shoults /* Solaris Kerberos */ 2202*661b8ac7SPeter Shoults kadm5_ret_t 2203*661b8ac7SPeter Shoults kadm5_check_min_life(void *server_handle, krb5_principal principal, 2204*661b8ac7SPeter Shoults char *msg_ret, unsigned int msg_len) 2205*661b8ac7SPeter Shoults { 2206*661b8ac7SPeter Shoults krb5_int32 now; 2207*661b8ac7SPeter Shoults kadm5_ret_t ret; 2208*661b8ac7SPeter Shoults kadm5_policy_ent_rec pol; 2209*661b8ac7SPeter Shoults kadm5_principal_ent_rec princ; 2210*661b8ac7SPeter Shoults kadm5_server_handle_t handle = server_handle; 2211*661b8ac7SPeter Shoults 2212*661b8ac7SPeter Shoults if (msg_ret != NULL) 2213*661b8ac7SPeter Shoults *msg_ret = '\0'; 2214*661b8ac7SPeter Shoults 2215*661b8ac7SPeter Shoults ret = krb5_timeofday(handle->context, &now); 2216*661b8ac7SPeter Shoults if (ret) 2217*661b8ac7SPeter Shoults return ret; 2218*661b8ac7SPeter Shoults 2219*661b8ac7SPeter Shoults ret = kadm5_get_principal(handle->lhandle, principal, 2220*661b8ac7SPeter Shoults &princ, KADM5_PRINCIPAL_NORMAL_MASK); 2221*661b8ac7SPeter Shoults if(ret) 2222*661b8ac7SPeter Shoults return ret; 2223*661b8ac7SPeter Shoults if(princ.aux_attributes & KADM5_POLICY) { 2224*661b8ac7SPeter Shoults if((ret=kadm5_get_policy(handle->lhandle, 2225*661b8ac7SPeter Shoults princ.policy, &pol)) != KADM5_OK) { 2226*661b8ac7SPeter Shoults (void) kadm5_free_principal_ent(handle->lhandle, &princ); 2227*661b8ac7SPeter Shoults return ret; 2228*661b8ac7SPeter Shoults } 2229*661b8ac7SPeter Shoults if((now - princ.last_pwd_change) < pol.pw_min_life && 2230*661b8ac7SPeter Shoults !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 2231*661b8ac7SPeter Shoults if (msg_ret != NULL) { 2232*661b8ac7SPeter Shoults time_t until; 2233*661b8ac7SPeter Shoults char *time_string, *ptr, *errstr; 2234*661b8ac7SPeter Shoults 2235*661b8ac7SPeter Shoults until = princ.last_pwd_change + pol.pw_min_life; 2236*661b8ac7SPeter Shoults 2237*661b8ac7SPeter Shoults time_string = ctime(&until); 2238*661b8ac7SPeter Shoults errstr = (char *)error_message(CHPASS_UTIL_PASSWORD_TOO_SOON); 2239*661b8ac7SPeter Shoults 2240*661b8ac7SPeter Shoults if (strlen(errstr) + strlen(time_string) >= msg_len) { 2241*661b8ac7SPeter Shoults *errstr = '\0'; 2242*661b8ac7SPeter Shoults } else { 2243*661b8ac7SPeter Shoults if (*(ptr = &time_string[strlen(time_string)-1]) == '\n') 2244*661b8ac7SPeter Shoults *ptr = '\0'; 2245*661b8ac7SPeter Shoults sprintf(msg_ret, errstr, time_string); 2246*661b8ac7SPeter Shoults } 2247*661b8ac7SPeter Shoults } 2248*661b8ac7SPeter Shoults 2249*661b8ac7SPeter Shoults (void) kadm5_free_policy_ent(handle->lhandle, &pol); 2250*661b8ac7SPeter Shoults (void) kadm5_free_principal_ent(handle->lhandle, &princ); 2251*661b8ac7SPeter Shoults return KADM5_PASS_TOOSOON; 2252*661b8ac7SPeter Shoults } 2253*661b8ac7SPeter Shoults 2254*661b8ac7SPeter Shoults ret = kadm5_free_policy_ent(handle->lhandle, &pol); 2255*661b8ac7SPeter Shoults if (ret) { 2256*661b8ac7SPeter Shoults (void) kadm5_free_principal_ent(handle->lhandle, &princ); 2257*661b8ac7SPeter Shoults return ret; 2258*661b8ac7SPeter Shoults } 2259*661b8ac7SPeter Shoults } 2260*661b8ac7SPeter Shoults 2261*661b8ac7SPeter Shoults return kadm5_free_principal_ent(handle->lhandle, &princ); 2262*661b8ac7SPeter Shoults } 2263