Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/hdb/print.c
105321 views
1
/*
2
* Copyright (c) 1999-2005 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
*
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
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.
16
*
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.
20
*
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. */
32
33
#include "hdb_locl.h"
34
#include <hex.h>
35
#include <ctype.h>
36
37
/*
38
This is the present contents of a dump line. This might change at
39
any time. Fields are separated by white space.
40
41
principal
42
keyblock
43
kvno
44
keys...
45
mkvno
46
enctype
47
keyvalue
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)
54
max ticket life
55
max renewable life
56
flags
57
generation number
58
*/
59
60
/*
61
* These utility functions return the number of bytes written or -1, and
62
* they set an error in the context.
63
*/
64
static ssize_t
65
append_string(krb5_context context, krb5_storage *sp, const char *fmt, ...)
66
{
67
ssize_t sz;
68
char *s;
69
int rc;
70
va_list ap;
71
va_start(ap, fmt);
72
rc = vasprintf(&s, fmt, ap);
73
va_end(ap);
74
if(rc < 0) {
75
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
76
return -1;
77
}
78
sz = krb5_storage_write(sp, s, strlen(s));
79
free(s);
80
return sz;
81
}
82
83
static krb5_error_code
84
append_hex(krb5_context context, krb5_storage *sp,
85
int always_encode, int lower, krb5_data *data)
86
{
87
ssize_t sz;
88
int printable = 1;
89
size_t i;
90
char *p;
91
92
p = data->data;
93
if (!always_encode) {
94
for (i = 0; i < data->length; i++) {
95
if (!isalnum((unsigned char)p[i]) && p[i] != '.'){
96
printable = 0;
97
break;
98
}
99
}
100
}
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;
106
if (lower)
107
strlwr(p);
108
sz = append_string(context, sp, "%s", p);
109
free(p);
110
return sz;
111
}
112
113
static char *
114
time2str(time_t t)
115
{
116
static char buf[128];
117
strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", gmtime(&t));
118
return buf;
119
}
120
121
static ssize_t
122
append_event(krb5_context context, krb5_storage *sp, Event *ev)
123
{
124
krb5_error_code ret;
125
ssize_t sz;
126
char *pr = NULL;
127
if(ev == NULL)
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 */
132
}
133
sz = append_string(context, sp, "%s:%s ", time2str(ev->time),
134
pr ? pr : "UNKNOWN");
135
free(pr);
136
return sz;
137
}
138
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
146
static ssize_t
147
append_mit_key(krb5_context context, krb5_storage *sp,
148
krb5_const_principal princ,
149
unsigned int kvno, Key *key)
150
{
151
krb5_error_code ret;
152
ssize_t sz;
153
size_t key_versions = key->salt ? 2 : 1;
154
size_t decrypted_key_length;
155
char buf[2];
156
krb5_data keylenbytes;
157
unsigned int salttype;
158
159
sz = append_string(context, sp, "\t%u\t%u\t%d\t%d\t", key_versions, kvno,
160
key->key.keytype, key->key.keyvalue.length + 2);
161
if (sz == -1) return sz;
162
ret = krb5_enctype_keysize(context, key->key.keytype, &decrypted_key_length);
163
if (ret) return -1; /* XXX we lose the error code */
164
buf[0] = decrypted_key_length & 0xff;
165
buf[1] = (decrypted_key_length & 0xff00) >> 8;
166
keylenbytes.data = buf;
167
keylenbytes.length = sizeof (buf);
168
sz = append_hex(context, sp, 1, 1, &keylenbytes);
169
if (sz == -1) return sz;
170
sz = append_hex(context, sp, 1, 1, &key->key.keyvalue);
171
if (!key->salt)
172
return sz;
173
174
/* Map salt to MIT KDB style */
175
if (key->salt->type == KRB5_PADATA_PW_SALT) {
176
krb5_salt k5salt;
177
178
/*
179
* Compute normal salt and then see whether it matches the stored one
180
*/
181
ret = krb5_get_pw_salt(context, princ, &k5salt);
182
if (ret) return -1;
183
if (k5salt.saltvalue.length == key->salt->salt.length &&
184
memcmp(k5salt.saltvalue.data, key->salt->salt.data,
185
k5salt.saltvalue.length) == 0)
186
salttype = KRB5_KDB_SALTTYPE_NORMAL; /* matches */
187
else if (key->salt->salt.length == strlen(princ->realm) &&
188
memcmp(key->salt->salt.data, princ->realm,
189
key->salt->salt.length) == 0)
190
salttype = KRB5_KDB_SALTTYPE_ONLYREALM; /* matches realm */
191
else if (key->salt->salt.length == k5salt.saltvalue.length - strlen(princ->realm) &&
192
memcmp((char *)k5salt.saltvalue.data + strlen(princ->realm),
193
key->salt->salt.data, key->salt->salt.length) == 0)
194
salttype = KRB5_KDB_SALTTYPE_NOREALM; /* matches w/o realm */
195
else
196
salttype = KRB5_KDB_SALTTYPE_NORMAL; /* hope for best */
197
198
} else if (key->salt->type == KRB5_PADATA_AFS3_SALT) {
199
salttype = KRB5_KDB_SALTTYPE_AFS3;
200
}
201
sz = append_string(context, sp, "\t%u\t%u\t", salttype,
202
key->salt->salt.length);
203
if (sz == -1) return sz;
204
return append_hex(context, sp, 1, 1, &key->salt->salt);
205
}
206
207
static krb5_error_code
208
entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent)
209
{
210
char *p;
211
int i;
212
krb5_error_code ret;
213
214
/* --- principal */
215
ret = krb5_unparse_name(context, ent->principal, &p);
216
if(ret)
217
return ret;
218
append_string(context, sp, "%s ", p);
219
free(p);
220
/* --- kvno */
221
append_string(context, sp, "%d", ent->kvno);
222
/* --- keys */
223
for(i = 0; i < ent->keys.len; i++){
224
/* --- mkvno, keytype */
225
if(ent->keys.val[i].mkvno)
226
append_string(context, sp, ":%d:%d:",
227
*ent->keys.val[i].mkvno,
228
ent->keys.val[i].key.keytype);
229
else
230
append_string(context, sp, "::%d:",
231
ent->keys.val[i].key.keytype);
232
/* --- keydata */
233
append_hex(context, sp, 0, 0, &ent->keys.val[i].key.keyvalue);
234
append_string(context, sp, ":");
235
/* --- salt */
236
if(ent->keys.val[i].salt){
237
append_string(context, sp, "%u/", ent->keys.val[i].salt->type);
238
append_hex(context, sp, 0, 0, &ent->keys.val[i].salt->salt);
239
}else
240
append_string(context, sp, "-");
241
}
242
append_string(context, sp, " ");
243
/* --- created by */
244
append_event(context, sp, &ent->created_by);
245
/* --- modified by */
246
append_event(context, sp, ent->modified_by);
247
248
/* --- valid start */
249
if(ent->valid_start)
250
append_string(context, sp, "%s ", time2str(*ent->valid_start));
251
else
252
append_string(context, sp, "- ");
253
254
/* --- valid end */
255
if(ent->valid_end)
256
append_string(context, sp, "%s ", time2str(*ent->valid_end));
257
else
258
append_string(context, sp, "- ");
259
260
/* --- password ends */
261
if(ent->pw_end)
262
append_string(context, sp, "%s ", time2str(*ent->pw_end));
263
else
264
append_string(context, sp, "- ");
265
266
/* --- max life */
267
if(ent->max_life)
268
append_string(context, sp, "%d ", *ent->max_life);
269
else
270
append_string(context, sp, "- ");
271
272
/* --- max renewable life */
273
if(ent->max_renew)
274
append_string(context, sp, "%d ", *ent->max_renew);
275
else
276
append_string(context, sp, "- ");
277
278
/* --- flags */
279
append_string(context, sp, "%d ", HDBFlags2int(ent->flags));
280
281
/* --- generation number */
282
if(ent->generation) {
283
append_string(context, sp, "%s:%d:%d ", time2str(ent->generation->time),
284
ent->generation->usec,
285
ent->generation->gen);
286
} else
287
append_string(context, sp, "- ");
288
289
/* --- extensions */
290
if(ent->extensions && ent->extensions->len > 0) {
291
for(i = 0; i < ent->extensions->len; i++) {
292
void *d;
293
size_t size, sz = 0;
294
295
ASN1_MALLOC_ENCODE(HDB_extension, d, size,
296
&ent->extensions->val[i], &sz, ret);
297
if (ret) {
298
krb5_clear_error_message(context);
299
return ret;
300
}
301
if(size != sz)
302
krb5_abortx(context, "internal asn.1 encoder error");
303
304
if (hex_encode(d, size, &p) < 0) {
305
free(d);
306
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
307
return ENOMEM;
308
}
309
310
free(d);
311
append_string(context, sp, "%s%s", p,
312
ent->extensions->len - 1 != i ? ":" : "");
313
free(p);
314
}
315
} else
316
append_string(context, sp, "-");
317
318
return 0;
319
}
320
321
#define KRB5_KDB_DISALLOW_POSTDATED 0x00000001
322
#define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002
323
#define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004
324
#define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008
325
#define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010
326
#define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020
327
#define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040
328
#define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080
329
#define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100
330
#define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200
331
#define KRB5_KDB_DISALLOW_SVR 0x00001000
332
#define KRB5_KDB_PWCHANGE_SERVICE 0x00002000
333
#define KRB5_KDB_SUPPORT_DESMD5 0x00004000
334
#define KRB5_KDB_NEW_PRINC 0x00008000
335
336
static int
337
flags_to_attr(HDBFlags flags)
338
{
339
int a = 0;
340
341
if (!flags.postdate)
342
a |= KRB5_KDB_DISALLOW_POSTDATED;
343
if (!flags.forwardable)
344
a |= KRB5_KDB_DISALLOW_FORWARDABLE;
345
if (flags.initial)
346
a |= KRB5_KDB_DISALLOW_TGT_BASED;
347
if (!flags.renewable)
348
a |= KRB5_KDB_DISALLOW_RENEWABLE;
349
if (!flags.proxiable)
350
a |= KRB5_KDB_DISALLOW_PROXIABLE;
351
if (flags.invalid)
352
a |= KRB5_KDB_DISALLOW_ALL_TIX;
353
if (flags.require_preauth)
354
a |= KRB5_KDB_REQUIRES_PRE_AUTH;
355
if (flags.require_hwauth)
356
a |= KRB5_KDB_REQUIRES_HW_AUTH;
357
if (!flags.server)
358
a |= KRB5_KDB_DISALLOW_SVR;
359
if (flags.change_pw)
360
a |= KRB5_KDB_PWCHANGE_SERVICE;
361
return a;
362
}
363
364
krb5_error_code
365
entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent)
366
{
367
krb5_error_code ret;
368
ssize_t sz;
369
size_t i, k;
370
size_t num_tl_data = 0;
371
size_t num_key_data = 0;
372
char *p;
373
HDB_Ext_KeySet *hist_keys = NULL;
374
HDB_extension *extp;
375
time_t last_pw_chg = 0;
376
time_t exp = 0;
377
time_t pwexp = 0;
378
unsigned int max_life = 0;
379
unsigned int max_renew = 0;
380
381
/* Always create a modified_by entry. */
382
num_tl_data++;
383
384
ret = hdb_entry_get_pw_change_time(ent, &last_pw_chg);
385
if (ret) return ret;
386
if (last_pw_chg)
387
num_tl_data++;
388
389
extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
390
if (extp)
391
hist_keys = &extp->data.u.hist_keys;
392
393
for (i = 0; i < ent->keys.len;i++) {
394
if (!mit_strong_etype(ent->keys.val[i].key.keytype))
395
continue;
396
num_key_data++;
397
}
398
if (hist_keys) {
399
for (i = 0; i < hist_keys->len; i++) {
400
/*
401
* MIT uses the highest kvno as the current kvno instead of
402
* tracking kvno separately, so we can't dump keysets with kvno
403
* higher than the entry's kvno.
404
*/
405
if (hist_keys->val[i].kvno >= ent->kvno)
406
continue;
407
for (k = 0; k < hist_keys->val[i].keys.len; k++) {
408
if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 ||
409
ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5)
410
continue;
411
num_key_data++;
412
}
413
}
414
}
415
416
ret = krb5_unparse_name(context, ent->principal, &p);
417
if (ret) return ret;
418
sz = append_string(context, sp, "princ\t38\t%u\t%u\t%u\t0\t%s\t%d",
419
strlen(p), num_tl_data, num_key_data, p,
420
flags_to_attr(ent->flags));
421
if (sz == -1) {
422
free(p);
423
return ENOMEM;
424
}
425
426
if (ent->max_life)
427
max_life = *ent->max_life;
428
if (ent->max_renew)
429
max_renew = *ent->max_renew;
430
if (ent->valid_end)
431
exp = *ent->valid_end;
432
if (ent->pw_end)
433
pwexp = *ent->pw_end;
434
435
sz = append_string(context, sp, "\t%u\t%u\t%u\t%u\t0\t0\t0",
436
max_life, max_renew, exp, pwexp);
437
if (sz == -1) {
438
free(p);
439
return ENOMEM;
440
}
441
442
/* Dump TL data we know: last pw chg and modified_by */
443
#define mit_KRB5_TL_LAST_PWD_CHANGE 1
444
#define mit_KRB5_TL_MOD_PRINC 2
445
if (last_pw_chg) {
446
krb5_data d;
447
time_t val;
448
unsigned char *ptr;
449
450
ptr = (unsigned char *)&last_pw_chg;
451
val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
452
d.data = &val;
453
d.length = sizeof (last_pw_chg);
454
sz = append_string(context, sp, "\t%u\t%u\t",
455
mit_KRB5_TL_LAST_PWD_CHANGE, d.length);
456
if (sz == -1) {
457
free(p);
458
return ENOMEM;
459
}
460
sz = append_hex(context, sp, 1, 1, &d);
461
if (sz == -1) {
462
free(p);
463
return ENOMEM;
464
}
465
}
466
if (ent->modified_by) {
467
krb5_data d;
468
unsigned int val;
469
size_t plen;
470
unsigned char *ptr;
471
char *modby_p;
472
473
free(p);
474
ptr = (unsigned char *)&ent->modified_by->time;
475
val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
476
d.data = &val;
477
d.length = sizeof (ent->modified_by->time);
478
ret = krb5_unparse_name(context, ent->modified_by->principal, &modby_p);
479
if (ret) return ret;
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 */);
484
if (sz == -1) {
485
free(modby_p);
486
return ENOMEM;
487
}
488
sz = append_hex(context, sp, 1, 1, &d);
489
if (sz == -1) {
490
free(modby_p);
491
return ENOMEM;
492
}
493
d.data = modby_p;
494
d.length = plen + 1;
495
sz = append_hex(context, sp, 1, 1, &d);
496
free(modby_p);
497
if (sz == -1) return ENOMEM;
498
} else {
499
krb5_data d;
500
unsigned int val;
501
size_t plen;
502
unsigned char *ptr;
503
504
/* Fake the entry to make MIT happy. */
505
ptr = (unsigned char *)&last_pw_chg;
506
val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
507
d.data = &val;
508
d.length = sizeof (last_pw_chg);
509
plen = strlen(p);
510
sz = append_string(context, sp, "\t%u\t%u\t",
511
mit_KRB5_TL_MOD_PRINC,
512
d.length + plen + 1 /* NULL counted */);
513
if (sz == -1) {
514
free(p);
515
return ENOMEM;
516
}
517
sz = append_hex(context, sp, 1, 1, &d);
518
if (sz == -1) {
519
free(p);
520
return ENOMEM;
521
}
522
d.data = p;
523
d.length = plen + 1;
524
sz = append_hex(context, sp, 1, 1, &d);
525
free(p);
526
if (sz == -1) return ENOMEM;
527
}
528
/*
529
* Dump keys (remembering to not include any with kvno higher than
530
* the entry's because MIT doesn't track entry kvno separately from
531
* the entry's keys -- max kvno is it)
532
*/
533
for (i = 0; i < ent->keys.len; i++) {
534
if (!mit_strong_etype(ent->keys.val[i].key.keytype))
535
continue;
536
sz = append_mit_key(context, sp, ent->principal, ent->kvno,
537
&ent->keys.val[i]);
538
if (sz == -1) return ENOMEM;
539
}
540
for (i = 0; hist_keys && i < ent->kvno; i++) {
541
size_t m;
542
543
/* dump historical keys */
544
for (k = 0; k < hist_keys->len; k++) {
545
if (hist_keys->val[k].kvno != ent->kvno - i)
546
continue;
547
for (m = 0; m < hist_keys->val[k].keys.len; m++) {
548
if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 ||
549
ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5)
550
continue;
551
sz = append_mit_key(context, sp, ent->principal,
552
hist_keys->val[k].kvno,
553
&hist_keys->val[k].keys.val[m]);
554
if (sz == -1) return ENOMEM;
555
}
556
}
557
}
558
sz = append_string(context, sp, "\t-1;"); /* "extra data" */
559
if (sz == -1) return ENOMEM;
560
return 0;
561
}
562
563
krb5_error_code
564
hdb_entry2string(krb5_context context, hdb_entry *ent, char **str)
565
{
566
krb5_error_code ret;
567
krb5_data data;
568
krb5_storage *sp;
569
570
sp = krb5_storage_emem();
571
if (sp == NULL) {
572
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
573
return ENOMEM;
574
}
575
576
ret = entry2string_int(context, sp, ent);
577
if (ret) {
578
krb5_storage_free(sp);
579
return ret;
580
}
581
582
krb5_storage_write(sp, "\0", 1);
583
krb5_storage_to_data(sp, &data);
584
krb5_storage_free(sp);
585
*str = data.data;
586
return 0;
587
}
588
589
/* print a hdb_entry to (FILE*)data; suitable for hdb_foreach */
590
591
krb5_error_code
592
hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry,
593
void *data)
594
{
595
struct hdb_print_entry_arg *parg = data;
596
krb5_error_code ret;
597
krb5_storage *sp;
598
599
fflush(parg->out);
600
sp = krb5_storage_from_fd(fileno(parg->out));
601
if (sp == NULL) {
602
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
603
return ENOMEM;
604
}
605
606
switch (parg->fmt) {
607
case HDB_DUMP_HEIMDAL:
608
ret = entry2string_int(context, sp, &entry->entry);
609
break;
610
case HDB_DUMP_MIT:
611
ret = entry2mit_string_int(context, sp, &entry->entry);
612
break;
613
default:
614
heim_abort("Only two dump formats supported: Heimdal and MIT");
615
}
616
if (ret) {
617
krb5_storage_free(sp);
618
return ret;
619
}
620
621
krb5_storage_write(sp, "\n", 1);
622
krb5_storage_free(sp);
623
return 0;
624
}
625
626