10Sstevel@tonic-gate /* 2*2881Smp153739 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 70Sstevel@tonic-gate 80Sstevel@tonic-gate /* 90Sstevel@tonic-gate * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 100Sstevel@tonic-gate * 110Sstevel@tonic-gate * Openvision retains the copyright to derivative works of 120Sstevel@tonic-gate * this source code. Do *NOT* create a derivative of this 130Sstevel@tonic-gate * source code before consulting with your legal department. 140Sstevel@tonic-gate * Do *NOT* integrate *ANY* of this source code into another 150Sstevel@tonic-gate * product before consulting with your legal department. 160Sstevel@tonic-gate * 170Sstevel@tonic-gate * For further information, read the top-level Openvision 180Sstevel@tonic-gate * copyright which is contained in the top-level MIT Kerberos 190Sstevel@tonic-gate * copyright. 200Sstevel@tonic-gate * 210Sstevel@tonic-gate * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 220Sstevel@tonic-gate * 230Sstevel@tonic-gate */ 240Sstevel@tonic-gate 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 280Sstevel@tonic-gate * 29*2881Smp153739 * $Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/svr_principal.c,v 1.30.8.1 2004/12/20 21:16:20 tlyu Exp $ 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #if !defined(lint) && !defined(__CODECENTER__) 33*2881Smp153739 static char *rcsid = "$Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/svr_principal.c,v 1.30.8.1 2004/12/20 21:16:20 tlyu Exp $"; 340Sstevel@tonic-gate #endif 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include <sys/types.h> 370Sstevel@tonic-gate #include <sys/time.h> 380Sstevel@tonic-gate #include <kadm5/admin.h> 390Sstevel@tonic-gate #include "adb.h" 400Sstevel@tonic-gate #include "k5-int.h" 410Sstevel@tonic-gate #include <krb5/kdb.h> 420Sstevel@tonic-gate #include <stdio.h> 430Sstevel@tonic-gate #include <string.h> 440Sstevel@tonic-gate #include "server_internal.h" 450Sstevel@tonic-gate #include <stdarg.h> 460Sstevel@tonic-gate #include <stdlib.h> 47*2881Smp153739 #ifdef USE_PASSWORD_SERVER 48*2881Smp153739 #include <sys/wait.h> 49*2881Smp153739 #endif 500Sstevel@tonic-gate 510Sstevel@tonic-gate extern krb5_principal master_princ; 520Sstevel@tonic-gate extern krb5_principal hist_princ; 530Sstevel@tonic-gate extern krb5_keyblock hist_key; 540Sstevel@tonic-gate extern krb5_db_entry master_db; 550Sstevel@tonic-gate extern krb5_db_entry hist_db; 560Sstevel@tonic-gate extern krb5_kvno hist_kvno; 570Sstevel@tonic-gate 580Sstevel@tonic-gate extern kadm5_ret_t 590Sstevel@tonic-gate krb5_free_key_data_contents(krb5_context context, krb5_key_data *key); 600Sstevel@tonic-gate 610Sstevel@tonic-gate static int decrypt_key_data(krb5_context context, 62*2881Smp153739 krb5_keyblock *, int n_key_data, krb5_key_data *key_data, 63*2881Smp153739 krb5_keyblock **keyblocks, int *n_keys); 640Sstevel@tonic-gate 650Sstevel@tonic-gate /* 660Sstevel@tonic-gate * XXX Functions that ought to be in libkrb5.a, but aren't. 670Sstevel@tonic-gate */ 680Sstevel@tonic-gate kadm5_ret_t krb5_copy_key_data_contents(context, from, to) 690Sstevel@tonic-gate krb5_context context; 700Sstevel@tonic-gate krb5_key_data *from, *to; 710Sstevel@tonic-gate { 720Sstevel@tonic-gate int i, idx; 730Sstevel@tonic-gate 740Sstevel@tonic-gate *to = *from; 750Sstevel@tonic-gate 760Sstevel@tonic-gate idx = (from->key_data_ver == 1 ? 1 : 2); 770Sstevel@tonic-gate 780Sstevel@tonic-gate for (i = 0; i < idx; i++) { 790Sstevel@tonic-gate if ( from->key_data_length[i] ) { 800Sstevel@tonic-gate to->key_data_contents[i] = malloc(from->key_data_length[i]); 810Sstevel@tonic-gate if (to->key_data_contents[i] == NULL) { 820Sstevel@tonic-gate for (i = 0; i < idx; i++) { 830Sstevel@tonic-gate if (to->key_data_contents[i]) { 840Sstevel@tonic-gate memset(to->key_data_contents[i], 0, 850Sstevel@tonic-gate to->key_data_length[i]); 860Sstevel@tonic-gate free(to->key_data_contents[i]); 870Sstevel@tonic-gate } 880Sstevel@tonic-gate } 890Sstevel@tonic-gate return ENOMEM; 900Sstevel@tonic-gate } 910Sstevel@tonic-gate memcpy(to->key_data_contents[i], from->key_data_contents[i], 920Sstevel@tonic-gate from->key_data_length[i]); 930Sstevel@tonic-gate } 940Sstevel@tonic-gate } 950Sstevel@tonic-gate return 0; 960Sstevel@tonic-gate } 970Sstevel@tonic-gate 980Sstevel@tonic-gate static krb5_tl_data *dup_tl_data(krb5_tl_data *tl) 990Sstevel@tonic-gate { 1000Sstevel@tonic-gate krb5_tl_data *n; 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)); 1030Sstevel@tonic-gate if (n == NULL) 1040Sstevel@tonic-gate return NULL; 1050Sstevel@tonic-gate n->tl_data_contents = malloc(tl->tl_data_length); 1060Sstevel@tonic-gate if (n->tl_data_contents == NULL) { 1070Sstevel@tonic-gate free(n); 1080Sstevel@tonic-gate return NULL; 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length); 1110Sstevel@tonic-gate n->tl_data_type = tl->tl_data_type; 1120Sstevel@tonic-gate n->tl_data_length = tl->tl_data_length; 1130Sstevel@tonic-gate n->tl_data_next = NULL; 1140Sstevel@tonic-gate return n; 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate /* This is in lib/kdb/kdb_cpw.c, but is static */ 1180Sstevel@tonic-gate static void cleanup_key_data(context, count, data) 1190Sstevel@tonic-gate krb5_context context; 1200Sstevel@tonic-gate int count; 1210Sstevel@tonic-gate krb5_key_data * data; 1220Sstevel@tonic-gate { 1230Sstevel@tonic-gate int i, j; 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate for (i = 0; i < count; i++) 1260Sstevel@tonic-gate for (j = 0; j < data[i].key_data_ver; j++) 1270Sstevel@tonic-gate if (data[i].key_data_length[j]) 1280Sstevel@tonic-gate free(data[i].key_data_contents[j]); 1290Sstevel@tonic-gate free(data); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate kadm5_ret_t 1330Sstevel@tonic-gate kadm5_create_principal(void *server_handle, 1340Sstevel@tonic-gate kadm5_principal_ent_t entry, long mask, 1350Sstevel@tonic-gate char *password) 1360Sstevel@tonic-gate { 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * Default to using the new API with the default set of 1390Sstevel@tonic-gate * key/salt combinations. 1400Sstevel@tonic-gate */ 141*2881Smp153739 return 142*2881Smp153739 kadm5_create_principal_3(server_handle, entry, mask, 143*2881Smp153739 0, NULL, password); 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate kadm5_ret_t 1460Sstevel@tonic-gate kadm5_create_principal_3(void *server_handle, 1470Sstevel@tonic-gate kadm5_principal_ent_t entry, long mask, 1480Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 1490Sstevel@tonic-gate char *password) 1500Sstevel@tonic-gate { 1510Sstevel@tonic-gate krb5_db_entry kdb; 1520Sstevel@tonic-gate osa_princ_ent_rec adb; 1530Sstevel@tonic-gate kadm5_policy_ent_rec polent; 1540Sstevel@tonic-gate krb5_int32 now; 1550Sstevel@tonic-gate krb5_tl_data *tl_data_orig, *tl_data_tail; 1560Sstevel@tonic-gate unsigned int ret; 1570Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate CHECK_HANDLE(server_handle); 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1620Sstevel@tonic-gate * Argument sanity checking, and opening up the DB 1630Sstevel@tonic-gate */ 1640Sstevel@tonic-gate if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) || 1650Sstevel@tonic-gate (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) || 1660Sstevel@tonic-gate (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) || 1670Sstevel@tonic-gate (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) || 1680Sstevel@tonic-gate (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) || 1690Sstevel@tonic-gate (mask & KADM5_FAIL_AUTH_COUNT)) 1700Sstevel@tonic-gate return KADM5_BAD_MASK; 1710Sstevel@tonic-gate if((mask & ~ALL_PRINC_MASK)) 1720Sstevel@tonic-gate return KADM5_BAD_MASK; 1730Sstevel@tonic-gate if (entry == (kadm5_principal_ent_t) NULL || password == NULL) 1740Sstevel@tonic-gate return EINVAL; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate /* 1770Sstevel@tonic-gate * Check to see if the principal exists 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate switch(ret) { 1820Sstevel@tonic-gate case KADM5_UNK_PRINC: 1830Sstevel@tonic-gate break; 1840Sstevel@tonic-gate case 0: 1850Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 1860Sstevel@tonic-gate return KADM5_DUP; 1870Sstevel@tonic-gate default: 1880Sstevel@tonic-gate return ret; 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate memset(&kdb, 0, sizeof(krb5_db_entry)); 1920Sstevel@tonic-gate memset(&adb, 0, sizeof(osa_princ_ent_rec)); 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * If a policy was specified, load it. 1960Sstevel@tonic-gate * If we can not find the one specified return an error 1970Sstevel@tonic-gate */ 1980Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 1990Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, entry->policy, 2000Sstevel@tonic-gate &polent)) != KADM5_OK) { 2010Sstevel@tonic-gate if(ret == EINVAL) 2020Sstevel@tonic-gate return KADM5_BAD_POLICY; 2030Sstevel@tonic-gate else 2040Sstevel@tonic-gate return ret; 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate } 207*2881Smp153739 if ((ret = passwd_check(handle, password, (mask & KADM5_POLICY), 208*2881Smp153739 &polent, entry->principal))) { 2090Sstevel@tonic-gate if (mask & KADM5_POLICY) 2100Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 2110Sstevel@tonic-gate return ret; 2120Sstevel@tonic-gate } 2130Sstevel@tonic-gate /* 2140Sstevel@tonic-gate * Start populating the various DB fields, using the 2150Sstevel@tonic-gate * "defaults" for fields that were not specified by the 2160Sstevel@tonic-gate * mask. 2170Sstevel@tonic-gate */ 218*2881Smp153739 if ((ret = krb5_timeofday(handle->context, &now))) { 219*2881Smp153739 if (mask & KADM5_POLICY) 220*2881Smp153739 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 221*2881Smp153739 return ret; 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate kdb.magic = KRB5_KDB_MAGIC_NUMBER; 2250Sstevel@tonic-gate kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */ 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate /* 2280Sstevel@tonic-gate * If KADM5_ATTRIBUTES is set, we want to rope in not only 2290Sstevel@tonic-gate * entry->attributes, but also the generic params.flags 2300Sstevel@tonic-gate * obtained previously via kadm5_get_config_params. 2310Sstevel@tonic-gate */ 2320Sstevel@tonic-gate if ((mask & KADM5_ATTRIBUTES)) { 2330Sstevel@tonic-gate kdb.attributes = handle->params.flags; 2340Sstevel@tonic-gate kdb.attributes |= entry->attributes; 2350Sstevel@tonic-gate } else { 236*2881Smp153739 kdb.attributes = handle->params.flags; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate if ((mask & KADM5_MAX_LIFE)) 2400Sstevel@tonic-gate kdb.max_life = entry->max_life; 2410Sstevel@tonic-gate else 2420Sstevel@tonic-gate kdb.max_life = handle->params.max_life; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate if (mask & KADM5_MAX_RLIFE) 2450Sstevel@tonic-gate kdb.max_renewable_life = entry->max_renewable_life; 2460Sstevel@tonic-gate else 2470Sstevel@tonic-gate kdb.max_renewable_life = handle->params.max_rlife; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if ((mask & KADM5_PRINC_EXPIRE_TIME)) 2500Sstevel@tonic-gate kdb.expiration = entry->princ_expire_time; 2510Sstevel@tonic-gate else 2520Sstevel@tonic-gate kdb.expiration = handle->params.expiration; 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate kdb.pw_expiration = 0; 2550Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 2560Sstevel@tonic-gate if(polent.pw_max_life) 2570Sstevel@tonic-gate kdb.pw_expiration = now + polent.pw_max_life; 2580Sstevel@tonic-gate else 2590Sstevel@tonic-gate kdb.pw_expiration = 0; 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate if ((mask & KADM5_PW_EXPIRATION)) 2620Sstevel@tonic-gate kdb.pw_expiration = entry->pw_expiration; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate kdb.last_success = 0; 2650Sstevel@tonic-gate kdb.last_failed = 0; 2660Sstevel@tonic-gate kdb.fail_auth_count = 0; 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate /* this is kind of gross, but in order to free the tl data, I need 2690Sstevel@tonic-gate to free the entire kdb entry, and that will try to free the 2700Sstevel@tonic-gate principal. */ 2710Sstevel@tonic-gate 272*2881Smp153739 if ((ret = krb5_copy_principal(handle->context, 273*2881Smp153739 entry->principal, &(kdb.princ)))) { 2740Sstevel@tonic-gate if (mask & KADM5_POLICY) 2750Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 2760Sstevel@tonic-gate return(ret); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 279*2881Smp153739 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) { 280*2881Smp153739 krb5_dbe_free_contents(handle->context, &kdb); 281*2881Smp153739 if (mask & KADM5_POLICY) 2820Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 283*2881Smp153739 return(ret); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate /* initialize the keys */ 2870Sstevel@tonic-gate 288*2881Smp153739 if ((ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, 289*2881Smp153739 n_ks_tuple?ks_tuple:handle->params.keysalts, 290*2881Smp153739 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 291*2881Smp153739 password, 292*2881Smp153739 (mask & KADM5_KVNO)?entry->kvno:1, 293*2881Smp153739 FALSE, &kdb))) { 2940Sstevel@tonic-gate krb5_dbe_free_contents(handle->context, &kdb); 2950Sstevel@tonic-gate if (mask & KADM5_POLICY) 2960Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 2970Sstevel@tonic-gate return(ret); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* populate the admin-server-specific fields. In the OV server, 3010Sstevel@tonic-gate this used to be in a separate database. Since there's already 3020Sstevel@tonic-gate marshalling code for the admin fields, to keep things simple, 3030Sstevel@tonic-gate I'm going to keep it, and make all the admin stuff occupy a 3040Sstevel@tonic-gate single tl_data record, */ 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate adb.admin_history_kvno = hist_kvno; 3070Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 3080Sstevel@tonic-gate adb.aux_attributes = KADM5_POLICY; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate /* this does *not* need to be strdup'ed, because adb is xdr */ 3110Sstevel@tonic-gate /* encoded in osa_adb_create_princ, and not ever freed */ 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate adb.policy = entry->policy; 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate /* increment the policy ref count, if any */ 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 3190Sstevel@tonic-gate polent.policy_refcnt++; 3200Sstevel@tonic-gate if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, 3210Sstevel@tonic-gate KADM5_REF_COUNT)) 3220Sstevel@tonic-gate != KADM5_OK) { 3230Sstevel@tonic-gate krb5_dbe_free_contents(handle->context, &kdb); 3240Sstevel@tonic-gate if (mask & KADM5_POLICY) 3250Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 3260Sstevel@tonic-gate return(ret); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 3310Sstevel@tonic-gate /* splice entry->tl_data onto the front of kdb.tl_data */ 3320Sstevel@tonic-gate tl_data_orig = kdb.tl_data; 3330Sstevel@tonic-gate for (tl_data_tail = entry->tl_data; tl_data_tail->tl_data_next; 3340Sstevel@tonic-gate tl_data_tail = tl_data_tail->tl_data_next) 3350Sstevel@tonic-gate ; 3360Sstevel@tonic-gate tl_data_tail->tl_data_next = kdb.tl_data; 3370Sstevel@tonic-gate kdb.tl_data = entry->tl_data; 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate /* store the new db entry */ 3410Sstevel@tonic-gate ret = kdb_put_entry(handle, &kdb, &adb); 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 3440Sstevel@tonic-gate /* remove entry->tl_data from the front of kdb.tl_data */ 3450Sstevel@tonic-gate tl_data_tail->tl_data_next = NULL; 3460Sstevel@tonic-gate kdb.tl_data = tl_data_orig; 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate krb5_dbe_free_contents(handle->context, &kdb); 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate if (ret) { 3520Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 3530Sstevel@tonic-gate /* decrement the policy ref count */ 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate polent.policy_refcnt--; 3560Sstevel@tonic-gate /* 3570Sstevel@tonic-gate * if this fails, there's nothing we can do anyway. the 3580Sstevel@tonic-gate * policy refcount wil be too high. 3590Sstevel@tonic-gate */ 3600Sstevel@tonic-gate (void) kadm5_modify_policy_internal(handle->lhandle, &polent, 3610Sstevel@tonic-gate KADM5_REF_COUNT); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate if (mask & KADM5_POLICY) 3650Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 3660Sstevel@tonic-gate return(ret); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate if (mask & KADM5_POLICY) 3700Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate return KADM5_OK; 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate kadm5_ret_t 3770Sstevel@tonic-gate kadm5_delete_principal(void *server_handle, krb5_principal principal) 3780Sstevel@tonic-gate { 3790Sstevel@tonic-gate unsigned int ret; 3800Sstevel@tonic-gate kadm5_policy_ent_rec polent; 3810Sstevel@tonic-gate krb5_db_entry kdb; 3820Sstevel@tonic-gate osa_princ_ent_rec adb; 3830Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate CHECK_HANDLE(server_handle); 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate if (principal == NULL) 3880Sstevel@tonic-gate return EINVAL; 3890Sstevel@tonic-gate 390*2881Smp153739 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 3910Sstevel@tonic-gate return(ret); 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 3940Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, 3950Sstevel@tonic-gate adb.policy, &polent)) 3960Sstevel@tonic-gate == KADM5_OK) { 3970Sstevel@tonic-gate polent.policy_refcnt--; 3980Sstevel@tonic-gate if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, 3990Sstevel@tonic-gate KADM5_REF_COUNT)) 4000Sstevel@tonic-gate != KADM5_OK) { 4010Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 4020Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 4030Sstevel@tonic-gate return(ret); 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate } 406*2881Smp153739 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) { 407*2881Smp153739 kdb_free_entry(handle, &kdb, &adb); 408*2881Smp153739 return ret; 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate ret = kdb_delete_entry(handle, principal); 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate return ret; 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate kadm5_ret_t 4200Sstevel@tonic-gate kadm5_modify_principal(void *server_handle, 4210Sstevel@tonic-gate kadm5_principal_ent_t entry, long mask) 4220Sstevel@tonic-gate { 4230Sstevel@tonic-gate int ret, ret2, i; 4240Sstevel@tonic-gate kadm5_policy_ent_rec npol, opol; 4250Sstevel@tonic-gate int have_npol = 0, have_opol = 0; 4260Sstevel@tonic-gate krb5_db_entry kdb; 427*2881Smp153739 krb5_tl_data *tl_data_orig; 4280Sstevel@tonic-gate osa_princ_ent_rec adb; 4290Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate CHECK_HANDLE(server_handle); 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) || 4340Sstevel@tonic-gate (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) || 4350Sstevel@tonic-gate (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) || 4360Sstevel@tonic-gate (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) || 4370Sstevel@tonic-gate (mask & KADM5_LAST_FAILED)) 4380Sstevel@tonic-gate return KADM5_BAD_MASK; 4390Sstevel@tonic-gate if((mask & ~ALL_PRINC_MASK)) 4400Sstevel@tonic-gate return KADM5_BAD_MASK; 4410Sstevel@tonic-gate if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR)) 4420Sstevel@tonic-gate return KADM5_BAD_MASK; 4430Sstevel@tonic-gate if(entry == (kadm5_principal_ent_t) NULL) 4440Sstevel@tonic-gate return EINVAL; 4450Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 4460Sstevel@tonic-gate tl_data_orig = entry->tl_data; 4470Sstevel@tonic-gate while (tl_data_orig) { 4480Sstevel@tonic-gate if (tl_data_orig->tl_data_type < 256) 4490Sstevel@tonic-gate return KADM5_BAD_TL_TYPE; 4500Sstevel@tonic-gate tl_data_orig = tl_data_orig->tl_data_next; 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 454*2881Smp153739 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); 455*2881Smp153739 if (ret) 4560Sstevel@tonic-gate return(ret); 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate /* 4590Sstevel@tonic-gate * This is pretty much the same as create ... 4600Sstevel@tonic-gate */ 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 4630Sstevel@tonic-gate /* get the new policy */ 4640Sstevel@tonic-gate ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol); 4650Sstevel@tonic-gate if (ret) { 4660Sstevel@tonic-gate switch (ret) { 4670Sstevel@tonic-gate case EINVAL: 4680Sstevel@tonic-gate ret = KADM5_BAD_POLICY; 4690Sstevel@tonic-gate break; 4700Sstevel@tonic-gate case KADM5_UNK_POLICY: 4710Sstevel@tonic-gate case KADM5_BAD_POLICY: 4720Sstevel@tonic-gate ret = KADM5_UNK_POLICY; 4730Sstevel@tonic-gate break; 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate goto done; 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate have_npol = 1; 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate /* if we already have a policy, get it to decrement the refcnt */ 4800Sstevel@tonic-gate if(adb.aux_attributes & KADM5_POLICY) { 4810Sstevel@tonic-gate /* ... but not if the old and new are the same */ 4820Sstevel@tonic-gate if(strcmp(adb.policy, entry->policy)) { 4830Sstevel@tonic-gate ret = kadm5_get_policy(handle->lhandle, 4840Sstevel@tonic-gate adb.policy, &opol); 4850Sstevel@tonic-gate switch(ret) { 4860Sstevel@tonic-gate case EINVAL: 4870Sstevel@tonic-gate case KADM5_BAD_POLICY: 4880Sstevel@tonic-gate case KADM5_UNK_POLICY: 4890Sstevel@tonic-gate break; 4900Sstevel@tonic-gate case KADM5_OK: 4910Sstevel@tonic-gate have_opol = 1; 4920Sstevel@tonic-gate opol.policy_refcnt--; 4930Sstevel@tonic-gate break; 4940Sstevel@tonic-gate default: 4950Sstevel@tonic-gate goto done; 496*2881Smp153739 break; 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate npol.policy_refcnt++; 4990Sstevel@tonic-gate } 5000Sstevel@tonic-gate } else npol.policy_refcnt++; 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate /* set us up to use the new policy */ 5030Sstevel@tonic-gate adb.aux_attributes |= KADM5_POLICY; 5040Sstevel@tonic-gate if (adb.policy) 5050Sstevel@tonic-gate free(adb.policy); 5060Sstevel@tonic-gate adb.policy = strdup(entry->policy); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate /* set pw_max_life based on new policy */ 5090Sstevel@tonic-gate if (npol.pw_max_life) { 510*2881Smp153739 ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, 511*2881Smp153739 &(kdb.pw_expiration)); 512*2881Smp153739 if (ret) 513*2881Smp153739 goto done; 514*2881Smp153739 kdb.pw_expiration += npol.pw_max_life; 5150Sstevel@tonic-gate } else { 516*2881Smp153739 kdb.pw_expiration = 0; 5170Sstevel@tonic-gate } 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate if ((mask & KADM5_POLICY_CLR) && 5210Sstevel@tonic-gate (adb.aux_attributes & KADM5_POLICY)) { 5220Sstevel@tonic-gate ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol); 5230Sstevel@tonic-gate switch(ret) { 5240Sstevel@tonic-gate case EINVAL: 5250Sstevel@tonic-gate case KADM5_BAD_POLICY: 5260Sstevel@tonic-gate case KADM5_UNK_POLICY: 5270Sstevel@tonic-gate ret = KADM5_BAD_DB; 5280Sstevel@tonic-gate goto done; 529*2881Smp153739 break; 5300Sstevel@tonic-gate case KADM5_OK: 5310Sstevel@tonic-gate have_opol = 1; 5320Sstevel@tonic-gate if (adb.policy) 5330Sstevel@tonic-gate free(adb.policy); 5340Sstevel@tonic-gate adb.policy = NULL; 5350Sstevel@tonic-gate adb.aux_attributes &= ~KADM5_POLICY; 5360Sstevel@tonic-gate kdb.pw_expiration = 0; 5370Sstevel@tonic-gate opol.policy_refcnt--; 5380Sstevel@tonic-gate break; 5390Sstevel@tonic-gate default: 5400Sstevel@tonic-gate goto done; 541*2881Smp153739 break; 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) && 5460Sstevel@tonic-gate (((have_opol) && 5470Sstevel@tonic-gate (ret = 5480Sstevel@tonic-gate kadm5_modify_policy_internal(handle->lhandle, &opol, 5490Sstevel@tonic-gate KADM5_REF_COUNT))) || 5500Sstevel@tonic-gate ((have_npol) && 5510Sstevel@tonic-gate (ret = 5520Sstevel@tonic-gate kadm5_modify_policy_internal(handle->lhandle, &npol, 5530Sstevel@tonic-gate KADM5_REF_COUNT))))) 5540Sstevel@tonic-gate goto done; 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate if ((mask & KADM5_ATTRIBUTES)) 5570Sstevel@tonic-gate kdb.attributes = entry->attributes; 5580Sstevel@tonic-gate if ((mask & KADM5_MAX_LIFE)) 5590Sstevel@tonic-gate kdb.max_life = entry->max_life; 5600Sstevel@tonic-gate if ((mask & KADM5_PRINC_EXPIRE_TIME)) 5610Sstevel@tonic-gate kdb.expiration = entry->princ_expire_time; 5620Sstevel@tonic-gate if (mask & KADM5_PW_EXPIRATION) 5630Sstevel@tonic-gate kdb.pw_expiration = entry->pw_expiration; 5640Sstevel@tonic-gate if (mask & KADM5_MAX_RLIFE) 5650Sstevel@tonic-gate kdb.max_renewable_life = entry->max_renewable_life; 5660Sstevel@tonic-gate if (mask & KADM5_FAIL_AUTH_COUNT) 5670Sstevel@tonic-gate kdb.fail_auth_count = entry->fail_auth_count; 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate if((mask & KADM5_KVNO)) { 5700Sstevel@tonic-gate for (i = 0; i < kdb.n_key_data; i++) 5710Sstevel@tonic-gate kdb.key_data[i].key_data_kvno = entry->kvno; 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 5750Sstevel@tonic-gate krb5_tl_data *tl, *tl2; 5760Sstevel@tonic-gate /* 5770Sstevel@tonic-gate * Replace kdb.tl_data with what was passed in. The 5780Sstevel@tonic-gate * KRB5_TL_KADM_DATA will be re-added (based on adb) by 5790Sstevel@tonic-gate * kdb_put_entry, below. 5800Sstevel@tonic-gate * 5810Sstevel@tonic-gate * Note that we have to duplicate the passed in tl_data 5820Sstevel@tonic-gate * before adding it to kdb. The reason is that kdb_put_entry 5830Sstevel@tonic-gate * will add its own tl_data entries that we will need to 5840Sstevel@tonic-gate * free, but we cannot free the caller's tl_data (an 5850Sstevel@tonic-gate * alternative would be to scan the tl_data after put_entry 5860Sstevel@tonic-gate * and only free those entries that were not passed in). 5870Sstevel@tonic-gate */ 5880Sstevel@tonic-gate while (kdb.tl_data) { 5890Sstevel@tonic-gate tl = kdb.tl_data->tl_data_next; 5900Sstevel@tonic-gate free(kdb.tl_data->tl_data_contents); 5910Sstevel@tonic-gate free(kdb.tl_data); 5920Sstevel@tonic-gate kdb.tl_data = tl; 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate kdb.n_tl_data = entry->n_tl_data; 5960Sstevel@tonic-gate kdb.tl_data = NULL; 5970Sstevel@tonic-gate tl2 = entry->tl_data; 5980Sstevel@tonic-gate while (tl2) { 5990Sstevel@tonic-gate tl = dup_tl_data(tl2); 6000Sstevel@tonic-gate tl->tl_data_next = kdb.tl_data; 6010Sstevel@tonic-gate kdb.tl_data = tl; 6020Sstevel@tonic-gate tl2 = tl2->tl_data_next; 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate ret = kdb_put_entry(handle, &kdb, &adb); 6070Sstevel@tonic-gate if (ret) goto done; 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate ret = KADM5_OK; 6100Sstevel@tonic-gate done: 6110Sstevel@tonic-gate if (have_opol) { 6120Sstevel@tonic-gate ret2 = kadm5_free_policy_ent(handle->lhandle, &opol); 6130Sstevel@tonic-gate ret = ret ? ret : ret2; 6140Sstevel@tonic-gate } 6150Sstevel@tonic-gate if (have_npol) { 6160Sstevel@tonic-gate ret2 = kadm5_free_policy_ent(handle->lhandle, &npol); 6170Sstevel@tonic-gate ret = ret ? ret : ret2; 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 6200Sstevel@tonic-gate return ret; 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate kadm5_ret_t 6240Sstevel@tonic-gate kadm5_rename_principal(void *server_handle, 6250Sstevel@tonic-gate krb5_principal source, krb5_principal target) 6260Sstevel@tonic-gate { 6270Sstevel@tonic-gate krb5_db_entry kdb; 6280Sstevel@tonic-gate osa_princ_ent_rec adb; 6290Sstevel@tonic-gate int ret, i; 6300Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate CHECK_HANDLE(server_handle); 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate if (source == NULL || target == NULL) 6350Sstevel@tonic-gate return EINVAL; 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) { 6380Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 6390Sstevel@tonic-gate return(KADM5_DUP); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, source, &kdb, &adb))) 6430Sstevel@tonic-gate return ret; 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate /* this is kinda gross, but unavoidable */ 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate for (i=0; i<kdb.n_key_data; i++) { 6480Sstevel@tonic-gate if ((kdb.key_data[i].key_data_ver == 1) || 6490Sstevel@tonic-gate (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) { 6500Sstevel@tonic-gate ret = KADM5_NO_RENAME_SALT; 6510Sstevel@tonic-gate goto done; 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate } 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate krb5_free_principal(handle->context, kdb.princ); 656*2881Smp153739 ret = krb5_copy_principal(handle->context, target, &kdb.princ); 657*2881Smp153739 if (ret) { 6580Sstevel@tonic-gate kdb.princ = NULL; /* so freeing the dbe doesn't lose */ 6590Sstevel@tonic-gate goto done; 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 6630Sstevel@tonic-gate goto done; 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate ret = kdb_delete_entry(handle, source); 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate done: 6680Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 6690Sstevel@tonic-gate return ret; 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate kadm5_ret_t 6730Sstevel@tonic-gate kadm5_get_principal(void *server_handle, krb5_principal principal, 6740Sstevel@tonic-gate kadm5_principal_ent_t entry, 6750Sstevel@tonic-gate long in_mask) 6760Sstevel@tonic-gate { 6770Sstevel@tonic-gate krb5_db_entry kdb; 6780Sstevel@tonic-gate osa_princ_ent_rec adb; 6790Sstevel@tonic-gate osa_adb_ret_t ret = 0; 6800Sstevel@tonic-gate long mask; 6810Sstevel@tonic-gate int i; 6820Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 6830Sstevel@tonic-gate kadm5_principal_ent_rec entry_local, *entry_orig; 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate CHECK_HANDLE(server_handle); 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate /* 6880Sstevel@tonic-gate * In version 1, all the defined fields are always returned. 6890Sstevel@tonic-gate * entry is a pointer to a kadm5_principal_ent_t_v1 that should be 6900Sstevel@tonic-gate * filled with allocated memory. 6910Sstevel@tonic-gate */ 6920Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_1) { 6930Sstevel@tonic-gate mask = KADM5_PRINCIPAL_NORMAL_MASK; 6940Sstevel@tonic-gate entry_orig = entry; 6950Sstevel@tonic-gate entry = &entry_local; 6960Sstevel@tonic-gate } else { 6970Sstevel@tonic-gate mask = in_mask; 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate memset((char *) entry, 0, sizeof(*entry)); 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate if (principal == NULL) 7030Sstevel@tonic-gate return EINVAL; 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 7060Sstevel@tonic-gate return ret; 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate if ((mask & KADM5_POLICY) && 7090Sstevel@tonic-gate adb.policy && (adb.aux_attributes & KADM5_POLICY)) { 7100Sstevel@tonic-gate if ((entry->policy = (char *) malloc(strlen(adb.policy) + 1)) == NULL) { 7110Sstevel@tonic-gate ret = ENOMEM; 7120Sstevel@tonic-gate goto done; 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate strcpy(entry->policy, adb.policy); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate if (mask & KADM5_AUX_ATTRIBUTES) 7180Sstevel@tonic-gate entry->aux_attributes = adb.aux_attributes; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate if ((mask & KADM5_PRINCIPAL) && 7210Sstevel@tonic-gate (ret = krb5_copy_principal(handle->context, principal, 7220Sstevel@tonic-gate &entry->principal))) { 7230Sstevel@tonic-gate goto done; 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate if (mask & KADM5_PRINC_EXPIRE_TIME) 7270Sstevel@tonic-gate entry->princ_expire_time = kdb.expiration; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate if ((mask & KADM5_LAST_PWD_CHANGE) && 7300Sstevel@tonic-gate (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, 7310Sstevel@tonic-gate &(entry->last_pwd_change)))) { 7320Sstevel@tonic-gate goto done; 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate if (mask & KADM5_PW_EXPIRATION) 7360Sstevel@tonic-gate entry->pw_expiration = kdb.pw_expiration; 7370Sstevel@tonic-gate if (mask & KADM5_MAX_LIFE) 7380Sstevel@tonic-gate entry->max_life = kdb.max_life; 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate /* this is a little non-sensical because the function returns two */ 7410Sstevel@tonic-gate /* values that must be checked separately against the mask */ 7420Sstevel@tonic-gate if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) { 743*2881Smp153739 ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb, 744*2881Smp153739 &(entry->mod_date), 745*2881Smp153739 &(entry->mod_name)); 746*2881Smp153739 if (ret) { 747*2881Smp153739 goto done; 748*2881Smp153739 } 749*2881Smp153739 750*2881Smp153739 if (! (mask & KADM5_MOD_TIME)) 751*2881Smp153739 entry->mod_date = 0; 752*2881Smp153739 if (! (mask & KADM5_MOD_NAME)) { 753*2881Smp153739 krb5_free_principal(handle->context, entry->principal); 754*2881Smp153739 entry->principal = NULL; 755*2881Smp153739 } 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate if (mask & KADM5_ATTRIBUTES) 7590Sstevel@tonic-gate entry->attributes = kdb.attributes; 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate if (mask & KADM5_KVNO) 7620Sstevel@tonic-gate for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++) 7630Sstevel@tonic-gate if (kdb.key_data[i].key_data_kvno > entry->kvno) 7640Sstevel@tonic-gate entry->kvno = kdb.key_data[i].key_data_kvno; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_2) 7670Sstevel@tonic-gate entry->mkvno = 0; 7680Sstevel@tonic-gate else { 7690Sstevel@tonic-gate /* XXX I'll be damned if I know how to deal with this one --marc */ 7700Sstevel@tonic-gate entry->mkvno = 1; 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate /* 7740Sstevel@tonic-gate * The new fields that only exist in version 2 start here 7750Sstevel@tonic-gate */ 7760Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_2) { 7770Sstevel@tonic-gate if (mask & KADM5_MAX_RLIFE) 7780Sstevel@tonic-gate entry->max_renewable_life = kdb.max_renewable_life; 7790Sstevel@tonic-gate if (mask & KADM5_LAST_SUCCESS) 7800Sstevel@tonic-gate entry->last_success = kdb.last_success; 7810Sstevel@tonic-gate if (mask & KADM5_LAST_FAILED) 7820Sstevel@tonic-gate entry->last_failed = kdb.last_failed; 7830Sstevel@tonic-gate if (mask & KADM5_FAIL_AUTH_COUNT) 7840Sstevel@tonic-gate entry->fail_auth_count = kdb.fail_auth_count; 7850Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 786*2881Smp153739 krb5_tl_data *tl, *tl2; 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate entry->tl_data = NULL; 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate tl = kdb.tl_data; 7910Sstevel@tonic-gate while (tl) { 7920Sstevel@tonic-gate if (tl->tl_data_type > 255) { 7930Sstevel@tonic-gate if ((tl2 = dup_tl_data(tl)) == NULL) { 7940Sstevel@tonic-gate ret = ENOMEM; 7950Sstevel@tonic-gate goto done; 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate tl2->tl_data_next = entry->tl_data; 7980Sstevel@tonic-gate entry->tl_data = tl2; 7990Sstevel@tonic-gate entry->n_tl_data++; 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate tl = tl->tl_data_next; 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate } 8050Sstevel@tonic-gate if (mask & KADM5_KEY_DATA) { 8060Sstevel@tonic-gate entry->n_key_data = kdb.n_key_data; 8070Sstevel@tonic-gate if(entry->n_key_data) { 8080Sstevel@tonic-gate entry->key_data = (krb5_key_data *) 8090Sstevel@tonic-gate malloc(entry->n_key_data*sizeof(krb5_key_data)); 8100Sstevel@tonic-gate if (entry->key_data == NULL) { 8110Sstevel@tonic-gate ret = ENOMEM; 8120Sstevel@tonic-gate goto done; 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate } else 8150Sstevel@tonic-gate entry->key_data = NULL; 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate for (i = 0; i < entry->n_key_data; i++) 818*2881Smp153739 ret = krb5_copy_key_data_contents(handle->context, 819*2881Smp153739 &kdb.key_data[i], 820*2881Smp153739 &entry->key_data[i]); 821*2881Smp153739 if (ret) 8220Sstevel@tonic-gate goto done; 8230Sstevel@tonic-gate } 8240Sstevel@tonic-gate } 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate /* 8270Sstevel@tonic-gate * If KADM5_API_VERSION_1, we return an allocated structure, and 8280Sstevel@tonic-gate * we need to convert the new structure back into the format the 8290Sstevel@tonic-gate * caller is expecting. 8300Sstevel@tonic-gate */ 8310Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_1) { 8320Sstevel@tonic-gate kadm5_principal_ent_t_v1 newv1; 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1))); 8350Sstevel@tonic-gate if (newv1 == NULL) { 8360Sstevel@tonic-gate ret = ENOMEM; 8370Sstevel@tonic-gate goto done; 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate newv1->principal = entry->principal; 8410Sstevel@tonic-gate newv1->princ_expire_time = entry->princ_expire_time; 8420Sstevel@tonic-gate newv1->last_pwd_change = entry->last_pwd_change; 8430Sstevel@tonic-gate newv1->pw_expiration = entry->pw_expiration; 8440Sstevel@tonic-gate newv1->max_life = entry->max_life; 8450Sstevel@tonic-gate newv1->mod_name = entry->mod_name; 8460Sstevel@tonic-gate newv1->mod_date = entry->mod_date; 8470Sstevel@tonic-gate newv1->attributes = entry->attributes; 8480Sstevel@tonic-gate newv1->kvno = entry->kvno; 8490Sstevel@tonic-gate newv1->mkvno = entry->mkvno; 8500Sstevel@tonic-gate newv1->policy = entry->policy; 8510Sstevel@tonic-gate newv1->aux_attributes = entry->aux_attributes; 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1; 8540Sstevel@tonic-gate } 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate ret = KADM5_OK; 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate done: 8590Sstevel@tonic-gate if (ret && entry->principal) 8600Sstevel@tonic-gate krb5_free_principal(handle->context, entry->principal); 8610Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate return ret; 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* 8670Sstevel@tonic-gate * Function: check_pw_reuse 8680Sstevel@tonic-gate * 8690Sstevel@tonic-gate * Purpose: Check if a key appears in a list of keys, in order to 8700Sstevel@tonic-gate * enforce password history. 8710Sstevel@tonic-gate * 8720Sstevel@tonic-gate * Arguments: 8730Sstevel@tonic-gate * 8740Sstevel@tonic-gate * context (r) the krb5 context 8750Sstevel@tonic-gate * hist_keyblock (r) the key that hist_key_data is 8760Sstevel@tonic-gate * encrypted in 8770Sstevel@tonic-gate * n_new_key_data (r) length of new_key_data 8780Sstevel@tonic-gate * new_key_data (r) keys to check against 8790Sstevel@tonic-gate * pw_hist_data, encrypted in hist_keyblock 8800Sstevel@tonic-gate * n_pw_hist_data (r) length of pw_hist_data 8810Sstevel@tonic-gate * pw_hist_data (r) passwords to check new_key_data against 8820Sstevel@tonic-gate * 8830Sstevel@tonic-gate * Effects: 8840Sstevel@tonic-gate * For each new_key in new_key_data: 8850Sstevel@tonic-gate * decrypt new_key with the master_keyblock 8860Sstevel@tonic-gate * for each password in pw_hist_data: 8870Sstevel@tonic-gate * for each hist_key in password: 8880Sstevel@tonic-gate * decrypt hist_key with hist_keyblock 8890Sstevel@tonic-gate * compare the new_key and hist_key 8900Sstevel@tonic-gate * 8910Sstevel@tonic-gate * Returns krb5 errors, KADM5_PASS_RESUSE if a key in 8920Sstevel@tonic-gate * new_key_data is the same as a key in pw_hist_data, or 0. 8930Sstevel@tonic-gate */ 8940Sstevel@tonic-gate static kadm5_ret_t 8950Sstevel@tonic-gate check_pw_reuse(krb5_context context, 8960Sstevel@tonic-gate krb5_keyblock *master_keyblock, 8970Sstevel@tonic-gate krb5_keyblock *hist_keyblock, 8980Sstevel@tonic-gate int n_new_key_data, krb5_key_data *new_key_data, 899*2881Smp153739 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data) 9000Sstevel@tonic-gate { 9010Sstevel@tonic-gate int x, y, z; 9020Sstevel@tonic-gate krb5_keyblock newkey, histkey; 9030Sstevel@tonic-gate krb5_error_code ret; 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate for (x = 0; x < n_new_key_data; x++) { 906*2881Smp153739 ret = krb5_dbekd_decrypt_key_data(context, 907*2881Smp153739 master_keyblock, 908*2881Smp153739 &(new_key_data[x]), 909*2881Smp153739 &newkey, NULL); 910*2881Smp153739 if (ret) 9110Sstevel@tonic-gate return(ret); 9120Sstevel@tonic-gate for (y = 0; y < n_pw_hist_data; y++) { 9130Sstevel@tonic-gate for (z = 0; z < pw_hist_data[y].n_key_data; z++) { 914*2881Smp153739 ret = krb5_dbekd_decrypt_key_data(context, 915*2881Smp153739 hist_keyblock, 916*2881Smp153739 &pw_hist_data[y].key_data[z], 917*2881Smp153739 &histkey, NULL); 918*2881Smp153739 if (ret) 919*2881Smp153739 return(ret); 920*2881Smp153739 921*2881Smp153739 if ((newkey.length == histkey.length) && 922*2881Smp153739 (newkey.enctype == histkey.enctype) && 923*2881Smp153739 (memcmp(newkey.contents, histkey.contents, 924*2881Smp153739 histkey.length) == 0)) { 925*2881Smp153739 krb5_free_keyblock_contents(context, &histkey); 926*2881Smp153739 krb5_free_keyblock_contents(context, &newkey); 927*2881Smp153739 928*2881Smp153739 return(KADM5_PASS_REUSE); 929*2881Smp153739 } 930*2881Smp153739 krb5_free_keyblock_contents(context, &histkey); 9310Sstevel@tonic-gate } 9320Sstevel@tonic-gate } 9330Sstevel@tonic-gate krb5_free_keyblock_contents(context, &newkey); 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate return(0); 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate /* 9400Sstevel@tonic-gate * Function: create_history_entry 9410Sstevel@tonic-gate * 9420Sstevel@tonic-gate * Purpose: Creates a password history entry from an array of 9430Sstevel@tonic-gate * key_data. 9440Sstevel@tonic-gate * 9450Sstevel@tonic-gate * Arguments: 9460Sstevel@tonic-gate * 9470Sstevel@tonic-gate * context (r) krb5_context to use 9480Sstevel@tonic-gate * master_keyblcok (r) master key block 9490Sstevel@tonic-gate * n_key_data (r) number of elements in key_data 9500Sstevel@tonic-gate * key_data (r) keys to add to the history entry 9510Sstevel@tonic-gate * hist (w) history entry to fill in 9520Sstevel@tonic-gate * 9530Sstevel@tonic-gate * Effects: 9540Sstevel@tonic-gate * 9550Sstevel@tonic-gate * hist->key_data is allocated to store n_key_data key_datas. Each 9560Sstevel@tonic-gate * element of key_data is decrypted with master_keyblock, re-encrypted 9570Sstevel@tonic-gate * in hist_key, and added to hist->key_data. hist->n_key_data is 9580Sstevel@tonic-gate * set to n_key_data. 9590Sstevel@tonic-gate */ 9600Sstevel@tonic-gate static 9610Sstevel@tonic-gate int create_history_entry(krb5_context context, 9620Sstevel@tonic-gate krb5_keyblock *master_keyblock, int n_key_data, 9630Sstevel@tonic-gate krb5_key_data *key_data, osa_pw_hist_ent *hist) 9640Sstevel@tonic-gate { 9650Sstevel@tonic-gate int i, ret; 9660Sstevel@tonic-gate krb5_keyblock key; 9670Sstevel@tonic-gate krb5_keysalt salt; 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data)); 9700Sstevel@tonic-gate if (hist->key_data == NULL) 9710Sstevel@tonic-gate return ENOMEM; 9720Sstevel@tonic-gate memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data)); 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate for (i = 0; i < n_key_data; i++) { 975*2881Smp153739 ret = krb5_dbekd_decrypt_key_data(context, 976*2881Smp153739 master_keyblock, 977*2881Smp153739 &key_data[i], 978*2881Smp153739 &key, &salt); 979*2881Smp153739 if (ret) 980*2881Smp153739 return ret; 981*2881Smp153739 982*2881Smp153739 ret = krb5_dbekd_encrypt_key_data(context, &hist_key, 983*2881Smp153739 &key, &salt, 984*2881Smp153739 key_data[i].key_data_kvno, 985*2881Smp153739 &hist->key_data[i]); 986*2881Smp153739 if (ret) 987*2881Smp153739 return ret; 988*2881Smp153739 989*2881Smp153739 krb5_free_keyblock_contents(context, &key); 990*2881Smp153739 /* krb5_free_keysalt(context, &salt); */ 9910Sstevel@tonic-gate } 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate hist->n_key_data = n_key_data; 9940Sstevel@tonic-gate return 0; 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate 997*2881Smp153739 static 9980Sstevel@tonic-gate void free_history_entry(krb5_context context, osa_pw_hist_ent *hist) 9990Sstevel@tonic-gate { 10000Sstevel@tonic-gate int i; 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate for (i = 0; i < hist->n_key_data; i++) 10030Sstevel@tonic-gate krb5_free_key_data_contents(context, &hist->key_data[i]); 10040Sstevel@tonic-gate free(hist->key_data); 10050Sstevel@tonic-gate } 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate /* 10080Sstevel@tonic-gate * Function: add_to_history 10090Sstevel@tonic-gate * 10100Sstevel@tonic-gate * Purpose: Adds a password to a principal's password history. 10110Sstevel@tonic-gate * 10120Sstevel@tonic-gate * Arguments: 10130Sstevel@tonic-gate * 10140Sstevel@tonic-gate * context (r) krb5_context to use 10150Sstevel@tonic-gate * adb (r/w) admin principal entry to add keys to 10160Sstevel@tonic-gate * pol (r) adb's policy 10170Sstevel@tonic-gate * pw (r) keys for the password to add to adb's key history 10180Sstevel@tonic-gate * 10190Sstevel@tonic-gate * Effects: 10200Sstevel@tonic-gate * 10210Sstevel@tonic-gate * add_to_history adds a single password to adb's password history. 10220Sstevel@tonic-gate * pw contains n_key_data keys in its key_data, in storage should be 10230Sstevel@tonic-gate * allocated but not freed by the caller (XXX blech!). 10240Sstevel@tonic-gate * 10250Sstevel@tonic-gate * This function maintains adb->old_keys as a circular queue. It 10260Sstevel@tonic-gate * starts empty, and grows each time this function is called until it 10270Sstevel@tonic-gate * is pol->pw_history_num items long. adb->old_key_len holds the 10280Sstevel@tonic-gate * number of allocated entries in the array, and must therefore be [0, 10290Sstevel@tonic-gate * pol->pw_history_num). adb->old_key_next is the index into the 10300Sstevel@tonic-gate * array where the next element should be written, and must be [0, 10310Sstevel@tonic-gate * adb->old_key_len). 10320Sstevel@tonic-gate */ 10330Sstevel@tonic-gate #define KADM_MOD(x) (x + adb->old_key_next) % adb->old_key_len 1034*2881Smp153739 static kadm5_ret_t add_to_history(krb5_context context, 1035*2881Smp153739 osa_princ_ent_t adb, 1036*2881Smp153739 kadm5_policy_ent_t pol, 1037*2881Smp153739 osa_pw_hist_ent *pw) 10380Sstevel@tonic-gate { 1039*2881Smp153739 osa_pw_hist_ent *histp; 1040*2881Smp153739 int i; 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate /* A history of 1 means just check the current password */ 10430Sstevel@tonic-gate if (pol->pw_history_num == 1) 10440Sstevel@tonic-gate return (0); 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate /* resize the adb->old_keys array if necessary */ 10470Sstevel@tonic-gate if (adb->old_key_len < pol->pw_history_num-1) { 10480Sstevel@tonic-gate if (adb->old_keys == NULL) { 10490Sstevel@tonic-gate adb->old_keys = (osa_pw_hist_ent *) 10500Sstevel@tonic-gate malloc((adb->old_key_len + 1) * 10510Sstevel@tonic-gate sizeof (osa_pw_hist_ent)); 10520Sstevel@tonic-gate } else { 10530Sstevel@tonic-gate adb->old_keys = (osa_pw_hist_ent *) 10540Sstevel@tonic-gate realloc(adb->old_keys, 10550Sstevel@tonic-gate (adb->old_key_len + 1) * 10560Sstevel@tonic-gate sizeof (osa_pw_hist_ent)); 10570Sstevel@tonic-gate } 10580Sstevel@tonic-gate if (adb->old_keys == NULL) 10590Sstevel@tonic-gate return (ENOMEM); 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate memset(&adb->old_keys[adb->old_key_len], 0, 10620Sstevel@tonic-gate sizeof (osa_pw_hist_ent)); 10630Sstevel@tonic-gate adb->old_key_len++; 10640Sstevel@tonic-gate for (i = adb->old_key_len - 1; i > adb->old_key_next; i--) 10650Sstevel@tonic-gate adb->old_keys[i] = adb->old_keys[i - 1]; 10660Sstevel@tonic-gate memset(&adb->old_keys[adb->old_key_next], 0, 10670Sstevel@tonic-gate sizeof (osa_pw_hist_ent)); 10680Sstevel@tonic-gate } else if (adb->old_key_len > pol->pw_history_num-1) { 10690Sstevel@tonic-gate /* 10700Sstevel@tonic-gate * The policy must have changed! Shrink the array. 10710Sstevel@tonic-gate * Can't simply realloc() down, since it might be wrapped. 10720Sstevel@tonic-gate * To understand the arithmetic below, note that we are 10730Sstevel@tonic-gate * copying into new positions 0 .. N-1 from old positions 10740Sstevel@tonic-gate * old_key_next-N .. old_key_next-1, modulo old_key_len, 10750Sstevel@tonic-gate * where N = pw_history_num - 1 is the length of the 10760Sstevel@tonic-gate * shortened list. Matt Crawford, FNAL 10770Sstevel@tonic-gate */ 10780Sstevel@tonic-gate int j; 10790Sstevel@tonic-gate histp = (osa_pw_hist_ent *) 10800Sstevel@tonic-gate malloc((pol->pw_history_num - 1) * sizeof (osa_pw_hist_ent)); 10810Sstevel@tonic-gate if (histp) { 10820Sstevel@tonic-gate for (i = 0; i < pol->pw_history_num - 1; i++) { 10830Sstevel@tonic-gate /* 10840Sstevel@tonic-gate * We need the number we use the modulus 10850Sstevel@tonic-gate * operator on to be positive, so after 10860Sstevel@tonic-gate * subtracting pol->pw_history_num-1, we 10870Sstevel@tonic-gate * add back adb->old_key_len. 10880Sstevel@tonic-gate */ 10890Sstevel@tonic-gate j = KADM_MOD(i - (pol->pw_history_num - 1) + 10900Sstevel@tonic-gate adb->old_key_len); 10910Sstevel@tonic-gate histp[i] = adb->old_keys[j]; 10920Sstevel@tonic-gate } 10930Sstevel@tonic-gate /* Now free the ones we don't keep (the oldest ones) */ 10940Sstevel@tonic-gate for (i = 0; i < adb->old_key_len - \ 10950Sstevel@tonic-gate (pol->pw_history_num-1); i++) { 10960Sstevel@tonic-gate for (j = 0; j < \ 10970Sstevel@tonic-gate adb->old_keys[KADM_MOD(i)].n_key_data; j++) 10980Sstevel@tonic-gate krb5_free_key_data_contents(context, 10990Sstevel@tonic-gate &adb->old_keys[KADM_MOD(i)]. 11000Sstevel@tonic-gate key_data[j]); 11010Sstevel@tonic-gate free(adb->old_keys[KADM_MOD(i)].key_data); 11020Sstevel@tonic-gate } 11030Sstevel@tonic-gate free((void *)adb->old_keys); 11040Sstevel@tonic-gate adb->old_keys = histp; 11050Sstevel@tonic-gate adb->old_key_len = pol->pw_history_num - 1; 11060Sstevel@tonic-gate adb->old_key_next = 0; 11070Sstevel@tonic-gate } else { 11080Sstevel@tonic-gate return (ENOMEM); 11090Sstevel@tonic-gate } 11100Sstevel@tonic-gate } 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate if (adb->old_key_next + 1 > adb->old_key_len) 11130Sstevel@tonic-gate adb->old_key_next = 0; 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate /* free the old pw history entry if it contains data */ 11160Sstevel@tonic-gate histp = &adb->old_keys[adb->old_key_next]; 11170Sstevel@tonic-gate for (i = 0; i < histp->n_key_data; i++) 11180Sstevel@tonic-gate krb5_free_key_data_contents(context, &histp->key_data[i]); 11190Sstevel@tonic-gate free(histp->key_data); 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate /* store the new entry */ 11220Sstevel@tonic-gate adb->old_keys[adb->old_key_next] = *pw; 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate /* update the next pointer */ 11250Sstevel@tonic-gate if (++adb->old_key_next == pol->pw_history_num-1) 11260Sstevel@tonic-gate adb->old_key_next = 0; 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate return (0); 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate #undef KADM_MOD 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate kadm5_ret_t 11330Sstevel@tonic-gate kadm5_chpass_principal(void *server_handle, 11340Sstevel@tonic-gate krb5_principal principal, char *password) 11350Sstevel@tonic-gate { 11360Sstevel@tonic-gate /* 11370Sstevel@tonic-gate * Default to using the new API with the default set of 11380Sstevel@tonic-gate * key/salt combinations. 11390Sstevel@tonic-gate */ 1140*2881Smp153739 return 1141*2881Smp153739 kadm5_chpass_principal_3(server_handle, principal, FALSE, 1142*2881Smp153739 0, NULL, password); 11430Sstevel@tonic-gate } 11440Sstevel@tonic-gate 11450Sstevel@tonic-gate kadm5_ret_t 11460Sstevel@tonic-gate kadm5_chpass_principal_3(void *server_handle, 11470Sstevel@tonic-gate krb5_principal principal, krb5_boolean keepold, 11480Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 11490Sstevel@tonic-gate char *password) 11500Sstevel@tonic-gate { 11510Sstevel@tonic-gate krb5_int32 now; 11520Sstevel@tonic-gate kadm5_policy_ent_rec pol; 11530Sstevel@tonic-gate osa_princ_ent_rec adb; 11540Sstevel@tonic-gate krb5_db_entry kdb, kdb_save; 1155*2881Smp153739 int ret, ret2, last_pwd, hist_added; 11560Sstevel@tonic-gate int have_pol = 0; 11570Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 11580Sstevel@tonic-gate osa_pw_hist_ent hist; 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate CHECK_HANDLE(server_handle); 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate hist_added = 0; 11630Sstevel@tonic-gate memset(&hist, 0, sizeof(hist)); 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate if (principal == NULL || password == NULL) 11660Sstevel@tonic-gate return EINVAL; 11670Sstevel@tonic-gate if ((krb5_principal_compare(handle->context, 11680Sstevel@tonic-gate principal, hist_princ)) == TRUE) 11690Sstevel@tonic-gate return KADM5_PROTECT_PRINCIPAL; 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 11720Sstevel@tonic-gate return(ret); 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate /* we are going to need the current keys after the new keys are set */ 11750Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) { 11760Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 11770Sstevel@tonic-gate return(ret); 11780Sstevel@tonic-gate } 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 11810Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol))) 11820Sstevel@tonic-gate goto done; 11830Sstevel@tonic-gate have_pol = 1; 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate if ((ret = passwd_check(handle, password, adb.aux_attributes & 11870Sstevel@tonic-gate KADM5_POLICY, &pol, principal))) 11880Sstevel@tonic-gate goto done; 11890Sstevel@tonic-gate 1190*2881Smp153739 ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, 1191*2881Smp153739 n_ks_tuple?ks_tuple:handle->params.keysalts, 1192*2881Smp153739 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 1193*2881Smp153739 password, 0 /* increment kvno */, 1194*2881Smp153739 keepold, &kdb); 1195*2881Smp153739 if (ret) 11960Sstevel@tonic-gate goto done; 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 11990Sstevel@tonic-gate 1200*2881Smp153739 ret = krb5_timeofday(handle->context, &now); 1201*2881Smp153739 if (ret) 12020Sstevel@tonic-gate goto done; 12030Sstevel@tonic-gate 12040Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 12050Sstevel@tonic-gate /* the policy was loaded before */ 12060Sstevel@tonic-gate 1207*2881Smp153739 ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1208*2881Smp153739 &kdb, &last_pwd); 1209*2881Smp153739 if (ret) 1210*2881Smp153739 goto done; 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate #if 0 12130Sstevel@tonic-gate /* 12140Sstevel@tonic-gate * The spec says this check is overridden if the caller has 12150Sstevel@tonic-gate * modify privilege. The admin server therefore makes this 12160Sstevel@tonic-gate * check itself (in chpass_principal_wrapper, misc.c). A 12170Sstevel@tonic-gate * local caller implicitly has all authorization bits. 12180Sstevel@tonic-gate */ 12190Sstevel@tonic-gate if ((now - last_pwd) < pol.pw_min_life && 12200Sstevel@tonic-gate !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 12210Sstevel@tonic-gate ret = KADM5_PASS_TOOSOON; 12220Sstevel@tonic-gate goto done; 12230Sstevel@tonic-gate } 12240Sstevel@tonic-gate #endif 12250Sstevel@tonic-gate 1226*2881Smp153739 ret = create_history_entry(handle->context, 1227*2881Smp153739 &handle->master_keyblock, kdb_save.n_key_data, 1228*2881Smp153739 kdb_save.key_data, &hist); 1229*2881Smp153739 if (ret) 1230*2881Smp153739 goto done; 12310Sstevel@tonic-gate 1232*2881Smp153739 ret = check_pw_reuse(handle->context, 1233*2881Smp153739 &handle->master_keyblock, 1234*2881Smp153739 &hist_key, 1235*2881Smp153739 kdb.n_key_data, kdb.key_data, 1236*2881Smp153739 1, &hist); 1237*2881Smp153739 if (ret) 1238*2881Smp153739 goto done; 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate if (pol.pw_history_num > 1) { 12410Sstevel@tonic-gate if (adb.admin_history_kvno != hist_kvno) { 12420Sstevel@tonic-gate ret = KADM5_BAD_HIST_KEY; 12430Sstevel@tonic-gate goto done; 12440Sstevel@tonic-gate } 12450Sstevel@tonic-gate 1246*2881Smp153739 ret = check_pw_reuse(handle->context, 12470Sstevel@tonic-gate &handle->master_keyblock, 12480Sstevel@tonic-gate &hist_key, 1249*2881Smp153739 kdb.n_key_data, kdb.key_data, 1250*2881Smp153739 adb.old_key_len, adb.old_keys); 1251*2881Smp153739 if (ret) 12520Sstevel@tonic-gate goto done; 12530Sstevel@tonic-gate 1254*2881Smp153739 ret = add_to_history(handle->context, &adb, &pol, &hist); 1255*2881Smp153739 if (ret) 1256*2881Smp153739 goto done; 12570Sstevel@tonic-gate hist_added = 1; 12580Sstevel@tonic-gate } 12590Sstevel@tonic-gate 12600Sstevel@tonic-gate if (pol.pw_max_life) 12610Sstevel@tonic-gate kdb.pw_expiration = now + pol.pw_max_life; 12620Sstevel@tonic-gate else 12630Sstevel@tonic-gate kdb.pw_expiration = 0; 12640Sstevel@tonic-gate } else { 12650Sstevel@tonic-gate kdb.pw_expiration = 0; 12660Sstevel@tonic-gate } 12670Sstevel@tonic-gate 1268*2881Smp153739 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 1269*2881Smp153739 if (ret) 12700Sstevel@tonic-gate goto done; 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 12730Sstevel@tonic-gate goto done; 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate ret = KADM5_OK; 12760Sstevel@tonic-gate done: 12770Sstevel@tonic-gate if (!hist_added && hist.key_data) 12780Sstevel@tonic-gate free_history_entry(handle->context, &hist); 12790Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 12800Sstevel@tonic-gate kdb_free_entry(handle, &kdb_save, NULL); 12810Sstevel@tonic-gate krb5_dbe_free_contents(handle->context, &kdb); 12820Sstevel@tonic-gate 12830Sstevel@tonic-gate if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol)) 12840Sstevel@tonic-gate && !ret) 12850Sstevel@tonic-gate ret = ret2; 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate return ret; 12880Sstevel@tonic-gate } 12890Sstevel@tonic-gate 12900Sstevel@tonic-gate kadm5_ret_t 12910Sstevel@tonic-gate kadm5_randkey_principal(void *server_handle, 12920Sstevel@tonic-gate krb5_principal principal, 12930Sstevel@tonic-gate krb5_keyblock **keyblocks, 12940Sstevel@tonic-gate int *n_keys) 12950Sstevel@tonic-gate { 12960Sstevel@tonic-gate krb5_key_salt_tuple keysalts[2]; 12970Sstevel@tonic-gate 12980Sstevel@tonic-gate /* 12990Sstevel@tonic-gate * Anyone calling this routine is forced to use only DES 13000Sstevel@tonic-gate * enctypes to be compatible with earlier releases that 13010Sstevel@tonic-gate * did not support stronger crypto. 13020Sstevel@tonic-gate * 13030Sstevel@tonic-gate * S10 (and later) kadmin clients will not use this API, 13040Sstevel@tonic-gate * so we can assume the request is from an older version. 13050Sstevel@tonic-gate */ 13060Sstevel@tonic-gate keysalts[0].ks_enctype = ENCTYPE_DES_CBC_MD5; 13070Sstevel@tonic-gate keysalts[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 13080Sstevel@tonic-gate keysalts[1].ks_enctype = ENCTYPE_DES_CBC_CRC; 13090Sstevel@tonic-gate keysalts[1].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 13100Sstevel@tonic-gate 13110Sstevel@tonic-gate return (kadm5_randkey_principal_3(server_handle, principal, 13120Sstevel@tonic-gate FALSE, 2, keysalts, keyblocks, n_keys)); 13130Sstevel@tonic-gate } 13140Sstevel@tonic-gate 13150Sstevel@tonic-gate kadm5_ret_t 13160Sstevel@tonic-gate kadm5_randkey_principal_3(void *server_handle, 13170Sstevel@tonic-gate krb5_principal principal, 13180Sstevel@tonic-gate krb5_boolean keepold, 13190Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 13200Sstevel@tonic-gate krb5_keyblock **keyblocks, 13210Sstevel@tonic-gate int *n_keys) 13220Sstevel@tonic-gate { 13230Sstevel@tonic-gate krb5_db_entry kdb; 13240Sstevel@tonic-gate osa_princ_ent_rec adb; 13250Sstevel@tonic-gate krb5_int32 now; 13260Sstevel@tonic-gate kadm5_policy_ent_rec pol; 13270Sstevel@tonic-gate krb5_key_data *key_data; 13280Sstevel@tonic-gate krb5_keyblock *keyblock; 13290Sstevel@tonic-gate int ret, last_pwd, have_pol = 0; 13300Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate if (keyblocks) 13330Sstevel@tonic-gate *keyblocks = NULL; 13340Sstevel@tonic-gate 13350Sstevel@tonic-gate CHECK_HANDLE(server_handle); 13360Sstevel@tonic-gate 13370Sstevel@tonic-gate if (principal == NULL) 13380Sstevel@tonic-gate return EINVAL; 13390Sstevel@tonic-gate if (hist_princ && /* this will be NULL when initializing the databse */ 13400Sstevel@tonic-gate ((krb5_principal_compare(handle->context, 13410Sstevel@tonic-gate principal, hist_princ)) == TRUE)) 13420Sstevel@tonic-gate return KADM5_PROTECT_PRINCIPAL; 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 13450Sstevel@tonic-gate return(ret); 13460Sstevel@tonic-gate 1347*2881Smp153739 ret = krb5_dbe_crk(handle->context, &handle->master_keyblock, 1348*2881Smp153739 n_ks_tuple?ks_tuple:handle->params.keysalts, 1349*2881Smp153739 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 1350*2881Smp153739 keepold, 1351*2881Smp153739 &kdb); 1352*2881Smp153739 if (ret) 1353*2881Smp153739 goto done; 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 13560Sstevel@tonic-gate 1357*2881Smp153739 ret = krb5_timeofday(handle->context, &now); 1358*2881Smp153739 if (ret) 13590Sstevel@tonic-gate goto done; 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 13620Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 13630Sstevel@tonic-gate &pol)) != KADM5_OK) 13640Sstevel@tonic-gate goto done; 13650Sstevel@tonic-gate have_pol = 1; 13660Sstevel@tonic-gate 1367*2881Smp153739 ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1368*2881Smp153739 &kdb, &last_pwd); 1369*2881Smp153739 if (ret) 13700Sstevel@tonic-gate goto done; 13710Sstevel@tonic-gate 13720Sstevel@tonic-gate #if 0 13730Sstevel@tonic-gate /* 13740Sstevel@tonic-gate * The spec says this check is overridden if the caller has 13750Sstevel@tonic-gate * modify privilege. The admin server therefore makes this 13760Sstevel@tonic-gate * check itself (in chpass_principal_wrapper, misc.c). A 13770Sstevel@tonic-gate * local caller implicitly has all authorization bits. 13780Sstevel@tonic-gate */ 13790Sstevel@tonic-gate if((now - last_pwd) < pol.pw_min_life && 13800Sstevel@tonic-gate !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 13810Sstevel@tonic-gate ret = KADM5_PASS_TOOSOON; 13820Sstevel@tonic-gate goto done; 13830Sstevel@tonic-gate } 13840Sstevel@tonic-gate #endif 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate if(pol.pw_history_num > 1) { 13870Sstevel@tonic-gate if(adb.admin_history_kvno != hist_kvno) { 13880Sstevel@tonic-gate ret = KADM5_BAD_HIST_KEY; 13890Sstevel@tonic-gate goto done; 13900Sstevel@tonic-gate } 13910Sstevel@tonic-gate 1392*2881Smp153739 ret = check_pw_reuse(handle->context, 1393*2881Smp153739 &handle->master_keyblock, 1394*2881Smp153739 &hist_key, 1395*2881Smp153739 kdb.n_key_data, kdb.key_data, 1396*2881Smp153739 adb.old_key_len, adb.old_keys); 1397*2881Smp153739 if (ret) 13980Sstevel@tonic-gate goto done; 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate if (pol.pw_max_life) 14010Sstevel@tonic-gate kdb.pw_expiration = now + pol.pw_max_life; 14020Sstevel@tonic-gate else 14030Sstevel@tonic-gate kdb.pw_expiration = 0; 14040Sstevel@tonic-gate } else { 14050Sstevel@tonic-gate kdb.pw_expiration = 0; 14060Sstevel@tonic-gate } 14070Sstevel@tonic-gate 1408*2881Smp153739 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 1409*2881Smp153739 if (ret) 14100Sstevel@tonic-gate goto done; 14110Sstevel@tonic-gate 14120Sstevel@tonic-gate if (keyblocks) { 14130Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_1) { 14140Sstevel@tonic-gate /* Version 1 clients will expect to see a DES_CRC enctype. */ 1415*2881Smp153739 ret = krb5_dbe_find_enctype(handle->context, &kdb, 1416*2881Smp153739 ENCTYPE_DES_CBC_CRC, 1417*2881Smp153739 -1, -1, &key_data); 1418*2881Smp153739 if (ret) 1419*2881Smp153739 goto done; 1420*2881Smp153739 1421*2881Smp153739 ret = decrypt_key_data(handle->context, 14220Sstevel@tonic-gate &handle->master_keyblock, 1, key_data, 1423*2881Smp153739 keyblocks, NULL); 1424*2881Smp153739 if (ret) 1425*2881Smp153739 goto done; 14260Sstevel@tonic-gate } else { 1427*2881Smp153739 ret = decrypt_key_data(handle->context, 1428*2881Smp153739 &handle->master_keyblock, 1429*2881Smp153739 kdb.n_key_data, kdb.key_data, 1430*2881Smp153739 keyblocks, n_keys); 1431*2881Smp153739 if (ret) 1432*2881Smp153739 goto done; 14330Sstevel@tonic-gate } 14340Sstevel@tonic-gate } 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 14370Sstevel@tonic-gate goto done; 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate ret = KADM5_OK; 14400Sstevel@tonic-gate done: 14410Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 14420Sstevel@tonic-gate if (have_pol) 14430Sstevel@tonic-gate kadm5_free_policy_ent(handle->lhandle, &pol); 14440Sstevel@tonic-gate 14450Sstevel@tonic-gate return ret; 14460Sstevel@tonic-gate } 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate kadm5_ret_t 14490Sstevel@tonic-gate kadm5_setkey_principal(void *server_handle, 14500Sstevel@tonic-gate krb5_principal principal, 14510Sstevel@tonic-gate krb5_keyblock *keyblocks, 14520Sstevel@tonic-gate int n_keys) 14530Sstevel@tonic-gate { 1454*2881Smp153739 return 1455*2881Smp153739 kadm5_setkey_principal_3(server_handle, principal, 1456*2881Smp153739 FALSE, 0, NULL, 1457*2881Smp153739 keyblocks, n_keys); 14580Sstevel@tonic-gate } 14590Sstevel@tonic-gate 14600Sstevel@tonic-gate kadm5_ret_t 14610Sstevel@tonic-gate kadm5_setkey_principal_3(void *server_handle, 14620Sstevel@tonic-gate krb5_principal principal, 14630Sstevel@tonic-gate krb5_boolean keepold, 14640Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 14650Sstevel@tonic-gate krb5_keyblock *keyblocks, 14660Sstevel@tonic-gate int n_keys) 14670Sstevel@tonic-gate { 14680Sstevel@tonic-gate krb5_db_entry kdb; 14690Sstevel@tonic-gate osa_princ_ent_rec adb; 14700Sstevel@tonic-gate krb5_int32 now; 14710Sstevel@tonic-gate kadm5_policy_ent_rec pol; 14720Sstevel@tonic-gate krb5_key_data *old_key_data; 14730Sstevel@tonic-gate int n_old_keys; 14740Sstevel@tonic-gate int i, j, kvno, ret, last_pwd, have_pol = 0; 14750Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 14760Sstevel@tonic-gate krb5_boolean similar; 14770Sstevel@tonic-gate krb5_keysalt keysalt; 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate CHECK_HANDLE(server_handle); 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate if (principal == NULL || keyblocks == NULL) 14820Sstevel@tonic-gate return EINVAL; 14830Sstevel@tonic-gate if (hist_princ && /* this will be NULL when initializing the databse */ 14840Sstevel@tonic-gate ((krb5_principal_compare(handle->context, 14850Sstevel@tonic-gate principal, hist_princ)) == TRUE)) 14860Sstevel@tonic-gate return KADM5_PROTECT_PRINCIPAL; 14870Sstevel@tonic-gate 14880Sstevel@tonic-gate for (i = 0; i < n_keys; i++) { 14890Sstevel@tonic-gate for (j = i+1; j < n_keys; j++) { 1490*2881Smp153739 if ((ret = krb5_c_enctype_compare(handle->context, 1491*2881Smp153739 keyblocks[i].enctype, 1492*2881Smp153739 keyblocks[j].enctype, 1493*2881Smp153739 &similar))) 14940Sstevel@tonic-gate return(ret); 1495*2881Smp153739 if (similar) { 14960Sstevel@tonic-gate if (n_ks_tuple) { 14970Sstevel@tonic-gate if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype) 14980Sstevel@tonic-gate return KADM5_SETKEY_DUP_ENCTYPES; 14990Sstevel@tonic-gate } else 15000Sstevel@tonic-gate return KADM5_SETKEY_DUP_ENCTYPES; 1501*2881Smp153739 } 15020Sstevel@tonic-gate } 15030Sstevel@tonic-gate } 15040Sstevel@tonic-gate 1505*2881Smp153739 if (n_ks_tuple && n_ks_tuple != n_keys) 15060Sstevel@tonic-gate return KADM5_SETKEY3_ETYPE_MISMATCH; 15070Sstevel@tonic-gate 15080Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 15090Sstevel@tonic-gate return(ret); 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate for (kvno = 0, i=0; i<kdb.n_key_data; i++) 15120Sstevel@tonic-gate if (kdb.key_data[i].key_data_kvno > kvno) 15130Sstevel@tonic-gate kvno = kdb.key_data[i].key_data_kvno; 15140Sstevel@tonic-gate 15150Sstevel@tonic-gate if (keepold) { 15160Sstevel@tonic-gate old_key_data = kdb.key_data; 15170Sstevel@tonic-gate n_old_keys = kdb.n_key_data; 15180Sstevel@tonic-gate } else { 15190Sstevel@tonic-gate if (kdb.key_data != NULL) 15200Sstevel@tonic-gate cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 15210Sstevel@tonic-gate n_old_keys = 0; 15220Sstevel@tonic-gate old_key_data = NULL; 15230Sstevel@tonic-gate } 15240Sstevel@tonic-gate 15250Sstevel@tonic-gate kdb.key_data = (krb5_key_data*)malloc((n_keys+n_old_keys) 15260Sstevel@tonic-gate *sizeof(krb5_key_data)); 15270Sstevel@tonic-gate if (kdb.key_data == NULL) 15280Sstevel@tonic-gate return ENOMEM; 15290Sstevel@tonic-gate memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data)); 15300Sstevel@tonic-gate kdb.n_key_data = 0; 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate for (i = 0; i < n_keys; i++) { 15330Sstevel@tonic-gate if (n_ks_tuple) { 15340Sstevel@tonic-gate keysalt.type = ks_tuple[i].ks_salttype; 15350Sstevel@tonic-gate keysalt.data.length = 0; 15360Sstevel@tonic-gate keysalt.data.data = NULL; 15370Sstevel@tonic-gate if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) { 15380Sstevel@tonic-gate cleanup_key_data(handle->context, kdb.n_key_data, 15390Sstevel@tonic-gate kdb.key_data); 15400Sstevel@tonic-gate return KADM5_SETKEY3_ETYPE_MISMATCH; 15410Sstevel@tonic-gate } 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate ret = krb5_dbekd_encrypt_key_data(handle->context, 15440Sstevel@tonic-gate &handle->master_keyblock, 15450Sstevel@tonic-gate &keyblocks[i], 15460Sstevel@tonic-gate n_ks_tuple ? &keysalt : NULL, 15470Sstevel@tonic-gate kvno + 1, 15480Sstevel@tonic-gate &kdb.key_data[i]); 15490Sstevel@tonic-gate if (ret) { 15500Sstevel@tonic-gate cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 15510Sstevel@tonic-gate return ret; 15520Sstevel@tonic-gate } 15530Sstevel@tonic-gate kdb.n_key_data++; 15540Sstevel@tonic-gate } 15550Sstevel@tonic-gate 15560Sstevel@tonic-gate /* copy old key data if necessary */ 15570Sstevel@tonic-gate for (i = 0; i < n_old_keys; i++) { 15580Sstevel@tonic-gate kdb.key_data[i+n_keys] = old_key_data[i]; 15590Sstevel@tonic-gate memset(&old_key_data[i], 0, sizeof (krb5_key_data)); 15600Sstevel@tonic-gate kdb.n_key_data++; 15610Sstevel@tonic-gate } 15620Sstevel@tonic-gate /* assert(kdb.n_key_data == n_keys + n_old_keys) */ 15630Sstevel@tonic-gate kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 15640Sstevel@tonic-gate 1565*2881Smp153739 if ((ret = krb5_timeofday(handle->context, &now))) 15660Sstevel@tonic-gate goto done; 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 15690Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 15700Sstevel@tonic-gate &pol)) != KADM5_OK) 15710Sstevel@tonic-gate goto done; 15720Sstevel@tonic-gate have_pol = 1; 15730Sstevel@tonic-gate 15740Sstevel@tonic-gate #if 0 15750Sstevel@tonic-gate /* 15760Sstevel@tonic-gate * The spec says this check is overridden if the caller has 15770Sstevel@tonic-gate * modify privilege. The admin server therefore makes this 15780Sstevel@tonic-gate * check itself (in chpass_principal_wrapper, misc.c). A 15790Sstevel@tonic-gate * local caller implicitly has all authorization bits. 15800Sstevel@tonic-gate */ 15810Sstevel@tonic-gate if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, 15820Sstevel@tonic-gate &kdb, &last_pwd)) 15830Sstevel@tonic-gate goto done; 15840Sstevel@tonic-gate if((now - last_pwd) < pol.pw_min_life && 15850Sstevel@tonic-gate !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 15860Sstevel@tonic-gate ret = KADM5_PASS_TOOSOON; 15870Sstevel@tonic-gate goto done; 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate #endif 15900Sstevel@tonic-gate #if 0 15910Sstevel@tonic-gate /* 15920Sstevel@tonic-gate * Should we be checking/updating pw history here? 15930Sstevel@tonic-gate */ 15940Sstevel@tonic-gate if(pol.pw_history_num > 1) { 15950Sstevel@tonic-gate if(adb.admin_history_kvno != hist_kvno) { 15960Sstevel@tonic-gate ret = KADM5_BAD_HIST_KEY; 15970Sstevel@tonic-gate goto done; 15980Sstevel@tonic-gate } 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate if (ret = check_pw_reuse(handle->context, 16010Sstevel@tonic-gate &handle->master_keyblock, 16020Sstevel@tonic-gate &hist_key, 16030Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 16040Sstevel@tonic-gate adb.old_key_len, adb.old_keys)) 16050Sstevel@tonic-gate goto done; 16060Sstevel@tonic-gate } 16070Sstevel@tonic-gate #endif 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate if (pol.pw_max_life) 16100Sstevel@tonic-gate kdb.pw_expiration = now + pol.pw_max_life; 16110Sstevel@tonic-gate else 16120Sstevel@tonic-gate kdb.pw_expiration = 0; 16130Sstevel@tonic-gate } else { 16140Sstevel@tonic-gate kdb.pw_expiration = 0; 16150Sstevel@tonic-gate } 16160Sstevel@tonic-gate 1617*2881Smp153739 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) 1618*2881Smp153739 goto done; 16190Sstevel@tonic-gate 16200Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 16210Sstevel@tonic-gate goto done; 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate ret = KADM5_OK; 16240Sstevel@tonic-gate done: 16250Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 16260Sstevel@tonic-gate if (have_pol) 16270Sstevel@tonic-gate kadm5_free_policy_ent(handle->lhandle, &pol); 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate return ret; 16300Sstevel@tonic-gate } 16310Sstevel@tonic-gate 16320Sstevel@tonic-gate /* 16330Sstevel@tonic-gate * Allocate an array of n_key_data krb5_keyblocks, fill in each 16340Sstevel@tonic-gate * element with the results of decrypting the nth key in key_data with 16350Sstevel@tonic-gate * master_keyblock, and if n_keys is not NULL fill it in with the 16360Sstevel@tonic-gate * number of keys decrypted. 16370Sstevel@tonic-gate */ 16380Sstevel@tonic-gate static int decrypt_key_data(krb5_context context, 1639*2881Smp153739 krb5_keyblock *master_keyblock, 1640*2881Smp153739 int n_key_data, krb5_key_data *key_data, 1641*2881Smp153739 krb5_keyblock **keyblocks, int *n_keys) 16420Sstevel@tonic-gate { 16430Sstevel@tonic-gate krb5_keyblock *keys; 16440Sstevel@tonic-gate int ret, i; 16450Sstevel@tonic-gate 16460Sstevel@tonic-gate keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock)); 16470Sstevel@tonic-gate if (keys == NULL) 16480Sstevel@tonic-gate return ENOMEM; 16490Sstevel@tonic-gate memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); 16500Sstevel@tonic-gate 16510Sstevel@tonic-gate for (i = 0; i < n_key_data; i++) { 1652*2881Smp153739 ret = krb5_dbekd_decrypt_key_data(context, 1653*2881Smp153739 master_keyblock, 1654*2881Smp153739 &key_data[i], 1655*2881Smp153739 &keys[i], NULL); 1656*2881Smp153739 if (ret) { 16570Sstevel@tonic-gate 16580Sstevel@tonic-gate memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); 16590Sstevel@tonic-gate free(keys); 16600Sstevel@tonic-gate return ret; 16610Sstevel@tonic-gate } 16620Sstevel@tonic-gate } 16630Sstevel@tonic-gate 16640Sstevel@tonic-gate *keyblocks = keys; 16650Sstevel@tonic-gate if (n_keys) 16660Sstevel@tonic-gate *n_keys = n_key_data; 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate return 0; 16690Sstevel@tonic-gate } 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate /* 16720Sstevel@tonic-gate * Function: kadm5_decrypt_key 16730Sstevel@tonic-gate * 16740Sstevel@tonic-gate * Purpose: Retrieves and decrypts a principal key. 16750Sstevel@tonic-gate * 16760Sstevel@tonic-gate * Arguments: 16770Sstevel@tonic-gate * 16780Sstevel@tonic-gate * server_handle (r) kadm5 handle 16790Sstevel@tonic-gate * entry (r) principal retrieved with kadm5_get_principal 16800Sstevel@tonic-gate * ktype (r) enctype to search for, or -1 to ignore 16810Sstevel@tonic-gate * stype (r) salt type to search for, or -1 to ignore 16820Sstevel@tonic-gate * kvno (r) kvno to search for, -1 for max, 0 for max 16830Sstevel@tonic-gate * only if it also matches ktype and stype 16840Sstevel@tonic-gate * keyblock (w) keyblock to fill in 16850Sstevel@tonic-gate * keysalt (w) keysalt to fill in, or NULL 16860Sstevel@tonic-gate * kvnop (w) kvno to fill in, or NULL 16870Sstevel@tonic-gate * 16880Sstevel@tonic-gate * Effects: Searches the key_data array of entry, which must have been 16890Sstevel@tonic-gate * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to 16900Sstevel@tonic-gate * find a key with a specified enctype, salt type, and kvno in a 16910Sstevel@tonic-gate * principal entry. If not found, return ENOENT. Otherwise, decrypt 16920Sstevel@tonic-gate * it with the master key, and return the key in keyblock, the salt 16930Sstevel@tonic-gate * in salttype, and the key version number in kvno. 16940Sstevel@tonic-gate * 16950Sstevel@tonic-gate * If ktype or stype is -1, it is ignored for the search. If kvno is 16960Sstevel@tonic-gate * -1, ktype and stype are ignored and the key with the max kvno is 16970Sstevel@tonic-gate * returned. If kvno is 0, only the key with the max kvno is returned 16980Sstevel@tonic-gate * and only if it matches the ktype and stype; otherwise, ENOENT is 16990Sstevel@tonic-gate * returned. 17000Sstevel@tonic-gate */ 17010Sstevel@tonic-gate kadm5_ret_t kadm5_decrypt_key(void *server_handle, 17020Sstevel@tonic-gate kadm5_principal_ent_t entry, krb5_int32 17030Sstevel@tonic-gate ktype, krb5_int32 stype, krb5_int32 17040Sstevel@tonic-gate kvno, krb5_keyblock *keyblock, 17050Sstevel@tonic-gate krb5_keysalt *keysalt, int *kvnop) 17060Sstevel@tonic-gate { 17070Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 17080Sstevel@tonic-gate krb5_db_entry dbent; 17090Sstevel@tonic-gate krb5_key_data *key_data; 17100Sstevel@tonic-gate int ret; 17110Sstevel@tonic-gate 17120Sstevel@tonic-gate CHECK_HANDLE(server_handle); 17130Sstevel@tonic-gate 17140Sstevel@tonic-gate if (entry->n_key_data == 0 || entry->key_data == NULL) 17150Sstevel@tonic-gate return EINVAL; 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate /* find_enctype only uses these two fields */ 17180Sstevel@tonic-gate dbent.n_key_data = entry->n_key_data; 17190Sstevel@tonic-gate dbent.key_data = entry->key_data; 1720*2881Smp153739 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype, 1721*2881Smp153739 stype, kvno, &key_data))) 17220Sstevel@tonic-gate return ret; 17230Sstevel@tonic-gate 1724*2881Smp153739 if ((ret = krb5_dbekd_decrypt_key_data(handle->context, 1725*2881Smp153739 &handle->master_keyblock, key_data, 1726*2881Smp153739 keyblock, keysalt))) 17270Sstevel@tonic-gate return ret; 17280Sstevel@tonic-gate 17290Sstevel@tonic-gate if (kvnop) 17300Sstevel@tonic-gate *kvnop = key_data->key_data_kvno; 17310Sstevel@tonic-gate 17320Sstevel@tonic-gate return KADM5_OK; 17330Sstevel@tonic-gate } 1734