1 /* $NetBSD: hdb-mitdb.c,v 1.3 2019/12/15 22:50:49 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 if ((flags & HDB_F_PRECHECK)) { 1044 code = db->hdb__get(context, db, key, &value); 1045 krb5_data_free(&key); 1046 if (code == 0) { 1047 krb5_data_free(&value); 1048 return 0; 1049 } 1050 return code; 1051 } 1052 1053 mdb_principal2key(context, principal, &key); 1054 code = db->hdb__del(context, db, key); 1055 krb5_data_free(&key); 1056 return code; 1057 } 1058 1059 static krb5_error_code 1060 mdb_open(krb5_context context, HDB *db, int flags, mode_t mode) 1061 { 1062 char *fn; 1063 char *actual_fn; 1064 krb5_error_code ret; 1065 struct stat st; 1066 1067 if (asprintf(&fn, "%s.db", db->hdb_name) < 0) { 1068 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 1069 return ENOMEM; 1070 } 1071 1072 if (stat(fn, &st) == 0) 1073 actual_fn = fn; 1074 else 1075 actual_fn = db->hdb_name; 1076 db->hdb_db = dbopen(actual_fn, flags, mode, DB_BTREE, NULL); 1077 if (db->hdb_db == NULL) { 1078 switch (errno) { 1079 #ifdef EFTYPE 1080 case EFTYPE: 1081 #endif 1082 case EINVAL: 1083 db->hdb_db = dbopen(actual_fn, flags, mode, DB_HASH, NULL); 1084 } 1085 } 1086 free(fn); 1087 1088 if (db->hdb_db == NULL) { 1089 ret = errno; 1090 krb5_set_error_message(context, ret, "dbopen (%s): %s", 1091 db->hdb_name, strerror(ret)); 1092 return ret; 1093 } 1094 #if 0 1095 /* 1096 * Don't do this -- MIT won't be able to handle the 1097 * HDB_DB_FORMAT_ENTRY key. 1098 */ 1099 if ((flags & O_ACCMODE) != O_RDONLY) 1100 ret = hdb_init_db(context, db); 1101 #endif 1102 ret = hdb_check_db_format(context, db); 1103 if (ret == HDB_ERR_NOENTRY) { 1104 krb5_clear_error_message(context); 1105 return 0; 1106 } 1107 if (ret) { 1108 mdb_close(context, db); 1109 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 1110 (flags & O_ACCMODE) == O_RDONLY ? 1111 "checking format of" : "initialize", 1112 db->hdb_name); 1113 } 1114 return ret; 1115 } 1116 1117 krb5_error_code 1118 hdb_mitdb_create(krb5_context context, HDB **db, 1119 const char *filename) 1120 { 1121 MITDB **mdb = (MITDB **)db; 1122 *mdb = calloc(1, sizeof(**mdb)); 1123 if (*mdb == NULL) { 1124 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 1125 return ENOMEM; 1126 } 1127 1128 (*db)->hdb_db = NULL; 1129 (*db)->hdb_name = strdup(filename); 1130 if ((*db)->hdb_name == NULL) { 1131 free(*db); 1132 *db = NULL; 1133 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 1134 return ENOMEM; 1135 } 1136 (*mdb)->do_sync = 1; 1137 (*db)->hdb_master_key_set = 0; 1138 (*db)->hdb_openp = 0; 1139 (*db)->hdb_capability_flags = 0; 1140 (*db)->hdb_open = mdb_open; 1141 (*db)->hdb_close = mdb_close; 1142 (*db)->hdb_fetch_kvno = mdb_fetch_kvno; 1143 (*db)->hdb_store = mdb_store; 1144 (*db)->hdb_remove = mdb_remove; 1145 (*db)->hdb_firstkey = mdb_firstkey; 1146 (*db)->hdb_nextkey= mdb_nextkey; 1147 (*db)->hdb_lock = mdb_lock; 1148 (*db)->hdb_unlock = mdb_unlock; 1149 (*db)->hdb_rename = mdb_rename; 1150 (*db)->hdb__get = mdb__get; 1151 (*db)->hdb__put = mdb__put; 1152 (*db)->hdb__del = mdb__del; 1153 (*db)->hdb_destroy = mdb_destroy; 1154 (*db)->hdb_set_sync = mdb_set_sync; 1155 return 0; 1156 } 1157 1158 #endif /* HAVE_DB1 */ 1159 1160 /* 1161 can have any number of princ stanzas. 1162 format is as follows (only \n indicates newlines) 1163 princ\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38) 1164 %d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU) 1165 %d\t (number of tl_data) 1166 %d\t (number of key data, e.g. how many keys for this user) 1167 %d\t (extra data length) 1168 %s\t (principal name) 1169 %d\t (attributes) 1170 %d\t (max lifetime, seconds) 1171 %d\t (max renewable life, seconds) 1172 %d\t (expiration, seconds since epoch or 2145830400 for never) 1173 %d\t (password expiration, seconds, 0 for never) 1174 %d\t (last successful auth, seconds since epoch) 1175 %d\t (last failed auth, per above) 1176 %d\t (failed auth count) 1177 foreach tl_data 0 to number of tl_data - 1 as above 1178 %d\t%d\t (data type, data length) 1179 foreach tl_data 0 to length-1 1180 %02x (tl data contents[element n]) 1181 except if tl_data length is 0 1182 %d (always -1) 1183 \t 1184 foreach key 0 to number of keys - 1 as above 1185 %d\t%d\t (key data version, kvno) 1186 foreach version 0 to key data version - 1 (a key or a salt) 1187 %d\t%d\t(data type for this key, data length for this key) 1188 foreach key data length 0 to length-1 1189 %02x (key data contents[element n]) 1190 except if key_data length is 0 1191 %d (always -1) 1192 \t 1193 foreach extra data length 0 to length - 1 1194 %02x (extra data part) 1195 unless no extra data 1196 %d (always -1) 1197 ;\n 1198 1199 */ 1200 1201 #if 0 1202 /* Why ever did we loop? */ 1203 static char * 1204 nexttoken(char **p) 1205 { 1206 char *q; 1207 do { 1208 q = strsep(p, " \t"); 1209 } while(q && *q == '\0'); 1210 return q; 1211 } 1212 #endif 1213 1214 static char * 1215 nexttoken(char **p, size_t len, const char *what) 1216 { 1217 char *q; 1218 1219 if (*p == NULL) 1220 return NULL; 1221 1222 q = *p; 1223 *p += len; 1224 /* Must be followed by a delimiter (right?) */ 1225 if (strsep(p, " \t") != q + len) { 1226 warnx("No tokens left in dump entry while looking for %s", what); 1227 return NULL; 1228 } 1229 if (*q == '\0') 1230 warnx("Empty last token in dump entry while looking for %s", what); 1231 return q; 1232 } 1233 1234 static size_t 1235 getdata(char **p, unsigned char *buf, size_t len, const char *what) 1236 { 1237 size_t i; 1238 int v; 1239 char *q = nexttoken(p, 0, what); 1240 if (q == NULL) { 1241 warnx("Failed to find hex-encoded binary data (%s) in dump", what); 1242 return 0; 1243 } 1244 i = 0; 1245 while (*q && i < len) { 1246 if (sscanf(q, "%02x", &v) != 1) 1247 break; 1248 buf[i++] = v; 1249 q += 2; 1250 } 1251 return i; 1252 } 1253 1254 static int 1255 getint(char **p, const char *what) 1256 { 1257 int val; 1258 char *q = nexttoken(p, 0, what); 1259 if (!q) { 1260 warnx("Failed to find a signed integer (%s) in dump", what); 1261 return -1; 1262 } 1263 if (sscanf(q, "%d", &val) != 1) 1264 return -1; 1265 return val; 1266 } 1267 1268 static unsigned int 1269 getuint(char **p, const char *what) 1270 { 1271 int val; 1272 char *q = nexttoken(p, 0, what); 1273 if (!q) { 1274 warnx("Failed to find an unsigned integer (%s) in dump", what); 1275 return 0; 1276 } 1277 if (sscanf(q, "%u", &val) != 1) 1278 return 0; 1279 return val; 1280 } 1281 1282 #define KRB5_KDB_SALTTYPE_NORMAL 0 1283 #define KRB5_KDB_SALTTYPE_V4 1 1284 #define KRB5_KDB_SALTTYPE_NOREALM 2 1285 #define KRB5_KDB_SALTTYPE_ONLYREALM 3 1286 #define KRB5_KDB_SALTTYPE_SPECIAL 4 1287 #define KRB5_KDB_SALTTYPE_AFS3 5 1288 1289 #define CHECK_UINT(num) \ 1290 if ((num) < 0 || (num) > INT_MAX) return EINVAL 1291 #define CHECK_UINT16(num) \ 1292 if ((num) < 0 || (num) > 1<<15) return EINVAL 1293 #define CHECK_NUM(num, maxv) \ 1294 if ((num) > (maxv)) return EINVAL 1295 1296 /* 1297 * This utility function converts an MIT dump entry to an MIT on-disk 1298 * encoded entry, which can then be decoded with _hdb_mdb_value2entry(). 1299 * This allows us to have a single decoding function (_hdb_mdb_value2entry), 1300 * which makes the code cleaner (less code duplication), if a bit less 1301 * efficient. It also will allow us to have a function to dump an HDB 1302 * entry in MIT format so we can dump HDB into MIT format for rollback 1303 * purposes. And that will allow us to write to MIT KDBs, again 1304 * somewhat inefficiently, also for migration/rollback purposes. 1305 */ 1306 int 1307 _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) 1308 { 1309 krb5_error_code ret = EINVAL; 1310 char *p = line, *q; 1311 char *princ; 1312 ssize_t sz; 1313 size_t i; 1314 size_t princ_len; 1315 unsigned int num_tl_data; 1316 size_t num_key_data; 1317 unsigned int attributes; 1318 int tmp; 1319 1320 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 1321 1322 q = nexttoken(&p, 0, "record type (princ or policy)"); 1323 if (strcmp(q, "kdb5_util") == 0 || strcmp(q, "policy") == 0 || 1324 strcmp(q, "princ") != 0) { 1325 warnx("Supposed MIT dump entry does not start with 'kdb5_util', " 1326 "'policy', nor 'princ'"); 1327 return -1; 1328 } 1329 if (getint(&p, "constant '38'") != 38) { 1330 warnx("Dump entry does not start with '38<TAB>'"); 1331 return EINVAL; 1332 } 1333 #define KDB_V1_BASE_LENGTH 38 1334 ret = krb5_store_int16(sp, KDB_V1_BASE_LENGTH); 1335 if (ret) return ret; 1336 1337 princ_len = getuint(&p, "principal name length"); 1338 if (princ_len > (1<<15) - 1) { 1339 warnx("Principal name in dump entry too long (%llu)", 1340 (unsigned long long)princ_len); 1341 return EINVAL; 1342 } 1343 num_tl_data = getuint(&p, "number of TL data"); 1344 num_key_data = getuint(&p, "number of key data"); 1345 getint(&p, "5th field, length of 'extra data'"); 1346 princ = nexttoken(&p, (int)princ_len, "principal name"); 1347 if (princ == NULL) { 1348 warnx("Failed to read principal name (expected length %llu)", 1349 (unsigned long long)princ_len); 1350 return -1; 1351 } 1352 1353 attributes = getuint(&p, "attributes"); 1354 ret = krb5_store_uint32(sp, attributes); 1355 if (ret) return ret; 1356 1357 tmp = getint(&p, "max life"); 1358 CHECK_UINT(tmp); 1359 ret = krb5_store_uint32(sp, tmp); 1360 if (ret) return ret; 1361 1362 tmp = getint(&p, "max renewable life"); 1363 CHECK_UINT(tmp); 1364 ret = krb5_store_uint32(sp, tmp); 1365 if (ret) return ret; 1366 1367 tmp = getint(&p, "expiration"); 1368 CHECK_UINT(tmp); 1369 ret = krb5_store_uint32(sp, tmp); 1370 if (ret) return ret; 1371 1372 tmp = getint(&p, "pw expiration"); 1373 CHECK_UINT(tmp); 1374 ret = krb5_store_uint32(sp, tmp); 1375 if (ret) return ret; 1376 1377 tmp = getint(&p, "last auth"); 1378 CHECK_UINT(tmp); 1379 ret = krb5_store_uint32(sp, tmp); 1380 if (ret) return ret; 1381 1382 tmp = getint(&p, "last failed auth"); 1383 CHECK_UINT(tmp); 1384 ret = krb5_store_uint32(sp, tmp); 1385 if (ret) return ret; 1386 1387 tmp = getint(&p,"fail auth count"); 1388 CHECK_UINT(tmp); 1389 ret = krb5_store_uint32(sp, tmp); 1390 if (ret) return ret; 1391 1392 /* add TL data count */ 1393 CHECK_NUM(num_tl_data, 1023); 1394 ret = krb5_store_uint16(sp, num_tl_data); 1395 if (ret) return ret; 1396 1397 /* add key count */ 1398 CHECK_NUM(num_key_data, 1023); 1399 ret = krb5_store_uint16(sp, num_key_data); 1400 if (ret) return ret; 1401 1402 /* add principal unparsed name length and unparsed name */ 1403 princ_len = strlen(princ); 1404 princ_len++; /* must count and write the NUL in the on-disk encoding */ 1405 ret = krb5_store_uint16(sp, princ_len); 1406 if (ret) return ret; 1407 sz = krb5_storage_write(sp, princ, princ_len); 1408 if (sz == -1) return ENOMEM; 1409 1410 /* scan and write TL data */ 1411 for (i = 0; i < num_tl_data; i++) { 1412 char *reading_what; 1413 int tl_type, tl_length; 1414 unsigned char *buf; 1415 1416 tl_type = getint(&p, "TL data type"); 1417 tl_length = getint(&p, "data length"); 1418 1419 if (asprintf(&reading_what, "TL data type %d (length %d)", 1420 tl_type, tl_length) < 0) 1421 return ENOMEM; 1422 1423 /* 1424 * XXX Leaking reading_what, but only on ENOMEM cases anyways, 1425 * so we don't care. 1426 */ 1427 CHECK_UINT16(tl_type); 1428 ret = krb5_store_uint16(sp, tl_type); 1429 if (ret) return ret; 1430 CHECK_UINT16(tl_length); 1431 ret = krb5_store_uint16(sp, tl_length); 1432 if (ret) return ret; 1433 1434 if (tl_length) { 1435 buf = malloc(tl_length); 1436 if (!buf) return ENOMEM; 1437 if (getdata(&p, buf, tl_length, reading_what) != tl_length) 1438 return EINVAL; 1439 sz = krb5_storage_write(sp, buf, tl_length); 1440 free(buf); 1441 if (sz == -1) return ENOMEM; 1442 } else { 1443 if (strcmp(nexttoken(&p, 0, "'-1' field"), "-1") != 0) return EINVAL; 1444 } 1445 free(reading_what); 1446 } 1447 1448 for (i = 0; i < num_key_data; i++) { 1449 unsigned char *buf; 1450 int key_versions; 1451 int kvno; 1452 int keytype; 1453 int keylen; 1454 size_t k; 1455 1456 key_versions = getint(&p, "key data 'version'"); 1457 CHECK_UINT16(key_versions); 1458 ret = krb5_store_int16(sp, key_versions); 1459 if (ret) return ret; 1460 1461 kvno = getint(&p, "kvno"); 1462 CHECK_UINT16(kvno); 1463 ret = krb5_store_int16(sp, kvno); 1464 if (ret) return ret; 1465 1466 for (k = 0; k < key_versions; k++) { 1467 keytype = getint(&p, "enctype"); 1468 CHECK_UINT16(keytype); 1469 ret = krb5_store_int16(sp, keytype); 1470 if (ret) return ret; 1471 1472 keylen = getint(&p, "encrypted key length"); 1473 CHECK_UINT16(keylen); 1474 ret = krb5_store_int16(sp, keylen); 1475 if (ret) return ret; 1476 1477 if (keylen) { 1478 buf = malloc(keylen); 1479 if (!buf) return ENOMEM; 1480 if (getdata(&p, buf, keylen, "key (or salt) data") != keylen) 1481 return EINVAL; 1482 sz = krb5_storage_write(sp, buf, keylen); 1483 free(buf); 1484 if (sz == -1) return ENOMEM; 1485 } else { 1486 if (strcmp(nexttoken(&p, 0, 1487 "'-1' zero-length key/salt field"), 1488 "-1") != 0) { 1489 warnx("Expected '-1' field because key/salt length is 0"); 1490 return -1; 1491 } 1492 } 1493 } 1494 } 1495 /* 1496 * The rest is "extra data", but there's never any and we wouldn't 1497 * know what to do with it. 1498 */ 1499 /* nexttoken(&p, 0, "extra data"); */ 1500 return 0; 1501 } 1502 1503