Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/plugins/kdb/test/kdb_test.c
34914 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* plugins/kdb/test/kdb_test.c - Test KDB module */
3
/*
4
* Copyright (C) 2015 by the Massachusetts Institute of Technology.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
*
11
* * Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
*
14
* * Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in
16
* the documentation and/or other materials provided with the
17
* distribution.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30
* OF THE POSSIBILITY OF SUCH DAMAGE.
31
*/
32
33
/*
34
* This is a read-only KDB module intended to help test KDC behavior which
35
* cannot be exercised with the DB2 module. Responses are read from the
36
* dbmodules subsection according to this example:
37
*
38
* [dbmodules]
39
* test = {
40
* alias = {
41
* aliasname = canonname
42
* # For cross-realm aliases, only the realm part will
43
* # matter to the client.
44
* aliasname = @FOREIGN_REALM
45
* enterprise@PRINC = @FOREIGN_REALM
46
* }
47
* princs = {
48
* krbtgt/KRBTEST.COM = {
49
* flags = +preauth +ok-to-auth-as-delegate
50
* maxlife = 1d
51
* maxrenewlife = 7d
52
* expiration = 14d # relative to current time
53
* pwexpiration = 1h
54
* # Initial number is kvno; defaults to 1.
55
* keys = 3 aes256-cts aes128-cts:normal
56
* keys = 2 rc4-hmac
57
* strings = key1:value1
58
* strings = key2:value2
59
* }
60
* }
61
* delegation = {
62
* # Traditional constrained delegation; target_service
63
* # must be in the same realm.
64
* intermediate_service = target_service
65
* }
66
* rbcd = {
67
* # Resource-based constrained delegation;
68
* # intermediate_service may be in a different realm.
69
* target_service = intermediate_service
70
* }
71
* }
72
*
73
* Key values are generated using a hash of the kvno, enctype, salt type,
74
* principal name, and lookup realm. This module does not use master key
75
* encryption, so it serves as a partial test of the DAL's ability to avoid
76
* that.
77
*
78
* Inbound cross-realm TGT entries are currently implicit; they will use the
79
* same configuration and key enctypes as the local krbtgt principal, although
80
* they will use different keys (because the lookup realm is hashed in).
81
* Outgoing cross-realm TGT entries must be added explicitly
82
* (krbtgt/OTHER_REALM).
83
*/
84
85
#include "k5-int.h"
86
#include "kdb5.h"
87
#include "adm_proto.h"
88
#include <ctype.h>
89
90
#define TEST_AD_TYPE -456
91
92
#define IS_TGS_PRINC(p) ((p)->length == 2 && \
93
data_eq_string((p)->data[0], KRB5_TGS_NAME))
94
95
typedef struct {
96
void *profile;
97
char *section;
98
const char *names[6];
99
} *testhandle;
100
101
static void *
102
ealloc(size_t sz)
103
{
104
void *p = calloc(sz, 1);
105
106
if (p == NULL)
107
abort();
108
return p;
109
}
110
111
static char *
112
estrdup(const char *s)
113
{
114
char *copy = strdup(s);
115
116
if (copy == NULL)
117
abort();
118
return copy;
119
}
120
121
static void
122
check(krb5_error_code code)
123
{
124
if (code != 0)
125
abort();
126
}
127
128
/* Set up for a profile query using h->names. Look up s1 -> s2 -> s3 (some of
129
* which may be NULL) within this database's dbmodules section. */
130
static void
131
set_names(testhandle h, const char *s1, const char *s2, const char *s3)
132
{
133
h->names[0] = KDB_MODULE_SECTION;
134
h->names[1] = h->section;
135
h->names[2] = s1;
136
h->names[3] = s2;
137
h->names[4] = s3;
138
h->names[5] = NULL;
139
}
140
141
/* Look up a string within this database's dbmodules section. */
142
static char *
143
get_string(testhandle h, const char *s1, const char *s2, const char *s3)
144
{
145
krb5_error_code ret;
146
char **values, *val;
147
148
set_names(h, s1, s2, s3);
149
ret = profile_get_values(h->profile, h->names, &values);
150
if (ret == PROF_NO_RELATION)
151
return NULL;
152
if (ret)
153
abort();
154
val = estrdup(values[0]);
155
profile_free_list(values);
156
return val;
157
}
158
159
/* Look up a duration within this database's dbmodules section. */
160
static krb5_deltat
161
get_duration(testhandle h, const char *s1, const char *s2, const char *s3)
162
{
163
char *strval = get_string(h, s1, s2, s3);
164
krb5_deltat val;
165
166
if (strval == NULL)
167
return 0;
168
check(krb5_string_to_deltat(strval, &val));
169
free(strval);
170
return val;
171
}
172
173
/* Look up an absolute time within this database's dbmodules section. The time
174
* is expressed in the profile as an interval relative to the current time. */
175
static krb5_timestamp
176
get_time(testhandle h, const char *s1, const char *s2, const char *s3)
177
{
178
char *strval = get_string(h, s1, s2, s3);
179
krb5_deltat val;
180
181
if (strval == NULL)
182
return 0;
183
check(krb5_string_to_deltat(strval, &val));
184
free(strval);
185
return val + time(NULL);
186
}
187
188
/* Initialize kb_out with a key of type etype, using a hash of kvno, etype,
189
* salttype, and princstr for the key bytes. */
190
static void
191
make_keyblock(krb5_kvno kvno, krb5_enctype etype, int32_t salttype,
192
const char *princstr, const krb5_data *realm,
193
krb5_keyblock *kb_out)
194
{
195
size_t keybytes, keylength, pos, n;
196
char *hashstr;
197
krb5_data d, rndin;
198
krb5_checksum cksum;
199
200
check(krb5_c_keylengths(NULL, etype, &keybytes, &keylength));
201
alloc_data(&rndin, keybytes);
202
203
/* Hash the kvno, enctype, salt type, and principal name together. */
204
if (asprintf(&hashstr, "%d %d %d %s %.*s", (int)kvno, (int)etype,
205
(int)salttype, princstr, (int)realm->length, realm->data) < 0)
206
abort();
207
d = string2data(hashstr);
208
check(krb5_c_make_checksum(NULL, CKSUMTYPE_SHA1, NULL, 0, &d, &cksum));
209
210
/* Make the appropriate number of input bytes from the hash result. */
211
for (pos = 0; pos < keybytes; pos += n) {
212
n = (cksum.length < keybytes - pos) ? cksum.length : keybytes - pos;
213
memcpy(rndin.data + pos, cksum.contents, n);
214
}
215
216
kb_out->enctype = etype;
217
kb_out->length = keylength;
218
kb_out->contents = ealloc(keylength);
219
check(krb5_c_random_to_key(NULL, etype, &rndin, kb_out));
220
free(cksum.contents);
221
free(rndin.data);
222
free(hashstr);
223
}
224
225
/* Return key data for the given key/salt tuple strings, using hashes of the
226
* enctypes, salts, and princstr for the key contents. */
227
static void
228
make_keys(char **strings, const char *princstr, const krb5_data *realm,
229
krb5_db_entry *ent)
230
{
231
krb5_key_data *key_data, *kd;
232
krb5_keyblock kb;
233
int32_t *ks_list_sizes, nstrings, nkeys, i, j;
234
krb5_key_salt_tuple **ks_lists, *ks;
235
krb5_kvno *kvnos;
236
char *s;
237
238
for (nstrings = 0; strings[nstrings] != NULL; nstrings++);
239
ks_lists = ealloc(nstrings * sizeof(*ks_lists));
240
ks_list_sizes = ealloc(nstrings * sizeof(*ks_list_sizes));
241
kvnos = ealloc(nstrings * sizeof(*kvnos));
242
243
/* Convert each string into a key/salt tuple list and count the total
244
* number of key data structures needed. */
245
nkeys = 0;
246
for (i = 0; i < nstrings; i++) {
247
s = strings[i];
248
/* Read a leading kvno if present; otherwise assume kvno 1. */
249
if (isdigit(*s)) {
250
kvnos[i] = strtol(s, &s, 10);
251
while (isspace(*s))
252
s++;
253
} else {
254
kvnos[i] = 1;
255
}
256
check(krb5_string_to_keysalts(s, NULL, NULL, FALSE, &ks_lists[i],
257
&ks_list_sizes[i]));
258
nkeys += ks_list_sizes[i];
259
}
260
261
/* Turn each key/salt tuple into a key data entry. */
262
kd = key_data = ealloc(nkeys * sizeof(*kd));
263
for (i = 0; i < nstrings; i++) {
264
ks = ks_lists[i];
265
for (j = 0; j < ks_list_sizes[i]; j++) {
266
make_keyblock(kvnos[i], ks[j].ks_enctype, ks[j].ks_salttype,
267
princstr, realm, &kb);
268
kd->key_data_ver = 2;
269
kd->key_data_kvno = kvnos[i];
270
kd->key_data_type[0] = ks[j].ks_enctype;
271
kd->key_data_length[0] = kb.length;
272
kd->key_data_contents[0] = kb.contents;
273
kd->key_data_type[1] = ks[j].ks_salttype;
274
kd++;
275
}
276
}
277
278
for (i = 0; i < nstrings; i++)
279
free(ks_lists[i]);
280
free(ks_lists);
281
free(ks_list_sizes);
282
free(kvnos);
283
ent->key_data = key_data;
284
ent->n_key_data = nkeys;
285
}
286
287
static void
288
make_strings(char **stringattrs, krb5_db_entry *ent)
289
{
290
struct k5buf buf;
291
char **p;
292
const char *str, *sep;
293
krb5_tl_data *tl;
294
295
k5_buf_init_dynamic(&buf);
296
for (p = stringattrs; *p != NULL; p++) {
297
str = *p;
298
sep = strchr(str, ':');
299
assert(sep != NULL);
300
k5_buf_add_len(&buf, str, sep - str);
301
k5_buf_add_len(&buf, "\0", 1);
302
k5_buf_add_len(&buf, sep + 1, strlen(sep + 1) + 1);
303
}
304
assert(buf.data != NULL);
305
306
tl = ealloc(sizeof(*ent->tl_data));
307
tl->tl_data_next = NULL;
308
tl->tl_data_type = KRB5_TL_STRING_ATTRS;
309
tl->tl_data_length = buf.len;
310
tl->tl_data_contents = buf.data;
311
ent->tl_data = tl;
312
}
313
314
static krb5_error_code
315
test_init(void)
316
{
317
return 0;
318
}
319
320
static krb5_error_code
321
test_cleanup(void)
322
{
323
return 0;
324
}
325
326
static krb5_error_code
327
test_open(krb5_context context, char *conf_section, char **db_args, int mode)
328
{
329
testhandle h;
330
331
h = ealloc(sizeof(*h));
332
h->profile = context->profile;
333
h->section = estrdup(conf_section);
334
context->dal_handle->db_context = h;
335
return 0;
336
}
337
338
static krb5_error_code
339
test_close(krb5_context context)
340
{
341
testhandle h = context->dal_handle->db_context;
342
343
free(h->section);
344
free(h);
345
return 0;
346
}
347
348
/* Return the principal name krbtgt/tgs_realm@our_realm. */
349
static krb5_principal
350
tgtname(krb5_context context, const krb5_data *tgs_realm,
351
const krb5_data *our_realm)
352
{
353
krb5_principal princ;
354
355
check(krb5_build_principal_ext(context, &princ,
356
our_realm->length, our_realm->data,
357
KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
358
tgs_realm->length, tgs_realm->data, 0));
359
princ->type = KRB5_NT_SRV_INST;
360
return princ;
361
}
362
363
/* Return true if search_for is within context's default realm or is an
364
* incoming cross-realm TGS name. */
365
static krb5_boolean
366
request_for_us(krb5_context context, krb5_const_principal search_for)
367
{
368
char *defrealm;
369
krb5_data realm;
370
krb5_boolean for_us;
371
krb5_principal local_tgs;
372
373
check(krb5_get_default_realm(context, &defrealm));
374
realm = string2data(defrealm);
375
local_tgs = tgtname(context, &realm, &realm);
376
krb5_free_default_realm(context, defrealm);
377
378
for_us = krb5_realm_compare(context, local_tgs, search_for) ||
379
krb5_principal_compare_any_realm(context, local_tgs, search_for);
380
krb5_free_principal(context, local_tgs);
381
return for_us;
382
}
383
384
static krb5_error_code
385
test_get_principal(krb5_context context, krb5_const_principal search_for,
386
unsigned int flags, krb5_db_entry **entry)
387
{
388
krb5_error_code ret;
389
krb5_principal princ = NULL, tgtprinc;
390
krb5_principal_data empty_princ = { KV5M_PRINCIPAL };
391
testhandle h = context->dal_handle->db_context;
392
char *search_name = NULL, *canon = NULL, *flagstr;
393
char **names, **key_strings, **stringattrs;
394
const char *ename;
395
krb5_db_entry *ent;
396
397
*entry = NULL;
398
399
if (!request_for_us(context, search_for))
400
return KRB5_KDB_NOENTRY;
401
402
check(krb5_unparse_name_flags(context, search_for,
403
KRB5_PRINCIPAL_UNPARSE_NO_REALM,
404
&search_name));
405
canon = get_string(h, "alias", search_name, NULL);
406
if (canon != NULL) {
407
check(krb5_parse_name(context, canon, &princ));
408
if (!krb5_realm_compare(context, search_for, princ)) {
409
/* Out of realm */
410
if ((flags & KRB5_KDB_FLAG_CLIENT) &&
411
(flags & KRB5_KDB_FLAG_REFERRAL_OK)) {
412
/* Return a client referral by creating an entry with only the
413
* principal set. */
414
*entry = ealloc(sizeof(**entry));
415
(*entry)->princ = princ;
416
princ = NULL;
417
ret = 0;
418
goto cleanup;
419
} else if (flags & KRB5_KDB_FLAG_REFERRAL_OK) {
420
/* Generate a server referral by looking up the TGT for the
421
* canonical name's realm. */
422
tgtprinc = tgtname(context, &princ->realm, &search_for->realm);
423
krb5_free_principal(context, princ);
424
princ = tgtprinc;
425
426
krb5_free_unparsed_name(context, search_name);
427
check(krb5_unparse_name_flags(context, princ,
428
KRB5_PRINCIPAL_UNPARSE_NO_REALM,
429
&search_name));
430
ename = search_name;
431
} else {
432
ret = KRB5_KDB_NOENTRY;
433
goto cleanup;
434
}
435
} else {
436
ename = canon;
437
}
438
} else {
439
check(krb5_copy_principal(context, search_for, &princ));
440
ename = search_name;
441
}
442
443
/* Check that the entry exists. */
444
set_names(h, "princs", ename, NULL);
445
ret = profile_get_relation_names(h->profile, h->names, &names);
446
if (ret == PROF_NO_RELATION) {
447
ret = KRB5_KDB_NOENTRY;
448
goto cleanup;
449
}
450
profile_free_list(names);
451
452
/* No error exits after this point. */
453
454
ent = ealloc(sizeof(*ent));
455
ent->princ = princ;
456
princ = NULL;
457
458
flagstr = get_string(h, "princs", ename, "flags");
459
if (flagstr != NULL) {
460
check(krb5_flagspec_to_mask(flagstr, &ent->attributes,
461
&ent->attributes));
462
}
463
free(flagstr);
464
465
ent->max_life = get_duration(h, "princs", ename, "maxlife");
466
ent->max_renewable_life = get_duration(h, "princs", ename, "maxrenewlife");
467
ent->expiration = get_time(h, "princs", ename, "expiration");
468
ent->pw_expiration = get_time(h, "princs", ename, "pwexpiration");
469
470
/* Leave last_success, last_failed, fail_auth_count zeroed. */
471
/* Leave e_data empty. */
472
473
set_names(h, "princs", ename, "keys");
474
ret = profile_get_values(h->profile, h->names, &key_strings);
475
if (ret != PROF_NO_RELATION) {
476
make_keys(key_strings, ename, &search_for->realm, ent);
477
profile_free_list(key_strings);
478
}
479
480
set_names(h, "princs", ename, "strings");
481
ret = profile_get_values(h->profile, h->names, &stringattrs);
482
if (ret != PROF_NO_RELATION) {
483
make_strings(stringattrs, ent);
484
profile_free_list(stringattrs);
485
}
486
487
/* We must include mod-princ data or kadm5_get_principal() won't work and
488
* we can't extract keys with kadmin.local. */
489
check(krb5_dbe_update_mod_princ_data(context, ent, 0, &empty_princ));
490
491
*entry = ent;
492
ret = 0;
493
494
cleanup:
495
krb5_free_unparsed_name(context, search_name);
496
krb5_free_principal(context, princ);
497
free(canon);
498
return ret;
499
}
500
501
static void
502
lookup_princ_by_cert(krb5_context context, const krb5_data *client_cert,
503
krb5_principal *princ)
504
{
505
krb5_error_code ret;
506
char *cert_princ_name;
507
508
/* The test client sends a principal string instead of a cert. */
509
cert_princ_name = k5memdup0(client_cert->data, client_cert->length, &ret);
510
check(ret);
511
512
check(krb5_parse_name_flags(context, cert_princ_name,
513
KRB5_PRINCIPAL_PARSE_ENTERPRISE, princ));
514
free(cert_princ_name);
515
}
516
517
static krb5_error_code
518
test_get_s4u_x509_principal(krb5_context context, const krb5_data *client_cert,
519
krb5_const_principal princ, unsigned int flags,
520
krb5_db_entry **entry)
521
{
522
krb5_error_code ret;
523
krb5_principal cert_princ, canon_princ;
524
testhandle h = context->dal_handle->db_context;
525
krb5_boolean match;
526
char *canon, *princ_name;
527
528
lookup_princ_by_cert(context, client_cert, &cert_princ);
529
530
ret = test_get_principal(context, cert_princ, flags, entry);
531
krb5_free_principal(context, cert_princ);
532
if (ret || (flags & KRB5_KDB_FLAG_REFERRAL_OK))
533
return ret;
534
535
if (!krb5_realm_compare(context, princ, (*entry)->princ))
536
abort();
537
538
if (princ->length == 0 ||
539
krb5_principal_compare(context, princ, (*entry)->princ))
540
return 0;
541
542
match = FALSE;
543
check(krb5_unparse_name_flags(context, princ,
544
KRB5_PRINCIPAL_UNPARSE_NO_REALM,
545
&princ_name));
546
canon = get_string(h, "alias", princ_name, NULL);
547
krb5_free_unparsed_name(context, princ_name);
548
if (canon != NULL) {
549
check(krb5_parse_name(context, canon, &canon_princ));
550
match = krb5_principal_compare(context, canon_princ, (*entry)->princ);
551
krb5_free_principal(context, canon_princ);
552
}
553
554
free(canon);
555
return match ? 0 : KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
556
}
557
558
static krb5_error_code
559
test_fetch_master_key(krb5_context context, krb5_principal mname,
560
krb5_keyblock *key_out, krb5_kvno *kvno_out,
561
char *db_args)
562
{
563
memset(key_out, 0, sizeof(*key_out));
564
*kvno_out = 0;
565
return 0;
566
}
567
568
static krb5_error_code
569
test_fetch_master_key_list(krb5_context context, krb5_principal mname,
570
const krb5_keyblock *key,
571
krb5_keylist_node **mkeys_out)
572
{
573
/* krb5_dbe_get_mkvno() returns an error if we produce NULL, so return an
574
* empty node to make kadm5_get_principal() work. */
575
*mkeys_out = ealloc(sizeof(**mkeys_out));
576
return 0;
577
}
578
579
static krb5_error_code
580
test_decrypt_key_data(krb5_context context, const krb5_keyblock *mkey,
581
const krb5_key_data *kd, krb5_keyblock *key_out,
582
krb5_keysalt *salt_out)
583
{
584
key_out->magic = KV5M_KEYBLOCK;
585
key_out->enctype = kd->key_data_type[0];
586
key_out->length = kd->key_data_length[0];
587
key_out->contents = ealloc(key_out->length);
588
memcpy(key_out->contents, kd->key_data_contents[0], key_out->length);
589
if (salt_out != NULL) {
590
salt_out->type = (kd->key_data_ver > 1) ? kd->key_data_type[1] :
591
KRB5_KDB_SALTTYPE_NORMAL;
592
salt_out->data = empty_data();
593
}
594
return 0;
595
}
596
597
static krb5_error_code
598
test_encrypt_key_data(krb5_context context, const krb5_keyblock *mkey,
599
const krb5_keyblock *key, const krb5_keysalt *salt,
600
int kvno, krb5_key_data *kd_out)
601
{
602
memset(kd_out, 0, sizeof(*kd_out));
603
kd_out->key_data_ver = 2;
604
kd_out->key_data_kvno = kvno;
605
kd_out->key_data_type[0] = key->enctype;
606
kd_out->key_data_length[0] = key->length;
607
kd_out->key_data_contents[0] = ealloc(key->length);
608
memcpy(kd_out->key_data_contents[0], key->contents, key->length);
609
kd_out->key_data_type[1] = (salt != NULL) ? salt->type :
610
KRB5_KDB_SALTTYPE_NORMAL;
611
return 0;
612
}
613
614
static void
615
change_auth_indicators(krb5_context context, krb5_data ***auth_indicators)
616
{
617
krb5_data **inds, d;
618
size_t i;
619
int val;
620
621
/* If we see an auth indicator "dbincrX", replace the whole indicator list
622
* with "dbincr{X+1}". */
623
inds = *auth_indicators;
624
for (i = 0; inds != NULL && inds[i] != NULL; i++) {
625
if (inds[i]->length == 7 && memcmp(inds[i]->data, "dbincr", 6) == 0) {
626
val = inds[i]->data[6];
627
k5_free_data_ptr_list(inds);
628
inds = ealloc(2 * sizeof(*inds));
629
d = string2data("dbincr0");
630
check(krb5_copy_data(context, &d, &inds[0]));
631
inds[0]->data[6] = val + 1;
632
inds[1] = NULL;
633
*auth_indicators = inds;
634
break;
635
}
636
}
637
}
638
639
static krb5_error_code
640
test_issue_pac(krb5_context context, unsigned int flags, krb5_db_entry *client,
641
krb5_keyblock *replaced_reply_key, krb5_db_entry *server,
642
krb5_db_entry *krb5tgt, krb5_timestamp authtime,
643
krb5_pac old_pac, krb5_pac new_pac,
644
krb5_data ***auth_indicators)
645
{
646
krb5_data data = empty_data();
647
krb5_boolean found_logon_info = FALSE;
648
krb5_ui_4 *types = NULL;
649
size_t num_buffers = 0, i;
650
651
change_auth_indicators(context, auth_indicators);
652
653
if (old_pac == NULL ||
654
(client != NULL && (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION))) {
655
/* Generating an initial PAC. */
656
assert(client != NULL);
657
data = string2data("fake");
658
check(krb5_pac_add_buffer(context, new_pac, KRB5_PAC_LOGON_INFO,
659
&data));
660
661
if (replaced_reply_key != NULL) {
662
/* Add a fake PAC_CREDENTIALS_INFO buffer so we can test whether
663
* this parameter was set. */
664
data = string2data("fake credinfo");
665
check(krb5_pac_add_buffer(context, new_pac,
666
KRB5_PAC_CREDENTIALS_INFO, &data));
667
}
668
return 0;
669
} else {
670
/* Field copying - my favorite! */
671
if (old_pac != NULL)
672
check(krb5_pac_get_types(context, old_pac, &num_buffers, &types));
673
674
for (i = 0; i < num_buffers; i++) {
675
/* Skip buffer types handled by KDC. */
676
if (types[i] == KRB5_PAC_SERVER_CHECKSUM ||
677
types[i] == KRB5_PAC_PRIVSVR_CHECKSUM ||
678
types[i] == KRB5_PAC_TICKET_CHECKSUM ||
679
types[i] == KRB5_PAC_CLIENT_INFO ||
680
types[i] == KRB5_PAC_DELEGATION_INFO)
681
continue;
682
683
check(krb5_pac_get_buffer(context, old_pac, types[i], &data));
684
685
if (types[i] == KRB5_PAC_LOGON_INFO) {
686
found_logon_info = TRUE;
687
assert(data_eq_string(data, "fake"));
688
}
689
690
check(krb5_pac_add_buffer(context, new_pac, types[i], &data));
691
krb5_free_data_contents(context, &data);
692
}
693
694
if (old_pac != NULL)
695
assert(found_logon_info);
696
697
free(types);
698
}
699
700
return 0;
701
}
702
703
static krb5_boolean
704
match_in_table(krb5_context context, const char *table, const char *sprinc,
705
const char *tprinc)
706
{
707
testhandle h = context->dal_handle->db_context;
708
krb5_error_code ret;
709
char **values, **v;
710
krb5_boolean found = FALSE;
711
712
set_names(h, table, sprinc, NULL);
713
ret = profile_get_values(h->profile, h->names, &values);
714
assert(ret == 0 || ret == PROF_NO_RELATION);
715
if (ret)
716
return FALSE;
717
for (v = values; *v != NULL; v++) {
718
if (tprinc == NULL || strcmp(*v, tprinc) == 0) {
719
found = TRUE;
720
break;
721
}
722
}
723
profile_free_list(values);
724
return found;
725
}
726
727
static krb5_error_code
728
test_check_allowed_to_delegate(krb5_context context,
729
krb5_const_principal client,
730
const krb5_db_entry *server,
731
krb5_const_principal proxy)
732
{
733
char *sprinc, *tprinc = NULL;
734
krb5_boolean found = FALSE;
735
736
check(krb5_unparse_name_flags(context, server->princ,
737
KRB5_PRINCIPAL_UNPARSE_NO_REALM, &sprinc));
738
if (proxy != NULL) {
739
check(krb5_unparse_name_flags(context, proxy,
740
KRB5_PRINCIPAL_UNPARSE_NO_REALM,
741
&tprinc));
742
}
743
found = match_in_table(context, "delegation", sprinc, tprinc);
744
krb5_free_unparsed_name(context, sprinc);
745
krb5_free_unparsed_name(context, tprinc);
746
return found ? 0 : KRB5KDC_ERR_BADOPTION;
747
}
748
749
static krb5_error_code
750
test_allowed_to_delegate_from(krb5_context context,
751
krb5_const_principal client,
752
krb5_const_principal server,
753
krb5_pac server_pac,
754
const krb5_db_entry *proxy)
755
{
756
char *proxy_princ, *server_princ, *pac_client_princ, *client_princ;
757
krb5_boolean found = FALSE;
758
759
assert(server_pac != NULL);
760
761
check(krb5_unparse_name(context, proxy->princ, &proxy_princ));
762
check(krb5_unparse_name(context, server, &server_princ));
763
check(krb5_unparse_name(context, client, &client_princ));
764
765
check(krb5_pac_get_client_info(context, server_pac, NULL,
766
&pac_client_princ));
767
768
/* Skip realm portion if not present in PAC. */
769
assert(strncmp(pac_client_princ, server_princ,
770
strlen(pac_client_princ)) == 0);
771
772
free(pac_client_princ);
773
774
found = match_in_table(context, "rbcd", proxy_princ, server_princ);
775
krb5_free_unparsed_name(context, proxy_princ);
776
krb5_free_unparsed_name(context, server_princ);
777
krb5_free_unparsed_name(context, client_princ);
778
return found ? 0 : KRB5KDC_ERR_BADOPTION;
779
}
780
781
kdb_vftabl PLUGIN_SYMBOL_NAME(krb5_test, kdb_function_table) = {
782
KRB5_KDB_DAL_MAJOR_VERSION, /* major version number */
783
0, /* minor version number */
784
test_init,
785
test_cleanup,
786
test_open,
787
test_close,
788
NULL, /* create */
789
NULL, /* destroy */
790
NULL, /* get_age */
791
NULL, /* lock */
792
NULL, /* unlock */
793
test_get_principal,
794
NULL, /* put_principal */
795
NULL, /* delete_principal */
796
NULL, /* rename_principal */
797
NULL, /* iterate */
798
NULL, /* create_policy */
799
NULL, /* get_policy */
800
NULL, /* put_policy */
801
NULL, /* iter_policy */
802
NULL, /* delete_policy */
803
test_fetch_master_key,
804
test_fetch_master_key_list,
805
NULL, /* store_master_key_list */
806
NULL, /* dbe_search_enctype */
807
NULL, /* change_pwd */
808
NULL, /* promote_db */
809
test_decrypt_key_data,
810
test_encrypt_key_data,
811
NULL, /* check_transited_realms */
812
NULL, /* check_policy_as */
813
NULL, /* check_policy_tgs */
814
NULL, /* audit_as_req */
815
NULL, /* refresh_config */
816
test_check_allowed_to_delegate,
817
NULL, /* free_principal_e_data */
818
test_get_s4u_x509_principal,
819
test_allowed_to_delegate_from,
820
test_issue_pac,
821
};
822
823