1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate /* 9*0Sstevel@tonic-gate * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 10*0Sstevel@tonic-gate * 11*0Sstevel@tonic-gate * Openvision retains the copyright to derivative works of 12*0Sstevel@tonic-gate * this source code. Do *NOT* create a derivative of this 13*0Sstevel@tonic-gate * source code before consulting with your legal department. 14*0Sstevel@tonic-gate * Do *NOT* integrate *ANY* of this source code into another 15*0Sstevel@tonic-gate * product before consulting with your legal department. 16*0Sstevel@tonic-gate * 17*0Sstevel@tonic-gate * For further information, read the top-level Openvision 18*0Sstevel@tonic-gate * copyright which is contained in the top-level MIT Kerberos 19*0Sstevel@tonic-gate * copyright. 20*0Sstevel@tonic-gate * 21*0Sstevel@tonic-gate * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 22*0Sstevel@tonic-gate * 23*0Sstevel@tonic-gate */ 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate 26*0Sstevel@tonic-gate /* 27*0Sstevel@tonic-gate * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 28*0Sstevel@tonic-gate * 29*0Sstevel@tonic-gate * $Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/svr_principal.c,v 1.19 2000/02/27 22:18:16 tlyu Exp $ 30*0Sstevel@tonic-gate */ 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #if !defined(lint) && !defined(__CODECENTER__) 33*0Sstevel@tonic-gate static char *rcsid = "$Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/svr_principal.c,v 1.19 2000/02/27 22:18:16 tlyu Exp $"; 34*0Sstevel@tonic-gate #endif 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate #include <sys/types.h> 37*0Sstevel@tonic-gate #include <sys/time.h> 38*0Sstevel@tonic-gate #include <kadm5/admin.h> 39*0Sstevel@tonic-gate #include "adb.h" 40*0Sstevel@tonic-gate #include "k5-int.h" 41*0Sstevel@tonic-gate #include <krb5/kdb.h> 42*0Sstevel@tonic-gate #include <stdio.h> 43*0Sstevel@tonic-gate #include <string.h> 44*0Sstevel@tonic-gate #include "server_internal.h" 45*0Sstevel@tonic-gate #include <stdarg.h> 46*0Sstevel@tonic-gate #include <stdlib.h> 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate extern krb5_principal master_princ; 49*0Sstevel@tonic-gate extern krb5_principal hist_princ; 50*0Sstevel@tonic-gate extern krb5_keyblock hist_key; 51*0Sstevel@tonic-gate extern krb5_db_entry master_db; 52*0Sstevel@tonic-gate extern krb5_db_entry hist_db; 53*0Sstevel@tonic-gate extern krb5_kvno hist_kvno; 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate extern kadm5_ret_t 56*0Sstevel@tonic-gate krb5_free_key_data_contents(krb5_context context, krb5_key_data *key); 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate static int decrypt_key_data(krb5_context context, 59*0Sstevel@tonic-gate krb5_keyblock *, int n_key_data, krb5_key_data *key_data, 60*0Sstevel@tonic-gate krb5_keyblock **keyblocks, int *n_keys); 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate /* 63*0Sstevel@tonic-gate * XXX Functions that ought to be in libkrb5.a, but aren't. 64*0Sstevel@tonic-gate */ 65*0Sstevel@tonic-gate kadm5_ret_t krb5_copy_key_data_contents(context, from, to) 66*0Sstevel@tonic-gate krb5_context context; 67*0Sstevel@tonic-gate krb5_key_data *from, *to; 68*0Sstevel@tonic-gate { 69*0Sstevel@tonic-gate int i, idx; 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate *to = *from; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate idx = (from->key_data_ver == 1 ? 1 : 2); 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate for (i = 0; i < idx; i++) { 76*0Sstevel@tonic-gate if ( from->key_data_length[i] ) { 77*0Sstevel@tonic-gate to->key_data_contents[i] = malloc(from->key_data_length[i]); 78*0Sstevel@tonic-gate if (to->key_data_contents[i] == NULL) { 79*0Sstevel@tonic-gate for (i = 0; i < idx; i++) { 80*0Sstevel@tonic-gate if (to->key_data_contents[i]) { 81*0Sstevel@tonic-gate memset(to->key_data_contents[i], 0, 82*0Sstevel@tonic-gate to->key_data_length[i]); 83*0Sstevel@tonic-gate free(to->key_data_contents[i]); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate } 86*0Sstevel@tonic-gate return ENOMEM; 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate memcpy(to->key_data_contents[i], from->key_data_contents[i], 89*0Sstevel@tonic-gate from->key_data_length[i]); 90*0Sstevel@tonic-gate } 91*0Sstevel@tonic-gate } 92*0Sstevel@tonic-gate return 0; 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate static krb5_tl_data *dup_tl_data(krb5_tl_data *tl) 96*0Sstevel@tonic-gate { 97*0Sstevel@tonic-gate krb5_tl_data *n; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)); 100*0Sstevel@tonic-gate if (n == NULL) 101*0Sstevel@tonic-gate return NULL; 102*0Sstevel@tonic-gate n->tl_data_contents = malloc(tl->tl_data_length); 103*0Sstevel@tonic-gate if (n->tl_data_contents == NULL) { 104*0Sstevel@tonic-gate free(n); 105*0Sstevel@tonic-gate return NULL; 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length); 108*0Sstevel@tonic-gate n->tl_data_type = tl->tl_data_type; 109*0Sstevel@tonic-gate n->tl_data_length = tl->tl_data_length; 110*0Sstevel@tonic-gate n->tl_data_next = NULL; 111*0Sstevel@tonic-gate return n; 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /* This is in lib/kdb/kdb_cpw.c, but is static */ 115*0Sstevel@tonic-gate static void cleanup_key_data(context, count, data) 116*0Sstevel@tonic-gate krb5_context context; 117*0Sstevel@tonic-gate int count; 118*0Sstevel@tonic-gate krb5_key_data * data; 119*0Sstevel@tonic-gate { 120*0Sstevel@tonic-gate int i, j; 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate for (i = 0; i < count; i++) 123*0Sstevel@tonic-gate for (j = 0; j < data[i].key_data_ver; j++) 124*0Sstevel@tonic-gate if (data[i].key_data_length[j]) 125*0Sstevel@tonic-gate free(data[i].key_data_contents[j]); 126*0Sstevel@tonic-gate free(data); 127*0Sstevel@tonic-gate } 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate kadm5_ret_t 130*0Sstevel@tonic-gate kadm5_create_principal(void *server_handle, 131*0Sstevel@tonic-gate kadm5_principal_ent_t entry, long mask, 132*0Sstevel@tonic-gate char *password) 133*0Sstevel@tonic-gate { 134*0Sstevel@tonic-gate /* 135*0Sstevel@tonic-gate * Default to using the new API with the default set of 136*0Sstevel@tonic-gate * key/salt combinations. 137*0Sstevel@tonic-gate */ 138*0Sstevel@tonic-gate return (kadm5_create_principal_3(server_handle, entry, mask, 139*0Sstevel@tonic-gate 0, NULL, password)); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate kadm5_ret_t 142*0Sstevel@tonic-gate kadm5_create_principal_3(void *server_handle, 143*0Sstevel@tonic-gate kadm5_principal_ent_t entry, long mask, 144*0Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 145*0Sstevel@tonic-gate char *password) 146*0Sstevel@tonic-gate { 147*0Sstevel@tonic-gate krb5_db_entry kdb; 148*0Sstevel@tonic-gate osa_princ_ent_rec adb; 149*0Sstevel@tonic-gate kadm5_policy_ent_rec polent; 150*0Sstevel@tonic-gate krb5_int32 now; 151*0Sstevel@tonic-gate krb5_tl_data *tl_data_orig, *tl_data_tail; 152*0Sstevel@tonic-gate unsigned int ret; 153*0Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate CHECK_HANDLE(server_handle); 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate /* 158*0Sstevel@tonic-gate * Argument sanity checking, and opening up the DB 159*0Sstevel@tonic-gate */ 160*0Sstevel@tonic-gate if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) || 161*0Sstevel@tonic-gate (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) || 162*0Sstevel@tonic-gate (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) || 163*0Sstevel@tonic-gate (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) || 164*0Sstevel@tonic-gate (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) || 165*0Sstevel@tonic-gate (mask & KADM5_FAIL_AUTH_COUNT)) 166*0Sstevel@tonic-gate return KADM5_BAD_MASK; 167*0Sstevel@tonic-gate if((mask & ~ALL_PRINC_MASK)) 168*0Sstevel@tonic-gate return KADM5_BAD_MASK; 169*0Sstevel@tonic-gate if (entry == (kadm5_principal_ent_t) NULL || password == NULL) 170*0Sstevel@tonic-gate return EINVAL; 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate /* 173*0Sstevel@tonic-gate * Check to see if the principal exists 174*0Sstevel@tonic-gate */ 175*0Sstevel@tonic-gate ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate switch(ret) { 178*0Sstevel@tonic-gate case KADM5_UNK_PRINC: 179*0Sstevel@tonic-gate break; 180*0Sstevel@tonic-gate case 0: 181*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 182*0Sstevel@tonic-gate return KADM5_DUP; 183*0Sstevel@tonic-gate default: 184*0Sstevel@tonic-gate return ret; 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate memset(&kdb, 0, sizeof(krb5_db_entry)); 188*0Sstevel@tonic-gate memset(&adb, 0, sizeof(osa_princ_ent_rec)); 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate /* 191*0Sstevel@tonic-gate * If a policy was specified, load it. 192*0Sstevel@tonic-gate * If we can not find the one specified return an error 193*0Sstevel@tonic-gate */ 194*0Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 195*0Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, entry->policy, 196*0Sstevel@tonic-gate &polent)) != KADM5_OK) { 197*0Sstevel@tonic-gate if(ret == EINVAL) 198*0Sstevel@tonic-gate return KADM5_BAD_POLICY; 199*0Sstevel@tonic-gate else 200*0Sstevel@tonic-gate return ret; 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate if (ret = passwd_check(handle, password, (mask & KADM5_POLICY), 204*0Sstevel@tonic-gate &polent, entry->principal)) { 205*0Sstevel@tonic-gate if (mask & KADM5_POLICY) 206*0Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 207*0Sstevel@tonic-gate return ret; 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * Start populating the various DB fields, using the 211*0Sstevel@tonic-gate * "defaults" for fields that were not specified by the 212*0Sstevel@tonic-gate * mask. 213*0Sstevel@tonic-gate */ 214*0Sstevel@tonic-gate if (ret = krb5_timeofday(handle->context, &now)) { 215*0Sstevel@tonic-gate if (mask & KADM5_POLICY) 216*0Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 217*0Sstevel@tonic-gate return ret; 218*0Sstevel@tonic-gate } 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate kdb.magic = KRB5_KDB_MAGIC_NUMBER; 221*0Sstevel@tonic-gate kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */ 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate /* 224*0Sstevel@tonic-gate * If KADM5_ATTRIBUTES is set, we want to rope in not only 225*0Sstevel@tonic-gate * entry->attributes, but also the generic params.flags 226*0Sstevel@tonic-gate * obtained previously via kadm5_get_config_params. 227*0Sstevel@tonic-gate */ 228*0Sstevel@tonic-gate if ((mask & KADM5_ATTRIBUTES)) { 229*0Sstevel@tonic-gate kdb.attributes = handle->params.flags; 230*0Sstevel@tonic-gate kdb.attributes |= entry->attributes; 231*0Sstevel@tonic-gate } else { 232*0Sstevel@tonic-gate kdb.attributes = handle->params.flags; 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate if ((mask & KADM5_MAX_LIFE)) 236*0Sstevel@tonic-gate kdb.max_life = entry->max_life; 237*0Sstevel@tonic-gate else 238*0Sstevel@tonic-gate kdb.max_life = handle->params.max_life; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate if (mask & KADM5_MAX_RLIFE) 241*0Sstevel@tonic-gate kdb.max_renewable_life = entry->max_renewable_life; 242*0Sstevel@tonic-gate else 243*0Sstevel@tonic-gate kdb.max_renewable_life = handle->params.max_rlife; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate if ((mask & KADM5_PRINC_EXPIRE_TIME)) 246*0Sstevel@tonic-gate kdb.expiration = entry->princ_expire_time; 247*0Sstevel@tonic-gate else 248*0Sstevel@tonic-gate kdb.expiration = handle->params.expiration; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate kdb.pw_expiration = 0; 251*0Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 252*0Sstevel@tonic-gate if(polent.pw_max_life) 253*0Sstevel@tonic-gate kdb.pw_expiration = now + polent.pw_max_life; 254*0Sstevel@tonic-gate else 255*0Sstevel@tonic-gate kdb.pw_expiration = 0; 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate if ((mask & KADM5_PW_EXPIRATION)) 258*0Sstevel@tonic-gate kdb.pw_expiration = entry->pw_expiration; 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate kdb.last_success = 0; 261*0Sstevel@tonic-gate kdb.last_failed = 0; 262*0Sstevel@tonic-gate kdb.fail_auth_count = 0; 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate /* this is kind of gross, but in order to free the tl data, I need 265*0Sstevel@tonic-gate to free the entire kdb entry, and that will try to free the 266*0Sstevel@tonic-gate principal. */ 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate if (ret = krb5_copy_principal(handle->context, 269*0Sstevel@tonic-gate entry->principal, &(kdb.princ))) { 270*0Sstevel@tonic-gate if (mask & KADM5_POLICY) 271*0Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 272*0Sstevel@tonic-gate return(ret); 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate if (ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)) { 276*0Sstevel@tonic-gate krb5_dbe_free_contents(handle->context, &kdb); 277*0Sstevel@tonic-gate if (mask & KADM5_POLICY) 278*0Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 279*0Sstevel@tonic-gate return(ret); 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate /* initialize the keys */ 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate if (ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, 285*0Sstevel@tonic-gate n_ks_tuple?ks_tuple:handle->params.keysalts, 286*0Sstevel@tonic-gate n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 287*0Sstevel@tonic-gate password, 288*0Sstevel@tonic-gate (mask & KADM5_KVNO)?entry->kvno:1, 289*0Sstevel@tonic-gate FALSE, &kdb)) { 290*0Sstevel@tonic-gate krb5_dbe_free_contents(handle->context, &kdb); 291*0Sstevel@tonic-gate if (mask & KADM5_POLICY) 292*0Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 293*0Sstevel@tonic-gate return(ret); 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate /* populate the admin-server-specific fields. In the OV server, 297*0Sstevel@tonic-gate this used to be in a separate database. Since there's already 298*0Sstevel@tonic-gate marshalling code for the admin fields, to keep things simple, 299*0Sstevel@tonic-gate I'm going to keep it, and make all the admin stuff occupy a 300*0Sstevel@tonic-gate single tl_data record, */ 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate adb.admin_history_kvno = hist_kvno; 303*0Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 304*0Sstevel@tonic-gate adb.aux_attributes = KADM5_POLICY; 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate /* this does *not* need to be strdup'ed, because adb is xdr */ 307*0Sstevel@tonic-gate /* encoded in osa_adb_create_princ, and not ever freed */ 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate adb.policy = entry->policy; 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate /* increment the policy ref count, if any */ 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 315*0Sstevel@tonic-gate polent.policy_refcnt++; 316*0Sstevel@tonic-gate if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, 317*0Sstevel@tonic-gate KADM5_REF_COUNT)) 318*0Sstevel@tonic-gate != KADM5_OK) { 319*0Sstevel@tonic-gate krb5_dbe_free_contents(handle->context, &kdb); 320*0Sstevel@tonic-gate if (mask & KADM5_POLICY) 321*0Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 322*0Sstevel@tonic-gate return(ret); 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 327*0Sstevel@tonic-gate /* splice entry->tl_data onto the front of kdb.tl_data */ 328*0Sstevel@tonic-gate tl_data_orig = kdb.tl_data; 329*0Sstevel@tonic-gate for (tl_data_tail = entry->tl_data; tl_data_tail->tl_data_next; 330*0Sstevel@tonic-gate tl_data_tail = tl_data_tail->tl_data_next) 331*0Sstevel@tonic-gate ; 332*0Sstevel@tonic-gate tl_data_tail->tl_data_next = kdb.tl_data; 333*0Sstevel@tonic-gate kdb.tl_data = entry->tl_data; 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate /* store the new db entry */ 337*0Sstevel@tonic-gate ret = kdb_put_entry(handle, &kdb, &adb); 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 340*0Sstevel@tonic-gate /* remove entry->tl_data from the front of kdb.tl_data */ 341*0Sstevel@tonic-gate tl_data_tail->tl_data_next = NULL; 342*0Sstevel@tonic-gate kdb.tl_data = tl_data_orig; 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate krb5_dbe_free_contents(handle->context, &kdb); 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate if (ret) { 348*0Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 349*0Sstevel@tonic-gate /* decrement the policy ref count */ 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate polent.policy_refcnt--; 352*0Sstevel@tonic-gate /* 353*0Sstevel@tonic-gate * if this fails, there's nothing we can do anyway. the 354*0Sstevel@tonic-gate * policy refcount wil be too high. 355*0Sstevel@tonic-gate */ 356*0Sstevel@tonic-gate (void) kadm5_modify_policy_internal(handle->lhandle, &polent, 357*0Sstevel@tonic-gate KADM5_REF_COUNT); 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate if (mask & KADM5_POLICY) 361*0Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 362*0Sstevel@tonic-gate return(ret); 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate if (mask & KADM5_POLICY) 366*0Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate return KADM5_OK; 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate kadm5_ret_t 373*0Sstevel@tonic-gate kadm5_delete_principal(void *server_handle, krb5_principal principal) 374*0Sstevel@tonic-gate { 375*0Sstevel@tonic-gate unsigned int ret; 376*0Sstevel@tonic-gate kadm5_policy_ent_rec polent; 377*0Sstevel@tonic-gate krb5_db_entry kdb; 378*0Sstevel@tonic-gate osa_princ_ent_rec adb; 379*0Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate CHECK_HANDLE(server_handle); 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate if (principal == NULL) 384*0Sstevel@tonic-gate return EINVAL; 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate if (ret = kdb_get_entry(handle, principal, &kdb, &adb)) 387*0Sstevel@tonic-gate return(ret); 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 390*0Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, 391*0Sstevel@tonic-gate adb.policy, &polent)) 392*0Sstevel@tonic-gate == KADM5_OK) { 393*0Sstevel@tonic-gate polent.policy_refcnt--; 394*0Sstevel@tonic-gate if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, 395*0Sstevel@tonic-gate KADM5_REF_COUNT)) 396*0Sstevel@tonic-gate != KADM5_OK) { 397*0Sstevel@tonic-gate (void) kadm5_free_policy_ent(handle->lhandle, &polent); 398*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 399*0Sstevel@tonic-gate return(ret); 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate } 402*0Sstevel@tonic-gate if (ret = kadm5_free_policy_ent(handle->lhandle, &polent)) { 403*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 404*0Sstevel@tonic-gate return ret; 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate ret = kdb_delete_entry(handle, principal); 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate return ret; 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate kadm5_ret_t 416*0Sstevel@tonic-gate kadm5_modify_principal(void *server_handle, 417*0Sstevel@tonic-gate kadm5_principal_ent_t entry, long mask) 418*0Sstevel@tonic-gate { 419*0Sstevel@tonic-gate int ret, ret2, i; 420*0Sstevel@tonic-gate kadm5_policy_ent_rec npol, opol; 421*0Sstevel@tonic-gate int have_npol = 0, have_opol = 0; 422*0Sstevel@tonic-gate krb5_db_entry kdb; 423*0Sstevel@tonic-gate krb5_tl_data *tl_data_orig, *tl_data_tail; 424*0Sstevel@tonic-gate osa_princ_ent_rec adb; 425*0Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate CHECK_HANDLE(server_handle); 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) || 430*0Sstevel@tonic-gate (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) || 431*0Sstevel@tonic-gate (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) || 432*0Sstevel@tonic-gate (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) || 433*0Sstevel@tonic-gate (mask & KADM5_LAST_FAILED)) 434*0Sstevel@tonic-gate return KADM5_BAD_MASK; 435*0Sstevel@tonic-gate if((mask & ~ALL_PRINC_MASK)) 436*0Sstevel@tonic-gate return KADM5_BAD_MASK; 437*0Sstevel@tonic-gate if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR)) 438*0Sstevel@tonic-gate return KADM5_BAD_MASK; 439*0Sstevel@tonic-gate if(entry == (kadm5_principal_ent_t) NULL) 440*0Sstevel@tonic-gate return EINVAL; 441*0Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 442*0Sstevel@tonic-gate tl_data_orig = entry->tl_data; 443*0Sstevel@tonic-gate while (tl_data_orig) { 444*0Sstevel@tonic-gate if (tl_data_orig->tl_data_type < 256) 445*0Sstevel@tonic-gate return KADM5_BAD_TL_TYPE; 446*0Sstevel@tonic-gate tl_data_orig = tl_data_orig->tl_data_next; 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate if (ret = kdb_get_entry(handle, entry->principal, &kdb, &adb)) 451*0Sstevel@tonic-gate return(ret); 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate /* 454*0Sstevel@tonic-gate * This is pretty much the same as create ... 455*0Sstevel@tonic-gate */ 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate if ((mask & KADM5_POLICY)) { 458*0Sstevel@tonic-gate /* get the new policy */ 459*0Sstevel@tonic-gate ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol); 460*0Sstevel@tonic-gate if (ret) { 461*0Sstevel@tonic-gate switch (ret) { 462*0Sstevel@tonic-gate case EINVAL: 463*0Sstevel@tonic-gate ret = KADM5_BAD_POLICY; 464*0Sstevel@tonic-gate break; 465*0Sstevel@tonic-gate case KADM5_UNK_POLICY: 466*0Sstevel@tonic-gate case KADM5_BAD_POLICY: 467*0Sstevel@tonic-gate ret = KADM5_UNK_POLICY; 468*0Sstevel@tonic-gate break; 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate goto done; 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate have_npol = 1; 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate /* if we already have a policy, get it to decrement the refcnt */ 475*0Sstevel@tonic-gate if(adb.aux_attributes & KADM5_POLICY) { 476*0Sstevel@tonic-gate /* ... but not if the old and new are the same */ 477*0Sstevel@tonic-gate if(strcmp(adb.policy, entry->policy)) { 478*0Sstevel@tonic-gate ret = kadm5_get_policy(handle->lhandle, 479*0Sstevel@tonic-gate adb.policy, &opol); 480*0Sstevel@tonic-gate switch(ret) { 481*0Sstevel@tonic-gate case EINVAL: 482*0Sstevel@tonic-gate case KADM5_BAD_POLICY: 483*0Sstevel@tonic-gate case KADM5_UNK_POLICY: 484*0Sstevel@tonic-gate break; 485*0Sstevel@tonic-gate case KADM5_OK: 486*0Sstevel@tonic-gate have_opol = 1; 487*0Sstevel@tonic-gate opol.policy_refcnt--; 488*0Sstevel@tonic-gate break; 489*0Sstevel@tonic-gate default: 490*0Sstevel@tonic-gate goto done; 491*0Sstevel@tonic-gate } 492*0Sstevel@tonic-gate npol.policy_refcnt++; 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate } else npol.policy_refcnt++; 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate /* set us up to use the new policy */ 497*0Sstevel@tonic-gate adb.aux_attributes |= KADM5_POLICY; 498*0Sstevel@tonic-gate if (adb.policy) 499*0Sstevel@tonic-gate free(adb.policy); 500*0Sstevel@tonic-gate adb.policy = strdup(entry->policy); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate /* set pw_max_life based on new policy */ 503*0Sstevel@tonic-gate if (npol.pw_max_life) { 504*0Sstevel@tonic-gate if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, 505*0Sstevel@tonic-gate &(kdb.pw_expiration))) 506*0Sstevel@tonic-gate goto done; 507*0Sstevel@tonic-gate kdb.pw_expiration += npol.pw_max_life; 508*0Sstevel@tonic-gate } else { 509*0Sstevel@tonic-gate kdb.pw_expiration = 0; 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate if ((mask & KADM5_POLICY_CLR) && 514*0Sstevel@tonic-gate (adb.aux_attributes & KADM5_POLICY)) { 515*0Sstevel@tonic-gate ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol); 516*0Sstevel@tonic-gate switch(ret) { 517*0Sstevel@tonic-gate case EINVAL: 518*0Sstevel@tonic-gate case KADM5_BAD_POLICY: 519*0Sstevel@tonic-gate case KADM5_UNK_POLICY: 520*0Sstevel@tonic-gate ret = KADM5_BAD_DB; 521*0Sstevel@tonic-gate goto done; 522*0Sstevel@tonic-gate case KADM5_OK: 523*0Sstevel@tonic-gate have_opol = 1; 524*0Sstevel@tonic-gate if (adb.policy) 525*0Sstevel@tonic-gate free(adb.policy); 526*0Sstevel@tonic-gate adb.policy = NULL; 527*0Sstevel@tonic-gate adb.aux_attributes &= ~KADM5_POLICY; 528*0Sstevel@tonic-gate kdb.pw_expiration = 0; 529*0Sstevel@tonic-gate opol.policy_refcnt--; 530*0Sstevel@tonic-gate break; 531*0Sstevel@tonic-gate default: 532*0Sstevel@tonic-gate goto done; 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) && 537*0Sstevel@tonic-gate (((have_opol) && 538*0Sstevel@tonic-gate (ret = 539*0Sstevel@tonic-gate kadm5_modify_policy_internal(handle->lhandle, &opol, 540*0Sstevel@tonic-gate KADM5_REF_COUNT))) || 541*0Sstevel@tonic-gate ((have_npol) && 542*0Sstevel@tonic-gate (ret = 543*0Sstevel@tonic-gate kadm5_modify_policy_internal(handle->lhandle, &npol, 544*0Sstevel@tonic-gate KADM5_REF_COUNT))))) 545*0Sstevel@tonic-gate goto done; 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate if ((mask & KADM5_ATTRIBUTES)) 548*0Sstevel@tonic-gate kdb.attributes = entry->attributes; 549*0Sstevel@tonic-gate if ((mask & KADM5_MAX_LIFE)) 550*0Sstevel@tonic-gate kdb.max_life = entry->max_life; 551*0Sstevel@tonic-gate if ((mask & KADM5_PRINC_EXPIRE_TIME)) 552*0Sstevel@tonic-gate kdb.expiration = entry->princ_expire_time; 553*0Sstevel@tonic-gate if (mask & KADM5_PW_EXPIRATION) 554*0Sstevel@tonic-gate kdb.pw_expiration = entry->pw_expiration; 555*0Sstevel@tonic-gate if (mask & KADM5_MAX_RLIFE) 556*0Sstevel@tonic-gate kdb.max_renewable_life = entry->max_renewable_life; 557*0Sstevel@tonic-gate if (mask & KADM5_FAIL_AUTH_COUNT) 558*0Sstevel@tonic-gate kdb.fail_auth_count = entry->fail_auth_count; 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate if((mask & KADM5_KVNO)) { 561*0Sstevel@tonic-gate for (i = 0; i < kdb.n_key_data; i++) 562*0Sstevel@tonic-gate kdb.key_data[i].key_data_kvno = entry->kvno; 563*0Sstevel@tonic-gate } 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 566*0Sstevel@tonic-gate krb5_tl_data *tl, *tl2; 567*0Sstevel@tonic-gate /* 568*0Sstevel@tonic-gate * Replace kdb.tl_data with what was passed in. The 569*0Sstevel@tonic-gate * KRB5_TL_KADM_DATA will be re-added (based on adb) by 570*0Sstevel@tonic-gate * kdb_put_entry, below. 571*0Sstevel@tonic-gate * 572*0Sstevel@tonic-gate * Note that we have to duplicate the passed in tl_data 573*0Sstevel@tonic-gate * before adding it to kdb. The reason is that kdb_put_entry 574*0Sstevel@tonic-gate * will add its own tl_data entries that we will need to 575*0Sstevel@tonic-gate * free, but we cannot free the caller's tl_data (an 576*0Sstevel@tonic-gate * alternative would be to scan the tl_data after put_entry 577*0Sstevel@tonic-gate * and only free those entries that were not passed in). 578*0Sstevel@tonic-gate */ 579*0Sstevel@tonic-gate while (kdb.tl_data) { 580*0Sstevel@tonic-gate tl = kdb.tl_data->tl_data_next; 581*0Sstevel@tonic-gate free(kdb.tl_data->tl_data_contents); 582*0Sstevel@tonic-gate free(kdb.tl_data); 583*0Sstevel@tonic-gate kdb.tl_data = tl; 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate kdb.n_tl_data = entry->n_tl_data; 587*0Sstevel@tonic-gate kdb.tl_data = NULL; 588*0Sstevel@tonic-gate tl2 = entry->tl_data; 589*0Sstevel@tonic-gate while (tl2) { 590*0Sstevel@tonic-gate tl = dup_tl_data(tl2); 591*0Sstevel@tonic-gate tl->tl_data_next = kdb.tl_data; 592*0Sstevel@tonic-gate kdb.tl_data = tl; 593*0Sstevel@tonic-gate tl2 = tl2->tl_data_next; 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate ret = kdb_put_entry(handle, &kdb, &adb); 598*0Sstevel@tonic-gate if (ret) goto done; 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate ret = KADM5_OK; 601*0Sstevel@tonic-gate done: 602*0Sstevel@tonic-gate if (have_opol) { 603*0Sstevel@tonic-gate ret2 = kadm5_free_policy_ent(handle->lhandle, &opol); 604*0Sstevel@tonic-gate ret = ret ? ret : ret2; 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate if (have_npol) { 607*0Sstevel@tonic-gate ret2 = kadm5_free_policy_ent(handle->lhandle, &npol); 608*0Sstevel@tonic-gate ret = ret ? ret : ret2; 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 611*0Sstevel@tonic-gate return ret; 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate kadm5_ret_t 615*0Sstevel@tonic-gate kadm5_rename_principal(void *server_handle, 616*0Sstevel@tonic-gate krb5_principal source, krb5_principal target) 617*0Sstevel@tonic-gate { 618*0Sstevel@tonic-gate krb5_db_entry kdb; 619*0Sstevel@tonic-gate osa_princ_ent_rec adb; 620*0Sstevel@tonic-gate int ret, i; 621*0Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate CHECK_HANDLE(server_handle); 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate if (source == NULL || target == NULL) 626*0Sstevel@tonic-gate return EINVAL; 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) { 629*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 630*0Sstevel@tonic-gate return(KADM5_DUP); 631*0Sstevel@tonic-gate } 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, source, &kdb, &adb))) 634*0Sstevel@tonic-gate return ret; 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate /* this is kinda gross, but unavoidable */ 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate for (i=0; i<kdb.n_key_data; i++) { 639*0Sstevel@tonic-gate if ((kdb.key_data[i].key_data_ver == 1) || 640*0Sstevel@tonic-gate (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) { 641*0Sstevel@tonic-gate ret = KADM5_NO_RENAME_SALT; 642*0Sstevel@tonic-gate goto done; 643*0Sstevel@tonic-gate } 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate krb5_free_principal(handle->context, kdb.princ); 647*0Sstevel@tonic-gate if (ret = krb5_copy_principal(handle->context, target, &kdb.princ)) { 648*0Sstevel@tonic-gate kdb.princ = NULL; /* so freeing the dbe doesn't lose */ 649*0Sstevel@tonic-gate goto done; 650*0Sstevel@tonic-gate } 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 653*0Sstevel@tonic-gate goto done; 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate ret = kdb_delete_entry(handle, source); 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate done: 658*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 659*0Sstevel@tonic-gate return ret; 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate kadm5_ret_t 663*0Sstevel@tonic-gate kadm5_get_principal(void *server_handle, krb5_principal principal, 664*0Sstevel@tonic-gate kadm5_principal_ent_t entry, 665*0Sstevel@tonic-gate long in_mask) 666*0Sstevel@tonic-gate { 667*0Sstevel@tonic-gate krb5_db_entry kdb; 668*0Sstevel@tonic-gate osa_princ_ent_rec adb; 669*0Sstevel@tonic-gate osa_adb_ret_t ret = 0; 670*0Sstevel@tonic-gate long mask; 671*0Sstevel@tonic-gate int i; 672*0Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 673*0Sstevel@tonic-gate kadm5_principal_ent_rec entry_local, *entry_orig; 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate CHECK_HANDLE(server_handle); 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate /* 678*0Sstevel@tonic-gate * In version 1, all the defined fields are always returned. 679*0Sstevel@tonic-gate * entry is a pointer to a kadm5_principal_ent_t_v1 that should be 680*0Sstevel@tonic-gate * filled with allocated memory. 681*0Sstevel@tonic-gate */ 682*0Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_1) { 683*0Sstevel@tonic-gate mask = KADM5_PRINCIPAL_NORMAL_MASK; 684*0Sstevel@tonic-gate entry_orig = entry; 685*0Sstevel@tonic-gate entry = &entry_local; 686*0Sstevel@tonic-gate } else { 687*0Sstevel@tonic-gate mask = in_mask; 688*0Sstevel@tonic-gate } 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate memset((char *) entry, 0, sizeof(*entry)); 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate if (principal == NULL) 693*0Sstevel@tonic-gate return EINVAL; 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 696*0Sstevel@tonic-gate return ret; 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate if ((mask & KADM5_POLICY) && 699*0Sstevel@tonic-gate adb.policy && (adb.aux_attributes & KADM5_POLICY)) { 700*0Sstevel@tonic-gate if ((entry->policy = (char *) malloc(strlen(adb.policy) + 1)) == NULL) { 701*0Sstevel@tonic-gate ret = ENOMEM; 702*0Sstevel@tonic-gate goto done; 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate strcpy(entry->policy, adb.policy); 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate if (mask & KADM5_AUX_ATTRIBUTES) 708*0Sstevel@tonic-gate entry->aux_attributes = adb.aux_attributes; 709*0Sstevel@tonic-gate 710*0Sstevel@tonic-gate if ((mask & KADM5_PRINCIPAL) && 711*0Sstevel@tonic-gate (ret = krb5_copy_principal(handle->context, principal, 712*0Sstevel@tonic-gate &entry->principal))) { 713*0Sstevel@tonic-gate goto done; 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate if (mask & KADM5_PRINC_EXPIRE_TIME) 717*0Sstevel@tonic-gate entry->princ_expire_time = kdb.expiration; 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate if ((mask & KADM5_LAST_PWD_CHANGE) && 720*0Sstevel@tonic-gate (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, 721*0Sstevel@tonic-gate &(entry->last_pwd_change)))) { 722*0Sstevel@tonic-gate goto done; 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate if (mask & KADM5_PW_EXPIRATION) 726*0Sstevel@tonic-gate entry->pw_expiration = kdb.pw_expiration; 727*0Sstevel@tonic-gate if (mask & KADM5_MAX_LIFE) 728*0Sstevel@tonic-gate entry->max_life = kdb.max_life; 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate /* this is a little non-sensical because the function returns two */ 731*0Sstevel@tonic-gate /* values that must be checked separately against the mask */ 732*0Sstevel@tonic-gate if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) { 733*0Sstevel@tonic-gate if (ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb, 734*0Sstevel@tonic-gate &(entry->mod_date), 735*0Sstevel@tonic-gate &(entry->mod_name))) { 736*0Sstevel@tonic-gate goto done; 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate if (! (mask & KADM5_MOD_TIME)) 739*0Sstevel@tonic-gate entry->mod_date = 0; 740*0Sstevel@tonic-gate if (! (mask & KADM5_MOD_NAME)) { 741*0Sstevel@tonic-gate krb5_free_principal(handle->context, entry->principal); 742*0Sstevel@tonic-gate entry->principal = NULL; 743*0Sstevel@tonic-gate } 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate if (mask & KADM5_ATTRIBUTES) 747*0Sstevel@tonic-gate entry->attributes = kdb.attributes; 748*0Sstevel@tonic-gate 749*0Sstevel@tonic-gate if (mask & KADM5_KVNO) 750*0Sstevel@tonic-gate for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++) 751*0Sstevel@tonic-gate if (kdb.key_data[i].key_data_kvno > entry->kvno) 752*0Sstevel@tonic-gate entry->kvno = kdb.key_data[i].key_data_kvno; 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_2) 755*0Sstevel@tonic-gate entry->mkvno = 0; 756*0Sstevel@tonic-gate else { 757*0Sstevel@tonic-gate /* XXX I'll be damned if I know how to deal with this one --marc */ 758*0Sstevel@tonic-gate entry->mkvno = 1; 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate /* 762*0Sstevel@tonic-gate * The new fields that only exist in version 2 start here 763*0Sstevel@tonic-gate */ 764*0Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_2) { 765*0Sstevel@tonic-gate if (mask & KADM5_MAX_RLIFE) 766*0Sstevel@tonic-gate entry->max_renewable_life = kdb.max_renewable_life; 767*0Sstevel@tonic-gate if (mask & KADM5_LAST_SUCCESS) 768*0Sstevel@tonic-gate entry->last_success = kdb.last_success; 769*0Sstevel@tonic-gate if (mask & KADM5_LAST_FAILED) 770*0Sstevel@tonic-gate entry->last_failed = kdb.last_failed; 771*0Sstevel@tonic-gate if (mask & KADM5_FAIL_AUTH_COUNT) 772*0Sstevel@tonic-gate entry->fail_auth_count = kdb.fail_auth_count; 773*0Sstevel@tonic-gate if (mask & KADM5_TL_DATA) { 774*0Sstevel@tonic-gate krb5_tl_data td, *tl, *tl2; 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate entry->tl_data = NULL; 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate tl = kdb.tl_data; 779*0Sstevel@tonic-gate while (tl) { 780*0Sstevel@tonic-gate if (tl->tl_data_type > 255) { 781*0Sstevel@tonic-gate if ((tl2 = dup_tl_data(tl)) == NULL) { 782*0Sstevel@tonic-gate ret = ENOMEM; 783*0Sstevel@tonic-gate goto done; 784*0Sstevel@tonic-gate } 785*0Sstevel@tonic-gate tl2->tl_data_next = entry->tl_data; 786*0Sstevel@tonic-gate entry->tl_data = tl2; 787*0Sstevel@tonic-gate entry->n_tl_data++; 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate tl = tl->tl_data_next; 791*0Sstevel@tonic-gate } 792*0Sstevel@tonic-gate } 793*0Sstevel@tonic-gate if (mask & KADM5_KEY_DATA) { 794*0Sstevel@tonic-gate entry->n_key_data = kdb.n_key_data; 795*0Sstevel@tonic-gate if(entry->n_key_data) { 796*0Sstevel@tonic-gate entry->key_data = (krb5_key_data *) 797*0Sstevel@tonic-gate malloc(entry->n_key_data*sizeof(krb5_key_data)); 798*0Sstevel@tonic-gate if (entry->key_data == NULL) { 799*0Sstevel@tonic-gate ret = ENOMEM; 800*0Sstevel@tonic-gate goto done; 801*0Sstevel@tonic-gate } 802*0Sstevel@tonic-gate } else 803*0Sstevel@tonic-gate entry->key_data = NULL; 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate for (i = 0; i < entry->n_key_data; i++) 806*0Sstevel@tonic-gate if (ret = krb5_copy_key_data_contents(handle->context, 807*0Sstevel@tonic-gate &kdb.key_data[i], 808*0Sstevel@tonic-gate &entry->key_data[i])) 809*0Sstevel@tonic-gate goto done; 810*0Sstevel@tonic-gate } 811*0Sstevel@tonic-gate } 812*0Sstevel@tonic-gate 813*0Sstevel@tonic-gate /* 814*0Sstevel@tonic-gate * If KADM5_API_VERSION_1, we return an allocated structure, and 815*0Sstevel@tonic-gate * we need to convert the new structure back into the format the 816*0Sstevel@tonic-gate * caller is expecting. 817*0Sstevel@tonic-gate */ 818*0Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_1) { 819*0Sstevel@tonic-gate kadm5_principal_ent_t_v1 newv1; 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1))); 822*0Sstevel@tonic-gate if (newv1 == NULL) { 823*0Sstevel@tonic-gate ret = ENOMEM; 824*0Sstevel@tonic-gate goto done; 825*0Sstevel@tonic-gate } 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate newv1->principal = entry->principal; 828*0Sstevel@tonic-gate newv1->princ_expire_time = entry->princ_expire_time; 829*0Sstevel@tonic-gate newv1->last_pwd_change = entry->last_pwd_change; 830*0Sstevel@tonic-gate newv1->pw_expiration = entry->pw_expiration; 831*0Sstevel@tonic-gate newv1->max_life = entry->max_life; 832*0Sstevel@tonic-gate newv1->mod_name = entry->mod_name; 833*0Sstevel@tonic-gate newv1->mod_date = entry->mod_date; 834*0Sstevel@tonic-gate newv1->attributes = entry->attributes; 835*0Sstevel@tonic-gate newv1->kvno = entry->kvno; 836*0Sstevel@tonic-gate newv1->mkvno = entry->mkvno; 837*0Sstevel@tonic-gate newv1->policy = entry->policy; 838*0Sstevel@tonic-gate newv1->aux_attributes = entry->aux_attributes; 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gate *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1; 841*0Sstevel@tonic-gate } 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate ret = KADM5_OK; 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate done: 846*0Sstevel@tonic-gate if (ret && entry->principal) 847*0Sstevel@tonic-gate krb5_free_principal(handle->context, entry->principal); 848*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gate return ret; 851*0Sstevel@tonic-gate } 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate /* 854*0Sstevel@tonic-gate * Function: check_pw_reuse 855*0Sstevel@tonic-gate * 856*0Sstevel@tonic-gate * Purpose: Check if a key appears in a list of keys, in order to 857*0Sstevel@tonic-gate * enforce password history. 858*0Sstevel@tonic-gate * 859*0Sstevel@tonic-gate * Arguments: 860*0Sstevel@tonic-gate * 861*0Sstevel@tonic-gate * context (r) the krb5 context 862*0Sstevel@tonic-gate * hist_keyblock (r) the key that hist_key_data is 863*0Sstevel@tonic-gate * encrypted in 864*0Sstevel@tonic-gate * n_new_key_data (r) length of new_key_data 865*0Sstevel@tonic-gate * new_key_data (r) keys to check against 866*0Sstevel@tonic-gate * pw_hist_data, encrypted in hist_keyblock 867*0Sstevel@tonic-gate * n_pw_hist_data (r) length of pw_hist_data 868*0Sstevel@tonic-gate * pw_hist_data (r) passwords to check new_key_data against 869*0Sstevel@tonic-gate * 870*0Sstevel@tonic-gate * Effects: 871*0Sstevel@tonic-gate * For each new_key in new_key_data: 872*0Sstevel@tonic-gate * decrypt new_key with the master_keyblock 873*0Sstevel@tonic-gate * for each password in pw_hist_data: 874*0Sstevel@tonic-gate * for each hist_key in password: 875*0Sstevel@tonic-gate * decrypt hist_key with hist_keyblock 876*0Sstevel@tonic-gate * compare the new_key and hist_key 877*0Sstevel@tonic-gate * 878*0Sstevel@tonic-gate * Returns krb5 errors, KADM5_PASS_RESUSE if a key in 879*0Sstevel@tonic-gate * new_key_data is the same as a key in pw_hist_data, or 0. 880*0Sstevel@tonic-gate */ 881*0Sstevel@tonic-gate static kadm5_ret_t 882*0Sstevel@tonic-gate check_pw_reuse(krb5_context context, 883*0Sstevel@tonic-gate krb5_keyblock *master_keyblock, 884*0Sstevel@tonic-gate krb5_keyblock *hist_keyblock, 885*0Sstevel@tonic-gate int n_new_key_data, krb5_key_data *new_key_data, 886*0Sstevel@tonic-gate int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data) 887*0Sstevel@tonic-gate { 888*0Sstevel@tonic-gate int x, y, z; 889*0Sstevel@tonic-gate krb5_keyblock newkey, histkey; 890*0Sstevel@tonic-gate krb5_error_code ret; 891*0Sstevel@tonic-gate 892*0Sstevel@tonic-gate for (x = 0; x < n_new_key_data; x++) { 893*0Sstevel@tonic-gate if (ret = krb5_dbekd_decrypt_key_data(context, 894*0Sstevel@tonic-gate master_keyblock, 895*0Sstevel@tonic-gate &(new_key_data[x]), 896*0Sstevel@tonic-gate &newkey, NULL)) 897*0Sstevel@tonic-gate return(ret); 898*0Sstevel@tonic-gate for (y = 0; y < n_pw_hist_data; y++) { 899*0Sstevel@tonic-gate for (z = 0; z < pw_hist_data[y].n_key_data; z++) { 900*0Sstevel@tonic-gate if (ret = 901*0Sstevel@tonic-gate krb5_dbekd_decrypt_key_data(context, 902*0Sstevel@tonic-gate hist_keyblock, 903*0Sstevel@tonic-gate &pw_hist_data[y].key_data[z], 904*0Sstevel@tonic-gate &histkey, NULL)) 905*0Sstevel@tonic-gate return(ret); 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate if ((newkey.length == histkey.length) && 908*0Sstevel@tonic-gate (newkey.enctype == histkey.enctype) && 909*0Sstevel@tonic-gate (memcmp(newkey.contents, histkey.contents, 910*0Sstevel@tonic-gate histkey.length) == 0)) { 911*0Sstevel@tonic-gate krb5_free_keyblock_contents(context, &histkey); 912*0Sstevel@tonic-gate krb5_free_keyblock_contents(context, &newkey); 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate return(KADM5_PASS_REUSE); 915*0Sstevel@tonic-gate } 916*0Sstevel@tonic-gate krb5_free_keyblock_contents(context, &histkey); 917*0Sstevel@tonic-gate } 918*0Sstevel@tonic-gate } 919*0Sstevel@tonic-gate krb5_free_keyblock_contents(context, &newkey); 920*0Sstevel@tonic-gate } 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate return(0); 923*0Sstevel@tonic-gate } 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate /* 926*0Sstevel@tonic-gate * Function: create_history_entry 927*0Sstevel@tonic-gate * 928*0Sstevel@tonic-gate * Purpose: Creates a password history entry from an array of 929*0Sstevel@tonic-gate * key_data. 930*0Sstevel@tonic-gate * 931*0Sstevel@tonic-gate * Arguments: 932*0Sstevel@tonic-gate * 933*0Sstevel@tonic-gate * context (r) krb5_context to use 934*0Sstevel@tonic-gate * master_keyblcok (r) master key block 935*0Sstevel@tonic-gate * n_key_data (r) number of elements in key_data 936*0Sstevel@tonic-gate * key_data (r) keys to add to the history entry 937*0Sstevel@tonic-gate * hist (w) history entry to fill in 938*0Sstevel@tonic-gate * 939*0Sstevel@tonic-gate * Effects: 940*0Sstevel@tonic-gate * 941*0Sstevel@tonic-gate * hist->key_data is allocated to store n_key_data key_datas. Each 942*0Sstevel@tonic-gate * element of key_data is decrypted with master_keyblock, re-encrypted 943*0Sstevel@tonic-gate * in hist_key, and added to hist->key_data. hist->n_key_data is 944*0Sstevel@tonic-gate * set to n_key_data. 945*0Sstevel@tonic-gate */ 946*0Sstevel@tonic-gate static 947*0Sstevel@tonic-gate int create_history_entry(krb5_context context, 948*0Sstevel@tonic-gate krb5_keyblock *master_keyblock, int n_key_data, 949*0Sstevel@tonic-gate krb5_key_data *key_data, osa_pw_hist_ent *hist) 950*0Sstevel@tonic-gate { 951*0Sstevel@tonic-gate int i, ret; 952*0Sstevel@tonic-gate krb5_keyblock key; 953*0Sstevel@tonic-gate krb5_keysalt salt; 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data)); 956*0Sstevel@tonic-gate if (hist->key_data == NULL) 957*0Sstevel@tonic-gate return ENOMEM; 958*0Sstevel@tonic-gate memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data)); 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate for (i = 0; i < n_key_data; i++) { 961*0Sstevel@tonic-gate if (ret = krb5_dbekd_decrypt_key_data(context, 962*0Sstevel@tonic-gate master_keyblock, 963*0Sstevel@tonic-gate &key_data[i], 964*0Sstevel@tonic-gate &key, &salt)) 965*0Sstevel@tonic-gate return ret; 966*0Sstevel@tonic-gate if (ret = krb5_dbekd_encrypt_key_data(context, 967*0Sstevel@tonic-gate &hist_key, 968*0Sstevel@tonic-gate &key, &salt, 969*0Sstevel@tonic-gate key_data[i].key_data_kvno, 970*0Sstevel@tonic-gate &hist->key_data[i])) 971*0Sstevel@tonic-gate return ret; 972*0Sstevel@tonic-gate krb5_free_keyblock_contents(context, &key); 973*0Sstevel@tonic-gate /* krb5_free_keysalt(context, &salt); */ 974*0Sstevel@tonic-gate } 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate hist->n_key_data = n_key_data; 977*0Sstevel@tonic-gate return 0; 978*0Sstevel@tonic-gate } 979*0Sstevel@tonic-gate 980*0Sstevel@tonic-gate void free_history_entry(krb5_context context, osa_pw_hist_ent *hist) 981*0Sstevel@tonic-gate { 982*0Sstevel@tonic-gate int i; 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate for (i = 0; i < hist->n_key_data; i++) 985*0Sstevel@tonic-gate krb5_free_key_data_contents(context, &hist->key_data[i]); 986*0Sstevel@tonic-gate free(hist->key_data); 987*0Sstevel@tonic-gate } 988*0Sstevel@tonic-gate 989*0Sstevel@tonic-gate /* 990*0Sstevel@tonic-gate * Function: add_to_history 991*0Sstevel@tonic-gate * 992*0Sstevel@tonic-gate * Purpose: Adds a password to a principal's password history. 993*0Sstevel@tonic-gate * 994*0Sstevel@tonic-gate * Arguments: 995*0Sstevel@tonic-gate * 996*0Sstevel@tonic-gate * context (r) krb5_context to use 997*0Sstevel@tonic-gate * adb (r/w) admin principal entry to add keys to 998*0Sstevel@tonic-gate * pol (r) adb's policy 999*0Sstevel@tonic-gate * pw (r) keys for the password to add to adb's key history 1000*0Sstevel@tonic-gate * 1001*0Sstevel@tonic-gate * Effects: 1002*0Sstevel@tonic-gate * 1003*0Sstevel@tonic-gate * add_to_history adds a single password to adb's password history. 1004*0Sstevel@tonic-gate * pw contains n_key_data keys in its key_data, in storage should be 1005*0Sstevel@tonic-gate * allocated but not freed by the caller (XXX blech!). 1006*0Sstevel@tonic-gate * 1007*0Sstevel@tonic-gate * This function maintains adb->old_keys as a circular queue. It 1008*0Sstevel@tonic-gate * starts empty, and grows each time this function is called until it 1009*0Sstevel@tonic-gate * is pol->pw_history_num items long. adb->old_key_len holds the 1010*0Sstevel@tonic-gate * number of allocated entries in the array, and must therefore be [0, 1011*0Sstevel@tonic-gate * pol->pw_history_num). adb->old_key_next is the index into the 1012*0Sstevel@tonic-gate * array where the next element should be written, and must be [0, 1013*0Sstevel@tonic-gate * adb->old_key_len). 1014*0Sstevel@tonic-gate */ 1015*0Sstevel@tonic-gate #define KADM_MOD(x) (x + adb->old_key_next) % adb->old_key_len 1016*0Sstevel@tonic-gate static kadm5_ret_t add_to_history( 1017*0Sstevel@tonic-gate krb5_context context, 1018*0Sstevel@tonic-gate osa_princ_ent_t adb, 1019*0Sstevel@tonic-gate kadm5_policy_ent_t pol, 1020*0Sstevel@tonic-gate osa_pw_hist_ent *pw) 1021*0Sstevel@tonic-gate { 1022*0Sstevel@tonic-gate osa_pw_hist_ent *histp; 1023*0Sstevel@tonic-gate int i; 1024*0Sstevel@tonic-gate 1025*0Sstevel@tonic-gate /* A history of 1 means just check the current password */ 1026*0Sstevel@tonic-gate if (pol->pw_history_num == 1) 1027*0Sstevel@tonic-gate return (0); 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate /* resize the adb->old_keys array if necessary */ 1030*0Sstevel@tonic-gate if (adb->old_key_len < pol->pw_history_num-1) { 1031*0Sstevel@tonic-gate if (adb->old_keys == NULL) { 1032*0Sstevel@tonic-gate adb->old_keys = (osa_pw_hist_ent *) 1033*0Sstevel@tonic-gate malloc((adb->old_key_len + 1) * 1034*0Sstevel@tonic-gate sizeof (osa_pw_hist_ent)); 1035*0Sstevel@tonic-gate } else { 1036*0Sstevel@tonic-gate adb->old_keys = (osa_pw_hist_ent *) 1037*0Sstevel@tonic-gate realloc(adb->old_keys, 1038*0Sstevel@tonic-gate (adb->old_key_len + 1) * 1039*0Sstevel@tonic-gate sizeof (osa_pw_hist_ent)); 1040*0Sstevel@tonic-gate } 1041*0Sstevel@tonic-gate if (adb->old_keys == NULL) 1042*0Sstevel@tonic-gate return (ENOMEM); 1043*0Sstevel@tonic-gate 1044*0Sstevel@tonic-gate memset(&adb->old_keys[adb->old_key_len], 0, 1045*0Sstevel@tonic-gate sizeof (osa_pw_hist_ent)); 1046*0Sstevel@tonic-gate adb->old_key_len++; 1047*0Sstevel@tonic-gate for (i = adb->old_key_len - 1; i > adb->old_key_next; i--) 1048*0Sstevel@tonic-gate adb->old_keys[i] = adb->old_keys[i - 1]; 1049*0Sstevel@tonic-gate memset(&adb->old_keys[adb->old_key_next], 0, 1050*0Sstevel@tonic-gate sizeof (osa_pw_hist_ent)); 1051*0Sstevel@tonic-gate } else if (adb->old_key_len > pol->pw_history_num-1) { 1052*0Sstevel@tonic-gate /* 1053*0Sstevel@tonic-gate * The policy must have changed! Shrink the array. 1054*0Sstevel@tonic-gate * Can't simply realloc() down, since it might be wrapped. 1055*0Sstevel@tonic-gate * To understand the arithmetic below, note that we are 1056*0Sstevel@tonic-gate * copying into new positions 0 .. N-1 from old positions 1057*0Sstevel@tonic-gate * old_key_next-N .. old_key_next-1, modulo old_key_len, 1058*0Sstevel@tonic-gate * where N = pw_history_num - 1 is the length of the 1059*0Sstevel@tonic-gate * shortened list. Matt Crawford, FNAL 1060*0Sstevel@tonic-gate */ 1061*0Sstevel@tonic-gate int j; 1062*0Sstevel@tonic-gate histp = (osa_pw_hist_ent *) 1063*0Sstevel@tonic-gate malloc((pol->pw_history_num - 1) * sizeof (osa_pw_hist_ent)); 1064*0Sstevel@tonic-gate if (histp) { 1065*0Sstevel@tonic-gate for (i = 0; i < pol->pw_history_num - 1; i++) { 1066*0Sstevel@tonic-gate /* 1067*0Sstevel@tonic-gate * We need the number we use the modulus 1068*0Sstevel@tonic-gate * operator on to be positive, so after 1069*0Sstevel@tonic-gate * subtracting pol->pw_history_num-1, we 1070*0Sstevel@tonic-gate * add back adb->old_key_len. 1071*0Sstevel@tonic-gate */ 1072*0Sstevel@tonic-gate j = KADM_MOD(i - (pol->pw_history_num - 1) + 1073*0Sstevel@tonic-gate adb->old_key_len); 1074*0Sstevel@tonic-gate histp[i] = adb->old_keys[j]; 1075*0Sstevel@tonic-gate } 1076*0Sstevel@tonic-gate /* Now free the ones we don't keep (the oldest ones) */ 1077*0Sstevel@tonic-gate for (i = 0; i < adb->old_key_len - \ 1078*0Sstevel@tonic-gate (pol->pw_history_num-1); i++) { 1079*0Sstevel@tonic-gate for (j = 0; j < \ 1080*0Sstevel@tonic-gate adb->old_keys[KADM_MOD(i)].n_key_data; j++) 1081*0Sstevel@tonic-gate krb5_free_key_data_contents(context, 1082*0Sstevel@tonic-gate &adb->old_keys[KADM_MOD(i)]. 1083*0Sstevel@tonic-gate key_data[j]); 1084*0Sstevel@tonic-gate free(adb->old_keys[KADM_MOD(i)].key_data); 1085*0Sstevel@tonic-gate } 1086*0Sstevel@tonic-gate free((void *)adb->old_keys); 1087*0Sstevel@tonic-gate adb->old_keys = histp; 1088*0Sstevel@tonic-gate adb->old_key_len = pol->pw_history_num - 1; 1089*0Sstevel@tonic-gate adb->old_key_next = 0; 1090*0Sstevel@tonic-gate } else { 1091*0Sstevel@tonic-gate return (ENOMEM); 1092*0Sstevel@tonic-gate } 1093*0Sstevel@tonic-gate } 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate if (adb->old_key_next + 1 > adb->old_key_len) 1096*0Sstevel@tonic-gate adb->old_key_next = 0; 1097*0Sstevel@tonic-gate 1098*0Sstevel@tonic-gate /* free the old pw history entry if it contains data */ 1099*0Sstevel@tonic-gate histp = &adb->old_keys[adb->old_key_next]; 1100*0Sstevel@tonic-gate for (i = 0; i < histp->n_key_data; i++) 1101*0Sstevel@tonic-gate krb5_free_key_data_contents(context, &histp->key_data[i]); 1102*0Sstevel@tonic-gate free(histp->key_data); 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate /* store the new entry */ 1105*0Sstevel@tonic-gate adb->old_keys[adb->old_key_next] = *pw; 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate /* update the next pointer */ 1108*0Sstevel@tonic-gate if (++adb->old_key_next == pol->pw_history_num-1) 1109*0Sstevel@tonic-gate adb->old_key_next = 0; 1110*0Sstevel@tonic-gate 1111*0Sstevel@tonic-gate return (0); 1112*0Sstevel@tonic-gate } 1113*0Sstevel@tonic-gate #undef KADM_MOD 1114*0Sstevel@tonic-gate 1115*0Sstevel@tonic-gate kadm5_ret_t 1116*0Sstevel@tonic-gate kadm5_chpass_principal(void *server_handle, 1117*0Sstevel@tonic-gate krb5_principal principal, char *password) 1118*0Sstevel@tonic-gate { 1119*0Sstevel@tonic-gate /* 1120*0Sstevel@tonic-gate * Default to using the new API with the default set of 1121*0Sstevel@tonic-gate * key/salt combinations. 1122*0Sstevel@tonic-gate */ 1123*0Sstevel@tonic-gate return (kadm5_chpass_principal_3(server_handle, principal, FALSE, 1124*0Sstevel@tonic-gate 0, NULL, password)); 1125*0Sstevel@tonic-gate } 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate kadm5_ret_t 1128*0Sstevel@tonic-gate kadm5_chpass_principal_3(void *server_handle, 1129*0Sstevel@tonic-gate krb5_principal principal, krb5_boolean keepold, 1130*0Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 1131*0Sstevel@tonic-gate char *password) 1132*0Sstevel@tonic-gate { 1133*0Sstevel@tonic-gate krb5_int32 now; 1134*0Sstevel@tonic-gate kadm5_policy_ent_rec pol; 1135*0Sstevel@tonic-gate osa_princ_ent_rec adb; 1136*0Sstevel@tonic-gate krb5_db_entry kdb, kdb_save; 1137*0Sstevel@tonic-gate int ret, ret2, last_pwd, i, hist_added; 1138*0Sstevel@tonic-gate int have_pol = 0; 1139*0Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 1140*0Sstevel@tonic-gate osa_pw_hist_ent hist; 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate CHECK_HANDLE(server_handle); 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate hist_added = 0; 1145*0Sstevel@tonic-gate memset(&hist, 0, sizeof(hist)); 1146*0Sstevel@tonic-gate 1147*0Sstevel@tonic-gate if (principal == NULL || password == NULL) 1148*0Sstevel@tonic-gate return EINVAL; 1149*0Sstevel@tonic-gate if ((krb5_principal_compare(handle->context, 1150*0Sstevel@tonic-gate principal, hist_princ)) == TRUE) 1151*0Sstevel@tonic-gate return KADM5_PROTECT_PRINCIPAL; 1152*0Sstevel@tonic-gate 1153*0Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1154*0Sstevel@tonic-gate return(ret); 1155*0Sstevel@tonic-gate 1156*0Sstevel@tonic-gate /* we are going to need the current keys after the new keys are set */ 1157*0Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) { 1158*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 1159*0Sstevel@tonic-gate return(ret); 1160*0Sstevel@tonic-gate } 1161*0Sstevel@tonic-gate 1162*0Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 1163*0Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol))) 1164*0Sstevel@tonic-gate goto done; 1165*0Sstevel@tonic-gate have_pol = 1; 1166*0Sstevel@tonic-gate } 1167*0Sstevel@tonic-gate 1168*0Sstevel@tonic-gate if ((ret = passwd_check(handle, password, adb.aux_attributes & 1169*0Sstevel@tonic-gate KADM5_POLICY, &pol, principal))) 1170*0Sstevel@tonic-gate goto done; 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate if (ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, 1173*0Sstevel@tonic-gate n_ks_tuple?ks_tuple:handle->params.keysalts, 1174*0Sstevel@tonic-gate n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 1175*0Sstevel@tonic-gate password, 0 /* increment kvno */, 1176*0Sstevel@tonic-gate keepold, &kdb)) 1177*0Sstevel@tonic-gate goto done; 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 1180*0Sstevel@tonic-gate 1181*0Sstevel@tonic-gate if (ret = krb5_timeofday(handle->context, &now)) 1182*0Sstevel@tonic-gate goto done; 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 1185*0Sstevel@tonic-gate /* the policy was loaded before */ 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1188*0Sstevel@tonic-gate &kdb, &last_pwd)) 1189*0Sstevel@tonic-gate goto done; 1190*0Sstevel@tonic-gate 1191*0Sstevel@tonic-gate #if 0 1192*0Sstevel@tonic-gate /* 1193*0Sstevel@tonic-gate * The spec says this check is overridden if the caller has 1194*0Sstevel@tonic-gate * modify privilege. The admin server therefore makes this 1195*0Sstevel@tonic-gate * check itself (in chpass_principal_wrapper, misc.c). A 1196*0Sstevel@tonic-gate * local caller implicitly has all authorization bits. 1197*0Sstevel@tonic-gate */ 1198*0Sstevel@tonic-gate if ((now - last_pwd) < pol.pw_min_life && 1199*0Sstevel@tonic-gate !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 1200*0Sstevel@tonic-gate ret = KADM5_PASS_TOOSOON; 1201*0Sstevel@tonic-gate goto done; 1202*0Sstevel@tonic-gate } 1203*0Sstevel@tonic-gate #endif 1204*0Sstevel@tonic-gate 1205*0Sstevel@tonic-gate if (ret = create_history_entry(handle->context, 1206*0Sstevel@tonic-gate &handle->master_keyblock, kdb_save.n_key_data, 1207*0Sstevel@tonic-gate kdb_save.key_data, &hist)) 1208*0Sstevel@tonic-gate goto done; 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate if (ret = check_pw_reuse(handle->context, 1211*0Sstevel@tonic-gate &handle->master_keyblock, 1212*0Sstevel@tonic-gate &hist_key, 1213*0Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 1214*0Sstevel@tonic-gate 1, &hist)) 1215*0Sstevel@tonic-gate goto done; 1216*0Sstevel@tonic-gate 1217*0Sstevel@tonic-gate if (pol.pw_history_num > 1) { 1218*0Sstevel@tonic-gate if (adb.admin_history_kvno != hist_kvno) { 1219*0Sstevel@tonic-gate ret = KADM5_BAD_HIST_KEY; 1220*0Sstevel@tonic-gate goto done; 1221*0Sstevel@tonic-gate } 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate if (ret = check_pw_reuse(handle->context, 1224*0Sstevel@tonic-gate &handle->master_keyblock, 1225*0Sstevel@tonic-gate &hist_key, 1226*0Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 1227*0Sstevel@tonic-gate adb.old_key_len, adb.old_keys)) 1228*0Sstevel@tonic-gate goto done; 1229*0Sstevel@tonic-gate 1230*0Sstevel@tonic-gate if (ret = add_to_history(handle->context, &adb, &pol, &hist)) 1231*0Sstevel@tonic-gate goto done; 1232*0Sstevel@tonic-gate hist_added = 1; 1233*0Sstevel@tonic-gate } 1234*0Sstevel@tonic-gate 1235*0Sstevel@tonic-gate if (pol.pw_max_life) 1236*0Sstevel@tonic-gate kdb.pw_expiration = now + pol.pw_max_life; 1237*0Sstevel@tonic-gate else 1238*0Sstevel@tonic-gate kdb.pw_expiration = 0; 1239*0Sstevel@tonic-gate } else { 1240*0Sstevel@tonic-gate kdb.pw_expiration = 0; 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate 1243*0Sstevel@tonic-gate if (ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)) 1244*0Sstevel@tonic-gate goto done; 1245*0Sstevel@tonic-gate 1246*0Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 1247*0Sstevel@tonic-gate goto done; 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gate ret = KADM5_OK; 1250*0Sstevel@tonic-gate done: 1251*0Sstevel@tonic-gate if (!hist_added && hist.key_data) 1252*0Sstevel@tonic-gate free_history_entry(handle->context, &hist); 1253*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 1254*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb_save, NULL); 1255*0Sstevel@tonic-gate krb5_dbe_free_contents(handle->context, &kdb); 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gate if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol)) 1258*0Sstevel@tonic-gate && !ret) 1259*0Sstevel@tonic-gate ret = ret2; 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate return ret; 1262*0Sstevel@tonic-gate } 1263*0Sstevel@tonic-gate 1264*0Sstevel@tonic-gate kadm5_ret_t 1265*0Sstevel@tonic-gate kadm5_randkey_principal(void *server_handle, 1266*0Sstevel@tonic-gate krb5_principal principal, 1267*0Sstevel@tonic-gate krb5_keyblock **keyblocks, 1268*0Sstevel@tonic-gate int *n_keys) 1269*0Sstevel@tonic-gate { 1270*0Sstevel@tonic-gate krb5_key_salt_tuple keysalts[2]; 1271*0Sstevel@tonic-gate 1272*0Sstevel@tonic-gate /* 1273*0Sstevel@tonic-gate * Anyone calling this routine is forced to use only DES 1274*0Sstevel@tonic-gate * enctypes to be compatible with earlier releases that 1275*0Sstevel@tonic-gate * did not support stronger crypto. 1276*0Sstevel@tonic-gate * 1277*0Sstevel@tonic-gate * S10 (and later) kadmin clients will not use this API, 1278*0Sstevel@tonic-gate * so we can assume the request is from an older version. 1279*0Sstevel@tonic-gate */ 1280*0Sstevel@tonic-gate keysalts[0].ks_enctype = ENCTYPE_DES_CBC_MD5; 1281*0Sstevel@tonic-gate keysalts[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 1282*0Sstevel@tonic-gate keysalts[1].ks_enctype = ENCTYPE_DES_CBC_CRC; 1283*0Sstevel@tonic-gate keysalts[1].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 1284*0Sstevel@tonic-gate 1285*0Sstevel@tonic-gate return (kadm5_randkey_principal_3(server_handle, principal, 1286*0Sstevel@tonic-gate FALSE, 2, keysalts, keyblocks, n_keys)); 1287*0Sstevel@tonic-gate } 1288*0Sstevel@tonic-gate 1289*0Sstevel@tonic-gate kadm5_ret_t 1290*0Sstevel@tonic-gate kadm5_randkey_principal_3(void *server_handle, 1291*0Sstevel@tonic-gate krb5_principal principal, 1292*0Sstevel@tonic-gate krb5_boolean keepold, 1293*0Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 1294*0Sstevel@tonic-gate krb5_keyblock **keyblocks, 1295*0Sstevel@tonic-gate int *n_keys) 1296*0Sstevel@tonic-gate { 1297*0Sstevel@tonic-gate krb5_db_entry kdb; 1298*0Sstevel@tonic-gate osa_princ_ent_rec adb; 1299*0Sstevel@tonic-gate krb5_int32 now; 1300*0Sstevel@tonic-gate kadm5_policy_ent_rec pol; 1301*0Sstevel@tonic-gate krb5_key_data *key_data; 1302*0Sstevel@tonic-gate krb5_keyblock *keyblock; 1303*0Sstevel@tonic-gate int ret, last_pwd, have_pol = 0; 1304*0Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate if (keyblocks) 1307*0Sstevel@tonic-gate *keyblocks = NULL; 1308*0Sstevel@tonic-gate 1309*0Sstevel@tonic-gate CHECK_HANDLE(server_handle); 1310*0Sstevel@tonic-gate 1311*0Sstevel@tonic-gate if (principal == NULL) 1312*0Sstevel@tonic-gate return EINVAL; 1313*0Sstevel@tonic-gate if (hist_princ && /* this will be NULL when initializing the databse */ 1314*0Sstevel@tonic-gate ((krb5_principal_compare(handle->context, 1315*0Sstevel@tonic-gate principal, hist_princ)) == TRUE)) 1316*0Sstevel@tonic-gate return KADM5_PROTECT_PRINCIPAL; 1317*0Sstevel@tonic-gate 1318*0Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1319*0Sstevel@tonic-gate return(ret); 1320*0Sstevel@tonic-gate 1321*0Sstevel@tonic-gate if (ret = krb5_dbe_crk(handle->context, &handle->master_keyblock, 1322*0Sstevel@tonic-gate n_ks_tuple?ks_tuple:handle->params.keysalts, 1323*0Sstevel@tonic-gate n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 1324*0Sstevel@tonic-gate keepold, 1325*0Sstevel@tonic-gate &kdb)) 1326*0Sstevel@tonic-gate goto done; 1327*0Sstevel@tonic-gate 1328*0Sstevel@tonic-gate kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate if (ret = krb5_timeofday(handle->context, &now)) 1331*0Sstevel@tonic-gate goto done; 1332*0Sstevel@tonic-gate 1333*0Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 1334*0Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 1335*0Sstevel@tonic-gate &pol)) != KADM5_OK) 1336*0Sstevel@tonic-gate goto done; 1337*0Sstevel@tonic-gate have_pol = 1; 1338*0Sstevel@tonic-gate 1339*0Sstevel@tonic-gate if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1340*0Sstevel@tonic-gate &kdb, &last_pwd)) 1341*0Sstevel@tonic-gate goto done; 1342*0Sstevel@tonic-gate 1343*0Sstevel@tonic-gate #if 0 1344*0Sstevel@tonic-gate /* 1345*0Sstevel@tonic-gate * The spec says this check is overridden if the caller has 1346*0Sstevel@tonic-gate * modify privilege. The admin server therefore makes this 1347*0Sstevel@tonic-gate * check itself (in chpass_principal_wrapper, misc.c). A 1348*0Sstevel@tonic-gate * local caller implicitly has all authorization bits. 1349*0Sstevel@tonic-gate */ 1350*0Sstevel@tonic-gate if((now - last_pwd) < pol.pw_min_life && 1351*0Sstevel@tonic-gate !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 1352*0Sstevel@tonic-gate ret = KADM5_PASS_TOOSOON; 1353*0Sstevel@tonic-gate goto done; 1354*0Sstevel@tonic-gate } 1355*0Sstevel@tonic-gate #endif 1356*0Sstevel@tonic-gate 1357*0Sstevel@tonic-gate if(pol.pw_history_num > 1) { 1358*0Sstevel@tonic-gate if(adb.admin_history_kvno != hist_kvno) { 1359*0Sstevel@tonic-gate ret = KADM5_BAD_HIST_KEY; 1360*0Sstevel@tonic-gate goto done; 1361*0Sstevel@tonic-gate } 1362*0Sstevel@tonic-gate 1363*0Sstevel@tonic-gate if (ret = check_pw_reuse(handle->context, 1364*0Sstevel@tonic-gate &handle->master_keyblock, 1365*0Sstevel@tonic-gate &hist_key, 1366*0Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 1367*0Sstevel@tonic-gate adb.old_key_len, adb.old_keys)) 1368*0Sstevel@tonic-gate goto done; 1369*0Sstevel@tonic-gate } 1370*0Sstevel@tonic-gate if (pol.pw_max_life) 1371*0Sstevel@tonic-gate kdb.pw_expiration = now + pol.pw_max_life; 1372*0Sstevel@tonic-gate else 1373*0Sstevel@tonic-gate kdb.pw_expiration = 0; 1374*0Sstevel@tonic-gate } else { 1375*0Sstevel@tonic-gate kdb.pw_expiration = 0; 1376*0Sstevel@tonic-gate } 1377*0Sstevel@tonic-gate 1378*0Sstevel@tonic-gate if (ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)) 1379*0Sstevel@tonic-gate goto done; 1380*0Sstevel@tonic-gate 1381*0Sstevel@tonic-gate if (keyblocks) { 1382*0Sstevel@tonic-gate if (handle->api_version == KADM5_API_VERSION_1) { 1383*0Sstevel@tonic-gate /* Version 1 clients will expect to see a DES_CRC enctype. */ 1384*0Sstevel@tonic-gate if (ret = krb5_dbe_find_enctype(handle->context, &kdb, 1385*0Sstevel@tonic-gate ENCTYPE_DES_CBC_CRC, 1386*0Sstevel@tonic-gate -1, -1, &key_data)) 1387*0Sstevel@tonic-gate goto done; 1388*0Sstevel@tonic-gate 1389*0Sstevel@tonic-gate if (ret = decrypt_key_data(handle->context, 1390*0Sstevel@tonic-gate &handle->master_keyblock, 1, key_data, 1391*0Sstevel@tonic-gate keyblocks, NULL)) 1392*0Sstevel@tonic-gate goto done; 1393*0Sstevel@tonic-gate } else { 1394*0Sstevel@tonic-gate ret = decrypt_key_data(handle->context, 1395*0Sstevel@tonic-gate &handle->master_keyblock, 1396*0Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 1397*0Sstevel@tonic-gate keyblocks, n_keys); 1398*0Sstevel@tonic-gate if (ret) 1399*0Sstevel@tonic-gate goto done; 1400*0Sstevel@tonic-gate } 1401*0Sstevel@tonic-gate } 1402*0Sstevel@tonic-gate 1403*0Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 1404*0Sstevel@tonic-gate goto done; 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate ret = KADM5_OK; 1407*0Sstevel@tonic-gate done: 1408*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 1409*0Sstevel@tonic-gate if (have_pol) 1410*0Sstevel@tonic-gate kadm5_free_policy_ent(handle->lhandle, &pol); 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gate return ret; 1413*0Sstevel@tonic-gate } 1414*0Sstevel@tonic-gate 1415*0Sstevel@tonic-gate kadm5_ret_t 1416*0Sstevel@tonic-gate kadm5_setkey_principal(void *server_handle, 1417*0Sstevel@tonic-gate krb5_principal principal, 1418*0Sstevel@tonic-gate krb5_keyblock *keyblocks, 1419*0Sstevel@tonic-gate int n_keys) 1420*0Sstevel@tonic-gate { 1421*0Sstevel@tonic-gate return (kadm5_setkey_principal_3(server_handle, principal, 1422*0Sstevel@tonic-gate FALSE, 0, NULL, keyblocks, n_keys)); 1423*0Sstevel@tonic-gate } 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate kadm5_ret_t 1426*0Sstevel@tonic-gate kadm5_setkey_principal_3(void *server_handle, 1427*0Sstevel@tonic-gate krb5_principal principal, 1428*0Sstevel@tonic-gate krb5_boolean keepold, 1429*0Sstevel@tonic-gate int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 1430*0Sstevel@tonic-gate krb5_keyblock *keyblocks, 1431*0Sstevel@tonic-gate int n_keys) 1432*0Sstevel@tonic-gate { 1433*0Sstevel@tonic-gate krb5_db_entry kdb; 1434*0Sstevel@tonic-gate osa_princ_ent_rec adb; 1435*0Sstevel@tonic-gate krb5_int32 now; 1436*0Sstevel@tonic-gate kadm5_policy_ent_rec pol; 1437*0Sstevel@tonic-gate krb5_key_data *old_key_data; 1438*0Sstevel@tonic-gate int n_old_keys; 1439*0Sstevel@tonic-gate int i, j, kvno, ret, last_pwd, have_pol = 0; 1440*0Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 1441*0Sstevel@tonic-gate krb5_boolean similar; 1442*0Sstevel@tonic-gate krb5_keysalt keysalt; 1443*0Sstevel@tonic-gate 1444*0Sstevel@tonic-gate CHECK_HANDLE(server_handle); 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate if (principal == NULL || keyblocks == NULL) 1447*0Sstevel@tonic-gate return EINVAL; 1448*0Sstevel@tonic-gate if (hist_princ && /* this will be NULL when initializing the databse */ 1449*0Sstevel@tonic-gate ((krb5_principal_compare(handle->context, 1450*0Sstevel@tonic-gate principal, hist_princ)) == TRUE)) 1451*0Sstevel@tonic-gate return KADM5_PROTECT_PRINCIPAL; 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate for (i = 0; i < n_keys; i++) { 1454*0Sstevel@tonic-gate for (j = i+1; j < n_keys; j++) { 1455*0Sstevel@tonic-gate if (ret = krb5_c_enctype_compare(handle->context, 1456*0Sstevel@tonic-gate keyblocks[i].enctype, 1457*0Sstevel@tonic-gate keyblocks[j].enctype, 1458*0Sstevel@tonic-gate &similar)) 1459*0Sstevel@tonic-gate return(ret); 1460*0Sstevel@tonic-gate if (similar) 1461*0Sstevel@tonic-gate if (n_ks_tuple) { 1462*0Sstevel@tonic-gate if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype) 1463*0Sstevel@tonic-gate return KADM5_SETKEY_DUP_ENCTYPES; 1464*0Sstevel@tonic-gate } else 1465*0Sstevel@tonic-gate return KADM5_SETKEY_DUP_ENCTYPES; 1466*0Sstevel@tonic-gate } 1467*0Sstevel@tonic-gate } 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate if (n_ks_tuple != n_keys) 1470*0Sstevel@tonic-gate return KADM5_SETKEY3_ETYPE_MISMATCH; 1471*0Sstevel@tonic-gate 1472*0Sstevel@tonic-gate if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1473*0Sstevel@tonic-gate return(ret); 1474*0Sstevel@tonic-gate 1475*0Sstevel@tonic-gate for (kvno = 0, i=0; i<kdb.n_key_data; i++) 1476*0Sstevel@tonic-gate if (kdb.key_data[i].key_data_kvno > kvno) 1477*0Sstevel@tonic-gate kvno = kdb.key_data[i].key_data_kvno; 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gate if (keepold) { 1480*0Sstevel@tonic-gate old_key_data = kdb.key_data; 1481*0Sstevel@tonic-gate n_old_keys = kdb.n_key_data; 1482*0Sstevel@tonic-gate } else { 1483*0Sstevel@tonic-gate if (kdb.key_data != NULL) 1484*0Sstevel@tonic-gate cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 1485*0Sstevel@tonic-gate n_old_keys = 0; 1486*0Sstevel@tonic-gate old_key_data = NULL; 1487*0Sstevel@tonic-gate } 1488*0Sstevel@tonic-gate 1489*0Sstevel@tonic-gate kdb.key_data = (krb5_key_data*)malloc((n_keys+n_old_keys) 1490*0Sstevel@tonic-gate *sizeof(krb5_key_data)); 1491*0Sstevel@tonic-gate if (kdb.key_data == NULL) 1492*0Sstevel@tonic-gate return ENOMEM; 1493*0Sstevel@tonic-gate memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data)); 1494*0Sstevel@tonic-gate kdb.n_key_data = 0; 1495*0Sstevel@tonic-gate 1496*0Sstevel@tonic-gate for (i = 0; i < n_keys; i++) { 1497*0Sstevel@tonic-gate if (n_ks_tuple) { 1498*0Sstevel@tonic-gate keysalt.type = ks_tuple[i].ks_salttype; 1499*0Sstevel@tonic-gate keysalt.data.length = 0; 1500*0Sstevel@tonic-gate keysalt.data.data = NULL; 1501*0Sstevel@tonic-gate if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) { 1502*0Sstevel@tonic-gate cleanup_key_data(handle->context, kdb.n_key_data, 1503*0Sstevel@tonic-gate kdb.key_data); 1504*0Sstevel@tonic-gate return KADM5_SETKEY3_ETYPE_MISMATCH; 1505*0Sstevel@tonic-gate } 1506*0Sstevel@tonic-gate } 1507*0Sstevel@tonic-gate ret = krb5_dbekd_encrypt_key_data(handle->context, 1508*0Sstevel@tonic-gate &handle->master_keyblock, 1509*0Sstevel@tonic-gate &keyblocks[i], 1510*0Sstevel@tonic-gate n_ks_tuple ? &keysalt : NULL, 1511*0Sstevel@tonic-gate kvno + 1, 1512*0Sstevel@tonic-gate &kdb.key_data[i]); 1513*0Sstevel@tonic-gate if (ret) { 1514*0Sstevel@tonic-gate cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 1515*0Sstevel@tonic-gate return ret; 1516*0Sstevel@tonic-gate } 1517*0Sstevel@tonic-gate kdb.n_key_data++; 1518*0Sstevel@tonic-gate } 1519*0Sstevel@tonic-gate 1520*0Sstevel@tonic-gate /* copy old key data if necessary */ 1521*0Sstevel@tonic-gate for (i = 0; i < n_old_keys; i++) { 1522*0Sstevel@tonic-gate kdb.key_data[i+n_keys] = old_key_data[i]; 1523*0Sstevel@tonic-gate memset(&old_key_data[i], 0, sizeof (krb5_key_data)); 1524*0Sstevel@tonic-gate kdb.n_key_data++; 1525*0Sstevel@tonic-gate } 1526*0Sstevel@tonic-gate /* assert(kdb.n_key_data == n_keys + n_old_keys) */ 1527*0Sstevel@tonic-gate kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 1528*0Sstevel@tonic-gate 1529*0Sstevel@tonic-gate if (ret = krb5_timeofday(handle->context, &now)) 1530*0Sstevel@tonic-gate goto done; 1531*0Sstevel@tonic-gate 1532*0Sstevel@tonic-gate if ((adb.aux_attributes & KADM5_POLICY)) { 1533*0Sstevel@tonic-gate if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 1534*0Sstevel@tonic-gate &pol)) != KADM5_OK) 1535*0Sstevel@tonic-gate goto done; 1536*0Sstevel@tonic-gate have_pol = 1; 1537*0Sstevel@tonic-gate 1538*0Sstevel@tonic-gate #if 0 1539*0Sstevel@tonic-gate /* 1540*0Sstevel@tonic-gate * The spec says this check is overridden if the caller has 1541*0Sstevel@tonic-gate * modify privilege. The admin server therefore makes this 1542*0Sstevel@tonic-gate * check itself (in chpass_principal_wrapper, misc.c). A 1543*0Sstevel@tonic-gate * local caller implicitly has all authorization bits. 1544*0Sstevel@tonic-gate */ 1545*0Sstevel@tonic-gate if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1546*0Sstevel@tonic-gate &kdb, &last_pwd)) 1547*0Sstevel@tonic-gate goto done; 1548*0Sstevel@tonic-gate if((now - last_pwd) < pol.pw_min_life && 1549*0Sstevel@tonic-gate !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 1550*0Sstevel@tonic-gate ret = KADM5_PASS_TOOSOON; 1551*0Sstevel@tonic-gate goto done; 1552*0Sstevel@tonic-gate } 1553*0Sstevel@tonic-gate #endif 1554*0Sstevel@tonic-gate #if 0 1555*0Sstevel@tonic-gate /* 1556*0Sstevel@tonic-gate * Should we be checking/updating pw history here? 1557*0Sstevel@tonic-gate */ 1558*0Sstevel@tonic-gate if(pol.pw_history_num > 1) { 1559*0Sstevel@tonic-gate if(adb.admin_history_kvno != hist_kvno) { 1560*0Sstevel@tonic-gate ret = KADM5_BAD_HIST_KEY; 1561*0Sstevel@tonic-gate goto done; 1562*0Sstevel@tonic-gate } 1563*0Sstevel@tonic-gate 1564*0Sstevel@tonic-gate if (ret = check_pw_reuse(handle->context, 1565*0Sstevel@tonic-gate &handle->master_keyblock, 1566*0Sstevel@tonic-gate &hist_key, 1567*0Sstevel@tonic-gate kdb.n_key_data, kdb.key_data, 1568*0Sstevel@tonic-gate adb.old_key_len, adb.old_keys)) 1569*0Sstevel@tonic-gate goto done; 1570*0Sstevel@tonic-gate } 1571*0Sstevel@tonic-gate #endif 1572*0Sstevel@tonic-gate 1573*0Sstevel@tonic-gate if (pol.pw_max_life) 1574*0Sstevel@tonic-gate kdb.pw_expiration = now + pol.pw_max_life; 1575*0Sstevel@tonic-gate else 1576*0Sstevel@tonic-gate kdb.pw_expiration = 0; 1577*0Sstevel@tonic-gate } else { 1578*0Sstevel@tonic-gate kdb.pw_expiration = 0; 1579*0Sstevel@tonic-gate } 1580*0Sstevel@tonic-gate 1581*0Sstevel@tonic-gate if (ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)) 1582*0Sstevel@tonic-gate goto done; 1583*0Sstevel@tonic-gate 1584*0Sstevel@tonic-gate if ((ret = kdb_put_entry(handle, &kdb, &adb))) 1585*0Sstevel@tonic-gate goto done; 1586*0Sstevel@tonic-gate 1587*0Sstevel@tonic-gate ret = KADM5_OK; 1588*0Sstevel@tonic-gate done: 1589*0Sstevel@tonic-gate kdb_free_entry(handle, &kdb, &adb); 1590*0Sstevel@tonic-gate if (have_pol) 1591*0Sstevel@tonic-gate kadm5_free_policy_ent(handle->lhandle, &pol); 1592*0Sstevel@tonic-gate 1593*0Sstevel@tonic-gate return ret; 1594*0Sstevel@tonic-gate } 1595*0Sstevel@tonic-gate 1596*0Sstevel@tonic-gate /* 1597*0Sstevel@tonic-gate * Allocate an array of n_key_data krb5_keyblocks, fill in each 1598*0Sstevel@tonic-gate * element with the results of decrypting the nth key in key_data with 1599*0Sstevel@tonic-gate * master_keyblock, and if n_keys is not NULL fill it in with the 1600*0Sstevel@tonic-gate * number of keys decrypted. 1601*0Sstevel@tonic-gate */ 1602*0Sstevel@tonic-gate static int decrypt_key_data(krb5_context context, 1603*0Sstevel@tonic-gate krb5_keyblock *master_keyblock, 1604*0Sstevel@tonic-gate int n_key_data, krb5_key_data *key_data, 1605*0Sstevel@tonic-gate krb5_keyblock **keyblocks, int *n_keys) 1606*0Sstevel@tonic-gate { 1607*0Sstevel@tonic-gate krb5_keyblock *keys; 1608*0Sstevel@tonic-gate int ret, i; 1609*0Sstevel@tonic-gate 1610*0Sstevel@tonic-gate keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock)); 1611*0Sstevel@tonic-gate if (keys == NULL) 1612*0Sstevel@tonic-gate return ENOMEM; 1613*0Sstevel@tonic-gate memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); 1614*0Sstevel@tonic-gate 1615*0Sstevel@tonic-gate for (i = 0; i < n_key_data; i++) { 1616*0Sstevel@tonic-gate if (ret = krb5_dbekd_decrypt_key_data(context, 1617*0Sstevel@tonic-gate master_keyblock, &key_data[i], &keys[i], NULL)) { 1618*0Sstevel@tonic-gate 1619*0Sstevel@tonic-gate memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); 1620*0Sstevel@tonic-gate free(keys); 1621*0Sstevel@tonic-gate return ret; 1622*0Sstevel@tonic-gate } 1623*0Sstevel@tonic-gate } 1624*0Sstevel@tonic-gate 1625*0Sstevel@tonic-gate *keyblocks = keys; 1626*0Sstevel@tonic-gate if (n_keys) 1627*0Sstevel@tonic-gate *n_keys = n_key_data; 1628*0Sstevel@tonic-gate 1629*0Sstevel@tonic-gate return 0; 1630*0Sstevel@tonic-gate } 1631*0Sstevel@tonic-gate 1632*0Sstevel@tonic-gate /* 1633*0Sstevel@tonic-gate * Function: kadm5_decrypt_key 1634*0Sstevel@tonic-gate * 1635*0Sstevel@tonic-gate * Purpose: Retrieves and decrypts a principal key. 1636*0Sstevel@tonic-gate * 1637*0Sstevel@tonic-gate * Arguments: 1638*0Sstevel@tonic-gate * 1639*0Sstevel@tonic-gate * server_handle (r) kadm5 handle 1640*0Sstevel@tonic-gate * entry (r) principal retrieved with kadm5_get_principal 1641*0Sstevel@tonic-gate * ktype (r) enctype to search for, or -1 to ignore 1642*0Sstevel@tonic-gate * stype (r) salt type to search for, or -1 to ignore 1643*0Sstevel@tonic-gate * kvno (r) kvno to search for, -1 for max, 0 for max 1644*0Sstevel@tonic-gate * only if it also matches ktype and stype 1645*0Sstevel@tonic-gate * keyblock (w) keyblock to fill in 1646*0Sstevel@tonic-gate * keysalt (w) keysalt to fill in, or NULL 1647*0Sstevel@tonic-gate * kvnop (w) kvno to fill in, or NULL 1648*0Sstevel@tonic-gate * 1649*0Sstevel@tonic-gate * Effects: Searches the key_data array of entry, which must have been 1650*0Sstevel@tonic-gate * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to 1651*0Sstevel@tonic-gate * find a key with a specified enctype, salt type, and kvno in a 1652*0Sstevel@tonic-gate * principal entry. If not found, return ENOENT. Otherwise, decrypt 1653*0Sstevel@tonic-gate * it with the master key, and return the key in keyblock, the salt 1654*0Sstevel@tonic-gate * in salttype, and the key version number in kvno. 1655*0Sstevel@tonic-gate * 1656*0Sstevel@tonic-gate * If ktype or stype is -1, it is ignored for the search. If kvno is 1657*0Sstevel@tonic-gate * -1, ktype and stype are ignored and the key with the max kvno is 1658*0Sstevel@tonic-gate * returned. If kvno is 0, only the key with the max kvno is returned 1659*0Sstevel@tonic-gate * and only if it matches the ktype and stype; otherwise, ENOENT is 1660*0Sstevel@tonic-gate * returned. 1661*0Sstevel@tonic-gate */ 1662*0Sstevel@tonic-gate kadm5_ret_t kadm5_decrypt_key(void *server_handle, 1663*0Sstevel@tonic-gate kadm5_principal_ent_t entry, krb5_int32 1664*0Sstevel@tonic-gate ktype, krb5_int32 stype, krb5_int32 1665*0Sstevel@tonic-gate kvno, krb5_keyblock *keyblock, 1666*0Sstevel@tonic-gate krb5_keysalt *keysalt, int *kvnop) 1667*0Sstevel@tonic-gate { 1668*0Sstevel@tonic-gate kadm5_server_handle_t handle = server_handle; 1669*0Sstevel@tonic-gate krb5_db_entry dbent; 1670*0Sstevel@tonic-gate krb5_key_data *key_data; 1671*0Sstevel@tonic-gate int ret; 1672*0Sstevel@tonic-gate 1673*0Sstevel@tonic-gate CHECK_HANDLE(server_handle); 1674*0Sstevel@tonic-gate 1675*0Sstevel@tonic-gate if (entry->n_key_data == 0 || entry->key_data == NULL) 1676*0Sstevel@tonic-gate return EINVAL; 1677*0Sstevel@tonic-gate 1678*0Sstevel@tonic-gate /* find_enctype only uses these two fields */ 1679*0Sstevel@tonic-gate dbent.n_key_data = entry->n_key_data; 1680*0Sstevel@tonic-gate dbent.key_data = entry->key_data; 1681*0Sstevel@tonic-gate if (ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype, 1682*0Sstevel@tonic-gate stype, kvno, &key_data)) 1683*0Sstevel@tonic-gate return ret; 1684*0Sstevel@tonic-gate 1685*0Sstevel@tonic-gate if (ret = krb5_dbekd_decrypt_key_data(handle->context, 1686*0Sstevel@tonic-gate &handle->master_keyblock, key_data, 1687*0Sstevel@tonic-gate keyblock, keysalt)) 1688*0Sstevel@tonic-gate return ret; 1689*0Sstevel@tonic-gate 1690*0Sstevel@tonic-gate if (kvnop) 1691*0Sstevel@tonic-gate *kvnop = key_data->key_data_kvno; 1692*0Sstevel@tonic-gate 1693*0Sstevel@tonic-gate return KADM5_OK; 1694*0Sstevel@tonic-gate } 1695