1 /* $NetBSD: hdb-mitdb.c,v 1.4 2023/06/19 21:41:43 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * 3. Neither the name of the Institute nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #define KRB5_KDB_DISALLOW_POSTDATED 0x00000001 39 #define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002 40 #define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004 41 #define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008 42 #define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010 43 #define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020 44 #define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040 45 #define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080 46 #define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100 47 #define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200 48 #define KRB5_KDB_DISALLOW_SVR 0x00001000 49 #define KRB5_KDB_PWCHANGE_SERVICE 0x00002000 50 #define KRB5_KDB_SUPPORT_DESMD5 0x00004000 51 #define KRB5_KDB_NEW_PRINC 0x00008000 52 53 /* 54 55 key: krb5_unparse_name + NUL 56 57 16: baselength 58 32: attributes 59 32: max time 60 32: max renewable time 61 32: client expire 62 32: passwd expire 63 32: last successful passwd 64 32: last failed attempt 65 32: num of failed attempts 66 16: num tl data 67 16: num data data 68 16: principal length 69 length: principal 70 for num tl data times 71 16: tl data type 72 16: tl data length 73 length: length 74 for num key data times 75 16: version (num keyblocks) 76 16: kvno 77 for version times: 78 16: type 79 16: length 80 length: keydata 81 82 83 key_data_contents[0] 84 85 int16: length 86 read-of-data: key-encrypted, key-usage 0, master-key 87 88 salt: 89 version2 = salt in key_data->key_data_contents[1] 90 else default salt. 91 92 */ 93 94 #include "hdb_locl.h" 95 96 typedef struct MITDB { 97 HDB db; /* Generic */ 98 int do_sync; /* MITDB-specific */ 99 } MITDB; 100 101 static void 102 attr_to_flags(unsigned attr, HDBFlags *flags) 103 { 104 flags->postdate = !(attr & KRB5_KDB_DISALLOW_POSTDATED); 105 flags->forwardable = !(attr & KRB5_KDB_DISALLOW_FORWARDABLE); 106 flags->initial = !!(attr & KRB5_KDB_DISALLOW_TGT_BASED); 107 flags->renewable = !(attr & KRB5_KDB_DISALLOW_RENEWABLE); 108 flags->proxiable = !(attr & KRB5_KDB_DISALLOW_PROXIABLE); 109 /* DUP_SKEY */ 110 flags->invalid = !!(attr & KRB5_KDB_DISALLOW_ALL_TIX); 111 flags->require_preauth = !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH); 112 flags->require_hwauth = !!(attr & KRB5_KDB_REQUIRES_HW_AUTH); 113 flags->server = !(attr & KRB5_KDB_DISALLOW_SVR); 114 flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE); 115 flags->client = 1; /* XXX */ 116 } 117 118 #define KDB_V1_BASE_LENGTH 38 119 120 #define CHECK(x) do { if ((x)) goto out; } while(0) 121 122 #ifdef HAVE_DB1 123 static krb5_error_code 124 mdb_principal2key(krb5_context context, 125 krb5_const_principal principal, 126 krb5_data *key) 127 { 128 krb5_error_code ret; 129 char *str; 130 131 ret = krb5_unparse_name(context, principal, &str); 132 if (ret) 133 return ret; 134 key->data = str; 135 key->length = strlen(str) + 1; 136 return 0; 137 } 138 #endif /* HAVE_DB1 */ 139 140 #define KRB5_KDB_SALTTYPE_NORMAL 0 141 #define KRB5_KDB_SALTTYPE_V4 1 142 #define KRB5_KDB_SALTTYPE_NOREALM 2 143 #define KRB5_KDB_SALTTYPE_ONLYREALM 3 144 #define KRB5_KDB_SALTTYPE_SPECIAL 4 145 #define KRB5_KDB_SALTTYPE_AFS3 5 146 #define KRB5_KDB_SALTTYPE_CERTHASH 6 147 148 static krb5_error_code 149 fix_salt(krb5_context context, hdb_entry *ent, Key *k) 150 { 151 krb5_error_code ret; 152 Salt *salt = k->salt; 153 /* fix salt type */ 154 switch((int)salt->type) { 155 case KRB5_KDB_SALTTYPE_NORMAL: 156 salt->type = KRB5_PADATA_PW_SALT; 157 break; 158 case KRB5_KDB_SALTTYPE_V4: 159 krb5_data_free(&salt->salt); 160 salt->type = KRB5_PADATA_PW_SALT; 161 break; 162 case KRB5_KDB_SALTTYPE_NOREALM: 163 { 164 size_t len; 165 size_t i; 166 char *p; 167 168 len = 0; 169 for (i = 0; i < ent->principal->name.name_string.len; ++i) 170 len += strlen(ent->principal->name.name_string.val[i]); 171 ret = krb5_data_alloc (&salt->salt, len); 172 if (ret) 173 return ret; 174 p = salt->salt.data; 175 for (i = 0; i < ent->principal->name.name_string.len; ++i) { 176 memcpy (p, 177 ent->principal->name.name_string.val[i], 178 strlen(ent->principal->name.name_string.val[i])); 179 p += strlen(ent->principal->name.name_string.val[i]); 180 } 181 182 salt->type = KRB5_PADATA_PW_SALT; 183 break; 184 } 185 case KRB5_KDB_SALTTYPE_ONLYREALM: 186 krb5_data_free(&salt->salt); 187 ret = krb5_data_copy(&salt->salt, 188 ent->principal->realm, 189 strlen(ent->principal->realm)); 190 if(ret) 191 return ret; 192 salt->type = KRB5_PADATA_PW_SALT; 193 break; 194 case KRB5_KDB_SALTTYPE_SPECIAL: 195 salt->type = KRB5_PADATA_PW_SALT; 196 break; 197 case KRB5_KDB_SALTTYPE_AFS3: 198 krb5_data_free(&salt->salt); 199 ret = krb5_data_copy(&salt->salt, 200 ent->principal->realm, 201 strlen(ent->principal->realm)); 202 if(ret) 203 return ret; 204 salt->type = KRB5_PADATA_AFS3_SALT; 205 break; 206 case KRB5_KDB_SALTTYPE_CERTHASH: 207 krb5_data_free(&salt->salt); 208 free(k->salt); 209 k->salt = NULL; 210 break; 211 default: 212 abort(); 213 } 214 return 0; 215 } 216 217 218 /** 219 * This function takes a key from a krb5_storage from an MIT KDB encoded 220 * entry and places it in the given Key object. 221 * 222 * @param context Context 223 * @param entry HDB entry 224 * @param sp krb5_storage with current offset set to the beginning of a 225 * key 226 * @param version See comments in caller body for the backstory on this 227 * @param k Key * to load the key into 228 */ 229 static krb5_error_code 230 mdb_keyvalue2key(krb5_context context, hdb_entry *entry, krb5_storage *sp, uint16_t version, Key *k) 231 { 232 size_t i; 233 uint16_t u16, type; 234 krb5_error_code ret; 235 236 k->mkvno = malloc(sizeof(*k->mkvno)); 237 if (k->mkvno == NULL) { 238 ret = ENOMEM; 239 goto out; 240 } 241 *k->mkvno = 1; 242 243 for (i = 0; i < version; i++) { 244 CHECK(ret = krb5_ret_uint16(sp, &type)); 245 CHECK(ret = krb5_ret_uint16(sp, &u16)); 246 if (i == 0) { 247 /* This "version" means we have a key */ 248 k->key.keytype = type; 249 /* 250 * MIT stores keys encrypted keys as {16-bit length 251 * of plaintext key, {encrypted key}}. The reason 252 * for this is that the Kerberos cryptosystem is not 253 * length-preserving. Heimdal's approach is to 254 * truncate the plaintext to the expected length of 255 * the key given its enctype, so we ignore this 256 * 16-bit length-of-plaintext-key field. 257 */ 258 if (u16 > 2) { 259 krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */ 260 k->key.keyvalue.length = u16 - 2; /* adjust cipher len */ 261 k->key.keyvalue.data = malloc(k->key.keyvalue.length); 262 krb5_storage_read(sp, k->key.keyvalue.data, 263 k->key.keyvalue.length); 264 } else { 265 /* We'll ignore this key; see our caller */ 266 k->key.keyvalue.length = 0; 267 k->key.keyvalue.data = NULL; 268 krb5_storage_seek(sp, u16, SEEK_CUR); /* skip real length */ 269 } 270 } else if (i == 1) { 271 /* This "version" means we have a salt */ 272 k->salt = calloc(1, sizeof(*k->salt)); 273 if (k->salt == NULL) { 274 ret = ENOMEM; 275 goto out; 276 } 277 k->salt->type = type; 278 if (u16 != 0) { 279 k->salt->salt.data = malloc(u16); 280 if (k->salt->salt.data == NULL) { 281 ret = ENOMEM; 282 goto out; 283 } 284 k->salt->salt.length = u16; 285 krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length); 286 } 287 fix_salt(context, entry, k); 288 } else { 289 /* 290 * Whatever this "version" might be, we skip it 291 * 292 * XXX A krb5.conf parameter requesting that we log 293 * about strangeness like this, or return an error 294 * from here, might be nice. 295 */ 296 krb5_storage_seek(sp, u16, SEEK_CUR); 297 } 298 } 299 300 return 0; 301 302 out: 303 free_Key(k); 304 return ret; 305 } 306 307 308 static krb5_error_code 309 add_1des_dup(krb5_context context, Keys *keys, Key *key, krb5_keytype keytype) 310 { 311 key->key.keytype = keytype; 312 return add_Keys(keys, key); 313 } 314 315 /* 316 * This monstrosity is here so we can avoid having to do enctype 317 * similarity checking in the KDC. This helper function dups 1DES keys 318 * in a keyset for all the similar 1DES enctypes for which keys are 319 * missing. And, of course, we do this only if there's any 1DES keys in 320 * the keyset to begin with. 321 */ 322 static krb5_error_code 323 dup_similar_keys_in_keyset(krb5_context context, Keys *keys) 324 { 325 krb5_error_code ret; 326 size_t i, k; 327 Key key; 328 int keyset_has_1des_crc = 0; 329 int keyset_has_1des_md4 = 0; 330 int keyset_has_1des_md5 = 0; 331 332 memset(&key, 0, sizeof (key)); 333 k = keys->len; 334 for (i = 0; i < keys->len; i++) { 335 if (keys->val[i].key.keytype == ETYPE_DES_CBC_CRC) { 336 keyset_has_1des_crc = 1; 337 if (k == keys->len) 338 k = i; 339 } else if (keys->val[i].key.keytype == ETYPE_DES_CBC_MD4) { 340 keyset_has_1des_crc = 1; 341 if (k == keys->len) 342 k = i; 343 } else if (keys->val[i].key.keytype == ETYPE_DES_CBC_MD5) { 344 keyset_has_1des_crc = 1; 345 if (k == keys->len) 346 k = i; 347 } 348 } 349 if (k == keys->len) 350 return 0; 351 352 ret = copy_Key(&keys->val[k], &key); 353 if (ret) 354 return ret; 355 if (!keyset_has_1des_crc) { 356 ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_CRC); 357 if (ret) 358 goto out; 359 } 360 if (!keyset_has_1des_md4) { 361 ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_MD4); 362 if (ret) 363 goto out; 364 } 365 if (!keyset_has_1des_md5) { 366 ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_MD5); 367 if (ret) 368 goto out; 369 } 370 371 out: 372 free_Key(&key); 373 return ret; 374 } 375 376 377 static krb5_error_code 378 dup_similar_keys(krb5_context context, hdb_entry *entry) 379 { 380 krb5_error_code ret; 381 HDB_Ext_KeySet *hist_keys; 382 HDB_extension *extp; 383 size_t i; 384 385 ret = dup_similar_keys_in_keyset(context, &entry->keys); 386 if (ret) 387 return ret; 388 extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); 389 if (extp == NULL) 390 return 0; 391 392 hist_keys = &extp->data.u.hist_keys; 393 for (i = 0; i < hist_keys->len; i++) { 394 ret = dup_similar_keys_in_keyset(context, &hist_keys->val[i].keys); 395 if (ret) 396 return ret; 397 } 398 return 0; 399 } 400 401 402 /** 403 * This function parses an MIT krb5 encoded KDB entry and fills in the 404 * given HDB entry with it. 405 * 406 * @param context krb5_context 407 * @param data Encoded MIT KDB entry 408 * @param target_kvno Desired kvno, or 0 for the entry's current kvno 409 * @param entry Desired kvno, or 0 for the entry's current kvno 410 */ 411 krb5_error_code 412 _hdb_mdb_value2entry(krb5_context context, krb5_data *data, 413 krb5_kvno target_kvno, hdb_entry *entry) 414 { 415 krb5_error_code ret; 416 krb5_storage *sp; 417 Key k; 418 krb5_kvno key_kvno; 419 uint32_t u32; 420 uint16_t u16, num_keys, num_tl; 421 ssize_t sz; 422 size_t i; 423 char *p; 424 425 memset(&k, 0, sizeof (k)); 426 memset(entry, 0, sizeof(*entry)); 427 428 sp = krb5_storage_from_data(data); 429 if (sp == NULL) { 430 krb5_set_error_message(context, ENOMEM, "out of memory"); 431 return ENOMEM; 432 } 433 434 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 435 436 /* 437 * 16: baselength 438 * 439 * The story here is that these 16 bits have to be a constant: 440 * KDB_V1_BASE_LENGTH. Once upon a time a different value here 441 * would have been used to indicate the presence of "extra data" 442 * between the "base" contents and the {principal name, TL data, 443 * keys} that follow it. Nothing supports such "extra data" 444 * nowadays, so neither do we here. 445 * 446 * XXX But... surely we ought to log about this extra data, or skip 447 * it, or something, in case anyone has MIT KDBs with ancient 448 * entries in them... Logging would allow the admin to know which 449 * entries to dump with MIT krb5's kdb5_util. But logging would be 450 * noisy. For now we do nothing. 451 */ 452 CHECK(ret = krb5_ret_uint16(sp, &u16)); 453 if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; } 454 /* 32: attributes */ 455 CHECK(ret = krb5_ret_uint32(sp, &u32)); 456 attr_to_flags(u32, &entry->flags); 457 458 /* 32: max time */ 459 CHECK(ret = krb5_ret_uint32(sp, &u32)); 460 if (u32) { 461 entry->max_life = malloc(sizeof(*entry->max_life)); 462 *entry->max_life = u32; 463 } 464 /* 32: max renewable time */ 465 CHECK(ret = krb5_ret_uint32(sp, &u32)); 466 if (u32) { 467 entry->max_renew = malloc(sizeof(*entry->max_renew)); 468 *entry->max_renew = u32; 469 } 470 /* 32: client expire */ 471 CHECK(ret = krb5_ret_uint32(sp, &u32)); 472 if (u32) { 473 entry->valid_end = malloc(sizeof(*entry->valid_end)); 474 *entry->valid_end = u32; 475 } 476 /* 32: passwd expire */ 477 CHECK(ret = krb5_ret_uint32(sp, &u32)); 478 if (u32) { 479 entry->pw_end = malloc(sizeof(*entry->pw_end)); 480 *entry->pw_end = u32; 481 } 482 /* 32: last successful passwd */ 483 CHECK(ret = krb5_ret_uint32(sp, &u32)); 484 /* 32: last failed attempt */ 485 CHECK(ret = krb5_ret_uint32(sp, &u32)); 486 /* 32: num of failed attempts */ 487 CHECK(ret = krb5_ret_uint32(sp, &u32)); 488 /* 16: num tl data */ 489 CHECK(ret = krb5_ret_uint16(sp, &u16)); 490 num_tl = u16; 491 /* 16: num key data */ 492 CHECK(ret = krb5_ret_uint16(sp, &u16)); 493 num_keys = u16; 494 /* 16: principal length */ 495 CHECK(ret = krb5_ret_uint16(sp, &u16)); 496 /* length: principal */ 497 { 498 /* 499 * Note that the principal name includes the NUL in the entry, 500 * but we don't want to take chances, so we add an extra NUL. 501 */ 502 p = malloc(u16 + 1); 503 if (p == NULL) { 504 ret = ENOMEM; 505 goto out; 506 } 507 sz = krb5_storage_read(sp, p, u16); 508 if (sz != u16) { 509 ret = EINVAL; /* XXX */ 510 goto out; 511 } 512 p[u16] = '\0'; 513 CHECK(ret = krb5_parse_name(context, p, &entry->principal)); 514 free(p); 515 } 516 /* for num tl data times 517 16: tl data type 518 16: tl data length 519 length: length */ 520 #define mit_KRB5_TL_LAST_PWD_CHANGE 1 521 #define mit_KRB5_TL_MOD_PRINC 2 522 for (i = 0; i < num_tl; i++) { 523 int tl_type; 524 krb5_principal modby; 525 /* 16: TL data type */ 526 CHECK(ret = krb5_ret_uint16(sp, &u16)); 527 tl_type = u16; 528 /* 16: TL data length */ 529 CHECK(ret = krb5_ret_uint16(sp, &u16)); 530 /* 531 * For rollback to MIT purposes we really must understand some 532 * TL data! 533 * 534 * XXX Move all this to separate functions, one per-TL type. 535 */ 536 switch (tl_type) { 537 case mit_KRB5_TL_LAST_PWD_CHANGE: 538 CHECK(ret = krb5_ret_uint32(sp, &u32)); 539 CHECK(ret = hdb_entry_set_pw_change_time(context, entry, u32)); 540 break; 541 case mit_KRB5_TL_MOD_PRINC: 542 if (u16 < 5) { 543 ret = EINVAL; /* XXX */ 544 goto out; 545 } 546 CHECK(ret = krb5_ret_uint32(sp, &u32)); /* mod time */ 547 p = malloc(u16 - 4 + 1); 548 if (!p) { 549 ret = ENOMEM; 550 goto out; 551 } 552 p[u16 - 4] = '\0'; 553 sz = krb5_storage_read(sp, p, u16 - 4); 554 if (sz != u16 - 4) { 555 ret = EINVAL; /* XXX */ 556 goto out; 557 } 558 CHECK(ret = krb5_parse_name(context, p, &modby)); 559 ret = hdb_set_last_modified_by(context, entry, modby, u32); 560 krb5_free_principal(context, modby); 561 free(p); 562 break; 563 default: 564 krb5_storage_seek(sp, u16, SEEK_CUR); 565 break; 566 } 567 } 568 /* 569 * for num key data times 570 * 16: "version" 571 * 16: kvno 572 * for version times: 573 * 16: type 574 * 16: length 575 * length: keydata 576 * 577 * "version" here is really 1 or 2, the first meaning there's only 578 * keys for this kvno, the second meaning there's keys and salt[s?]. 579 * That's right... hold that gag reflex, you can do it. 580 */ 581 for (i = 0; i < num_keys; i++) { 582 uint16_t version; 583 584 CHECK(ret = krb5_ret_uint16(sp, &u16)); 585 version = u16; 586 CHECK(ret = krb5_ret_uint16(sp, &u16)); 587 key_kvno = u16; 588 589 ret = mdb_keyvalue2key(context, entry, sp, version, &k); 590 if (ret) 591 goto out; 592 if (k.key.keytype == 0 || k.key.keyvalue.length == 0) { 593 /* 594 * Older MIT KDBs may have enctype 0 / length 0 keys. We 595 * ignore these. 596 */ 597 free_Key(&k); 598 continue; 599 } 600 601 if ((target_kvno == 0 && entry->kvno < key_kvno) || 602 (target_kvno == key_kvno && entry->kvno != target_kvno)) { 603 /* 604 * MIT's KDB doesn't keep track of kvno. The highest kvno 605 * is the current kvno, and we just found a new highest 606 * kvno or the desired kvno. 607 * 608 * Note that there's no guarantee of any key ordering, but 609 * generally MIT KDB entries have keys in strictly 610 * descending kvno order. 611 * 612 * XXX We do assume that keys are clustered by kvno. If 613 * not, then bad. It might be possible to construct 614 * non-clustered keys via the kadm5 API. It wouldn't be 615 * hard to cope with this, since if it happens the worst 616 * that will happen is that some of the current keys can be 617 * found in the history extension, and we could just pull 618 * them back out in that case. 619 */ 620 ret = hdb_add_current_keys_to_history(context, entry); 621 if (ret) 622 goto out; 623 free_Keys(&entry->keys); 624 ret = add_Keys(&entry->keys, &k); 625 free_Key(&k); 626 if (ret) 627 goto out; 628 entry->kvno = key_kvno; 629 continue; 630 } 631 632 if (entry->kvno == key_kvno) { 633 /* 634 * Note that if key_kvno == 0 and target_kvno == 0 then we 635 * end up adding those keys here. Yeah, kvno 0 is very 636 * special for us, but just in case, we keep such keys. 637 */ 638 ret = add_Keys(&entry->keys, &k); 639 free_Key(&k); 640 if (ret) 641 goto out; 642 entry->kvno = key_kvno; 643 } else { 644 ret = hdb_add_history_key(context, entry, key_kvno, &k); 645 if (ret) 646 goto out; 647 free_Key(&k); 648 } 649 } 650 651 if (target_kvno != 0 && entry->kvno != target_kvno) { 652 ret = HDB_ERR_KVNO_NOT_FOUND; 653 goto out; 654 } 655 656 krb5_storage_free(sp); 657 658 return dup_similar_keys(context, entry); 659 660 out: 661 krb5_storage_free(sp); 662 663 if (ret == HEIM_ERR_EOF) 664 /* Better error code than "end of file" */ 665 ret = HEIM_ERR_BAD_HDBENT_ENCODING; 666 free_hdb_entry(entry); 667 free_Key(&k); 668 return ret; 669 } 670 671 #if 0 672 static krb5_error_code 673 mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data) 674 { 675 return EINVAL; 676 } 677 #endif 678 679 #if HAVE_DB1 680 681 #if defined(HAVE_DB_185_H) 682 #include <db_185.h> 683 #elif defined(HAVE_DB_H) 684 #include <db.h> 685 #endif 686 687 688 static krb5_error_code 689 mdb_close(krb5_context context, HDB *db) 690 { 691 DB *d = (DB*)db->hdb_db; 692 (*d->close)(d); 693 return 0; 694 } 695 696 static krb5_error_code 697 mdb_destroy(krb5_context context, HDB *db) 698 { 699 krb5_error_code ret; 700 701 ret = hdb_clear_master_key (context, db); 702 free(db->hdb_name); 703 free(db); 704 return ret; 705 } 706 707 static krb5_error_code 708 mdb_set_sync(krb5_context context, HDB *db, int on) 709 { 710 MITDB *mdb = (MITDB *)db; 711 DB *d = (DB*)db->hdb_db; 712 713 mdb->do_sync = on; 714 if (on) 715 return fsync((*d->fd)(d)); 716 return 0; 717 } 718 719 static krb5_error_code 720 mdb_lock(krb5_context context, HDB *db, int operation) 721 { 722 DB *d = (DB*)db->hdb_db; 723 int fd = (*d->fd)(d); 724 krb5_error_code ret; 725 726 if (db->lock_count > 1) { 727 db->lock_count++; 728 if (db->lock_type == HDB_WLOCK || db->lock_count == operation) 729 return 0; 730 } 731 732 if(fd < 0) { 733 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 734 "Can't lock database: %s", db->hdb_name); 735 return HDB_ERR_CANT_LOCK_DB; 736 } 737 ret = hdb_lock(fd, operation); 738 if (ret) 739 return ret; 740 db->lock_count++; 741 return 0; 742 } 743 744 static krb5_error_code 745 mdb_unlock(krb5_context context, HDB *db) 746 { 747 DB *d = (DB*)db->hdb_db; 748 int fd = (*d->fd)(d); 749 750 if (db->lock_count > 1) { 751 db->lock_count--; 752 return 0; 753 } 754 heim_assert(db->lock_count == 1, "HDB lock/unlock sequence does not match"); 755 db->lock_count--; 756 757 if(fd < 0) { 758 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 759 "Can't unlock database: %s", db->hdb_name); 760 return HDB_ERR_CANT_LOCK_DB; 761 } 762 return hdb_unlock(fd); 763 } 764 765 766 static krb5_error_code 767 mdb_seq(krb5_context context, HDB *db, 768 unsigned flags, hdb_entry_ex *entry, int flag) 769 { 770 DB *d = (DB*)db->hdb_db; 771 DBT key, value; 772 krb5_data key_data, data; 773 int code; 774 775 code = db->hdb_lock(context, db, HDB_RLOCK); 776 if(code == -1) { 777 krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name); 778 return HDB_ERR_DB_INUSE; 779 } 780 code = (*d->seq)(d, &key, &value, flag); 781 db->hdb_unlock(context, db); /* XXX check value */ 782 if(code == -1) { 783 code = errno; 784 krb5_set_error_message(context, code, "Database %s seq error: %s", 785 db->hdb_name, strerror(code)); 786 return code; 787 } 788 if(code == 1) { 789 krb5_clear_error_message(context); 790 return HDB_ERR_NOENTRY; 791 } 792 793 key_data.data = key.data; 794 key_data.length = key.size; 795 data.data = value.data; 796 data.length = value.size; 797 memset(entry, 0, sizeof(*entry)); 798 799 if (_hdb_mdb_value2entry(context, &data, 0, &entry->entry)) 800 return mdb_seq(context, db, flags, entry, R_NEXT); 801 802 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 803 code = hdb_unseal_keys (context, db, &entry->entry); 804 if (code) 805 hdb_free_entry (context, entry); 806 } 807 808 return code; 809 } 810 811 812 static krb5_error_code 813 mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 814 { 815 return mdb_seq(context, db, flags, entry, R_FIRST); 816 } 817 818 819 static krb5_error_code 820 mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 821 { 822 return mdb_seq(context, db, flags, entry, R_NEXT); 823 } 824 825 static krb5_error_code 826 mdb_rename(krb5_context context, HDB *db, const char *new_name) 827 { 828 int ret; 829 char *old = NULL; 830 char *new = NULL; 831 832 if (asprintf(&old, "%s.db", db->hdb_name) < 0) 833 goto out; 834 if (asprintf(&new, "%s.db", new_name) < 0) 835 goto out; 836 ret = rename(old, new); 837 if(ret) 838 goto out; 839 840 free(db->hdb_name); 841 db->hdb_name = strdup(new_name); 842 errno = 0; 843 844 out: 845 free(old); 846 free(new); 847 return errno; 848 } 849 850 static krb5_error_code 851 mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 852 { 853 DB *d = (DB*)db->hdb_db; 854 DBT k, v; 855 int code; 856 857 k.data = key.data; 858 k.size = key.length; 859 code = db->hdb_lock(context, db, HDB_RLOCK); 860 if(code) 861 return code; 862 code = (*d->get)(d, &k, &v, 0); 863 db->hdb_unlock(context, db); 864 if(code < 0) { 865 code = errno; 866 krb5_set_error_message(context, code, "Database %s get error: %s", 867 db->hdb_name, strerror(code)); 868 return code; 869 } 870 if(code == 1) { 871 krb5_clear_error_message(context); 872 return HDB_ERR_NOENTRY; 873 } 874 875 krb5_data_copy(reply, v.data, v.size); 876 return 0; 877 } 878 879 static krb5_error_code 880 mdb__put(krb5_context context, HDB *db, int replace, 881 krb5_data key, krb5_data value) 882 { 883 MITDB *mdb = (MITDB *)db; 884 DB *d = (DB*)db->hdb_db; 885 DBT k, v; 886 int code; 887 888 k.data = key.data; 889 k.size = key.length; 890 v.data = value.data; 891 v.size = value.length; 892 code = db->hdb_lock(context, db, HDB_WLOCK); 893 if(code) 894 return code; 895 code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE); 896 if (code == 0) { 897 code = mdb_set_sync(context, db, mdb->do_sync); 898 db->hdb_unlock(context, db); 899 return code; 900 } 901 db->hdb_unlock(context, db); 902 if(code < 0) { 903 code = errno; 904 krb5_set_error_message(context, code, "Database %s put error: %s", 905 db->hdb_name, strerror(code)); 906 return code; 907 } 908 krb5_clear_error_message(context); 909 return HDB_ERR_EXISTS; 910 } 911 912 static krb5_error_code 913 mdb__del(krb5_context context, HDB *db, krb5_data key) 914 { 915 MITDB *mdb = (MITDB *)db; 916 DB *d = (DB*)db->hdb_db; 917 DBT k; 918 krb5_error_code code; 919 k.data = key.data; 920 k.size = key.length; 921 code = db->hdb_lock(context, db, HDB_WLOCK); 922 if(code) 923 return code; 924 code = (*d->del)(d, &k, 0); 925 if (code == 0) { 926 code = mdb_set_sync(context, db, mdb->do_sync); 927 db->hdb_unlock(context, db); 928 return code; 929 } 930 db->hdb_unlock(context, db); 931 if(code == 1) { 932 code = errno; 933 krb5_set_error_message(context, code, "Database %s put error: %s", 934 db->hdb_name, strerror(code)); 935 return code; 936 } 937 if(code < 0) 938 return errno; 939 return 0; 940 } 941 942 static krb5_error_code 943 mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, 944 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) 945 { 946 krb5_data key, value; 947 krb5_error_code ret; 948 949 ret = mdb_principal2key(context, principal, &key); 950 if (ret) 951 return ret; 952 ret = db->hdb__get(context, db, key, &value); 953 krb5_data_free(&key); 954 if(ret) 955 return ret; 956 ret = _hdb_mdb_value2entry(context, &value, kvno, &entry->entry); 957 krb5_data_free(&value); 958 if (ret) 959 return ret; 960 961 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 962 ret = hdb_unseal_keys (context, db, &entry->entry); 963 if (ret) { 964 hdb_free_entry(context, entry); 965 return ret; 966 } 967 } 968 969 return 0; 970 } 971 972 static krb5_error_code 973 mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 974 { 975 krb5_error_code ret; 976 krb5_storage *sp = NULL; 977 krb5_storage *spent = NULL; 978 krb5_data line = { 0, 0 }; 979 krb5_data kdb_ent = { 0, 0 }; 980 krb5_data key = { 0, 0 }; 981 krb5_data value = { 0, 0 }; 982 ssize_t sz; 983 984 if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE)) 985 return 0; 986 987 if ((flags & HDB_F_PRECHECK)) { 988 ret = mdb_principal2key(context, entry->entry.principal, &key); 989 if (ret) return ret; 990 ret = db->hdb__get(context, db, key, &value); 991 krb5_data_free(&key); 992 if (ret == 0) 993 krb5_data_free(&value); 994 if (ret == HDB_ERR_NOENTRY) 995 return 0; 996 return ret ? ret : HDB_ERR_EXISTS; 997 } 998 999 sp = krb5_storage_emem(); 1000 if (!sp) return ENOMEM; 1001 ret = _hdb_set_master_key_usage(context, db, 0); /* MIT KDB uses KU 0 */ 1002 ret = hdb_seal_keys(context, db, &entry->entry); 1003 if (ret) return ret; 1004 ret = entry2mit_string_int(context, sp, &entry->entry); 1005 if (ret) goto out; 1006 sz = krb5_storage_write(sp, "\n", 2); /* NUL-terminate */ 1007 ret = ENOMEM; 1008 if (sz == -1) goto out; 1009 ret = krb5_storage_to_data(sp, &line); 1010 if (ret) goto out; 1011 1012 ret = ENOMEM; 1013 spent = krb5_storage_emem(); 1014 if (!spent) goto out; 1015 ret = _hdb_mit_dump2mitdb_entry(context, line.data, spent); 1016 if (ret) goto out; 1017 ret = krb5_storage_to_data(spent, &kdb_ent); 1018 if (ret) goto out; 1019 ret = mdb_principal2key(context, entry->entry.principal, &key); 1020 if (ret) goto out; 1021 ret = mdb__put(context, db, 1, key, kdb_ent); 1022 1023 out: 1024 if (sp) 1025 krb5_storage_free(sp); 1026 if (spent) 1027 krb5_storage_free(spent); 1028 krb5_data_free(&line); 1029 krb5_data_free(&kdb_ent); 1030 krb5_data_free(&key); 1031 1032 return ret; 1033 } 1034 1035 static krb5_error_code 1036 mdb_remove(krb5_context context, HDB *db, 1037 unsigned flags, krb5_const_principal principal) 1038 { 1039 krb5_error_code code; 1040 krb5_data key; 1041 krb5_data value = { 0, 0 }; 1042 1043 code = mdb_principal2key(context, principal, &key); 1044 if (code) 1045 return code; 1046 if ((flags & HDB_F_PRECHECK)) { 1047 code = db->hdb__get(context, db, key, &value); 1048 krb5_data_free(&key); 1049 if (code == 0) { 1050 krb5_data_free(&value); 1051 return 0; 1052 } 1053 return code; 1054 } 1055 1056 code = db->hdb__del(context, db, key); 1057 krb5_data_free(&key); 1058 return code; 1059 } 1060 1061 static krb5_error_code 1062 mdb_open(krb5_context context, HDB *db, int flags, mode_t mode) 1063 { 1064 char *fn; 1065 char *actual_fn; 1066 krb5_error_code ret; 1067 struct stat st; 1068 1069 if (asprintf(&fn, "%s.db", db->hdb_name) < 0) { 1070 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 1071 return ENOMEM; 1072 } 1073 1074 if (stat(fn, &st) == 0) 1075 actual_fn = fn; 1076 else 1077 actual_fn = db->hdb_name; 1078 db->hdb_db = dbopen(actual_fn, flags, mode, DB_BTREE, NULL); 1079 if (db->hdb_db == NULL) { 1080 switch (errno) { 1081 #ifdef EFTYPE 1082 case EFTYPE: 1083 #endif 1084 case EINVAL: 1085 db->hdb_db = dbopen(actual_fn, flags, mode, DB_HASH, NULL); 1086 } 1087 } 1088 free(fn); 1089 1090 if (db->hdb_db == NULL) { 1091 ret = errno; 1092 krb5_set_error_message(context, ret, "dbopen (%s): %s", 1093 db->hdb_name, strerror(ret)); 1094 return ret; 1095 } 1096 #if 0 1097 /* 1098 * Don't do this -- MIT won't be able to handle the 1099 * HDB_DB_FORMAT_ENTRY key. 1100 */ 1101 if ((flags & O_ACCMODE) != O_RDONLY) 1102 ret = hdb_init_db(context, db); 1103 #endif 1104 ret = hdb_check_db_format(context, db); 1105 if (ret == HDB_ERR_NOENTRY) { 1106 krb5_clear_error_message(context); 1107 return 0; 1108 } 1109 if (ret) { 1110 mdb_close(context, db); 1111 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 1112 (flags & O_ACCMODE) == O_RDONLY ? 1113 "checking format of" : "initialize", 1114 db->hdb_name); 1115 } 1116 return ret; 1117 } 1118 1119 krb5_error_code 1120 hdb_mitdb_create(krb5_context context, HDB **db, 1121 const char *filename) 1122 { 1123 MITDB **mdb = (MITDB **)db; 1124 *mdb = calloc(1, sizeof(**mdb)); 1125 if (*mdb == NULL) { 1126 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 1127 return ENOMEM; 1128 } 1129 1130 (*db)->hdb_db = NULL; 1131 (*db)->hdb_name = strdup(filename); 1132 if ((*db)->hdb_name == NULL) { 1133 free(*db); 1134 *db = NULL; 1135 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 1136 return ENOMEM; 1137 } 1138 (*mdb)->do_sync = 1; 1139 (*db)->hdb_master_key_set = 0; 1140 (*db)->hdb_openp = 0; 1141 (*db)->hdb_capability_flags = 0; 1142 (*db)->hdb_open = mdb_open; 1143 (*db)->hdb_close = mdb_close; 1144 (*db)->hdb_fetch_kvno = mdb_fetch_kvno; 1145 (*db)->hdb_store = mdb_store; 1146 (*db)->hdb_remove = mdb_remove; 1147 (*db)->hdb_firstkey = mdb_firstkey; 1148 (*db)->hdb_nextkey= mdb_nextkey; 1149 (*db)->hdb_lock = mdb_lock; 1150 (*db)->hdb_unlock = mdb_unlock; 1151 (*db)->hdb_rename = mdb_rename; 1152 (*db)->hdb__get = mdb__get; 1153 (*db)->hdb__put = mdb__put; 1154 (*db)->hdb__del = mdb__del; 1155 (*db)->hdb_destroy = mdb_destroy; 1156 (*db)->hdb_set_sync = mdb_set_sync; 1157 return 0; 1158 } 1159 1160 #endif /* HAVE_DB1 */ 1161 1162 /* 1163 can have any number of princ stanzas. 1164 format is as follows (only \n indicates newlines) 1165 princ\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38) 1166 %d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU) 1167 %d\t (number of tl_data) 1168 %d\t (number of key data, e.g. how many keys for this user) 1169 %d\t (extra data length) 1170 %s\t (principal name) 1171 %d\t (attributes) 1172 %d\t (max lifetime, seconds) 1173 %d\t (max renewable life, seconds) 1174 %d\t (expiration, seconds since epoch or 2145830400 for never) 1175 %d\t (password expiration, seconds, 0 for never) 1176 %d\t (last successful auth, seconds since epoch) 1177 %d\t (last failed auth, per above) 1178 %d\t (failed auth count) 1179 foreach tl_data 0 to number of tl_data - 1 as above 1180 %d\t%d\t (data type, data length) 1181 foreach tl_data 0 to length-1 1182 %02x (tl data contents[element n]) 1183 except if tl_data length is 0 1184 %d (always -1) 1185 \t 1186 foreach key 0 to number of keys - 1 as above 1187 %d\t%d\t (key data version, kvno) 1188 foreach version 0 to key data version - 1 (a key or a salt) 1189 %d\t%d\t(data type for this key, data length for this key) 1190 foreach key data length 0 to length-1 1191 %02x (key data contents[element n]) 1192 except if key_data length is 0 1193 %d (always -1) 1194 \t 1195 foreach extra data length 0 to length - 1 1196 %02x (extra data part) 1197 unless no extra data 1198 %d (always -1) 1199 ;\n 1200 1201 */ 1202 1203 #if 0 1204 /* Why ever did we loop? */ 1205 static char * 1206 nexttoken(char **p) 1207 { 1208 char *q; 1209 do { 1210 q = strsep(p, " \t"); 1211 } while(q && *q == '\0'); 1212 return q; 1213 } 1214 #endif 1215 1216 static char * 1217 nexttoken(char **p, size_t len, const char *what) 1218 { 1219 char *q; 1220 1221 if (*p == NULL) 1222 return NULL; 1223 1224 q = *p; 1225 *p += len; 1226 /* Must be followed by a delimiter (right?) */ 1227 if (strsep(p, " \t") != q + len) { 1228 warnx("No tokens left in dump entry while looking for %s", what); 1229 return NULL; 1230 } 1231 if (*q == '\0') 1232 warnx("Empty last token in dump entry while looking for %s", what); 1233 return q; 1234 } 1235 1236 static size_t 1237 getdata(char **p, unsigned char *buf, size_t len, const char *what) 1238 { 1239 size_t i; 1240 int v; 1241 char *q = nexttoken(p, 0, what); 1242 if (q == NULL) { 1243 warnx("Failed to find hex-encoded binary data (%s) in dump", what); 1244 return 0; 1245 } 1246 i = 0; 1247 while (*q && i < len) { 1248 if (sscanf(q, "%02x", &v) != 1) 1249 break; 1250 buf[i++] = v; 1251 q += 2; 1252 } 1253 return i; 1254 } 1255 1256 static int 1257 getint(char **p, const char *what) 1258 { 1259 int val; 1260 char *q = nexttoken(p, 0, what); 1261 if (!q) { 1262 warnx("Failed to find a signed integer (%s) in dump", what); 1263 return -1; 1264 } 1265 if (sscanf(q, "%d", &val) != 1) 1266 return -1; 1267 return val; 1268 } 1269 1270 static unsigned int 1271 getuint(char **p, const char *what) 1272 { 1273 int val; 1274 char *q = nexttoken(p, 0, what); 1275 if (!q) { 1276 warnx("Failed to find an unsigned integer (%s) in dump", what); 1277 return 0; 1278 } 1279 if (sscanf(q, "%u", &val) != 1) 1280 return 0; 1281 return val; 1282 } 1283 1284 #define KRB5_KDB_SALTTYPE_NORMAL 0 1285 #define KRB5_KDB_SALTTYPE_V4 1 1286 #define KRB5_KDB_SALTTYPE_NOREALM 2 1287 #define KRB5_KDB_SALTTYPE_ONLYREALM 3 1288 #define KRB5_KDB_SALTTYPE_SPECIAL 4 1289 #define KRB5_KDB_SALTTYPE_AFS3 5 1290 1291 #define CHECK_UINT(num) \ 1292 if ((num) < 0 || (num) > INT_MAX) return EINVAL 1293 #define CHECK_UINT16(num) \ 1294 if ((num) < 0 || (num) > 1<<15) return EINVAL 1295 #define CHECK_NUM(num, maxv) \ 1296 if ((num) > (maxv)) return EINVAL 1297 1298 /* 1299 * This utility function converts an MIT dump entry to an MIT on-disk 1300 * encoded entry, which can then be decoded with _hdb_mdb_value2entry(). 1301 * This allows us to have a single decoding function (_hdb_mdb_value2entry), 1302 * which makes the code cleaner (less code duplication), if a bit less 1303 * efficient. It also will allow us to have a function to dump an HDB 1304 * entry in MIT format so we can dump HDB into MIT format for rollback 1305 * purposes. And that will allow us to write to MIT KDBs, again 1306 * somewhat inefficiently, also for migration/rollback purposes. 1307 */ 1308 int 1309 _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) 1310 { 1311 krb5_error_code ret = EINVAL; 1312 char *p = line, *q; 1313 char *princ; 1314 ssize_t sz; 1315 size_t i; 1316 size_t princ_len; 1317 unsigned int num_tl_data; 1318 size_t num_key_data; 1319 unsigned int attributes; 1320 int tmp; 1321 1322 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 1323 1324 q = nexttoken(&p, 0, "record type (princ or policy)"); 1325 if (strcmp(q, "kdb5_util") == 0 || strcmp(q, "policy") == 0 || 1326 strcmp(q, "princ") != 0) { 1327 warnx("Supposed MIT dump entry does not start with 'kdb5_util', " 1328 "'policy', nor 'princ'"); 1329 return -1; 1330 } 1331 if (getint(&p, "constant '38'") != 38) { 1332 warnx("Dump entry does not start with '38<TAB>'"); 1333 return EINVAL; 1334 } 1335 #define KDB_V1_BASE_LENGTH 38 1336 ret = krb5_store_int16(sp, KDB_V1_BASE_LENGTH); 1337 if (ret) return ret; 1338 1339 princ_len = getuint(&p, "principal name length"); 1340 if (princ_len > (1<<15) - 1) { 1341 warnx("Principal name in dump entry too long (%llu)", 1342 (unsigned long long)princ_len); 1343 return EINVAL; 1344 } 1345 num_tl_data = getuint(&p, "number of TL data"); 1346 num_key_data = getuint(&p, "number of key data"); 1347 getint(&p, "5th field, length of 'extra data'"); 1348 princ = nexttoken(&p, (int)princ_len, "principal name"); 1349 if (princ == NULL) { 1350 warnx("Failed to read principal name (expected length %llu)", 1351 (unsigned long long)princ_len); 1352 return -1; 1353 } 1354 1355 attributes = getuint(&p, "attributes"); 1356 ret = krb5_store_uint32(sp, attributes); 1357 if (ret) return ret; 1358 1359 tmp = getint(&p, "max life"); 1360 CHECK_UINT(tmp); 1361 ret = krb5_store_uint32(sp, tmp); 1362 if (ret) return ret; 1363 1364 tmp = getint(&p, "max renewable life"); 1365 CHECK_UINT(tmp); 1366 ret = krb5_store_uint32(sp, tmp); 1367 if (ret) return ret; 1368 1369 tmp = getint(&p, "expiration"); 1370 CHECK_UINT(tmp); 1371 ret = krb5_store_uint32(sp, tmp); 1372 if (ret) return ret; 1373 1374 tmp = getint(&p, "pw expiration"); 1375 CHECK_UINT(tmp); 1376 ret = krb5_store_uint32(sp, tmp); 1377 if (ret) return ret; 1378 1379 tmp = getint(&p, "last auth"); 1380 CHECK_UINT(tmp); 1381 ret = krb5_store_uint32(sp, tmp); 1382 if (ret) return ret; 1383 1384 tmp = getint(&p, "last failed auth"); 1385 CHECK_UINT(tmp); 1386 ret = krb5_store_uint32(sp, tmp); 1387 if (ret) return ret; 1388 1389 tmp = getint(&p,"fail auth count"); 1390 CHECK_UINT(tmp); 1391 ret = krb5_store_uint32(sp, tmp); 1392 if (ret) return ret; 1393 1394 /* add TL data count */ 1395 CHECK_NUM(num_tl_data, 1023); 1396 ret = krb5_store_uint16(sp, num_tl_data); 1397 if (ret) return ret; 1398 1399 /* add key count */ 1400 CHECK_NUM(num_key_data, 1023); 1401 ret = krb5_store_uint16(sp, num_key_data); 1402 if (ret) return ret; 1403 1404 /* add principal unparsed name length and unparsed name */ 1405 princ_len = strlen(princ); 1406 princ_len++; /* must count and write the NUL in the on-disk encoding */ 1407 ret = krb5_store_uint16(sp, princ_len); 1408 if (ret) return ret; 1409 sz = krb5_storage_write(sp, princ, princ_len); 1410 if (sz == -1) return ENOMEM; 1411 1412 /* scan and write TL data */ 1413 for (i = 0; i < num_tl_data; i++) { 1414 char *reading_what; 1415 int tl_type, tl_length; 1416 unsigned char *buf; 1417 1418 tl_type = getint(&p, "TL data type"); 1419 tl_length = getint(&p, "data length"); 1420 1421 if (asprintf(&reading_what, "TL data type %d (length %d)", 1422 tl_type, tl_length) < 0) 1423 return ENOMEM; 1424 1425 /* 1426 * XXX Leaking reading_what, but only on ENOMEM cases anyways, 1427 * so we don't care. 1428 */ 1429 CHECK_UINT16(tl_type); 1430 ret = krb5_store_uint16(sp, tl_type); 1431 if (ret) return ret; 1432 CHECK_UINT16(tl_length); 1433 ret = krb5_store_uint16(sp, tl_length); 1434 if (ret) return ret; 1435 1436 if (tl_length) { 1437 buf = malloc(tl_length); 1438 if (!buf) return ENOMEM; 1439 if (getdata(&p, buf, tl_length, reading_what) != tl_length) 1440 return EINVAL; 1441 sz = krb5_storage_write(sp, buf, tl_length); 1442 free(buf); 1443 if (sz == -1) return ENOMEM; 1444 } else { 1445 if (strcmp(nexttoken(&p, 0, "'-1' field"), "-1") != 0) return EINVAL; 1446 } 1447 free(reading_what); 1448 } 1449 1450 for (i = 0; i < num_key_data; i++) { 1451 unsigned char *buf; 1452 int key_versions; 1453 int kvno; 1454 int keytype; 1455 int keylen; 1456 size_t k; 1457 1458 key_versions = getint(&p, "key data 'version'"); 1459 CHECK_UINT16(key_versions); 1460 ret = krb5_store_int16(sp, key_versions); 1461 if (ret) return ret; 1462 1463 kvno = getint(&p, "kvno"); 1464 CHECK_UINT16(kvno); 1465 ret = krb5_store_int16(sp, kvno); 1466 if (ret) return ret; 1467 1468 for (k = 0; k < key_versions; k++) { 1469 keytype = getint(&p, "enctype"); 1470 CHECK_UINT16(keytype); 1471 ret = krb5_store_int16(sp, keytype); 1472 if (ret) return ret; 1473 1474 keylen = getint(&p, "encrypted key length"); 1475 CHECK_UINT16(keylen); 1476 ret = krb5_store_int16(sp, keylen); 1477 if (ret) return ret; 1478 1479 if (keylen) { 1480 buf = malloc(keylen); 1481 if (!buf) return ENOMEM; 1482 if (getdata(&p, buf, keylen, "key (or salt) data") != keylen) 1483 return EINVAL; 1484 sz = krb5_storage_write(sp, buf, keylen); 1485 free(buf); 1486 if (sz == -1) return ENOMEM; 1487 } else { 1488 if (strcmp(nexttoken(&p, 0, 1489 "'-1' zero-length key/salt field"), 1490 "-1") != 0) { 1491 warnx("Expected '-1' field because key/salt length is 0"); 1492 return -1; 1493 } 1494 } 1495 } 1496 } 1497 /* 1498 * The rest is "extra data", but there's never any and we wouldn't 1499 * know what to do with it. 1500 */ 1501 /* nexttoken(&p, 0, "extra data"); */ 1502 return 0; 1503 } 1504 1505