roken: qsort provide ANSI C prototype for swapfunc()
[heimdal.git] / lib / hdb / hdb-mitdb.c
blob7436f39edbbe6dbf284ae16e7e9a5778af5e7872
1 /*
2 * Copyright (c) 1997 - 2017 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #define KRB5_KDB_DISALLOW_POSTDATED 0x00000001
37 #define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002
38 #define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004
39 #define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008
40 #define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010
41 #define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020
42 #define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040
43 #define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080
44 #define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100
45 #define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200
46 #define KRB5_KDB_DISALLOW_SVR 0x00001000
47 #define KRB5_KDB_PWCHANGE_SERVICE 0x00002000
48 #define KRB5_KDB_SUPPORT_DESMD5 0x00004000
49 #define KRB5_KDB_NEW_PRINC 0x00008000
53 key: krb5_unparse_name + NUL
55 16: baselength
56 32: attributes
57 32: max time
58 32: max renewable time
59 32: client expire
60 32: passwd expire
61 32: last successful passwd
62 32: last failed attempt
63 32: num of failed attempts
64 16: num tl data
65 16: num data data
66 16: principal length
67 length: principal
68 for num tl data times
69 16: tl data type
70 16: tl data length
71 length: length
72 for num key data times
73 16: version (num keyblocks)
74 16: kvno
75 for version times:
76 16: type
77 16: length
78 length: keydata
81 key_data_contents[0]
83 int16: length
84 read-of-data: key-encrypted, key-usage 0, master-key
86 salt:
87 version2 = salt in key_data->key_data_contents[1]
88 else default salt.
92 #include "hdb_locl.h"
94 typedef struct MITDB {
95 HDB db; /* Generic */
96 int do_sync; /* MITDB-specific */
97 } MITDB;
99 static void
100 attr_to_flags(unsigned attr, HDBFlags *flags)
102 flags->postdate = !(attr & KRB5_KDB_DISALLOW_POSTDATED);
103 flags->forwardable = !(attr & KRB5_KDB_DISALLOW_FORWARDABLE);
104 flags->initial = !!(attr & KRB5_KDB_DISALLOW_TGT_BASED);
105 flags->renewable = !(attr & KRB5_KDB_DISALLOW_RENEWABLE);
106 flags->proxiable = !(attr & KRB5_KDB_DISALLOW_PROXIABLE);
107 /* DUP_SKEY */
108 flags->invalid = !!(attr & KRB5_KDB_DISALLOW_ALL_TIX);
109 flags->require_preauth = !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH);
110 flags->require_hwauth = !!(attr & KRB5_KDB_REQUIRES_HW_AUTH);
111 flags->require_pwchange = !!(attr & KRB5_KDB_REQUIRES_PWCHANGE);
112 flags->server = !(attr & KRB5_KDB_DISALLOW_SVR);
113 flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE);
114 flags->client = 1; /* XXX */
117 #define KDB_V1_BASE_LENGTH 38
119 #define CHECK(x) do { if ((x)) goto out; } while(0)
121 #ifdef HAVE_DB1
122 static krb5_error_code
123 mdb_principal2key(krb5_context context,
124 krb5_const_principal principal,
125 krb5_data *key)
127 krb5_error_code ret;
128 char *str;
130 ret = krb5_unparse_name(context, principal, &str);
131 if (ret)
132 return ret;
133 key->data = str;
134 key->length = strlen(str) + 1;
135 return 0;
137 #endif /* HAVE_DB1 */
139 #define KRB5_KDB_SALTTYPE_NORMAL 0
140 #define KRB5_KDB_SALTTYPE_V4 1
141 #define KRB5_KDB_SALTTYPE_NOREALM 2
142 #define KRB5_KDB_SALTTYPE_ONLYREALM 3
143 #define KRB5_KDB_SALTTYPE_SPECIAL 4
144 #define KRB5_KDB_SALTTYPE_AFS3 5
145 #define KRB5_KDB_SALTTYPE_CERTHASH 6
147 static krb5_error_code
148 fix_salt(krb5_context context, hdb_entry *ent, Key *k)
150 krb5_error_code ret;
151 Salt *salt = k->salt;
152 /* fix salt type */
153 switch((int)salt->type) {
154 case KRB5_KDB_SALTTYPE_NORMAL:
155 salt->type = KRB5_PADATA_PW_SALT;
156 break;
157 case KRB5_KDB_SALTTYPE_V4:
158 krb5_data_free(&salt->salt);
159 salt->type = KRB5_PADATA_PW_SALT;
160 break;
161 case KRB5_KDB_SALTTYPE_NOREALM:
163 size_t len;
164 size_t i;
165 char *p;
167 len = 0;
168 for (i = 0; i < ent->principal->name.name_string.len; ++i)
169 len += strlen(ent->principal->name.name_string.val[i]);
170 ret = krb5_data_alloc (&salt->salt, len);
171 if (ret)
172 return ret;
173 p = salt->salt.data;
174 for (i = 0; i < ent->principal->name.name_string.len; ++i) {
175 memcpy (p,
176 ent->principal->name.name_string.val[i],
177 strlen(ent->principal->name.name_string.val[i]));
178 p += strlen(ent->principal->name.name_string.val[i]);
181 salt->type = KRB5_PADATA_PW_SALT;
182 break;
184 case KRB5_KDB_SALTTYPE_ONLYREALM:
185 krb5_data_free(&salt->salt);
186 ret = krb5_data_copy(&salt->salt,
187 ent->principal->realm,
188 strlen(ent->principal->realm));
189 if(ret)
190 return ret;
191 salt->type = KRB5_PADATA_PW_SALT;
192 break;
193 case KRB5_KDB_SALTTYPE_SPECIAL:
194 salt->type = KRB5_PADATA_PW_SALT;
195 break;
196 case KRB5_KDB_SALTTYPE_AFS3:
197 krb5_data_free(&salt->salt);
198 ret = krb5_data_copy(&salt->salt,
199 ent->principal->realm,
200 strlen(ent->principal->realm));
201 if(ret)
202 return ret;
203 salt->type = KRB5_PADATA_AFS3_SALT;
204 break;
205 case KRB5_KDB_SALTTYPE_CERTHASH:
206 krb5_data_free(&salt->salt);
207 free(k->salt);
208 k->salt = NULL;
209 break;
210 default:
211 abort();
213 return 0;
218 * This function takes a key from a krb5_storage from an MIT KDB encoded
219 * entry and places it in the given Key object.
221 * @param context Context
222 * @param entry HDB entry
223 * @param sp krb5_storage with current offset set to the beginning of a
224 * key
225 * @param version See comments in caller body for the backstory on this
226 * @param k Key * to load the key into
228 static krb5_error_code
229 mdb_keyvalue2key(krb5_context context, hdb_entry *entry, krb5_storage *sp, uint16_t version, Key *k)
231 size_t i;
232 uint16_t u16, type;
233 krb5_error_code ret;
235 k->mkvno = malloc(sizeof(*k->mkvno));
236 if (k->mkvno == NULL) {
237 ret = ENOMEM;
238 goto out;
240 *k->mkvno = 1;
242 for (i = 0; i < version; i++) {
243 CHECK(ret = krb5_ret_uint16(sp, &type));
244 CHECK(ret = krb5_ret_uint16(sp, &u16));
245 if (i == 0) {
246 /* This "version" means we have a key */
247 k->key.keytype = type;
249 * MIT stores keys encrypted keys as {16-bit length
250 * of plaintext key, {encrypted key}}. The reason
251 * for this is that the Kerberos cryptosystem is not
252 * length-preserving. Heimdal's approach is to
253 * truncate the plaintext to the expected length of
254 * the key given its enctype, so we ignore this
255 * 16-bit length-of-plaintext-key field.
257 if (u16 > 2) {
258 krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */
259 k->key.keyvalue.length = u16 - 2; /* adjust cipher len */
260 k->key.keyvalue.data = malloc(k->key.keyvalue.length);
261 krb5_storage_read(sp, k->key.keyvalue.data,
262 k->key.keyvalue.length);
263 } else {
264 /* We'll ignore this key; see our caller */
265 k->key.keyvalue.length = 0;
266 k->key.keyvalue.data = NULL;
267 krb5_storage_seek(sp, u16, SEEK_CUR); /* skip real length */
269 } else if (i == 1) {
270 /* This "version" means we have a salt */
271 k->salt = calloc(1, sizeof(*k->salt));
272 if (k->salt == NULL) {
273 ret = ENOMEM;
274 goto out;
276 k->salt->type = type;
277 if (u16 != 0) {
278 k->salt->salt.data = malloc(u16);
279 if (k->salt->salt.data == NULL) {
280 ret = ENOMEM;
281 goto out;
283 k->salt->salt.length = u16;
284 krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length);
286 fix_salt(context, entry, k);
287 } else {
289 * Whatever this "version" might be, we skip it
291 * XXX A krb5.conf parameter requesting that we log
292 * about strangeness like this, or return an error
293 * from here, might be nice.
295 krb5_storage_seek(sp, u16, SEEK_CUR);
299 return 0;
301 out:
302 free_Key(k);
303 return ret;
307 static krb5_error_code
308 add_1des_dup(krb5_context context, Keys *keys, Key *key, krb5_keytype keytype)
310 key->key.keytype = keytype;
311 return add_Keys(keys, key);
315 * This monstrosity is here so we can avoid having to do enctype
316 * similarity checking in the KDC. This helper function dups 1DES keys
317 * in a keyset for all the similar 1DES enctypes for which keys are
318 * missing. And, of course, we do this only if there's any 1DES keys in
319 * the keyset to begin with.
321 static krb5_error_code
322 dup_similar_keys_in_keyset(krb5_context context, Keys *keys)
324 krb5_error_code ret;
325 size_t i, k;
326 Key key;
327 int keyset_has_1des_crc = 0;
328 int keyset_has_1des_md4 = 0;
329 int keyset_has_1des_md5 = 0;
331 memset(&key, 0, sizeof (key));
332 k = keys->len;
333 for (i = 0; i < keys->len; i++) {
334 if (keys->val[i].key.keytype == ETYPE_DES_CBC_CRC) {
335 keyset_has_1des_crc = 1;
336 if (k == keys->len)
337 k = i;
338 } else if (keys->val[i].key.keytype == ETYPE_DES_CBC_MD4) {
339 keyset_has_1des_crc = 1;
340 if (k == keys->len)
341 k = i;
342 } else if (keys->val[i].key.keytype == ETYPE_DES_CBC_MD5) {
343 keyset_has_1des_crc = 1;
344 if (k == keys->len)
345 k = i;
348 if (k == keys->len)
349 return 0;
351 ret = copy_Key(&keys->val[k], &key);
352 if (ret)
353 return ret;
354 if (!keyset_has_1des_crc) {
355 ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_CRC);
356 if (ret)
357 goto out;
359 if (!keyset_has_1des_md4) {
360 ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_MD4);
361 if (ret)
362 goto out;
364 if (!keyset_has_1des_md5) {
365 ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_MD5);
366 if (ret)
367 goto out;
370 out:
371 free_Key(&key);
372 return ret;
376 static krb5_error_code
377 dup_similar_keys(krb5_context context, hdb_entry *entry)
379 krb5_error_code ret;
380 HDB_Ext_KeySet *hist_keys;
381 HDB_extension *extp;
382 size_t i;
384 ret = dup_similar_keys_in_keyset(context, &entry->keys);
385 if (ret)
386 return ret;
387 extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
388 if (extp == NULL)
389 return 0;
391 hist_keys = &extp->data.u.hist_keys;
392 for (i = 0; i < hist_keys->len; i++) {
393 ret = dup_similar_keys_in_keyset(context, &hist_keys->val[i].keys);
394 if (ret)
395 return ret;
397 return 0;
402 * This function parses an MIT krb5 encoded KDB entry and fills in the
403 * given HDB entry with it.
405 * @param context krb5_context
406 * @param data Encoded MIT KDB entry
407 * @param target_kvno Desired kvno, or 0 for the entry's current kvno
408 * @param entry Desired kvno, or 0 for the entry's current kvno
410 krb5_error_code
411 _hdb_mdb_value2entry(krb5_context context, krb5_data *data,
412 krb5_kvno target_kvno, hdb_entry *entry)
414 krb5_error_code ret;
415 krb5_storage *sp;
416 Key k;
417 krb5_kvno key_kvno;
418 uint32_t u32;
419 uint16_t u16, num_keys, num_tl;
420 ssize_t sz;
421 size_t i;
422 char *p;
424 memset(&k, 0, sizeof (k));
425 memset(entry, 0, sizeof(*entry));
427 sp = krb5_storage_from_data(data);
428 if (sp == NULL) {
429 krb5_set_error_message(context, ENOMEM, "out of memory");
430 return ENOMEM;
433 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
436 * 16: baselength
438 * The story here is that these 16 bits have to be a constant:
439 * KDB_V1_BASE_LENGTH. Once upon a time a different value here
440 * would have been used to indicate the presence of "extra data"
441 * between the "base" contents and the {principal name, TL data,
442 * keys} that follow it. Nothing supports such "extra data"
443 * nowadays, so neither do we here.
445 * XXX But... surely we ought to log about this extra data, or skip
446 * it, or something, in case anyone has MIT KDBs with ancient
447 * entries in them... Logging would allow the admin to know which
448 * entries to dump with MIT krb5's kdb5_util. But logging would be
449 * noisy. For now we do nothing.
451 CHECK(ret = krb5_ret_uint16(sp, &u16));
452 if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; }
453 /* 32: attributes */
454 CHECK(ret = krb5_ret_uint32(sp, &u32));
455 attr_to_flags(u32, &entry->flags);
457 /* 32: max time */
458 CHECK(ret = krb5_ret_uint32(sp, &u32));
459 if (u32) {
460 entry->max_life = malloc(sizeof(*entry->max_life));
461 *entry->max_life = u32;
463 /* 32: max renewable time */
464 CHECK(ret = krb5_ret_uint32(sp, &u32));
465 if (u32) {
466 entry->max_renew = malloc(sizeof(*entry->max_renew));
467 *entry->max_renew = u32;
469 /* 32: client expire */
470 CHECK(ret = krb5_ret_uint32(sp, &u32));
471 if (u32) {
472 entry->valid_end = malloc(sizeof(*entry->valid_end));
473 *entry->valid_end = u32;
475 /* 32: passwd expire */
476 CHECK(ret = krb5_ret_uint32(sp, &u32));
477 if (u32) {
478 entry->pw_end = malloc(sizeof(*entry->pw_end));
479 *entry->pw_end = u32;
481 /* 32: last successful passwd */
482 CHECK(ret = krb5_ret_uint32(sp, &u32));
483 /* 32: last failed attempt */
484 CHECK(ret = krb5_ret_uint32(sp, &u32));
485 /* 32: num of failed attempts */
486 CHECK(ret = krb5_ret_uint32(sp, &u32));
487 /* 16: num tl data */
488 CHECK(ret = krb5_ret_uint16(sp, &u16));
489 num_tl = u16;
490 /* 16: num key data */
491 CHECK(ret = krb5_ret_uint16(sp, &u16));
492 num_keys = u16;
493 /* 16: principal length */
494 CHECK(ret = krb5_ret_uint16(sp, &u16));
495 /* length: principal */
498 * Note that the principal name includes the NUL in the entry,
499 * but we don't want to take chances, so we add an extra NUL.
501 p = malloc(u16 + 1);
502 if (p == NULL) {
503 ret = ENOMEM;
504 goto out;
506 sz = krb5_storage_read(sp, p, u16);
507 if (sz != u16) {
508 ret = EINVAL; /* XXX */
509 goto out;
511 p[u16] = '\0';
512 CHECK(ret = krb5_parse_name(context, p, &entry->principal));
513 free(p);
515 /* for num tl data times
516 16: tl data type
517 16: tl data length
518 length: length */
519 #define mit_KRB5_TL_LAST_PWD_CHANGE 1
520 #define mit_KRB5_TL_MOD_PRINC 2
521 for (i = 0; i < num_tl; i++) {
522 int tl_type;
523 krb5_principal modby;
524 /* 16: TL data type */
525 CHECK(ret = krb5_ret_uint16(sp, &u16));
526 tl_type = u16;
527 /* 16: TL data length */
528 CHECK(ret = krb5_ret_uint16(sp, &u16));
530 * For rollback to MIT purposes we really must understand some
531 * TL data!
533 * XXX Move all this to separate functions, one per-TL type.
535 switch (tl_type) {
536 case mit_KRB5_TL_LAST_PWD_CHANGE:
537 CHECK(ret = krb5_ret_uint32(sp, &u32));
538 CHECK(ret = hdb_entry_set_pw_change_time(context, entry, u32));
539 break;
540 case mit_KRB5_TL_MOD_PRINC:
541 if (u16 < 5) {
542 ret = EINVAL; /* XXX */
543 goto out;
545 CHECK(ret = krb5_ret_uint32(sp, &u32)); /* mod time */
546 p = malloc(u16 - 4 + 1);
547 if (!p) {
548 ret = ENOMEM;
549 goto out;
551 p[u16 - 4] = '\0';
552 sz = krb5_storage_read(sp, p, u16 - 4);
553 if (sz != u16 - 4) {
554 ret = EINVAL; /* XXX */
555 goto out;
557 CHECK(ret = krb5_parse_name(context, p, &modby));
558 CHECK(ret = hdb_set_last_modified_by(context, entry, modby, u32));
559 krb5_free_principal(context, modby);
560 free(p);
561 break;
562 default:
563 krb5_storage_seek(sp, u16, SEEK_CUR);
564 break;
568 * for num key data times
569 * 16: "version"
570 * 16: kvno
571 * for version times:
572 * 16: type
573 * 16: length
574 * length: keydata
576 * "version" here is really 1 or 2, the first meaning there's only
577 * keys for this kvno, the second meaning there's keys and salt[s?].
578 * That's right... hold that gag reflex, you can do it.
580 for (i = 0; i < num_keys; i++) {
581 uint16_t version;
583 CHECK(ret = krb5_ret_uint16(sp, &u16));
584 version = u16;
585 CHECK(ret = krb5_ret_uint16(sp, &u16));
586 key_kvno = u16;
588 ret = mdb_keyvalue2key(context, entry, sp, version, &k);
589 if (ret)
590 goto out;
591 if (k.key.keytype == 0 || k.key.keyvalue.length == 0) {
593 * Older MIT KDBs may have enctype 0 / length 0 keys. We
594 * ignore these.
596 free_Key(&k);
597 continue;
600 if ((target_kvno == 0 && entry->kvno < key_kvno) ||
601 (target_kvno == key_kvno && entry->kvno != target_kvno)) {
603 * MIT's KDB doesn't keep track of kvno. The highest kvno
604 * is the current kvno, and we just found a new highest
605 * kvno or the desired kvno.
607 * Note that there's no guarantee of any key ordering, but
608 * generally MIT KDB entries have keys in strictly
609 * descending kvno order.
611 * XXX We do assume that keys are clustered by kvno. If
612 * not, then bad. It might be possible to construct
613 * non-clustered keys via the kadm5 API. It wouldn't be
614 * hard to cope with this, since if it happens the worst
615 * that will happen is that some of the current keys can be
616 * found in the history extension, and we could just pull
617 * them back out in that case.
619 ret = hdb_add_current_keys_to_history(context, entry);
620 if (ret)
621 goto out;
622 free_Keys(&entry->keys);
623 ret = add_Keys(&entry->keys, &k);
624 free_Key(&k);
625 if (ret)
626 goto out;
627 entry->kvno = key_kvno;
628 continue;
631 if (entry->kvno == key_kvno) {
633 * Note that if key_kvno == 0 and target_kvno == 0 then we
634 * end up adding those keys here. Yeah, kvno 0 is very
635 * special for us, but just in case, we keep such keys.
637 ret = add_Keys(&entry->keys, &k);
638 free_Key(&k);
639 if (ret)
640 goto out;
641 entry->kvno = key_kvno;
642 } else {
643 ret = hdb_add_history_key(context, entry, key_kvno, &k);
644 if (ret)
645 goto out;
646 free_Key(&k);
650 if (target_kvno != 0 && entry->kvno != target_kvno) {
651 ret = HDB_ERR_KVNO_NOT_FOUND;
652 goto out;
655 krb5_storage_free(sp);
657 return dup_similar_keys(context, entry);
659 out:
660 krb5_storage_free(sp);
662 if (ret == HEIM_ERR_EOF)
663 /* Better error code than "end of file" */
664 ret = HEIM_ERR_BAD_HDBENT_ENCODING;
665 free_HDB_entry(entry);
666 free_Key(&k);
667 return ret;
670 #if 0
671 static krb5_error_code
672 mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data)
674 return EINVAL;
676 #endif
678 #if HAVE_DB1
680 #if defined(HAVE_DB_185_H)
681 #include <db_185.h>
682 #elif defined(HAVE_DB_H)
683 #include <db.h>
684 #endif
687 static krb5_error_code
688 mdb_close(krb5_context context, HDB *db)
690 DB *d = (DB*)db->hdb_db;
691 (*d->close)(d);
692 return 0;
695 static krb5_error_code
696 mdb_destroy(krb5_context context, HDB *db)
698 krb5_error_code ret;
700 ret = hdb_clear_master_key(context, db);
701 krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
702 free(db->hdb_name);
703 free(db);
704 return ret;
707 static krb5_error_code
708 mdb_set_sync(krb5_context context, HDB *db, int on)
710 MITDB *mdb = (MITDB *)db;
711 DB *d = (DB*)db->hdb_db;
713 mdb->do_sync = on;
714 if (on)
715 return fsync((*d->fd)(d));
716 return 0;
719 static krb5_error_code
720 mdb_lock(krb5_context context, HDB *db, int operation)
722 DB *d = (DB*)db->hdb_db;
723 int fd = (*d->fd)(d);
724 krb5_error_code ret;
726 if (db->lock_count > 1) {
727 db->lock_count++;
728 if (db->lock_type == HDB_WLOCK || db->lock_count == operation)
729 return 0;
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;
737 ret = hdb_lock(fd, operation);
738 if (ret)
739 return ret;
740 db->lock_count++;
741 return 0;
744 static krb5_error_code
745 mdb_unlock(krb5_context context, HDB *db)
747 DB *d = (DB*)db->hdb_db;
748 int fd = (*d->fd)(d);
750 if (db->lock_count > 1) {
751 db->lock_count--;
752 return 0;
754 heim_assert(db->lock_count == 1, "HDB lock/unlock sequence does not match");
755 db->lock_count--;
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;
762 return hdb_unlock(fd);
766 static krb5_error_code
767 mdb_seq(krb5_context context, HDB *db,
768 unsigned flags, hdb_entry *entry, int flag)
770 DB *d = (DB*)db->hdb_db;
771 DBT key, value;
772 krb5_data key_data, data;
773 int code;
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;
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;
788 if(code == 1) {
789 krb5_clear_error_message(context);
790 return HDB_ERR_NOENTRY;
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));
799 if (_hdb_mdb_value2entry(context, &data, 0, entry))
800 return mdb_seq(context, db, flags, entry, R_NEXT);
802 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
803 code = hdb_unseal_keys (context, db, entry);
804 if (code)
805 hdb_free_entry (context, db, entry);
808 return code;
812 static krb5_error_code
813 mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
815 return mdb_seq(context, db, flags, entry, R_FIRST);
819 static krb5_error_code
820 mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
822 return mdb_seq(context, db, flags, entry, R_NEXT);
825 static krb5_error_code
826 mdb_rename(krb5_context context, HDB *db, const char *new_name)
828 int ret;
829 char *old = NULL;
830 char *new = NULL;
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;
840 free(db->hdb_name);
841 db->hdb_name = strdup(new_name);
842 errno = 0;
844 out:
845 free(old);
846 free(new);
847 return errno;
850 static krb5_error_code
851 mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
853 DB *d = (DB*)db->hdb_db;
854 DBT k, v;
855 int code;
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;
870 if(code == 1) {
871 krb5_clear_error_message(context);
872 return HDB_ERR_NOENTRY;
875 krb5_data_copy(reply, v.data, v.size);
876 return 0;
879 static krb5_error_code
880 mdb__put(krb5_context context, HDB *db, int replace,
881 krb5_data key, krb5_data value)
883 MITDB *mdb = (MITDB *)db;
884 DB *d = (DB*)db->hdb_db;
885 DBT k, v;
886 int code;
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;
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;
908 krb5_clear_error_message(context);
909 return HDB_ERR_EXISTS;
912 static krb5_error_code
913 mdb__del(krb5_context context, HDB *db, krb5_data key)
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;
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;
937 if(code < 0)
938 return errno;
939 return 0;
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 *entry)
946 krb5_data key, value;
947 krb5_error_code ret;
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);
957 krb5_data_free(&value);
958 if (ret)
959 return ret;
961 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
962 ret = hdb_unseal_keys (context, db, entry);
963 if (ret) {
964 hdb_free_entry(context, db, entry);
965 return ret;
969 return 0;
972 static krb5_error_code
973 mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
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 krb5_ssize_t sz;
984 if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE))
985 return 0;
987 if ((flags & HDB_F_PRECHECK)) {
988 ret = mdb_principal2key(context, 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;
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);
1003 if (ret) return ret;
1004 ret = entry2mit_string_int(context, sp, entry);
1005 if (ret) goto out;
1006 sz = krb5_storage_write(sp, "\n", 2); /* NUL-terminate */
1007 ret = ENOMEM;
1008 if (sz != 2) goto out;
1009 ret = krb5_storage_to_data(sp, &line);
1010 if (ret) goto out;
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->principal, &key);
1020 if (ret) goto out;
1021 ret = mdb__put(context, db, 1, key, kdb_ent);
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);
1032 return ret;
1035 static krb5_error_code
1036 mdb_remove(krb5_context context, HDB *db,
1037 unsigned flags, krb5_const_principal principal)
1039 krb5_error_code code;
1040 krb5_data key;
1041 krb5_data value = { 0, 0 };
1043 mdb_principal2key(context, principal, &key);
1045 if ((flags & HDB_F_PRECHECK)) {
1046 code = db->hdb__get(context, db, key, &value);
1047 krb5_data_free(&key);
1048 if (code == 0) {
1049 krb5_data_free(&value);
1050 return 0;
1052 return code;
1055 code = db->hdb__del(context, db, key);
1056 krb5_data_free(&key);
1057 return code;
1060 static krb5_error_code
1061 mdb_open(krb5_context context, HDB *db, int flags, mode_t mode)
1063 char *fn;
1064 char *actual_fn;
1065 krb5_error_code ret;
1066 struct stat st;
1068 if (asprintf(&fn, "%s.db", db->hdb_name) < 0) {
1069 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1070 return ENOMEM;
1073 if (stat(fn, &st) == 0)
1074 actual_fn = fn;
1075 else
1076 actual_fn = db->hdb_name;
1077 db->hdb_db = dbopen(actual_fn, flags, mode, DB_BTREE, NULL);
1078 if (db->hdb_db == NULL) {
1079 switch (errno) {
1080 #ifdef EFTYPE
1081 case EFTYPE:
1082 #endif
1083 case EINVAL:
1084 db->hdb_db = dbopen(actual_fn, flags, mode, DB_HASH, NULL);
1087 free(fn);
1089 if (db->hdb_db == NULL) {
1090 ret = errno;
1091 krb5_set_error_message(context, ret, "dbopen (%s): %s",
1092 db->hdb_name, strerror(ret));
1093 return ret;
1095 #if 0
1097 * Don't do this -- MIT won't be able to handle the
1098 * HDB_DB_FORMAT_ENTRY key.
1100 if ((flags & O_ACCMODE) != O_RDONLY)
1101 ret = hdb_init_db(context, db);
1102 #endif
1103 ret = hdb_check_db_format(context, db);
1104 if (ret == HDB_ERR_NOENTRY) {
1105 krb5_clear_error_message(context);
1106 return 0;
1108 if (ret) {
1109 mdb_close(context, db);
1110 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",
1111 (flags & O_ACCMODE) == O_RDONLY ?
1112 "checking format of" : "initialize",
1113 db->hdb_name);
1115 return ret;
1118 krb5_error_code
1119 hdb_mitdb_create(krb5_context context, HDB **db,
1120 const char *filename)
1122 MITDB **mdb = (MITDB **)db;
1123 *mdb = calloc(1, sizeof(**mdb));
1124 if (*mdb == NULL) {
1125 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1126 return ENOMEM;
1129 (*db)->hdb_db = NULL;
1130 (*db)->hdb_name = strdup(filename);
1131 if ((*db)->hdb_name == NULL) {
1132 free(*db);
1133 *db = NULL;
1134 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1135 return ENOMEM;
1137 (*mdb)->do_sync = 1;
1138 (*db)->hdb_master_key_set = 0;
1139 (*db)->hdb_openp = 0;
1140 (*db)->hdb_capability_flags = 0;
1141 (*db)->hdb_open = mdb_open;
1142 (*db)->hdb_close = mdb_close;
1143 (*db)->hdb_fetch_kvno = mdb_fetch_kvno;
1144 (*db)->hdb_store = mdb_store;
1145 (*db)->hdb_remove = mdb_remove;
1146 (*db)->hdb_firstkey = mdb_firstkey;
1147 (*db)->hdb_nextkey= mdb_nextkey;
1148 (*db)->hdb_lock = mdb_lock;
1149 (*db)->hdb_unlock = mdb_unlock;
1150 (*db)->hdb_rename = mdb_rename;
1151 (*db)->hdb__get = mdb__get;
1152 (*db)->hdb__put = mdb__put;
1153 (*db)->hdb__del = mdb__del;
1154 (*db)->hdb_destroy = mdb_destroy;
1155 (*db)->hdb_set_sync = mdb_set_sync;
1156 return 0;
1159 #endif /* HAVE_DB1 */
1162 can have any number of princ stanzas.
1163 format is as follows (only \n indicates newlines)
1164 princ\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38)
1165 %d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU)
1166 %d\t (number of tl_data)
1167 %d\t (number of key data, e.g. how many keys for this user)
1168 %d\t (extra data length)
1169 %s\t (principal name)
1170 %d\t (attributes)
1171 %d\t (max lifetime, seconds)
1172 %d\t (max renewable life, seconds)
1173 %d\t (expiration, seconds since epoch or 2145830400 for never)
1174 %d\t (password expiration, seconds, 0 for never)
1175 %d\t (last successful auth, seconds since epoch)
1176 %d\t (last failed auth, per above)
1177 %d\t (failed auth count)
1178 foreach tl_data 0 to number of tl_data - 1 as above
1179 %d\t%d\t (data type, data length)
1180 foreach tl_data 0 to length-1
1181 %02x (tl data contents[element n])
1182 except if tl_data length is 0
1183 %d (always -1)
1185 foreach key 0 to number of keys - 1 as above
1186 %d\t%d\t (key data version, kvno)
1187 foreach version 0 to key data version - 1 (a key or a salt)
1188 %d\t%d\t(data type for this key, data length for this key)
1189 foreach key data length 0 to length-1
1190 %02x (key data contents[element n])
1191 except if key_data length is 0
1192 %d (always -1)
1194 foreach extra data length 0 to length - 1
1195 %02x (extra data part)
1196 unless no extra data
1197 %d (always -1)
1202 #if 0
1203 /* Why ever did we loop? */
1204 static char *
1205 nexttoken(char **p)
1207 char *q;
1208 do {
1209 q = strsep(p, " \t");
1210 } while(q && *q == '\0');
1211 return q;
1213 #endif
1215 static char *
1216 nexttoken(char **p, size_t len, const char *what)
1218 char *q;
1220 if (*p == NULL)
1221 return NULL;
1223 q = *p;
1224 *p += len;
1225 /* Must be followed by a delimiter (right?) */
1226 if (strsep(p, " \t") != q + len) {
1227 warnx("No tokens left in dump entry while looking for %s", what);
1228 return NULL;
1230 if (*q == '\0')
1231 warnx("Empty last token in dump entry while looking for %s", what);
1232 return q;
1235 static size_t
1236 getdata(char **p, unsigned char *buf, size_t len, const char *what)
1238 size_t i;
1239 int v;
1240 char *q = nexttoken(p, 0, what);
1241 if (q == NULL) {
1242 warnx("Failed to find hex-encoded binary data (%s) in dump", what);
1243 return 0;
1245 i = 0;
1246 while (*q && i < len) {
1247 if (sscanf(q, "%02x", &v) != 1)
1248 break;
1249 buf[i++] = v;
1250 q += 2;
1252 return i;
1255 static int
1256 getint(char **p, const char *what, 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;
1263 if (sscanf(q, "%d", val) != 1)
1264 return 1;
1265 return 0;
1268 static unsigned int
1269 getuint(char **p, const char *what)
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;
1277 if (sscanf(q, "%u", &val) != 1)
1278 return 0;
1279 return val;
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
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
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.
1307 _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp)
1309 krb5_error_code ret = EINVAL;
1310 char *p = line, *q;
1311 char *princ;
1312 krb5_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;
1320 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
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;
1329 if (getint(&p, "constant '38'", &tmp) || tmp != 38) {
1330 warnx("Dump entry does not start with '38<TAB>'");
1331 return EINVAL;
1333 #define KDB_V1_BASE_LENGTH 38
1334 ret = krb5_store_int16(sp, KDB_V1_BASE_LENGTH);
1335 if (ret) return ret;
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;
1343 num_tl_data = getuint(&p, "number of TL data");
1344 num_key_data = getuint(&p, "number of key data");
1345 (void) getint(&p, "5th field, length of 'extra data'", &tmp);
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;
1353 attributes = getuint(&p, "attributes");
1354 ret = krb5_store_uint32(sp, attributes);
1355 if (ret) return ret;
1357 if (getint(&p, "max life", &tmp)) return EINVAL;
1358 ret = krb5_store_uint32(sp, tmp);
1359 if (ret) return ret;
1361 if (getint(&p, "max renewable life", &tmp)) return EINVAL;
1362 ret = krb5_store_uint32(sp, tmp);
1363 if (ret) return ret;
1365 if (getint(&p, "expiration", &tmp)) return EINVAL;
1366 ret = krb5_store_uint32(sp, tmp);
1367 if (ret) return ret;
1369 if (getint(&p, "pw expiration", &tmp)) return EINVAL;
1370 ret = krb5_store_uint32(sp, tmp);
1371 if (ret) return ret;
1373 if (getint(&p, "last auth", &tmp)) return EINVAL;
1374 ret = krb5_store_uint32(sp, tmp);
1375 if (ret) return ret;
1377 if (getint(&p, "last failed auth", &tmp)) return EINVAL;
1378 ret = krb5_store_uint32(sp, tmp);
1379 if (ret) return ret;
1381 if (getint(&p,"fail auth count", &tmp)) return EINVAL;
1382 ret = krb5_store_uint32(sp, tmp);
1383 if (ret) return ret;
1385 /* add TL data count */
1386 CHECK_NUM(num_tl_data, 1023);
1387 ret = krb5_store_uint16(sp, num_tl_data);
1388 if (ret) return ret;
1390 /* add key count */
1391 CHECK_NUM(num_key_data, 1023);
1392 ret = krb5_store_uint16(sp, num_key_data);
1393 if (ret) return ret;
1395 /* add principal unparsed name length and unparsed name */
1396 princ_len = strlen(princ);
1397 princ_len++; /* must count and write the NUL in the on-disk encoding */
1398 ret = krb5_store_uint16(sp, princ_len);
1399 if (ret) return ret;
1400 sz = krb5_storage_write(sp, princ, princ_len);
1401 if (sz != princ_len) return ENOMEM;
1403 /* scan and write TL data */
1404 for (i = 0; i < num_tl_data; i++) {
1405 char *reading_what;
1406 int tl_type, tl_length;
1407 unsigned char *buf;
1409 if (getint(&p, "TL data type", &tl_type) ||
1410 getint(&p, "data length", &tl_length))
1411 return EINVAL;
1413 if (asprintf(&reading_what, "TL data type %d (length %d)",
1414 tl_type, tl_length) < 0)
1415 return ENOMEM;
1418 * XXX Leaking reading_what, but only on ENOMEM cases anyways,
1419 * so we don't care.
1421 CHECK_UINT16(tl_type);
1422 ret = krb5_store_uint16(sp, tl_type);
1423 if (ret) return ret;
1424 CHECK_UINT16(tl_length);
1425 ret = krb5_store_uint16(sp, tl_length);
1426 if (ret) return ret;
1428 if (tl_length) {
1429 buf = malloc(tl_length);
1430 if (!buf) return ENOMEM;
1431 if (getdata(&p, buf, tl_length, reading_what) != tl_length) {
1432 free(buf);
1433 return EINVAL;
1435 sz = krb5_storage_write(sp, buf, tl_length);
1436 free(buf);
1437 if (sz != tl_length) return ENOMEM;
1438 } else {
1439 if (strcmp(nexttoken(&p, 0, "'-1' field"), "-1") != 0) return EINVAL;
1441 free(reading_what);
1444 for (i = 0; i < num_key_data; i++) {
1445 unsigned char *buf;
1446 int key_versions;
1447 int kvno;
1448 int keytype;
1449 int keylen;
1450 size_t k;
1452 if (getint(&p, "key data 'version'", &key_versions)) return EINVAL;
1453 CHECK_UINT16(key_versions);
1454 ret = krb5_store_int16(sp, key_versions);
1455 if (ret) return ret;
1457 if (getint(&p, "kvno", &kvno)) return EINVAL;
1458 CHECK_UINT16(kvno);
1459 ret = krb5_store_int16(sp, kvno);
1460 if (ret) return ret;
1462 for (k = 0; k < key_versions; k++) {
1463 if (getint(&p, "enctype", &keytype)) return EINVAL;
1464 CHECK_UINT16(keytype);
1465 ret = krb5_store_int16(sp, keytype);
1466 if (ret) return ret;
1468 if (getint(&p, "encrypted key length", &keylen)) return EINVAL;
1469 CHECK_UINT16(keylen);
1470 ret = krb5_store_int16(sp, keylen);
1471 if (ret) return ret;
1473 if (keylen) {
1474 buf = malloc(keylen);
1475 if (!buf) return ENOMEM;
1476 if (getdata(&p, buf, keylen, "key (or salt) data") != keylen) {
1477 free(buf);
1478 return EINVAL;
1480 sz = krb5_storage_write(sp, buf, keylen);
1481 free(buf);
1482 if (sz != keylen) return ENOMEM;
1483 } else {
1484 if (strcmp(nexttoken(&p, 0,
1485 "'-1' zero-length key/salt field"),
1486 "-1") != 0) {
1487 warnx("Expected '-1' field because key/salt length is 0");
1488 return -1;
1494 * The rest is "extra data", but there's never any and we wouldn't
1495 * know what to do with it.
1497 /* nexttoken(&p, 0, "extra data"); */
1498 return 0;