2 * Copyright (c) 1999-2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of KTH nor the names of its contributors may be
18 * used to endorse or promote products derived from this software without
19 * specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
38 This is the present contents of a dump line. This might change at
39 any time. Fields are separated by white space.
48 salt (- means use normal salt)
49 creation date and principal
50 modification date and principal
51 principal valid from date (not used)
52 principal valid end date (not used)
53 principal key expires (not used)
61 * These utility functions return the number of bytes written or -1, and
62 * they set an error in the context.
65 append_string(krb5_context context
, krb5_storage
*sp
, const char *fmt
, ...)
72 rc
= vasprintf(&s
, fmt
, ap
);
75 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
78 sz
= krb5_storage_write(sp
, s
, strlen(s
));
83 static krb5_error_code
84 append_hex(krb5_context context
, krb5_storage
*sp
,
85 int always_encode
, int lower
, krb5_data
*data
)
94 for (i
= 0; i
< data
->length
; i
++) {
95 if (!isalnum((unsigned char)p
[i
]) && p
[i
] != '.'){
101 if (printable
&& !always_encode
)
102 return append_string(context
, sp
, "\"%.*s\"",
103 data
->length
, data
->data
);
104 sz
= hex_encode(data
->data
, data
->length
, &p
);
105 if (sz
== -1) return sz
;
108 sz
= append_string(context
, sp
, "%s", p
);
116 static char buf
[128];
117 strftime(buf
, sizeof(buf
), "%Y%m%d%H%M%S", gmtime(&t
));
122 append_event(krb5_context context
, krb5_storage
*sp
, Event
*ev
)
128 return append_string(context
, sp
, "- ");
129 if (ev
->principal
!= NULL
) {
130 ret
= krb5_unparse_name(context
, ev
->principal
, &pr
);
131 if (ret
) return -1; /* krb5_unparse_name() sets error info */
133 sz
= append_string(context
, sp
, "%s:%s ", time2str(ev
->time
),
134 pr
? pr
: "UNKNOWN");
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
147 append_mit_key(krb5_context context
, krb5_storage
*sp
,
148 krb5_const_principal princ
,
149 unsigned int kvno
, Key
*key
)
154 size_t key_versions
= key
->salt
? 2 : 1;
155 size_t decrypted_key_length
;
157 krb5_data keylenbytes
;
158 unsigned int salttype
;
160 sz
= append_string(context
, sp
, "\t%u\t%u\t%d\t%d\t", key_versions
, kvno
,
161 key
->key
.keytype
, key
->key
.keyvalue
.length
+ 2);
162 if (sz
== -1) return sz
;
163 ret
= krb5_enctype_keysize(context
, key
->key
.keytype
, &decrypted_key_length
);
164 if (ret
) return -1; /* XXX we lose the error code */
165 buf
[0] = decrypted_key_length
& 0xff;
166 buf
[1] = (decrypted_key_length
& 0xff00) >> 8;
167 keylenbytes
.data
= buf
;
168 keylenbytes
.length
= sizeof (buf
);
169 sz
= append_hex(context
, sp
, 1, 1, &keylenbytes
);
170 if (sz
== -1) return sz
;
171 sz
= append_hex(context
, sp
, 1, 1, &key
->key
.keyvalue
);
175 /* Map salt to MIT KDB style */
176 switch (key
->salt
->type
) {
177 case KRB5_PADATA_PW_SALT
:
180 * Compute normal salt and then see whether it matches the stored one
182 ret
= krb5_get_pw_salt(context
, princ
, &k5salt
);
184 if (k5salt
.saltvalue
.length
== key
->salt
->salt
.length
&&
185 memcmp(k5salt
.saltvalue
.data
, key
->salt
->salt
.data
,
186 k5salt
.saltvalue
.length
) == 0)
187 salttype
= KRB5_KDB_SALTTYPE_NORMAL
; /* matches */
188 else if (key
->salt
->salt
.length
== strlen(princ
->realm
) &&
189 memcmp(key
->salt
->salt
.data
, princ
->realm
,
190 key
->salt
->salt
.length
) == 0)
191 salttype
= KRB5_KDB_SALTTYPE_ONLYREALM
; /* matches realm */
192 else if (key
->salt
->salt
.length
==
193 k5salt
.saltvalue
.length
- strlen(princ
->realm
) &&
194 memcmp((char *)k5salt
.saltvalue
.data
+ strlen(princ
->realm
),
195 key
->salt
->salt
.data
, key
->salt
->salt
.length
) == 0)
196 salttype
= KRB5_KDB_SALTTYPE_NOREALM
; /* matches w/o realm */
198 salttype
= KRB5_KDB_SALTTYPE_NORMAL
; /* hope for best */
202 case KRB5_PADATA_AFS3_SALT
:
203 salttype
= KRB5_KDB_SALTTYPE_AFS3
;
210 sz
= append_string(context
, sp
, "\t%u\t%u\t", salttype
,
211 key
->salt
->salt
.length
);
212 if (sz
== -1) return sz
;
213 return append_hex(context
, sp
, 1, 1, &key
->salt
->salt
);
216 static krb5_error_code
217 entry2string_int (krb5_context context
, krb5_storage
*sp
, hdb_entry
*ent
)
224 ret
= krb5_unparse_name(context
, ent
->principal
, &p
);
227 append_string(context
, sp
, "%s ", p
);
230 append_string(context
, sp
, "%d", ent
->kvno
);
232 for(i
= 0; i
< ent
->keys
.len
; i
++){
233 /* --- mkvno, keytype */
234 if(ent
->keys
.val
[i
].mkvno
)
235 append_string(context
, sp
, ":%d:%d:",
236 *ent
->keys
.val
[i
].mkvno
,
237 ent
->keys
.val
[i
].key
.keytype
);
239 append_string(context
, sp
, "::%d:",
240 ent
->keys
.val
[i
].key
.keytype
);
242 append_hex(context
, sp
, 0, 0, &ent
->keys
.val
[i
].key
.keyvalue
);
243 append_string(context
, sp
, ":");
245 if(ent
->keys
.val
[i
].salt
){
246 append_string(context
, sp
, "%u/", ent
->keys
.val
[i
].salt
->type
);
247 append_hex(context
, sp
, 0, 0, &ent
->keys
.val
[i
].salt
->salt
);
249 append_string(context
, sp
, "-");
251 append_string(context
, sp
, " ");
253 append_event(context
, sp
, &ent
->created_by
);
254 /* --- modified by */
255 append_event(context
, sp
, ent
->modified_by
);
257 /* --- valid start */
259 append_string(context
, sp
, "%s ", time2str(*ent
->valid_start
));
261 append_string(context
, sp
, "- ");
265 append_string(context
, sp
, "%s ", time2str(*ent
->valid_end
));
267 append_string(context
, sp
, "- ");
269 /* --- password ends */
271 append_string(context
, sp
, "%s ", time2str(*ent
->pw_end
));
273 append_string(context
, sp
, "- ");
277 append_string(context
, sp
, "%d ", *ent
->max_life
);
279 append_string(context
, sp
, "- ");
281 /* --- max renewable life */
283 append_string(context
, sp
, "%d ", *ent
->max_renew
);
285 append_string(context
, sp
, "- ");
288 append_string(context
, sp
, "%d ", HDBFlags2int(ent
->flags
));
290 /* --- generation number */
291 if(ent
->generation
) {
292 append_string(context
, sp
, "%s:%d:%d ", time2str(ent
->generation
->time
),
293 ent
->generation
->usec
,
294 ent
->generation
->gen
);
296 append_string(context
, sp
, "- ");
299 if(ent
->extensions
&& ent
->extensions
->len
> 0) {
300 for(i
= 0; i
< ent
->extensions
->len
; i
++) {
304 ASN1_MALLOC_ENCODE(HDB_extension
, d
, size
,
305 &ent
->extensions
->val
[i
], &sz
, ret
);
307 krb5_clear_error_message(context
);
311 krb5_abortx(context
, "internal asn.1 encoder error");
313 if (hex_encode(d
, size
, &p
) < 0) {
315 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
320 append_string(context
, sp
, "%s%s", p
,
321 ent
->extensions
->len
- 1 != i
? ":" : "");
325 append_string(context
, sp
, "-");
330 #define KRB5_KDB_DISALLOW_POSTDATED 0x00000001
331 #define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002
332 #define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004
333 #define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008
334 #define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010
335 #define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020
336 #define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040
337 #define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080
338 #define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100
339 #define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200
340 #define KRB5_KDB_DISALLOW_SVR 0x00001000
341 #define KRB5_KDB_PWCHANGE_SERVICE 0x00002000
342 #define KRB5_KDB_SUPPORT_DESMD5 0x00004000
343 #define KRB5_KDB_NEW_PRINC 0x00008000
346 flags_to_attr(HDBFlags flags
)
351 a
|= KRB5_KDB_DISALLOW_POSTDATED
;
352 if (!flags
.forwardable
)
353 a
|= KRB5_KDB_DISALLOW_FORWARDABLE
;
355 a
|= KRB5_KDB_DISALLOW_TGT_BASED
;
356 if (!flags
.renewable
)
357 a
|= KRB5_KDB_DISALLOW_RENEWABLE
;
358 if (!flags
.proxiable
)
359 a
|= KRB5_KDB_DISALLOW_PROXIABLE
;
361 a
|= KRB5_KDB_DISALLOW_ALL_TIX
;
362 if (flags
.require_preauth
)
363 a
|= KRB5_KDB_REQUIRES_PRE_AUTH
;
364 if (flags
.require_hwauth
)
365 a
|= KRB5_KDB_REQUIRES_HW_AUTH
;
367 a
|= KRB5_KDB_DISALLOW_SVR
;
369 a
|= KRB5_KDB_PWCHANGE_SERVICE
;
374 entry2mit_string_int(krb5_context context
, krb5_storage
*sp
, hdb_entry
*ent
)
379 size_t num_tl_data
= 0;
380 size_t num_key_data
= 0;
382 HDB_Ext_KeySet
*hist_keys
= NULL
;
384 time_t last_pw_chg
= 0;
387 unsigned int max_life
= 0;
388 unsigned int max_renew
= 0;
390 if (ent
->modified_by
)
393 ret
= hdb_entry_get_pw_change_time(ent
, &last_pw_chg
);
398 extp
= hdb_find_extension(ent
, choice_HDB_extension_data_hist_keys
);
400 hist_keys
= &extp
->data
.u
.hist_keys
;
402 for (i
= 0; i
< ent
->keys
.len
;i
++) {
403 if (ent
->keys
.val
[i
].key
.keytype
== ETYPE_DES_CBC_MD4
||
404 ent
->keys
.val
[i
].key
.keytype
== ETYPE_DES_CBC_MD5
)
409 for (i
= 0; i
< hist_keys
->len
; i
++) {
411 * MIT uses the highest kvno as the current kvno instead of
412 * tracking kvno separately, so we can't dump keysets with kvno
413 * higher than the entry's kvno.
415 if (hist_keys
->val
[i
].kvno
>= ent
->kvno
)
417 for (k
= 0; k
< hist_keys
->val
[i
].keys
.len
; k
++) {
418 if (ent
->keys
.val
[k
].key
.keytype
== ETYPE_DES_CBC_MD4
||
419 ent
->keys
.val
[k
].key
.keytype
== ETYPE_DES_CBC_MD5
)
426 ret
= krb5_unparse_name(context
, ent
->principal
, &p
);
428 sz
= append_string(context
, sp
, "princ\t38\t%u\t%u\t%u\t0\t%s\t%d",
429 strlen(p
), num_tl_data
, num_key_data
, p
,
430 flags_to_attr(ent
->flags
));
432 if (sz
== -1) return ENOMEM
;
435 max_life
= *ent
->max_life
;
437 max_renew
= *ent
->max_renew
;
439 exp
= *ent
->valid_end
;
441 pwexp
= *ent
->pw_end
;
443 sz
= append_string(context
, sp
, "\t%u\t%u\t%u\t%u\t0\t0\t0",
444 max_life
, max_renew
, exp
, pwexp
);
445 if (sz
== -1) return ENOMEM
;
447 /* Dump TL data we know: last pw chg and modified_by */
448 #define mit_KRB5_TL_LAST_PWD_CHANGE 1
449 #define mit_KRB5_TL_MOD_PRINC 2
455 ptr
= (unsigned char *)&last_pw_chg
;
456 val
= ((unsigned long)ptr
[3] << 24) | (ptr
[2] << 16)
457 | (ptr
[1] << 8) | ptr
[0];
459 d
.length
= sizeof (last_pw_chg
);
460 sz
= append_string(context
, sp
, "\t%u\t%u\t",
461 mit_KRB5_TL_LAST_PWD_CHANGE
, d
.length
);
462 if (sz
== -1) return ENOMEM
;
463 sz
= append_hex(context
, sp
, 1, 1, &d
);
464 if (sz
== -1) return ENOMEM
;
466 if (ent
->modified_by
) {
473 ptr
= (unsigned char *)&ent
->modified_by
->time
;
474 val
= ptr
[0] | (ptr
[1] << 8) | (ptr
[2] << 16) | (ptr
[3] << 24);
476 d
.length
= sizeof (ent
->modified_by
->time
);
477 ret
= krb5_unparse_name(context
, ent
->modified_by
->principal
, &modby_p
);
480 plen
= strlen(modby_p
);
481 sz
= append_string(context
, sp
, "\t%u\t%u\t",
482 mit_KRB5_TL_MOD_PRINC
,
483 d
.length
+ plen
+ 1 /* NULL counted */);
488 sz
= append_hex(context
, sp
, 1, 1, &d
);
495 sz
= append_hex(context
, sp
, 1, 1, &d
);
501 * Dump keys (remembering to not include any with kvno higher than
502 * the entry's because MIT doesn't track entry kvno separately from
503 * the entry's keys -- max kvno is it)
505 for (i
= 0; i
< ent
->keys
.len
; i
++) {
506 if (ent
->keys
.val
[i
].key
.keytype
== ETYPE_DES_CBC_MD4
||
507 ent
->keys
.val
[i
].key
.keytype
== ETYPE_DES_CBC_MD5
)
509 sz
= append_mit_key(context
, sp
, ent
->principal
, ent
->kvno
,
511 if (sz
== -1) return ENOMEM
;
513 for (i
= 0; hist_keys
&& i
< ent
->kvno
; i
++) {
516 /* dump historical keys */
517 for (k
= 0; k
< hist_keys
->len
; k
++) {
518 if (hist_keys
->val
[k
].kvno
!= ent
->kvno
- i
)
520 for (m
= 0; m
< hist_keys
->val
[k
].keys
.len
; m
++) {
521 if (ent
->keys
.val
[k
].key
.keytype
== ETYPE_DES_CBC_MD4
||
522 ent
->keys
.val
[k
].key
.keytype
== ETYPE_DES_CBC_MD5
)
524 sz
= append_mit_key(context
, sp
, ent
->principal
,
525 hist_keys
->val
[k
].kvno
,
526 &hist_keys
->val
[k
].keys
.val
[m
]);
527 if (sz
== -1) return ENOMEM
;
531 sz
= append_string(context
, sp
, "\t-1;"); /* "extra data" */
532 if (sz
== -1) return ENOMEM
;
537 hdb_entry2string(krb5_context context
, hdb_entry
*ent
, char **str
)
543 sp
= krb5_storage_emem();
545 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
549 ret
= entry2string_int(context
, sp
, ent
);
551 krb5_storage_free(sp
);
555 krb5_storage_write(sp
, "\0", 1);
556 krb5_storage_to_data(sp
, &data
);
557 krb5_storage_free(sp
);
562 /* print a hdb_entry to (FILE*)data; suitable for hdb_foreach */
565 hdb_print_entry(krb5_context context
, HDB
*db
, hdb_entry
*entry
,
568 struct hdb_print_entry_arg
*parg
= data
;
573 sp
= krb5_storage_from_fd(fileno(parg
->out
));
575 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
580 case HDB_DUMP_HEIMDAL
:
581 ret
= entry2string_int(context
, sp
, entry
);
584 ret
= entry2mit_string_int(context
, sp
, entry
);
587 heim_abort("Only two dump formats supported: Heimdal and MIT");
590 krb5_storage_free(sp
);
594 krb5_storage_write(sp
, "\n", 1);
595 krb5_storage_free(sp
);