-: 0:Source:svr_principal.c -: 0:Graph:/var/tsitkova/Sources/v10/trunk/src/lib/kadm5/srv/svr_principal.so.gcno -: 0:Data:/var/tsitkova/Sources/v10/trunk/src/lib/kadm5/srv/svr_principal.so.gcda -: 0:Runs:951 -: 0:Programs:1 -: 1:/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -: 2:/* -: 3: * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved -: 4: * -: 5: * $Header$ -: 6: */ -: 7:#include "k5-int.h" -: 8:#include -: 9:#include -: 10:#include -: 11:#include "server_internal.h" -: 12:#ifdef USE_PASSWORD_SERVER -: 13:#include -: 14:#include -: 15:#endif -: 16: -: 17:#include -: 18: -: 19:#ifdef USE_VALGRIND -: 20:#include -: 21:#else -: 22:#define VALGRIND_CHECK_DEFINED(LVALUE) ((void)0) -: 23:#endif -: 24: -: 25:extern krb5_principal master_princ; -: 26:extern krb5_principal hist_princ; -: 27:extern krb5_keyblock master_keyblock; -: 28:extern krb5_keylist_node *master_keylist; -: 29:extern krb5_actkvno_node *active_mkey_list; -: 30:extern krb5_db_entry master_db; -: 31: -: 32:static int decrypt_key_data(krb5_context context, -: 33: int n_key_data, krb5_key_data *key_data, -: 34: krb5_keyblock **keyblocks, int *n_keys); -: 35: -: 36:static krb5_error_code 628: 37:kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc) -: 38:{ -: 39: register krb5_principal tempprinc; -: 40: register int i, nelems; -: 41: 628: 42: tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data)); -: 43: 628: 44: if (tempprinc == 0) #####: 45: return ENOMEM; -: 46: -: 47: VALGRIND_CHECK_DEFINED(*inprinc); 628: 48: *tempprinc = *inprinc; -: 49: 628: 50: nelems = (int) krb5_princ_size(context, inprinc); 628: 51: tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data)); 628: 52: if (tempprinc->data == 0) { #####: 53: krb5_db_free(context, (char *)tempprinc); #####: 54: return ENOMEM; -: 55: } -: 56: 1763: 57: for (i = 0; i < nelems; i++) { 1135: 58: unsigned int len = krb5_princ_component(context, inprinc, i)->length; 1135: 59: krb5_princ_component(context, tempprinc, i)->length = len; 2270: 60: if (((krb5_princ_component(context, tempprinc, i)->data = 1135: 61: krb5_db_alloc(context, NULL, len)) == 0) && len) { #####: 62: while (--i >= 0) #####: 63: krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data); #####: 64: krb5_db_free (context, tempprinc->data); #####: 65: krb5_db_free (context, tempprinc); #####: 66: return ENOMEM; -: 67: } 1135: 68: if (len) 1135: 69: memcpy(krb5_princ_component(context, tempprinc, i)->data, 1135: 70: krb5_princ_component(context, inprinc, i)->data, len); 1135: 71: krb5_princ_component(context, tempprinc, i)->magic = KV5M_DATA; -: 72: } -: 73: 1256: 74: tempprinc->realm.data = 1256: 75: krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length); 628: 76: if (!tempprinc->realm.data && tempprinc->realm.length) { #####: 77: for (i = 0; i < nelems; i++) #####: 78: krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data); #####: 79: krb5_db_free(context, tempprinc->data); #####: 80: krb5_db_free(context, tempprinc); #####: 81: return ENOMEM; -: 82: } 628: 83: if (tempprinc->realm.length) 628: 84: memcpy(tempprinc->realm.data, inprinc->realm.data, -: 85: inprinc->realm.length); -: 86: 628: 87: *outprinc = tempprinc; 628: 88: return 0; -: 89:} -: 90: -: 91:static void 6: 92:kadm5_free_principal(krb5_context context, krb5_principal val) -: 93:{ -: 94: register krb5_int32 i; -: 95: 6: 96: if (!val) #####: 97: return; -: 98: 6: 99: if (val->data) { 6: 100: i = krb5_princ_size(context, val); 19: 101: while(--i >= 0) 7: 102: krb5_db_free(context, krb5_princ_component(context, val, i)->data); 6: 103: krb5_db_free(context, val->data); -: 104: } 6: 105: if (val->realm.data) 6: 106: krb5_db_free(context, val->realm.data); 6: 107: krb5_db_free(context, val); -: 108:} -: 109: -: 110:/* -: 111: * XXX Functions that ought to be in libkrb5.a, but aren't. -: 112: */ 13: 113:kadm5_ret_t krb5_copy_key_data_contents(context, from, to) -: 114: krb5_context context; -: 115: krb5_key_data *from, *to; -: 116:{ -: 117: int i, idx; -: 118: 13: 119: *to = *from; -: 120: 13: 121: idx = (from->key_data_ver == 1 ? 1 : 2); -: 122: 26: 123: for (i = 0; i < idx; i++) { 13: 124: if ( from->key_data_length[i] ) { 13: 125: to->key_data_contents[i] = malloc(from->key_data_length[i]); 13: 126: if (to->key_data_contents[i] == NULL) { #####: 127: for (i = 0; i < idx; i++) { #####: 128: if (to->key_data_contents[i]) { #####: 129: memset(to->key_data_contents[i], 0, #####: 130: to->key_data_length[i]); #####: 131: free(to->key_data_contents[i]); -: 132: } -: 133: } #####: 134: return ENOMEM; -: 135: } 13: 136: memcpy(to->key_data_contents[i], from->key_data_contents[i], 13: 137: from->key_data_length[i]); -: 138: } -: 139: } 13: 140: return 0; -: 141:} -: 142: #####: 143:static krb5_tl_data *dup_tl_data(krb5_tl_data *tl) -: 144:{ -: 145: krb5_tl_data *n; -: 146: #####: 147: n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)); #####: 148: if (n == NULL) #####: 149: return NULL; #####: 150: n->tl_data_contents = malloc(tl->tl_data_length); #####: 151: if (n->tl_data_contents == NULL) { #####: 152: free(n); #####: 153: return NULL; -: 154: } #####: 155: memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length); #####: 156: n->tl_data_type = tl->tl_data_type; #####: 157: n->tl_data_length = tl->tl_data_length; #####: 158: n->tl_data_next = NULL; #####: 159: return n; -: 160:} -: 161: -: 162:/* This is in lib/kdb/kdb_cpw.c, but is static */ 1: 163:static void cleanup_key_data(context, count, data) -: 164: krb5_context context; -: 165: int count; -: 166: krb5_key_data * data; -: 167:{ -: 168: int i, j; -: 169: 3: 170: for (i = 0; i < count; i++) 4: 171: for (j = 0; j < data[i].key_data_ver; j++) 2: 172: if (data[i].key_data_length[j]) 2: 173: krb5_db_free(context, data[i].key_data_contents[j]); 1: 174: krb5_db_free(context, data); 1: 175:} -: 176: -: 177:/* -: 178: * Set *passptr to NULL if the request looks like the first part of a krb5 1.6 -: 179: * addprinc -randkey operation. The krb5 1.6 dummy password for these requests -: 180: * was invalid UTF-8, which runs afoul of the arcfour string-to-key. -: 181: */ -: 182:static void 622: 183:check_1_6_dummy(kadm5_principal_ent_t entry, long mask, -: 184: int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char **passptr) -: 185:{ -: 186: int i; 622: 187: char *password = *passptr; -: 188: -: 189: /* Old-style randkey operations disallowed tickets to start. */ 922: 190: if (!(mask & KADM5_ATTRIBUTES) || 300: 191: !(entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX)) 328: 192: return; -: 193: -: 194: /* The 1.6 dummy password was the octets 1..255. */ 294: 195: for (i = 0; (unsigned char) password[i] == i + 1; i++); 294: 196: if (password[i] != '\0' || i != 255) 294: 197: return; -: 198: -: 199: /* This will make the caller use a random password instead. */ #####: 200: *passptr = NULL; -: 201:} -: 202: -: 203:kadm5_ret_t 618: 204:kadm5_create_principal(void *server_handle, -: 205: kadm5_principal_ent_t entry, long mask, -: 206: char *password) -: 207:{ 618: 208: return 618: 209: kadm5_create_principal_3(server_handle, entry, mask, -: 210: 0, NULL, password); -: 211:} -: 212:kadm5_ret_t 622: 213:kadm5_create_principal_3(void *server_handle, -: 214: kadm5_principal_ent_t entry, long mask, -: 215: int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, -: 216: char *password) -: 217:{ -: 218: krb5_db_entry *kdb; -: 219: osa_princ_ent_rec adb; -: 220: kadm5_policy_ent_rec polent; 622: 221: krb5_boolean have_polent = FALSE; -: 222: krb5_int32 now; -: 223: krb5_tl_data *tl_data_orig, *tl_data_tail; -: 224: unsigned int ret; 622: 225: kadm5_server_handle_t handle = server_handle; -: 226: krb5_keyblock *act_mkey; -: 227: krb5_kvno act_kvno; -: 228: 622: 229: CHECK_HANDLE(server_handle); -: 230: 622: 231: krb5_clear_error_message(handle->context); -: 232: 622: 233: check_1_6_dummy(entry, mask, n_ks_tuple, ks_tuple, &password); -: 234: -: 235: /* -: 236: * Argument sanity checking, and opening up the DB -: 237: */ 6220: 238: if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) || 1244: 239: (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) || 1244: 240: (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) || 1244: 241: (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) || 1244: 242: (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) || 622: 243: (mask & KADM5_FAIL_AUTH_COUNT)) #####: 244: return KADM5_BAD_MASK; 622: 245: if((mask & ~ALL_PRINC_MASK)) #####: 246: return KADM5_BAD_MASK; 622: 247: if (entry == NULL) #####: 248: return EINVAL; -: 249: -: 250: /* Use default keysalts if caller did not provide any. */ 622: 251: if (n_ks_tuple == 0) { 618: 252: ks_tuple = handle->params.keysalts; 618: 253: n_ks_tuple = handle->params.num_keysalts; -: 254: } -: 255: -: 256: /* -: 257: * Check to see if the principal exists -: 258: */ 622: 259: ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); -: 260: 622: 261: switch(ret) { -: 262: case KADM5_UNK_PRINC: -: 263: break; -: 264: case 0: #####: 265: kdb_free_entry(handle, kdb, &adb); #####: 266: return KADM5_DUP; -: 267: default: #####: 268: return ret; -: 269: } -: 270: 622: 271: kdb = krb5_db_alloc(handle->context, NULL, sizeof(*kdb)); 622: 272: if (kdb == NULL) #####: 273: return ENOMEM; 622: 274: memset(kdb, 0, sizeof(*kdb)); 622: 275: memset(&adb, 0, sizeof(osa_princ_ent_rec)); -: 276: -: 277: /* -: 278: * If a policy was specified, load it. -: 279: * If we can not find the one specified return an error -: 280: */ 622: 281: if ((mask & KADM5_POLICY)) { #####: 282: if ((ret = kadm5_get_policy(handle->lhandle, entry->policy, -: 283: &polent)) != KADM5_OK) { #####: 284: if (ret == EINVAL) #####: 285: ret = KADM5_BAD_POLICY; #####: 286: if (ret) #####: 287: goto cleanup; -: 288: } #####: 289: have_polent = TRUE; -: 290: } 622: 291: if (password) { 530: 292: ret = passwd_check(handle, password, have_polent ? &polent : NULL, -: 293: entry->principal); 530: 294: if (ret) #####: 295: goto cleanup; -: 296: } -: 297: /* -: 298: * Start populating the various DB fields, using the -: 299: * "defaults" for fields that were not specified by the -: 300: * mask. -: 301: */ 622: 302: if ((ret = krb5_timeofday(handle->context, &now))) #####: 303: goto cleanup; -: 304: 622: 305: kdb->magic = KRB5_KDB_MAGIC_NUMBER; 622: 306: kdb->len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */ -: 307: 622: 308: if ((mask & KADM5_ATTRIBUTES)) 300: 309: kdb->attributes = entry->attributes; -: 310: else 322: 311: kdb->attributes = handle->params.flags; -: 312: 622: 313: if ((mask & KADM5_MAX_LIFE)) 294: 314: kdb->max_life = entry->max_life; -: 315: else 328: 316: kdb->max_life = handle->params.max_life; -: 317: 622: 318: if (mask & KADM5_MAX_RLIFE) #####: 319: kdb->max_renewable_life = entry->max_renewable_life; -: 320: else 622: 321: kdb->max_renewable_life = handle->params.max_rlife; -: 322: 622: 323: if ((mask & KADM5_PRINC_EXPIRE_TIME)) #####: 324: kdb->expiration = entry->princ_expire_time; -: 325: else 622: 326: kdb->expiration = handle->params.expiration; -: 327: 622: 328: kdb->pw_expiration = 0; 622: 329: if (have_polent) { #####: 330: if(polent.pw_max_life) #####: 331: kdb->pw_expiration = now + polent.pw_max_life; -: 332: else #####: 333: kdb->pw_expiration = 0; -: 334: } 622: 335: if ((mask & KADM5_PW_EXPIRATION)) 9: 336: kdb->pw_expiration = entry->pw_expiration; -: 337: 622: 338: kdb->last_success = 0; 622: 339: kdb->last_failed = 0; 622: 340: kdb->fail_auth_count = 0; -: 341: -: 342: /* this is kind of gross, but in order to free the tl data, I need -: 343: to free the entire kdb entry, and that will try to free the -: 344: principal. */ -: 345: 1244: 346: if ((ret = kadm5_copy_principal(handle->context, 1244: 347: entry->principal, &(kdb->princ)))) #####: 348: goto cleanup; -: 349: 622: 350: if ((ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now))) #####: 351: goto cleanup; -: 352: 622: 353: if (mask & KADM5_TL_DATA) { -: 354: /* splice entry->tl_data onto the front of kdb->tl_data */ #####: 355: tl_data_orig = kdb->tl_data; #####: 356: for (tl_data_tail = entry->tl_data; tl_data_tail; #####: 357: tl_data_tail = tl_data_tail->tl_data_next) -: 358: { #####: 359: ret = krb5_dbe_update_tl_data(handle->context, kdb, tl_data_tail); #####: 360: if( ret ) #####: 361: goto cleanup; -: 362: } -: 363: } -: 364: -: 365: /* initialize the keys */ -: 366: 622: 367: ret = krb5_dbe_find_act_mkey(handle->context, master_keylist, -: 368: active_mkey_list, &act_kvno, &act_mkey); 622: 369: if (ret) #####: 370: goto cleanup; -: 371: 622: 372: if (password) { 1060: 373: ret = krb5_dbe_cpw(handle->context, act_mkey, ks_tuple, n_ks_tuple, 530: 374: password, (mask & KADM5_KVNO)?entry->kvno:1, -: 375: FALSE, kdb); -: 376: } else { -: 377: /* Null password means create with random key (new in 1.8). */ 92: 378: ret = krb5_dbe_crk(handle->context, &master_keyblock, -: 379: ks_tuple, n_ks_tuple, FALSE, kdb); -: 380: } 622: 381: if (ret) #####: 382: goto cleanup; -: 383: -: 384: /* Record the master key VNO used to encrypt this entry's keys */ 622: 385: ret = krb5_dbe_update_mkvno(handle->context, kdb, act_kvno); 622: 386: if (ret) #####: 387: goto cleanup; -: 388: 622: 389: ret = k5_kadm5_hook_create(handle->context, handle->hook_handles, -: 390: KADM5_HOOK_STAGE_PRECOMMIT, entry, mask, -: 391: n_ks_tuple, ks_tuple, password); 622: 392: if (ret) #####: 393: goto cleanup; -: 394: -: 395: /* populate the admin-server-specific fields. In the OV server, -: 396: this used to be in a separate database. Since there's already -: 397: marshalling code for the admin fields, to keep things simple, -: 398: I'm going to keep it, and make all the admin stuff occupy a -: 399: single tl_data record, */ -: 400: 622: 401: adb.admin_history_kvno = INITIAL_HIST_KVNO; 622: 402: if (have_polent) { #####: 403: adb.aux_attributes = KADM5_POLICY; -: 404: -: 405: /* this does *not* need to be strdup'ed, because adb is xdr */ -: 406: /* encoded in osa_adb_create_princ, and not ever freed */ -: 407: #####: 408: adb.policy = entry->policy; -: 409: } -: 410: -: 411: /* increment the policy ref count, if any */ -: 412: 622: 413: if (have_polent) { #####: 414: polent.policy_refcnt++; #####: 415: if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, -: 416: KADM5_REF_COUNT)) -: 417: != KADM5_OK) #####: 418: goto cleanup; -: 419: } -: 420: -: 421: /* In all cases key and the principal data is set, let the database provider know */ 622: 422: kdb->mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL ; -: 423: -: 424: /* store the new db entry */ 622: 425: ret = kdb_put_entry(handle, kdb, &adb); -: 426: -: 427: 622: 428: if (ret) { #####: 429: if (have_polent) { -: 430: /* decrement the policy ref count */ -: 431: #####: 432: polent.policy_refcnt--; -: 433: /* -: 434: * if this fails, there's nothing we can do anyway. the -: 435: * policy refcount wil be too high. -: 436: */ #####: 437: (void) kadm5_modify_policy_internal(handle->lhandle, &polent, -: 438: KADM5_REF_COUNT); -: 439: } -: 440: } -: 441: 622: 442: (void) k5_kadm5_hook_create(handle->context, handle->hook_handles, -: 443: KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask, -: 444: n_ks_tuple, ks_tuple, password); -: 445: -: 446:cleanup: 622: 447: krb5_db_free_principal(handle->context, kdb); 622: 448: if (have_polent) #####: 449: (void) kadm5_free_policy_ent(handle->lhandle, &polent); 622: 450: return ret; -: 451:} -: 452: -: 453: -: 454:kadm5_ret_t #####: 455:kadm5_delete_principal(void *server_handle, krb5_principal principal) -: 456:{ -: 457: unsigned int ret; -: 458: kadm5_policy_ent_rec polent; -: 459: krb5_db_entry *kdb; -: 460: osa_princ_ent_rec adb; #####: 461: kadm5_server_handle_t handle = server_handle; -: 462: #####: 463: CHECK_HANDLE(server_handle); -: 464: #####: 465: krb5_clear_error_message(handle->context); -: 466: #####: 467: if (principal == NULL) #####: 468: return EINVAL; -: 469: #####: 470: if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) #####: 471: return(ret); #####: 472: ret = k5_kadm5_hook_remove(handle->context, handle->hook_handles, -: 473: KADM5_HOOK_STAGE_PRECOMMIT, principal); #####: 474: if (ret) { #####: 475: kdb_free_entry(handle, kdb, &adb); #####: 476: return ret; -: 477: } -: 478: #####: 479: if ((adb.aux_attributes & KADM5_POLICY)) { #####: 480: if ((ret = kadm5_get_policy(handle->lhandle, -: 481: adb.policy, &polent)) -: 482: == KADM5_OK) { #####: 483: polent.policy_refcnt--; #####: 484: if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, -: 485: KADM5_REF_COUNT)) -: 486: != KADM5_OK) { #####: 487: (void) kadm5_free_policy_ent(handle->lhandle, &polent); #####: 488: kdb_free_entry(handle, kdb, &adb); #####: 489: return(ret); -: 490: } -: 491: } #####: 492: if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) { #####: 493: kdb_free_entry(handle, kdb, &adb); #####: 494: return ret; -: 495: } -: 496: } -: 497: #####: 498: ret = kdb_delete_entry(handle, principal); -: 499: #####: 500: kdb_free_entry(handle, kdb, &adb); -: 501: #####: 502: if (ret == 0) #####: 503: (void) k5_kadm5_hook_remove(handle->context, -: 504: handle->hook_handles, -: 505: KADM5_HOOK_STAGE_POSTCOMMIT, principal); -: 506: #####: 507: return ret; -: 508:} -: 509: -: 510:kadm5_ret_t 304: 511:kadm5_modify_principal(void *server_handle, -: 512: kadm5_principal_ent_t entry, long mask) -: 513:{ -: 514: int ret, ret2, i; -: 515: kadm5_policy_ent_rec npol, opol; 304: 516: int have_npol = 0, have_opol = 0; -: 517: krb5_db_entry *kdb; -: 518: krb5_tl_data *tl_data_orig; -: 519: osa_princ_ent_rec adb; 304: 520: kadm5_server_handle_t handle = server_handle; -: 521: 304: 522: CHECK_HANDLE(server_handle); -: 523: 304: 524: krb5_clear_error_message(handle->context); -: 525: 2432: 526: if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) || 608: 527: (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) || 608: 528: (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) || 608: 529: (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) || 304: 530: (mask & KADM5_LAST_FAILED)) #####: 531: return KADM5_BAD_MASK; 304: 532: if((mask & ~ALL_PRINC_MASK)) #####: 533: return KADM5_BAD_MASK; 304: 534: if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR)) #####: 535: return KADM5_BAD_MASK; 304: 536: if(entry == (kadm5_principal_ent_t) NULL) #####: 537: return EINVAL; 304: 538: if (mask & KADM5_TL_DATA) { 1: 539: tl_data_orig = entry->tl_data; 3: 540: while (tl_data_orig) { 1: 541: if (tl_data_orig->tl_data_type < 256) #####: 542: return KADM5_BAD_TL_TYPE; 1: 543: tl_data_orig = tl_data_orig->tl_data_next; -: 544: } -: 545: } -: 546: 304: 547: ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); 304: 548: if (ret) #####: 549: return(ret); -: 550: -: 551: /* -: 552: * This is pretty much the same as create ... -: 553: */ -: 554: 304: 555: if ((mask & KADM5_POLICY)) { -: 556: /* get the new policy */ 1: 557: ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol); 1: 558: if (ret) { #####: 559: switch (ret) { -: 560: case EINVAL: #####: 561: ret = KADM5_BAD_POLICY; #####: 562: break; -: 563: case KADM5_UNK_POLICY: -: 564: case KADM5_BAD_POLICY: #####: 565: ret = KADM5_UNK_POLICY; -: 566: break; -: 567: } #####: 568: goto done; -: 569: } 1: 570: have_npol = 1; -: 571: -: 572: /* if we already have a policy, get it to decrement the refcnt */ 1: 573: if(adb.aux_attributes & KADM5_POLICY) { -: 574: /* ... but not if the old and new are the same */ #####: 575: if(strcmp(adb.policy, entry->policy)) { #####: 576: ret = kadm5_get_policy(handle->lhandle, -: 577: adb.policy, &opol); #####: 578: switch(ret) { -: 579: case EINVAL: -: 580: case KADM5_BAD_POLICY: -: 581: case KADM5_UNK_POLICY: #####: 582: break; -: 583: case KADM5_OK: #####: 584: have_opol = 1; #####: 585: opol.policy_refcnt--; #####: 586: break; -: 587: default: #####: 588: goto done; -: 589: break; -: 590: } #####: 591: npol.policy_refcnt++; -: 592: } 1: 593: } else npol.policy_refcnt++; -: 594: -: 595: /* set us up to use the new policy */ 1: 596: adb.aux_attributes |= KADM5_POLICY; 1: 597: if (adb.policy) #####: 598: free(adb.policy); 1: 599: adb.policy = strdup(entry->policy); -: 600: -: 601: /* set pw_max_life based on new policy */ 1: 602: if (npol.pw_max_life) { #####: 603: ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb, #####: 604: &(kdb->pw_expiration)); #####: 605: if (ret) #####: 606: goto done; #####: 607: kdb->pw_expiration += npol.pw_max_life; -: 608: } else { 1: 609: kdb->pw_expiration = 0; -: 610: } -: 611: } -: 612: 304: 613: if ((mask & KADM5_POLICY_CLR) && #####: 614: (adb.aux_attributes & KADM5_POLICY)) { #####: 615: ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol); #####: 616: switch(ret) { -: 617: case EINVAL: -: 618: case KADM5_BAD_POLICY: -: 619: case KADM5_UNK_POLICY: #####: 620: ret = KADM5_BAD_DB; #####: 621: goto done; -: 622: break; -: 623: case KADM5_OK: #####: 624: have_opol = 1; #####: 625: if (adb.policy) #####: 626: free(adb.policy); #####: 627: adb.policy = NULL; #####: 628: adb.aux_attributes &= ~KADM5_POLICY; #####: 629: kdb->pw_expiration = 0; #####: 630: opol.policy_refcnt--; #####: 631: break; -: 632: default: #####: 633: goto done; -: 634: break; -: 635: } -: 636: } -: 637: 305: 638: if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) && -: 639: (((have_opol) && -: 640: (ret = #####: 641: kadm5_modify_policy_internal(handle->lhandle, &opol, -: 642: KADM5_REF_COUNT))) || -: 643: ((have_npol) && -: 644: (ret = 1: 645: kadm5_modify_policy_internal(handle->lhandle, &npol, -: 646: KADM5_REF_COUNT))))) -: 647: goto done; -: 648: 304: 649: if ((mask & KADM5_ATTRIBUTES)) 295: 650: kdb->attributes = entry->attributes; 304: 651: if ((mask & KADM5_MAX_LIFE)) #####: 652: kdb->max_life = entry->max_life; 304: 653: if ((mask & KADM5_PRINC_EXPIRE_TIME)) #####: 654: kdb->expiration = entry->princ_expire_time; 304: 655: if (mask & KADM5_PW_EXPIRATION) #####: 656: kdb->pw_expiration = entry->pw_expiration; 304: 657: if (mask & KADM5_MAX_RLIFE) 2: 658: kdb->max_renewable_life = entry->max_renewable_life; -: 659: 304: 660: if((mask & KADM5_KVNO)) { 18: 661: for (i = 0; i < kdb->n_key_data; i++) 12: 662: kdb->key_data[i].key_data_kvno = entry->kvno; -: 663: } -: 664: 304: 665: if (mask & KADM5_TL_DATA) { -: 666: krb5_tl_data *tl; -: 667: -: 668: /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */ -: 669: 3: 670: for (tl = entry->tl_data; tl; 1: 671: tl = tl->tl_data_next) -: 672: { 1: 673: ret = krb5_dbe_update_tl_data(handle->context, kdb, tl); 1: 674: if( ret ) -: 675: { #####: 676: goto done; -: 677: } -: 678: } -: 679: } -: 680: -: 681: /* -: 682: * Setting entry->fail_auth_count to 0 can be used to manually unlock -: 683: * an account. It is not possible to set fail_auth_count to any other -: 684: * value using kadmin. -: 685: */ 304: 686: if (mask & KADM5_FAIL_AUTH_COUNT) { 1: 687: if (entry->fail_auth_count != 0) { #####: 688: ret = KADM5_BAD_SERVER_PARAMS; #####: 689: goto done; -: 690: } -: 691: 1: 692: kdb->fail_auth_count = 0; -: 693: } -: 694: -: 695: /* let the mask propagate to the database provider */ 304: 696: kdb->mask = mask; -: 697: 304: 698: ret = k5_kadm5_hook_modify(handle->context, handle->hook_handles, -: 699: KADM5_HOOK_STAGE_PRECOMMIT, entry, mask); 304: 700: if (ret) #####: 701: goto done; -: 702: 304: 703: ret = kdb_put_entry(handle, kdb, &adb); 304: 704: if (ret) goto done; 304: 705: (void) k5_kadm5_hook_modify(handle->context, handle->hook_handles, -: 706: KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask); -: 707: 304: 708: ret = KADM5_OK; -: 709:done: 304: 710: if (have_opol) { #####: 711: ret2 = kadm5_free_policy_ent(handle->lhandle, &opol); #####: 712: ret = ret ? ret : ret2; -: 713: } 304: 714: if (have_npol) { 1: 715: ret2 = kadm5_free_policy_ent(handle->lhandle, &npol); 1: 716: ret = ret ? ret : ret2; -: 717: } 304: 718: kdb_free_entry(handle, kdb, &adb); 304: 719: return ret; -: 720:} -: 721: -: 722:kadm5_ret_t 6: 723:kadm5_rename_principal(void *server_handle, -: 724: krb5_principal source, krb5_principal target) -: 725:{ -: 726: krb5_db_entry *kdb; -: 727: osa_princ_ent_rec adb; -: 728: krb5_error_code ret; 6: 729: kadm5_server_handle_t handle = server_handle; -: 730: krb5_int16 stype, i; 6: 731: krb5_data *salt = NULL; -: 732: 6: 733: CHECK_HANDLE(server_handle); -: 734: 6: 735: krb5_clear_error_message(handle->context); -: 736: 6: 737: if (source == NULL || target == NULL) #####: 738: return EINVAL; -: 739: 6: 740: if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) { #####: 741: kdb_free_entry(handle, kdb, &adb); #####: 742: return(KADM5_DUP); -: 743: } -: 744: 6: 745: if ((ret = kdb_get_entry(handle, source, &kdb, &adb))) #####: 746: return ret; -: 747: -: 748: /* Transform salts as necessary. */ 15: 749: for (i = 0; i < kdb->n_key_data; i++) { 9: 750: ret = krb5_dbe_compute_salt(handle->context, &kdb->key_data[i], 9: 751: kdb->princ, &stype, &salt); 9: 752: if (ret == KRB5_KDB_BAD_SALTTYPE) #####: 753: ret = KADM5_NO_RENAME_SALT; 9: 754: if (ret) #####: 755: goto done; 9: 756: kdb->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL; 9: 757: free(kdb->key_data[i].key_data_contents[1]); 9: 758: kdb->key_data[i].key_data_contents[1] = (krb5_octet *)salt->data; 9: 759: kdb->key_data[i].key_data_length[1] = salt->length; 9: 760: kdb->key_data[i].key_data_ver = 2; 9: 761: free(salt); 9: 762: salt = NULL; -: 763: } -: 764: 6: 765: kadm5_free_principal(handle->context, kdb->princ); 6: 766: ret = kadm5_copy_principal(handle->context, target, &kdb->princ); 6: 767: if (ret) { #####: 768: kdb->princ = NULL; /* so freeing the dbe doesn't lose */ #####: 769: goto done; -: 770: } -: 771: 6: 772: if ((ret = kdb_put_entry(handle, kdb, &adb))) #####: 773: goto done; -: 774: 6: 775: ret = kdb_delete_entry(handle, source); -: 776: -: 777:done: 6: 778: krb5_free_data(handle->context, salt); 6: 779: kdb_free_entry(handle, kdb, &adb); 6: 780: return ret; -: 781:} -: 782: -: 783:kadm5_ret_t 135: 784:kadm5_get_principal(void *server_handle, krb5_principal principal, -: 785: kadm5_principal_ent_t entry, -: 786: long in_mask) -: 787:{ -: 788: krb5_db_entry *kdb; -: 789: osa_princ_ent_rec adb; 135: 790: krb5_error_code ret = 0; -: 791: long mask; -: 792: int i; 135: 793: kadm5_server_handle_t handle = server_handle; -: 794: 135: 795: CHECK_HANDLE(server_handle); -: 796: 135: 797: krb5_clear_error_message(handle->context); -: 798: -: 799: /* -: 800: * In version 1, all the defined fields are always returned. -: 801: * entry is a pointer to a kadm5_principal_ent_t_v1 that should be -: 802: * filled with allocated memory. -: 803: */ 135: 804: mask = in_mask; -: 805: 135: 806: memset(entry, 0, sizeof(*entry)); -: 807: 135: 808: if (principal == NULL) #####: 809: return EINVAL; -: 810: 135: 811: if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) #####: 812: return ret; -: 813: 271: 814: if ((mask & KADM5_POLICY) && 136: 815: adb.policy && (adb.aux_attributes & KADM5_POLICY)) { 1: 816: if ((entry->policy = strdup(adb.policy)) == NULL) { #####: 817: ret = ENOMEM; #####: 818: goto done; -: 819: } -: 820: } -: 821: 135: 822: if (mask & KADM5_AUX_ATTRIBUTES) 135: 823: entry->aux_attributes = adb.aux_attributes; -: 824: 270: 825: if ((mask & KADM5_PRINCIPAL) && 135: 826: (ret = krb5_copy_principal(handle->context, kdb->princ, -: 827: &entry->principal))) { #####: 828: goto done; -: 829: } -: 830: 135: 831: if (mask & KADM5_PRINC_EXPIRE_TIME) 135: 832: entry->princ_expire_time = kdb->expiration; -: 833: 270: 834: if ((mask & KADM5_LAST_PWD_CHANGE) && 135: 835: (ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb, -: 836: &(entry->last_pwd_change)))) { #####: 837: goto done; -: 838: } -: 839: 135: 840: if (mask & KADM5_PW_EXPIRATION) 135: 841: entry->pw_expiration = kdb->pw_expiration; 135: 842: if (mask & KADM5_MAX_LIFE) 135: 843: entry->max_life = kdb->max_life; -: 844: -: 845: /* this is a little non-sensical because the function returns two */ -: 846: /* values that must be checked separately against the mask */ 135: 847: if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) { 135: 848: ret = krb5_dbe_lookup_mod_princ_data(handle->context, kdb, -: 849: &(entry->mod_date), -: 850: &(entry->mod_name)); 135: 851: if (ret) { #####: 852: goto done; -: 853: } -: 854: 135: 855: if (! (mask & KADM5_MOD_TIME)) #####: 856: entry->mod_date = 0; 135: 857: if (! (mask & KADM5_MOD_NAME)) { #####: 858: krb5_free_principal(handle->context, entry->mod_name); #####: 859: entry->mod_name = NULL; -: 860: } -: 861: } -: 862: 135: 863: if (mask & KADM5_ATTRIBUTES) 135: 864: entry->attributes = kdb->attributes; -: 865: 135: 866: if (mask & KADM5_KVNO) 492: 867: for (entry->kvno = 0, i=0; in_key_data; i++) 357: 868: if ((krb5_kvno) kdb->key_data[i].key_data_kvno > entry->kvno) 135: 869: entry->kvno = kdb->key_data[i].key_data_kvno; -: 870: 135: 871: if (mask & KADM5_MKVNO) { 135: 872: ret = krb5_dbe_get_mkvno(handle->context, kdb, master_keylist, -: 873: &entry->mkvno); 135: 874: if (ret) #####: 875: goto done; -: 876: } -: 877: 135: 878: if (mask & KADM5_MAX_RLIFE) 135: 879: entry->max_renewable_life = kdb->max_renewable_life; 135: 880: if (mask & KADM5_LAST_SUCCESS) 135: 881: entry->last_success = kdb->last_success; 135: 882: if (mask & KADM5_LAST_FAILED) 135: 883: entry->last_failed = kdb->last_failed; 135: 884: if (mask & KADM5_FAIL_AUTH_COUNT) 135: 885: entry->fail_auth_count = kdb->fail_auth_count; 135: 886: if (mask & KADM5_TL_DATA) { -: 887: krb5_tl_data *tl, *tl2; -: 888: #####: 889: entry->tl_data = NULL; -: 890: #####: 891: tl = kdb->tl_data; #####: 892: while (tl) { #####: 893: if (tl->tl_data_type > 255) { #####: 894: if ((tl2 = dup_tl_data(tl)) == NULL) { #####: 895: ret = ENOMEM; #####: 896: goto done; -: 897: } #####: 898: tl2->tl_data_next = entry->tl_data; #####: 899: entry->tl_data = tl2; #####: 900: entry->n_tl_data++; -: 901: } -: 902: #####: 903: tl = tl->tl_data_next; -: 904: } -: 905: } 135: 906: if (mask & KADM5_KEY_DATA) { 7: 907: entry->n_key_data = kdb->n_key_data; 7: 908: if(entry->n_key_data) { 7: 909: entry->key_data = malloc(entry->n_key_data*sizeof(krb5_key_data)); 7: 910: if (entry->key_data == NULL) { #####: 911: ret = ENOMEM; #####: 912: goto done; -: 913: } -: 914: } else #####: 915: entry->key_data = NULL; -: 916: 20: 917: for (i = 0; i < entry->n_key_data; i++) 52: 918: ret = krb5_copy_key_data_contents(handle->context, 26: 919: &kdb->key_data[i], 13: 920: &entry->key_data[i]); 7: 921: if (ret) #####: 922: goto done; -: 923: } -: 924: 135: 925: ret = KADM5_OK; -: 926: -: 927:done: 135: 928: if (ret && entry->principal) { #####: 929: krb5_free_principal(handle->context, entry->principal); #####: 930: entry->principal = NULL; -: 931: } 135: 932: kdb_free_entry(handle, kdb, &adb); -: 933: 135: 934: return ret; -: 935:} -: 936: -: 937:/* -: 938: * Function: check_pw_reuse -: 939: * -: 940: * Purpose: Check if a key appears in a list of keys, in order to -: 941: * enforce password history. -: 942: * -: 943: * Arguments: -: 944: * -: 945: * context (r) the krb5 context -: 946: * hist_keyblock (r) the key that hist_key_data is -: 947: * encrypted in -: 948: * n_new_key_data (r) length of new_key_data -: 949: * new_key_data (r) keys to check against -: 950: * pw_hist_data, encrypted in hist_keyblock -: 951: * n_pw_hist_data (r) length of pw_hist_data -: 952: * pw_hist_data (r) passwords to check new_key_data against -: 953: * -: 954: * Effects: -: 955: * For each new_key in new_key_data: -: 956: * decrypt new_key with the master_keyblock -: 957: * for each password in pw_hist_data: -: 958: * for each hist_key in password: -: 959: * decrypt hist_key with hist_keyblock -: 960: * compare the new_key and hist_key -: 961: * -: 962: * Returns krb5 errors, KADM5_PASS_RESUSE if a key in -: 963: * new_key_data is the same as a key in pw_hist_data, or 0. -: 964: */ -: 965:static kadm5_ret_t #####: 966:check_pw_reuse(krb5_context context, -: 967: krb5_keyblock *hist_keyblock, -: 968: int n_new_key_data, krb5_key_data *new_key_data, -: 969: unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data) -: 970:{ -: 971: unsigned int x, y, z; -: 972: krb5_keyblock newkey, histkey; -: 973: krb5_error_code ret; -: 974: #####: 975: assert (n_new_key_data >= 0); #####: 976: for (x = 0; x < (unsigned) n_new_key_data; x++) { #####: 977: ret = krb5_dbe_decrypt_key_data(context, NULL, &(new_key_data[x]), -: 978: &newkey, NULL); #####: 979: if (ret) #####: 980: return(ret); #####: 981: for (y = 0; y < n_pw_hist_data; y++) { #####: 982: for (z = 0; z < (unsigned int) pw_hist_data[y].n_key_data; z++) { #####: 983: ret = krb5_dbe_decrypt_key_data(context, hist_keyblock, #####: 984: &pw_hist_data[y].key_data[z], -: 985: &histkey, NULL); #####: 986: if (ret) #####: 987: return(ret); -: 988: #####: 989: if ((newkey.length == histkey.length) && #####: 990: (newkey.enctype == histkey.enctype) && #####: 991: (memcmp(newkey.contents, histkey.contents, -: 992: histkey.length) == 0)) { #####: 993: krb5_free_keyblock_contents(context, &histkey); #####: 994: krb5_free_keyblock_contents(context, &newkey); -: 995: #####: 996: return(KADM5_PASS_REUSE); -: 997: } #####: 998: krb5_free_keyblock_contents(context, &histkey); -: 999: } -: 1000: } #####: 1001: krb5_free_keyblock_contents(context, &newkey); -: 1002: } -: 1003: #####: 1004: return(0); -: 1005:} -: 1006: -: 1007:/* -: 1008: * Function: create_history_entry -: 1009: * -: 1010: * Purpose: Creates a password history entry from an array of -: 1011: * key_data. -: 1012: * -: 1013: * Arguments: -: 1014: * -: 1015: * context (r) krb5_context to use -: 1016: * mkey (r) master keyblock to decrypt key data with -: 1017: * hist_key (r) history keyblock to encrypt key data with -: 1018: * n_key_data (r) number of elements in key_data -: 1019: * key_data (r) keys to add to the history entry -: 1020: * hist (w) history entry to fill in -: 1021: * -: 1022: * Effects: -: 1023: * -: 1024: * hist->key_data is allocated to store n_key_data key_datas. Each -: 1025: * element of key_data is decrypted with master_keyblock, re-encrypted -: 1026: * in hist_key, and added to hist->key_data. hist->n_key_data is -: 1027: * set to n_key_data. -: 1028: */ -: 1029:static #####: 1030:int create_history_entry(krb5_context context, -: 1031: krb5_keyblock *hist_key, int n_key_data, -: 1032: krb5_key_data *key_data, osa_pw_hist_ent *hist) -: 1033:{ -: 1034: int i, ret; -: 1035: krb5_keyblock key; -: 1036: krb5_keysalt salt; -: 1037: #####: 1038: hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data)); #####: 1039: if (hist->key_data == NULL) #####: 1040: return ENOMEM; #####: 1041: memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data)); -: 1042: #####: 1043: for (i = 0; i < n_key_data; i++) { #####: 1044: ret = krb5_dbe_decrypt_key_data(context, NULL, &key_data[i], &key, -: 1045: &salt); #####: 1046: if (ret) #####: 1047: return ret; -: 1048: #####: 1049: ret = krb5_dbe_encrypt_key_data(context, hist_key, &key, &salt, #####: 1050: key_data[i].key_data_kvno, #####: 1051: &hist->key_data[i]); #####: 1052: if (ret) #####: 1053: return ret; -: 1054: #####: 1055: krb5_free_keyblock_contents(context, &key); -: 1056: /* krb5_free_keysalt(context, &salt); */ -: 1057: } -: 1058: #####: 1059: hist->n_key_data = n_key_data; #####: 1060: return 0; -: 1061:} -: 1062: -: 1063:static #####: 1064:void free_history_entry(krb5_context context, osa_pw_hist_ent *hist) -: 1065:{ -: 1066: int i; -: 1067: #####: 1068: for (i = 0; i < hist->n_key_data; i++) #####: 1069: krb5_free_key_data_contents(context, &hist->key_data[i]); #####: 1070: free(hist->key_data); #####: 1071:} -: 1072: -: 1073:/* -: 1074: * Function: add_to_history -: 1075: * -: 1076: * Purpose: Adds a password to a principal's password history. -: 1077: * -: 1078: * Arguments: -: 1079: * -: 1080: * context (r) krb5_context to use -: 1081: * hist_kvno (r) kvno of current history key -: 1082: * adb (r/w) admin principal entry to add keys to -: 1083: * pol (r) adb's policy -: 1084: * pw (r) keys for the password to add to adb's key history -: 1085: * -: 1086: * Effects: -: 1087: * -: 1088: * add_to_history adds a single password to adb's password history. -: 1089: * pw contains n_key_data keys in its key_data, in storage should be -: 1090: * allocated but not freed by the caller (XXX blech!). -: 1091: * -: 1092: * This function maintains adb->old_keys as a circular queue. It -: 1093: * starts empty, and grows each time this function is called until it -: 1094: * is pol->pw_history_num items long. adb->old_key_len holds the -: 1095: * number of allocated entries in the array, and must therefore be [0, -: 1096: * pol->pw_history_num). adb->old_key_next is the index into the -: 1097: * array where the next element should be written, and must be [0, -: 1098: * adb->old_key_len). -: 1099: */ #####: 1100:static kadm5_ret_t add_to_history(krb5_context context, -: 1101: krb5_kvno hist_kvno, -: 1102: osa_princ_ent_t adb, -: 1103: kadm5_policy_ent_t pol, -: 1104: osa_pw_hist_ent *pw) -: 1105:{ -: 1106: osa_pw_hist_ent *histp; -: 1107: uint32_t nhist; -: 1108: unsigned int i, knext, nkeys; -: 1109: #####: 1110: nhist = pol->pw_history_num; -: 1111: /* A history of 1 means just check the current password */ #####: 1112: if (nhist <= 1) #####: 1113: return 0; -: 1114: #####: 1115: if (adb->admin_history_kvno != hist_kvno) { -: 1116: /* The history key has changed since the last password change, so we -: 1117: * have to reset the password history. */ #####: 1118: free(adb->old_keys); #####: 1119: adb->old_keys = NULL; #####: 1120: adb->old_key_len = 0; #####: 1121: adb->old_key_next = 0; #####: 1122: adb->admin_history_kvno = hist_kvno; -: 1123: } -: 1124: #####: 1125: nkeys = adb->old_key_len; #####: 1126: knext = adb->old_key_next; -: 1127: /* resize the adb->old_keys array if necessary */ #####: 1128: if (nkeys + 1 < nhist) { #####: 1129: if (adb->old_keys == NULL) { #####: 1130: adb->old_keys = (osa_pw_hist_ent *) -: 1131: malloc((nkeys + 1) * sizeof (osa_pw_hist_ent)); -: 1132: } else { #####: 1133: adb->old_keys = (osa_pw_hist_ent *) #####: 1134: realloc(adb->old_keys, -: 1135: (nkeys + 1) * sizeof (osa_pw_hist_ent)); -: 1136: } #####: 1137: if (adb->old_keys == NULL) #####: 1138: return(ENOMEM); -: 1139: #####: 1140: memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent)); #####: 1141: nkeys = ++adb->old_key_len; -: 1142: /* -: 1143: * To avoid losing old keys, shift forward each entry after -: 1144: * knext. -: 1145: */ #####: 1146: for (i = nkeys - 1; i > knext; i--) { #####: 1147: adb->old_keys[i] = adb->old_keys[i - 1]; -: 1148: } #####: 1149: memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent)); #####: 1150: } else if (nkeys + 1 > nhist) { -: 1151: /* -: 1152: * The policy must have changed! Shrink the array. -: 1153: * Can't simply realloc() down, since it might be wrapped. -: 1154: * To understand the arithmetic below, note that we are -: 1155: * copying into new positions 0 .. N-1 from old positions -: 1156: * old_key_next-N .. old_key_next-1, modulo old_key_len, -: 1157: * where N = pw_history_num - 1 is the length of the -: 1158: * shortened list. Matt Crawford, FNAL -: 1159: */ -: 1160: /* -: 1161: * M = adb->old_key_len, N = pol->pw_history_num - 1 -: 1162: * -: 1163: * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M] -: 1164: */ -: 1165: int j; -: 1166: osa_pw_hist_t tmp; -: 1167: #####: 1168: tmp = (osa_pw_hist_ent *) -: 1169: malloc((nhist - 1) * sizeof (osa_pw_hist_ent)); #####: 1170: if (tmp == NULL) #####: 1171: return ENOMEM; #####: 1172: for (i = 0; i < nhist - 1; i++) { -: 1173: /* -: 1174: * Add nkeys once before taking remainder to avoid -: 1175: * negative values. -: 1176: */ #####: 1177: j = (i + nkeys + knext - (nhist - 1)) % nkeys; #####: 1178: tmp[i] = adb->old_keys[j]; -: 1179: } -: 1180: /* Now free the ones we don't keep (the oldest ones) */ #####: 1181: for (i = 0; i < nkeys - (nhist - 1); i++) { #####: 1182: j = (i + nkeys + knext) % nkeys; #####: 1183: histp = &adb->old_keys[j]; #####: 1184: for (j = 0; j < histp->n_key_data; j++) { #####: 1185: krb5_free_key_data_contents(context, &histp->key_data[j]); -: 1186: } #####: 1187: free(histp->key_data); -: 1188: } #####: 1189: free(adb->old_keys); #####: 1190: adb->old_keys = tmp; #####: 1191: nkeys = adb->old_key_len = nhist - 1; #####: 1192: knext = adb->old_key_next = 0; -: 1193: } -: 1194: -: 1195: /* -: 1196: * If nhist decreased since the last password change, and nkeys+1 -: 1197: * is less than the previous nhist, it is possible for knext to -: 1198: * index into unallocated space. This condition would not be -: 1199: * caught by the resizing code above. -: 1200: */ #####: 1201: if (knext + 1 > nkeys) #####: 1202: knext = adb->old_key_next = 0; -: 1203: /* free the old pw history entry if it contains data */ #####: 1204: histp = &adb->old_keys[knext]; #####: 1205: for (i = 0; i < (unsigned int) histp->n_key_data; i++) #####: 1206: krb5_free_key_data_contents(context, &histp->key_data[i]); #####: 1207: free(histp->key_data); -: 1208: -: 1209: /* store the new entry */ #####: 1210: adb->old_keys[knext] = *pw; -: 1211: -: 1212: /* update the next pointer */ #####: 1213: if (++adb->old_key_next == nhist - 1) #####: 1214: adb->old_key_next = 0; -: 1215: #####: 1216: return(0); -: 1217:} -: 1218: -: 1219:/* FIXME: don't use global variable for this */ -: 1220:krb5_boolean use_password_server = 0; -: 1221: -: 1222:#ifdef USE_PASSWORD_SERVER -: 1223:static krb5_boolean -: 1224:kadm5_use_password_server (void) -: 1225:{ -: 1226: return use_password_server; -: 1227:} -: 1228:#endif -: 1229: -: 1230:void #####: 1231:kadm5_set_use_password_server (void) -: 1232:{ #####: 1233: use_password_server = 1; #####: 1234:} -: 1235: -: 1236:#ifdef USE_PASSWORD_SERVER -: 1237: -: 1238:/* -: 1239: * kadm5_launch_task () runs a program (task_path) to synchronize the -: 1240: * Apple password server with the Kerberos database. Password server -: 1241: * programs can receive arguments on the command line (task_argv) -: 1242: * and a block of data via stdin (data_buffer). -: 1243: * -: 1244: * Because a failure to communicate with the tool results in the -: 1245: * password server falling out of sync with the database, -: 1246: * kadm5_launch_task() always fails if it can't talk to the tool. -: 1247: */ -: 1248: -: 1249:static kadm5_ret_t -: 1250:kadm5_launch_task (krb5_context context, -: 1251: const char *task_path, char * const task_argv[], -: 1252: const char *buffer) -: 1253:{ -: 1254: kadm5_ret_t ret; -: 1255: int data_pipe[2]; -: 1256: -: 1257: ret = pipe (data_pipe); -: 1258: if (ret) -: 1259: ret = errno; -: 1260: -: 1261: if (!ret) { -: 1262: pid_t pid = fork (); -: 1263: if (pid == -1) { -: 1264: ret = errno; -: 1265: close (data_pipe[0]); -: 1266: close (data_pipe[1]); -: 1267: } else if (pid == 0) { -: 1268: /* The child: */ -: 1269: -: 1270: if (dup2 (data_pipe[0], STDIN_FILENO) == -1) -: 1271: _exit (1); -: 1272: -: 1273: close (data_pipe[0]); -: 1274: close (data_pipe[1]); -: 1275: -: 1276: execv (task_path, task_argv); -: 1277: -: 1278: _exit (1); /* Fail if execv fails */ -: 1279: } else { -: 1280: /* The parent: */ -: 1281: int status; -: 1282: -: 1283: ret = 0; -: 1284: -: 1285: close (data_pipe[0]); -: 1286: -: 1287: /* Write out the buffer to the child, add \n */ -: 1288: if (buffer) { -: 1289: if (krb5_net_write (context, data_pipe[1], buffer, strlen (buffer)) < 0 -: 1290: || krb5_net_write (context, data_pipe[1], "\n", 1) < 0) -: 1291: { -: 1292: /* kill the child to make sure waitpid() won't hang later */ -: 1293: ret = errno; -: 1294: kill (pid, SIGKILL); -: 1295: } -: 1296: } -: 1297: close (data_pipe[1]); -: 1298: -: 1299: waitpid (pid, &status, 0); -: 1300: -: 1301: if (!ret) { -: 1302: if (WIFEXITED (status)) { -: 1303: /* child read password and exited. Check the return value. */ -: 1304: if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) { -: 1305: ret = KRB5KDC_ERR_POLICY; /* password change rejected */ -: 1306: } -: 1307: } else { -: 1308: /* child read password but crashed or was killed */ -: 1309: ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */ -: 1310: } -: 1311: } -: 1312: } -: 1313: } -: 1314: -: 1315: return ret; -: 1316:} -: 1317: -: 1318:#endif -: 1319: -: 1320:kadm5_ret_t #####: 1321:kadm5_chpass_principal(void *server_handle, -: 1322: krb5_principal principal, char *password) -: 1323:{ #####: 1324: return #####: 1325: kadm5_chpass_principal_3(server_handle, principal, FALSE, -: 1326: 0, NULL, password); -: 1327:} -: 1328: -: 1329:kadm5_ret_t #####: 1330:kadm5_chpass_principal_3(void *server_handle, -: 1331: krb5_principal principal, krb5_boolean keepold, -: 1332: int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, -: 1333: char *password) -: 1334:{ -: 1335: krb5_int32 now; -: 1336: kadm5_policy_ent_rec pol; -: 1337: osa_princ_ent_rec adb; -: 1338: krb5_db_entry *kdb; -: 1339: int ret, ret2, last_pwd, hist_added; #####: 1340: int have_pol = 0; #####: 1341: kadm5_server_handle_t handle = server_handle; -: 1342: osa_pw_hist_ent hist; -: 1343: krb5_keyblock *act_mkey, hist_keyblock; -: 1344: krb5_kvno act_kvno, hist_kvno; -: 1345: #####: 1346: CHECK_HANDLE(server_handle); -: 1347: #####: 1348: krb5_clear_error_message(handle->context); -: 1349: #####: 1350: hist_added = 0; #####: 1351: memset(&hist, 0, sizeof(hist)); #####: 1352: memset(&hist_keyblock, 0, sizeof(hist_keyblock)); -: 1353: #####: 1354: if (principal == NULL || password == NULL) #####: 1355: return EINVAL; #####: 1356: if ((krb5_principal_compare(handle->context, -: 1357: principal, hist_princ)) == TRUE) #####: 1358: return KADM5_PROTECT_PRINCIPAL; -: 1359: -: 1360: /* Use default keysalts if caller did not provide any. */ #####: 1361: if (n_ks_tuple == 0) { #####: 1362: ks_tuple = handle->params.keysalts; #####: 1363: n_ks_tuple = handle->params.num_keysalts; -: 1364: } -: 1365: #####: 1366: if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) #####: 1367: return(ret); -: 1368: #####: 1369: if ((adb.aux_attributes & KADM5_POLICY)) { #####: 1370: if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol))) #####: 1371: goto done; #####: 1372: have_pol = 1; -: 1373: -: 1374: /* Create a password history entry before we change kdb's key_data. */ #####: 1375: ret = kdb_get_hist_key(handle, &hist_keyblock, &hist_kvno); #####: 1376: if (ret) #####: 1377: goto done; #####: 1378: ret = create_history_entry(handle->context, &hist_keyblock, #####: 1379: kdb->n_key_data, kdb->key_data, &hist); #####: 1380: if (ret) #####: 1381: goto done; -: 1382: } -: 1383: #####: 1384: if ((ret = passwd_check(handle, password, have_pol ? &pol : NULL, -: 1385: principal))) #####: 1386: goto done; -: 1387: #####: 1388: ret = krb5_dbe_find_act_mkey(handle->context, master_keylist, -: 1389: active_mkey_list, &act_kvno, &act_mkey); #####: 1390: if (ret) #####: 1391: goto done; -: 1392: #####: 1393: ret = krb5_dbe_cpw(handle->context, act_mkey, ks_tuple, n_ks_tuple, -: 1394: password, 0 /* increment kvno */, -: 1395: keepold, kdb); #####: 1396: if (ret) #####: 1397: goto done; -: 1398: #####: 1399: ret = krb5_dbe_update_mkvno(handle->context, kdb, act_kvno); #####: 1400: if (ret) #####: 1401: goto done; -: 1402: #####: 1403: kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; -: 1404: #####: 1405: ret = krb5_timeofday(handle->context, &now); #####: 1406: if (ret) #####: 1407: goto done; -: 1408: #####: 1409: if ((adb.aux_attributes & KADM5_POLICY)) { -: 1410: /* the policy was loaded before */ -: 1411: #####: 1412: ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb, &last_pwd); #####: 1413: if (ret) #####: 1414: goto done; -: 1415: -: 1416:#if 0 -: 1417: /* -: 1418: * The spec says this check is overridden if the caller has -: 1419: * modify privilege. The admin server therefore makes this -: 1420: * check itself (in chpass_principal_wrapper, misc.c). A -: 1421: * local caller implicitly has all authorization bits. -: 1422: */ -: 1423: if ((now - last_pwd) < pol.pw_min_life && -: 1424: !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { -: 1425: ret = KADM5_PASS_TOOSOON; -: 1426: goto done; -: 1427: } -: 1428:#endif -: 1429: #####: 1430: ret = check_pw_reuse(handle->context, &hist_keyblock, #####: 1431: kdb->n_key_data, kdb->key_data, -: 1432: 1, &hist); #####: 1433: if (ret) #####: 1434: goto done; -: 1435: #####: 1436: if (pol.pw_history_num > 1) { -: 1437: /* If hist_kvno has changed since the last password change, we -: 1438: * can't check the history. */ #####: 1439: if (adb.admin_history_kvno == hist_kvno) { #####: 1440: ret = check_pw_reuse(handle->context, &hist_keyblock, #####: 1441: kdb->n_key_data, kdb->key_data, -: 1442: adb.old_key_len, adb.old_keys); #####: 1443: if (ret) #####: 1444: goto done; -: 1445: } -: 1446: #####: 1447: ret = add_to_history(handle->context, hist_kvno, &adb, &pol, -: 1448: &hist); #####: 1449: if (ret) #####: 1450: goto done; #####: 1451: hist_added = 1; -: 1452: } -: 1453: #####: 1454: if (pol.pw_max_life) #####: 1455: kdb->pw_expiration = now + pol.pw_max_life; -: 1456: else #####: 1457: kdb->pw_expiration = 0; -: 1458: } else { #####: 1459: kdb->pw_expiration = 0; -: 1460: } -: 1461: -: 1462:#ifdef USE_PASSWORD_SERVER -: 1463: if (kadm5_use_password_server () && -: 1464: (krb5_princ_size (handle->context, principal) == 1)) { -: 1465: krb5_data *princ = krb5_princ_component (handle->context, principal, 0); -: 1466: const char *path = "/usr/sbin/mkpassdb"; -: 1467: char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL }; -: 1468: char *pstring = NULL; -: 1469: -: 1470: if (!ret) { -: 1471: pstring = malloc ((princ->length + 1) * sizeof (char)); -: 1472: if (pstring == NULL) { ret = ENOMEM; } -: 1473: } -: 1474: -: 1475: if (!ret) { -: 1476: memcpy (pstring, princ->data, princ->length); -: 1477: pstring [princ->length] = '\0'; -: 1478: argv[2] = pstring; -: 1479: -: 1480: ret = kadm5_launch_task (handle->context, path, argv, password); -: 1481: } -: 1482: -: 1483: if (pstring != NULL) -: 1484: free (pstring); -: 1485: -: 1486: if (ret) -: 1487: goto done; -: 1488: } -: 1489:#endif -: 1490: #####: 1491: ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now); #####: 1492: if (ret) #####: 1493: goto done; -: 1494: -: 1495: /* unlock principal on this KDC */ #####: 1496: kdb->fail_auth_count = 0; -: 1497: -: 1498: /* key data and attributes changed, let the database provider know */ #####: 1499: kdb->mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES | -: 1500: KADM5_FAIL_AUTH_COUNT; -: 1501: /* | KADM5_CPW_FUNCTION */ -: 1502: #####: 1503: ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles, -: 1504: KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold, -: 1505: n_ks_tuple, ks_tuple, password); #####: 1506: if (ret) #####: 1507: goto done; -: 1508: #####: 1509: if ((ret = kdb_put_entry(handle, kdb, &adb))) #####: 1510: goto done; -: 1511: #####: 1512: (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles, -: 1513: KADM5_HOOK_STAGE_POSTCOMMIT, principal, -: 1514: keepold, n_ks_tuple, ks_tuple, password); #####: 1515: ret = KADM5_OK; -: 1516:done: #####: 1517: if (!hist_added && hist.key_data) #####: 1518: free_history_entry(handle->context, &hist); #####: 1519: kdb_free_entry(handle, kdb, &adb); #####: 1520: krb5_free_keyblock_contents(handle->context, &hist_keyblock); -: 1521: #####: 1522: if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol)) -: 1523: && !ret) #####: 1524: ret = ret2; -: 1525: #####: 1526: return ret; -: 1527:} -: 1528: -: 1529:kadm5_ret_t 340: 1530:kadm5_randkey_principal(void *server_handle, -: 1531: krb5_principal principal, -: 1532: krb5_keyblock **keyblocks, -: 1533: int *n_keys) -: 1534:{ 340: 1535: return 340: 1536: kadm5_randkey_principal_3(server_handle, principal, -: 1537: FALSE, 0, NULL, -: 1538: keyblocks, n_keys); -: 1539:} -: 1540:kadm5_ret_t 350: 1541:kadm5_randkey_principal_3(void *server_handle, -: 1542: krb5_principal principal, -: 1543: krb5_boolean keepold, -: 1544: int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, -: 1545: krb5_keyblock **keyblocks, -: 1546: int *n_keys) -: 1547:{ -: 1548: krb5_db_entry *kdb; -: 1549: osa_princ_ent_rec adb; -: 1550: krb5_int32 now; -: 1551: kadm5_policy_ent_rec pol; 350: 1552: int ret, last_pwd, have_pol = 0; 350: 1553: kadm5_server_handle_t handle = server_handle; -: 1554: krb5_keyblock *act_mkey; -: 1555: 350: 1556: if (keyblocks) 43: 1557: *keyblocks = NULL; -: 1558: 350: 1559: CHECK_HANDLE(server_handle); -: 1560: -: 1561: /* Use default keysalts if caller did not provide any. */ 350: 1562: if (n_ks_tuple == 0) { 340: 1563: ks_tuple = handle->params.keysalts; 340: 1564: n_ks_tuple = handle->params.num_keysalts; -: 1565: } -: 1566: 350: 1567: krb5_clear_error_message(handle->context); -: 1568: 350: 1569: if (principal == NULL) #####: 1570: return EINVAL; 350: 1571: if (krb5_principal_compare(handle->context, principal, hist_princ)) { -: 1572: /* If changing the history entry, the new entry must have exactly one -: 1573: * key. */ #####: 1574: if (keepold) #####: 1575: return KADM5_PROTECT_PRINCIPAL; #####: 1576: n_ks_tuple = 1; -: 1577: } -: 1578: 350: 1579: if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) #####: 1580: return(ret); -: 1581: 350: 1582: ret = krb5_dbe_find_act_mkey(handle->context, master_keylist, -: 1583: active_mkey_list, NULL, &act_mkey); 350: 1584: if (ret) #####: 1585: goto done; -: 1586: 350: 1587: ret = krb5_dbe_crk(handle->context, act_mkey, ks_tuple, n_ks_tuple, -: 1588: keepold, kdb); 350: 1589: if (ret) #####: 1590: goto done; -: 1591: 350: 1592: kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; -: 1593: 350: 1594: ret = krb5_timeofday(handle->context, &now); 350: 1595: if (ret) #####: 1596: goto done; -: 1597: 350: 1598: if ((adb.aux_attributes & KADM5_POLICY)) { #####: 1599: if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, -: 1600: &pol)) != KADM5_OK) #####: 1601: goto done; #####: 1602: have_pol = 1; -: 1603: #####: 1604: ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb, &last_pwd); #####: 1605: if (ret) #####: 1606: goto done; -: 1607: -: 1608:#if 0 -: 1609: /* -: 1610: * The spec says this check is overridden if the caller has -: 1611: * modify privilege. The admin server therefore makes this -: 1612: * check itself (in chpass_principal_wrapper, misc.c). A -: 1613: * local caller implicitly has all authorization bits. -: 1614: */ -: 1615: if((now - last_pwd) < pol.pw_min_life && -: 1616: !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { -: 1617: ret = KADM5_PASS_TOOSOON; -: 1618: goto done; -: 1619: } -: 1620:#endif -: 1621: #####: 1622: if (pol.pw_max_life) #####: 1623: kdb->pw_expiration = now + pol.pw_max_life; -: 1624: else #####: 1625: kdb->pw_expiration = 0; -: 1626: } else { 350: 1627: kdb->pw_expiration = 0; -: 1628: } -: 1629: 350: 1630: ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now); 350: 1631: if (ret) #####: 1632: goto done; -: 1633: -: 1634: /* unlock principal on this KDC */ 350: 1635: kdb->fail_auth_count = 0; -: 1636: 350: 1637: if (keyblocks) { 86: 1638: ret = decrypt_key_data(handle->context, 86: 1639: kdb->n_key_data, kdb->key_data, -: 1640: keyblocks, n_keys); 43: 1641: if (ret) #####: 1642: goto done; -: 1643: } -: 1644: -: 1645: /* key data changed, let the database provider know */ 350: 1646: kdb->mask = KADM5_KEY_DATA | KADM5_FAIL_AUTH_COUNT; -: 1647: /* | KADM5_RANDKEY_USED */; -: 1648: 350: 1649: ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles, -: 1650: KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold, -: 1651: n_ks_tuple, ks_tuple, NULL); 350: 1652: if (ret) #####: 1653: goto done; 350: 1654: if ((ret = kdb_put_entry(handle, kdb, &adb))) #####: 1655: goto done; -: 1656: 350: 1657: (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles, -: 1658: KADM5_HOOK_STAGE_POSTCOMMIT, principal, -: 1659: keepold, n_ks_tuple, ks_tuple, NULL); 350: 1660: ret = KADM5_OK; -: 1661:done: 350: 1662: kdb_free_entry(handle, kdb, &adb); 350: 1663: if (have_pol) #####: 1664: kadm5_free_policy_ent(handle->lhandle, &pol); -: 1665: 350: 1666: return ret; -: 1667:} -: 1668: -: 1669:/* -: 1670: * kadm5_setv4key_principal: -: 1671: * -: 1672: * Set only ONE key of the principal, removing all others. This key -: 1673: * must have the DES_CBC_CRC enctype and is entered as having the -: 1674: * krb4 salttype. This is to enable things like kadmind4 to work. -: 1675: */ -: 1676:kadm5_ret_t #####: 1677:kadm5_setv4key_principal(void *server_handle, -: 1678: krb5_principal principal, -: 1679: krb5_keyblock *keyblock) -: 1680:{ -: 1681: krb5_db_entry *kdb; -: 1682: osa_princ_ent_rec adb; -: 1683: krb5_int32 now; -: 1684: kadm5_policy_ent_rec pol; -: 1685: krb5_keysalt keysalt; #####: 1686: int i, k, kvno, ret, have_pol = 0; -: 1687:#if 0 -: 1688: int last_pwd; -: 1689:#endif #####: 1690: kadm5_server_handle_t handle = server_handle; -: 1691: krb5_key_data tmp_key_data; -: 1692: krb5_keyblock *act_mkey; -: 1693: #####: 1694: memset( &tmp_key_data, 0, sizeof(tmp_key_data)); -: 1695: #####: 1696: CHECK_HANDLE(server_handle); -: 1697: #####: 1698: krb5_clear_error_message(handle->context); -: 1699: #####: 1700: if (principal == NULL || keyblock == NULL) #####: 1701: return EINVAL; #####: 1702: if (hist_princ && /* this will be NULL when initializing the databse */ #####: 1703: ((krb5_principal_compare(handle->context, -: 1704: principal, hist_princ)) == TRUE)) #####: 1705: return KADM5_PROTECT_PRINCIPAL; -: 1706: #####: 1707: if (keyblock->enctype != ENCTYPE_DES_CBC_CRC) #####: 1708: return KADM5_SETV4KEY_INVAL_ENCTYPE; -: 1709: #####: 1710: if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) #####: 1711: return(ret); -: 1712: #####: 1713: for (kvno = 0, i=0; in_key_data; i++) #####: 1714: if (kdb->key_data[i].key_data_kvno > kvno) #####: 1715: kvno = kdb->key_data[i].key_data_kvno; -: 1716: #####: 1717: if (kdb->key_data != NULL) #####: 1718: cleanup_key_data(handle->context, kdb->n_key_data, kdb->key_data); -: 1719: #####: 1720: kdb->key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data)); #####: 1721: if (kdb->key_data == NULL) #####: 1722: return ENOMEM; #####: 1723: memset(kdb->key_data, 0, sizeof(krb5_key_data)); #####: 1724: kdb->n_key_data = 1; #####: 1725: keysalt.type = KRB5_KDB_SALTTYPE_V4; -: 1726: /* XXX data.magic? */ #####: 1727: keysalt.data.length = 0; #####: 1728: keysalt.data.data = NULL; -: 1729: #####: 1730: ret = krb5_dbe_find_act_mkey(handle->context, master_keylist, -: 1731: active_mkey_list, NULL, &act_mkey); #####: 1732: if (ret) #####: 1733: goto done; -: 1734: -: 1735: /* use tmp_key_data as temporary location and reallocate later */ #####: 1736: ret = krb5_dbe_encrypt_key_data(handle->context, act_mkey, keyblock, -: 1737: &keysalt, kvno + 1, &tmp_key_data); #####: 1738: if (ret) { #####: 1739: goto done; -: 1740: } -: 1741: #####: 1742: for (k = 0; k < tmp_key_data.key_data_ver; k++) { #####: 1743: kdb->key_data->key_data_type[k] = tmp_key_data.key_data_type[k]; #####: 1744: kdb->key_data->key_data_length[k] = tmp_key_data.key_data_length[k]; #####: 1745: if (tmp_key_data.key_data_contents[k]) { #####: 1746: kdb->key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]); #####: 1747: if (kdb->key_data->key_data_contents[k] == NULL) { #####: 1748: cleanup_key_data(handle->context, kdb->n_key_data, kdb->key_data); #####: 1749: kdb->key_data = NULL; #####: 1750: kdb->n_key_data = 0; #####: 1751: ret = ENOMEM; #####: 1752: goto done; -: 1753: } #####: 1754: memcpy (kdb->key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); -: 1755: #####: 1756: memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); #####: 1757: free (tmp_key_data.key_data_contents[k]); #####: 1758: tmp_key_data.key_data_contents[k] = NULL; -: 1759: } -: 1760: } -: 1761: -: 1762: -: 1763: #####: 1764: kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; -: 1765: #####: 1766: ret = krb5_timeofday(handle->context, &now); #####: 1767: if (ret) #####: 1768: goto done; -: 1769: #####: 1770: if ((adb.aux_attributes & KADM5_POLICY)) { #####: 1771: if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, -: 1772: &pol)) != KADM5_OK) #####: 1773: goto done; #####: 1774: have_pol = 1; -: 1775: -: 1776:#if 0 -: 1777: /* -: 1778: * The spec says this check is overridden if the caller has -: 1779: * modify privilege. The admin server therefore makes this -: 1780: * check itself (in chpass_principal_wrapper, misc.c). A -: 1781: * local caller implicitly has all authorization bits. -: 1782: */ -: 1783: if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, -: 1784: kdb, &last_pwd)) -: 1785: goto done; -: 1786: if((now - last_pwd) < pol.pw_min_life && -: 1787: !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { -: 1788: ret = KADM5_PASS_TOOSOON; -: 1789: goto done; -: 1790: } -: 1791:#endif -: 1792: #####: 1793: if (pol.pw_max_life) #####: 1794: kdb->pw_expiration = now + pol.pw_max_life; -: 1795: else #####: 1796: kdb->pw_expiration = 0; -: 1797: } else { #####: 1798: kdb->pw_expiration = 0; -: 1799: } -: 1800: #####: 1801: ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now); #####: 1802: if (ret) #####: 1803: goto done; -: 1804: -: 1805: /* unlock principal on this KDC */ #####: 1806: kdb->fail_auth_count = 0; -: 1807: #####: 1808: if ((ret = kdb_put_entry(handle, kdb, &adb))) #####: 1809: goto done; -: 1810: #####: 1811: ret = KADM5_OK; -: 1812:done: #####: 1813: for (i = 0; i < tmp_key_data.key_data_ver; i++) { #####: 1814: if (tmp_key_data.key_data_contents[i]) { #####: 1815: memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]); #####: 1816: free (tmp_key_data.key_data_contents[i]); -: 1817: } -: 1818: } -: 1819: #####: 1820: kdb_free_entry(handle, kdb, &adb); #####: 1821: if (have_pol) #####: 1822: kadm5_free_policy_ent(handle->lhandle, &pol); -: 1823: #####: 1824: return ret; -: 1825:} -: 1826: -: 1827:kadm5_ret_t #####: 1828:kadm5_setkey_principal(void *server_handle, -: 1829: krb5_principal principal, -: 1830: krb5_keyblock *keyblocks, -: 1831: int n_keys) -: 1832:{ #####: 1833: return #####: 1834: kadm5_setkey_principal_3(server_handle, principal, -: 1835: FALSE, 0, NULL, -: 1836: keyblocks, n_keys); -: 1837:} -: 1838: -: 1839:kadm5_ret_t #####: 1840:kadm5_setkey_principal_3(void *server_handle, -: 1841: krb5_principal principal, -: 1842: krb5_boolean keepold, -: 1843: int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, -: 1844: krb5_keyblock *keyblocks, -: 1845: int n_keys) -: 1846:{ -: 1847: krb5_db_entry *kdb; -: 1848: osa_princ_ent_rec adb; -: 1849: krb5_int32 now; -: 1850: kadm5_policy_ent_rec pol; -: 1851: krb5_key_data *old_key_data; -: 1852: int n_old_keys; #####: 1853: int i, j, k, kvno, ret, have_pol = 0; -: 1854:#if 0 -: 1855: int last_pwd; -: 1856:#endif #####: 1857: kadm5_server_handle_t handle = server_handle; -: 1858: krb5_boolean similar; -: 1859: krb5_keysalt keysalt; -: 1860: krb5_key_data tmp_key_data; -: 1861: krb5_key_data *tptr; -: 1862: krb5_keyblock *act_mkey; -: 1863: #####: 1864: CHECK_HANDLE(server_handle); -: 1865: #####: 1866: krb5_clear_error_message(handle->context); -: 1867: #####: 1868: if (principal == NULL || keyblocks == NULL) #####: 1869: return EINVAL; #####: 1870: if (hist_princ && /* this will be NULL when initializing the databse */ #####: 1871: ((krb5_principal_compare(handle->context, -: 1872: principal, hist_princ)) == TRUE)) #####: 1873: return KADM5_PROTECT_PRINCIPAL; -: 1874: #####: 1875: for (i = 0; i < n_keys; i++) { #####: 1876: for (j = i+1; j < n_keys; j++) { #####: 1877: if ((ret = krb5_c_enctype_compare(handle->context, #####: 1878: keyblocks[i].enctype, #####: 1879: keyblocks[j].enctype, -: 1880: &similar))) #####: 1881: return(ret); #####: 1882: if (similar) { #####: 1883: if (n_ks_tuple) { #####: 1884: if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype) #####: 1885: return KADM5_SETKEY_DUP_ENCTYPES; -: 1886: } else #####: 1887: return KADM5_SETKEY_DUP_ENCTYPES; -: 1888: } -: 1889: } -: 1890: } -: 1891: #####: 1892: if (n_ks_tuple && n_ks_tuple != n_keys) #####: 1893: return KADM5_SETKEY3_ETYPE_MISMATCH; -: 1894: #####: 1895: if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) #####: 1896: return(ret); -: 1897: #####: 1898: for (kvno = 0, i=0; in_key_data; i++) #####: 1899: if (kdb->key_data[i].key_data_kvno > kvno) #####: 1900: kvno = kdb->key_data[i].key_data_kvno; -: 1901: #####: 1902: if (keepold) { #####: 1903: old_key_data = kdb->key_data; #####: 1904: n_old_keys = kdb->n_key_data; -: 1905: } else { #####: 1906: if (kdb->key_data != NULL) #####: 1907: cleanup_key_data(handle->context, kdb->n_key_data, kdb->key_data); #####: 1908: n_old_keys = 0; #####: 1909: old_key_data = NULL; -: 1910: } -: 1911: #####: 1912: kdb->key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys) -: 1913: *sizeof(krb5_key_data)); #####: 1914: if (kdb->key_data == NULL) { #####: 1915: ret = ENOMEM; #####: 1916: goto done; -: 1917: } -: 1918: #####: 1919: memset(kdb->key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data)); #####: 1920: kdb->n_key_data = 0; -: 1921: #####: 1922: for (i = 0; i < n_keys; i++) { #####: 1923: if (n_ks_tuple) { #####: 1924: keysalt.type = ks_tuple[i].ks_salttype; #####: 1925: keysalt.data.length = 0; #####: 1926: keysalt.data.data = NULL; #####: 1927: if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) { #####: 1928: ret = KADM5_SETKEY3_ETYPE_MISMATCH; #####: 1929: goto done; -: 1930: } -: 1931: } #####: 1932: memset (&tmp_key_data, 0, sizeof(tmp_key_data)); -: 1933: #####: 1934: ret = krb5_dbe_find_act_mkey(handle->context, master_keylist, -: 1935: active_mkey_list, NULL, &act_mkey); #####: 1936: if (ret) #####: 1937: goto done; -: 1938: #####: 1939: ret = krb5_dbe_encrypt_key_data(handle->context, act_mkey, #####: 1940: &keyblocks[i], -: 1941: n_ks_tuple ? &keysalt : NULL, kvno + 1, -: 1942: &tmp_key_data); #####: 1943: if (ret) #####: 1944: goto done; -: 1945: #####: 1946: tptr = &kdb->key_data[i]; #####: 1947: tptr->key_data_ver = tmp_key_data.key_data_ver; #####: 1948: tptr->key_data_kvno = tmp_key_data.key_data_kvno; #####: 1949: for (k = 0; k < tmp_key_data.key_data_ver; k++) { #####: 1950: tptr->key_data_type[k] = tmp_key_data.key_data_type[k]; #####: 1951: tptr->key_data_length[k] = tmp_key_data.key_data_length[k]; #####: 1952: if (tmp_key_data.key_data_contents[k]) { #####: 1953: tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]); #####: 1954: if (tptr->key_data_contents[k] == NULL) { -: 1955: int i1; #####: 1956: for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) { #####: 1957: if (tmp_key_data.key_data_contents[i1]) { #####: 1958: memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]); #####: 1959: free (tmp_key_data.key_data_contents[i1]); -: 1960: } -: 1961: } -: 1962: #####: 1963: ret = ENOMEM; #####: 1964: goto done; -: 1965: } #####: 1966: memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); -: 1967: #####: 1968: memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); #####: 1969: free (tmp_key_data.key_data_contents[k]); #####: 1970: tmp_key_data.key_data_contents[k] = NULL; -: 1971: } -: 1972: } #####: 1973: kdb->n_key_data++; -: 1974: } -: 1975: -: 1976: /* copy old key data if necessary */ #####: 1977: for (i = 0; i < n_old_keys; i++) { #####: 1978: kdb->key_data[i+n_keys] = old_key_data[i]; #####: 1979: memset(&old_key_data[i], 0, sizeof (krb5_key_data)); #####: 1980: kdb->n_key_data++; -: 1981: } -: 1982: #####: 1983: if (old_key_data) #####: 1984: krb5_db_free(handle->context, old_key_data); -: 1985: -: 1986: /* assert(kdb->n_key_data == n_keys + n_old_keys) */ #####: 1987: kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; -: 1988: #####: 1989: if ((ret = krb5_timeofday(handle->context, &now))) #####: 1990: goto done; -: 1991: #####: 1992: if ((adb.aux_attributes & KADM5_POLICY)) { #####: 1993: if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, -: 1994: &pol)) != KADM5_OK) #####: 1995: goto done; #####: 1996: have_pol = 1; -: 1997: -: 1998:#if 0 -: 1999: /* -: 2000: * The spec says this check is overridden if the caller has -: 2001: * modify privilege. The admin server therefore makes this -: 2002: * check itself (in chpass_principal_wrapper, misc.c). A -: 2003: * local caller implicitly has all authorization bits. -: 2004: */ -: 2005: if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, -: 2006: kdb, &last_pwd)) -: 2007: goto done; -: 2008: if((now - last_pwd) < pol.pw_min_life && -: 2009: !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { -: 2010: ret = KADM5_PASS_TOOSOON; -: 2011: goto done; -: 2012: } -: 2013:#endif -: 2014: #####: 2015: if (pol.pw_max_life) #####: 2016: kdb->pw_expiration = now + pol.pw_max_life; -: 2017: else #####: 2018: kdb->pw_expiration = 0; -: 2019: } else { #####: 2020: kdb->pw_expiration = 0; -: 2021: } -: 2022: #####: 2023: if ((ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now))) #####: 2024: goto done; -: 2025: -: 2026: /* unlock principal on this KDC */ #####: 2027: kdb->fail_auth_count = 0; -: 2028: #####: 2029: if ((ret = kdb_put_entry(handle, kdb, &adb))) #####: 2030: goto done; -: 2031: #####: 2032: ret = KADM5_OK; -: 2033:done: #####: 2034: kdb_free_entry(handle, kdb, &adb); #####: 2035: if (have_pol) #####: 2036: kadm5_free_policy_ent(handle->lhandle, &pol); -: 2037: #####: 2038: return ret; -: 2039:} -: 2040: -: 2041:/* -: 2042: * Return the list of keys like kadm5_randkey_principal, -: 2043: * but don't modify the principal. -: 2044: */ -: 2045:kadm5_ret_t 75: 2046:kadm5_get_principal_keys(void *server_handle /* IN */, -: 2047: krb5_principal principal /* IN */, -: 2048: krb5_keyblock **keyblocks /* OUT */, -: 2049: int *n_keys /* OUT */) -: 2050:{ -: 2051: krb5_db_entry *kdb; -: 2052: osa_princ_ent_rec adb; -: 2053: kadm5_ret_t ret; 75: 2054: kadm5_server_handle_t handle = server_handle; -: 2055: 75: 2056: if (keyblocks) 75: 2057: *keyblocks = NULL; -: 2058: 75: 2059: CHECK_HANDLE(server_handle); -: 2060: 75: 2061: if (principal == NULL) #####: 2062: return EINVAL; -: 2063: 75: 2064: if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) #####: 2065: return(ret); -: 2066: 75: 2067: if (keyblocks) { 150: 2068: ret = decrypt_key_data(handle->context, 150: 2069: kdb->n_key_data, kdb->key_data, -: 2070: keyblocks, n_keys); 75: 2071: if (ret) #####: 2072: goto done; -: 2073: } -: 2074: 75: 2075: ret = KADM5_OK; -: 2076:done: 75: 2077: kdb_free_entry(handle, kdb, &adb); -: 2078: 75: 2079: return ret; -: 2080:} -: 2081: -: 2082: -: 2083:/* -: 2084: * Allocate an array of n_key_data krb5_keyblocks, fill in each -: 2085: * element with the results of decrypting the nth key in key_data, -: 2086: * and if n_keys is not NULL fill it in with the -: 2087: * number of keys decrypted. -: 2088: */ 118: 2089:static int decrypt_key_data(krb5_context context, -: 2090: int n_key_data, krb5_key_data *key_data, -: 2091: krb5_keyblock **keyblocks, int *n_keys) -: 2092:{ -: 2093: krb5_keyblock *keys; -: 2094: int ret, i; -: 2095: 118: 2096: keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock)); 118: 2097: if (keys == NULL) #####: 2098: return ENOMEM; 118: 2099: memset(keys, 0, n_key_data*sizeof(krb5_keyblock)); -: 2100: 434: 2101: for (i = 0; i < n_key_data; i++) { 316: 2102: ret = krb5_dbe_decrypt_key_data(context, NULL, &key_data[i], &keys[i], -: 2103: NULL); 316: 2104: if (ret) { #####: 2105: for (; i >= 0; i--) { #####: 2106: if (keys[i].contents) { #####: 2107: memset (keys[i].contents, 0, keys[i].length); #####: 2108: free( keys[i].contents ); -: 2109: } -: 2110: } -: 2111: #####: 2112: memset(keys, 0, n_key_data*sizeof(krb5_keyblock)); #####: 2113: free(keys); #####: 2114: return ret; -: 2115: } -: 2116: } -: 2117: 118: 2118: *keyblocks = keys; 118: 2119: if (n_keys) 118: 2120: *n_keys = n_key_data; -: 2121: 118: 2122: return 0; -: 2123:} -: 2124: -: 2125:/* -: 2126: * Function: kadm5_decrypt_key -: 2127: * -: 2128: * Purpose: Retrieves and decrypts a principal key. -: 2129: * -: 2130: * Arguments: -: 2131: * -: 2132: * server_handle (r) kadm5 handle -: 2133: * entry (r) principal retrieved with kadm5_get_principal -: 2134: * ktype (r) enctype to search for, or -1 to ignore -: 2135: * stype (r) salt type to search for, or -1 to ignore -: 2136: * kvno (r) kvno to search for, -1 for max, 0 for max -: 2137: * only if it also matches ktype and stype -: 2138: * keyblock (w) keyblock to fill in -: 2139: * keysalt (w) keysalt to fill in, or NULL -: 2140: * kvnop (w) kvno to fill in, or NULL -: 2141: * -: 2142: * Effects: Searches the key_data array of entry, which must have been -: 2143: * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to -: 2144: * find a key with a specified enctype, salt type, and kvno in a -: 2145: * principal entry. If not found, return ENOENT. Otherwise, decrypt -: 2146: * it with the master key, and return the key in keyblock, the salt -: 2147: * in salttype, and the key version number in kvno. -: 2148: * -: 2149: * If ktype or stype is -1, it is ignored for the search. If kvno is -: 2150: * -1, ktype and stype are ignored and the key with the max kvno is -: 2151: * returned. If kvno is 0, only the key with the max kvno is returned -: 2152: * and only if it matches the ktype and stype; otherwise, ENOENT is -: 2153: * returned. -: 2154: */ #####: 2155:kadm5_ret_t kadm5_decrypt_key(void *server_handle, -: 2156: kadm5_principal_ent_t entry, krb5_int32 -: 2157: ktype, krb5_int32 stype, krb5_int32 -: 2158: kvno, krb5_keyblock *keyblock, -: 2159: krb5_keysalt *keysalt, int *kvnop) -: 2160:{ #####: 2161: kadm5_server_handle_t handle = server_handle; -: 2162: krb5_db_entry dbent; -: 2163: krb5_key_data *key_data; -: 2164: krb5_keyblock *mkey_ptr; -: 2165: int ret; -: 2166: #####: 2167: CHECK_HANDLE(server_handle); -: 2168: #####: 2169: if (entry->n_key_data == 0 || entry->key_data == NULL) #####: 2170: return EINVAL; -: 2171: -: 2172: /* find_enctype only uses these two fields */ #####: 2173: dbent.n_key_data = entry->n_key_data; #####: 2174: dbent.key_data = entry->key_data; #####: 2175: if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype, -: 2176: stype, kvno, &key_data))) #####: 2177: return ret; -: 2178: -: 2179: /* find_mkey only uses this field */ #####: 2180: dbent.tl_data = entry->tl_data; #####: 2181: if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &dbent, -: 2182: &mkey_ptr))) { -: 2183: krb5_keylist_node *tmp_mkey_list; -: 2184: /* try refreshing master key list */ -: 2185: /* XXX it would nice if we had the mkvno here for optimization */ #####: 2186: if (krb5_db_fetch_mkey_list(handle->context, master_princ, -: 2187: &master_keyblock, 0, &tmp_mkey_list) == 0) { #####: 2188: krb5_dbe_free_key_list(handle->context, master_keylist); #####: 2189: master_keylist = tmp_mkey_list; #####: 2190: if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, -: 2191: &dbent, &mkey_ptr))) { #####: 2192: return ret; -: 2193: } -: 2194: } else { #####: 2195: return ret; -: 2196: } -: 2197: } -: 2198: #####: 2199: if ((ret = krb5_dbe_decrypt_key_data(handle->context, NULL, key_data, -: 2200: keyblock, keysalt))) #####: 2201: return ret; -: 2202: -: 2203: /* -: 2204: * Coerce the enctype of the output keyblock in case we got an -: 2205: * inexact match on the enctype; this behavior will go away when -: 2206: * the key storage architecture gets redesigned for 1.3. -: 2207: */ #####: 2208: if (ktype != -1) #####: 2209: keyblock->enctype = ktype; -: 2210: #####: 2211: if (kvnop) #####: 2212: *kvnop = key_data->key_data_kvno; -: 2213: #####: 2214: return KADM5_OK; -: 2215:} -: 2216: -: 2217:kadm5_ret_t 1: 2218:kadm5_purgekeys(void *server_handle, -: 2219: krb5_principal principal, -: 2220: int keepkvno) -: 2221:{ 1: 2222: kadm5_server_handle_t handle = server_handle; -: 2223: kadm5_ret_t ret; -: 2224: krb5_db_entry *kdb; -: 2225: osa_princ_ent_rec adb; -: 2226: krb5_key_data *old_keydata; -: 2227: int n_old_keydata; -: 2228: int i, j, k; -: 2229: 1: 2230: CHECK_HANDLE(server_handle); -: 2231: 1: 2232: if (principal == NULL) #####: 2233: return EINVAL; -: 2234: 1: 2235: ret = kdb_get_entry(handle, principal, &kdb, &adb); 1: 2236: if (ret) #####: 2237: return(ret); -: 2238: 1: 2239: if (keepkvno <= 0) { 1: 2240: keepkvno = krb5_db_get_key_data_kvno(handle->context, kdb->n_key_data, 1: 2241: kdb->key_data); -: 2242: } -: 2243: 1: 2244: old_keydata = kdb->key_data; 1: 2245: n_old_keydata = kdb->n_key_data; 1: 2246: kdb->n_key_data = 0; 1: 2247: kdb->key_data = krb5_db_alloc(handle->context, NULL, -: 2248: n_old_keydata * sizeof(krb5_key_data)); 1: 2249: if (kdb->key_data == NULL) { #####: 2250: ret = ENOMEM; #####: 2251: goto done; -: 2252: } 1: 2253: memset(kdb->key_data, 0, n_old_keydata * sizeof(krb5_key_data)); 3: 2254: for (i = 0, j = 0; i < n_old_keydata; i++) { 2: 2255: if (old_keydata[i].key_data_kvno < keepkvno) 1: 2256: continue; -: 2257: -: 2258: /* Alias the key_data_contents pointers; we null them out in the -: 2259: * source array immediately after. */ 1: 2260: kdb->key_data[j] = old_keydata[i]; 2: 2261: for (k = 0; k < old_keydata[i].key_data_ver; k++) { 1: 2262: old_keydata[i].key_data_contents[k] = NULL; -: 2263: } 1: 2264: j++; -: 2265: } 1: 2266: kdb->n_key_data = j; 1: 2267: cleanup_key_data(handle->context, n_old_keydata, old_keydata); -: 2268: 1: 2269: kdb->mask = KADM5_KEY_DATA; 1: 2270: ret = kdb_put_entry(handle, kdb, &adb); -: 2271: if (ret) -: 2272: goto done; -: 2273: -: 2274:done: 1: 2275: kdb_free_entry(handle, kdb, &adb); 1: 2276: return ret; -: 2277:} -: 2278: -: 2279:kadm5_ret_t 2: 2280:kadm5_get_strings(void *server_handle, krb5_principal principal, -: 2281: krb5_string_attr **strings_out, int *count_out) -: 2282:{ 2: 2283: kadm5_server_handle_t handle = server_handle; -: 2284: kadm5_ret_t ret; 2: 2285: krb5_db_entry *kdb = NULL; -: 2286: 2: 2287: *strings_out = NULL; 2: 2288: *count_out = 0; 2: 2289: CHECK_HANDLE(server_handle); 2: 2290: if (principal == NULL) #####: 2291: return EINVAL; -: 2292: 2: 2293: ret = kdb_get_entry(handle, principal, &kdb, NULL); 2: 2294: if (ret) #####: 2295: return ret; -: 2296: 2: 2297: ret = krb5_dbe_get_strings(handle->context, kdb, strings_out, count_out); 2: 2298: kdb_free_entry(handle, kdb, NULL); 2: 2299: return ret; -: 2300:} -: 2301: -: 2302:kadm5_ret_t 4: 2303:kadm5_set_string(void *server_handle, krb5_principal principal, -: 2304: const char *key, const char *value) -: 2305:{ 4: 2306: kadm5_server_handle_t handle = server_handle; -: 2307: kadm5_ret_t ret; -: 2308: krb5_db_entry *kdb; -: 2309: osa_princ_ent_rec adb; -: 2310: 4: 2311: CHECK_HANDLE(server_handle); 4: 2312: if (principal == NULL || key == NULL) #####: 2313: return EINVAL; -: 2314: 4: 2315: ret = kdb_get_entry(handle, principal, &kdb, &adb); 4: 2316: if (ret) #####: 2317: return ret; -: 2318: 4: 2319: ret = krb5_dbe_set_string(handle->context, kdb, key, value); 4: 2320: if (ret) #####: 2321: goto done; -: 2322: 4: 2323: kdb->mask = KADM5_TL_DATA; 4: 2324: ret = kdb_put_entry(handle, kdb, &adb); -: 2325: -: 2326:done: 4: 2327: kdb_free_entry(handle, kdb, &adb); 4: 2328: return ret; -: 2329:}