Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/kdc/krb5tgs.c
34860 views
1
/*
2
* Copyright (c) 1997-2008 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 the Institute nor the names of its contributors
18
* may be used to endorse or promote products derived from this software
19
* without specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
34
#include "kdc_locl.h"
35
36
/*
37
* return the realm of a krbtgt-ticket or NULL
38
*/
39
40
static Realm
41
get_krbtgt_realm(const PrincipalName *p)
42
{
43
if(p->name_string.len == 2
44
&& strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
45
return p->name_string.val[1];
46
else
47
return NULL;
48
}
49
50
/*
51
* The KDC might add a signed path to the ticket authorization data
52
* field. This is to avoid server impersonating clients and the
53
* request constrained delegation.
54
*
55
* This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
56
* entry of type KRB5SignedPath.
57
*/
58
59
static krb5_error_code
60
find_KRB5SignedPath(krb5_context context,
61
const AuthorizationData *ad,
62
krb5_data *data)
63
{
64
AuthorizationData child;
65
krb5_error_code ret;
66
int pos;
67
68
if (ad == NULL || ad->len == 0)
69
return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
70
71
pos = ad->len - 1;
72
73
if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
74
return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
75
76
ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
77
ad->val[pos].ad_data.length,
78
&child,
79
NULL);
80
if (ret) {
81
krb5_set_error_message(context, ret, "Failed to decode "
82
"IF_RELEVANT with %d", ret);
83
return ret;
84
}
85
86
if (child.len != 1) {
87
free_AuthorizationData(&child);
88
return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
89
}
90
91
if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
92
free_AuthorizationData(&child);
93
return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
94
}
95
96
if (data)
97
ret = der_copy_octet_string(&child.val[0].ad_data, data);
98
free_AuthorizationData(&child);
99
return ret;
100
}
101
102
krb5_error_code
103
_kdc_add_KRB5SignedPath(krb5_context context,
104
krb5_kdc_configuration *config,
105
hdb_entry_ex *krbtgt,
106
krb5_enctype enctype,
107
krb5_principal client,
108
krb5_const_principal server,
109
krb5_principals principals,
110
EncTicketPart *tkt)
111
{
112
krb5_error_code ret;
113
KRB5SignedPath sp;
114
krb5_data data;
115
krb5_crypto crypto = NULL;
116
size_t size = 0;
117
118
if (server && principals) {
119
ret = add_Principals(principals, server);
120
if (ret)
121
return ret;
122
}
123
124
{
125
KRB5SignedPathData spd;
126
127
spd.client = client;
128
spd.authtime = tkt->authtime;
129
spd.delegated = principals;
130
spd.method_data = NULL;
131
132
ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
133
&spd, &size, ret);
134
if (ret)
135
return ret;
136
if (data.length != size)
137
krb5_abortx(context, "internal asn.1 encoder error");
138
}
139
140
{
141
Key *key;
142
ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
143
if (ret == 0)
144
ret = krb5_crypto_init(context, &key->key, 0, &crypto);
145
if (ret) {
146
free(data.data);
147
return ret;
148
}
149
}
150
151
/*
152
* Fill in KRB5SignedPath
153
*/
154
155
sp.etype = enctype;
156
sp.delegated = principals;
157
sp.method_data = NULL;
158
159
ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
160
data.data, data.length, &sp.cksum);
161
krb5_crypto_destroy(context, crypto);
162
free(data.data);
163
if (ret)
164
return ret;
165
166
ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
167
free_Checksum(&sp.cksum);
168
if (ret)
169
return ret;
170
if (data.length != size)
171
krb5_abortx(context, "internal asn.1 encoder error");
172
173
174
/*
175
* Add IF-RELEVANT(KRB5SignedPath) to the last slot in
176
* authorization data field.
177
*/
178
179
ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
180
KRB5_AUTHDATA_SIGNTICKET, &data);
181
krb5_data_free(&data);
182
183
return ret;
184
}
185
186
static krb5_error_code
187
check_KRB5SignedPath(krb5_context context,
188
krb5_kdc_configuration *config,
189
hdb_entry_ex *krbtgt,
190
krb5_principal cp,
191
EncTicketPart *tkt,
192
krb5_principals *delegated,
193
int *signedpath)
194
{
195
krb5_error_code ret;
196
krb5_data data;
197
krb5_crypto crypto = NULL;
198
199
if (delegated)
200
*delegated = NULL;
201
202
ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
203
if (ret == 0) {
204
KRB5SignedPathData spd;
205
KRB5SignedPath sp;
206
size_t size = 0;
207
208
ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
209
krb5_data_free(&data);
210
if (ret)
211
return ret;
212
213
spd.client = cp;
214
spd.authtime = tkt->authtime;
215
spd.delegated = sp.delegated;
216
spd.method_data = sp.method_data;
217
218
ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
219
&spd, &size, ret);
220
if (ret) {
221
free_KRB5SignedPath(&sp);
222
return ret;
223
}
224
if (data.length != size)
225
krb5_abortx(context, "internal asn.1 encoder error");
226
227
{
228
Key *key;
229
ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
230
if (ret == 0)
231
ret = krb5_crypto_init(context, &key->key, 0, &crypto);
232
if (ret) {
233
free(data.data);
234
free_KRB5SignedPath(&sp);
235
return ret;
236
}
237
}
238
ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
239
data.data, data.length,
240
&sp.cksum);
241
krb5_crypto_destroy(context, crypto);
242
free(data.data);
243
if (ret) {
244
free_KRB5SignedPath(&sp);
245
kdc_log(context, config, 5,
246
"KRB5SignedPath not signed correctly, not marking as signed");
247
return 0;
248
}
249
250
if (delegated && sp.delegated) {
251
252
*delegated = malloc(sizeof(*sp.delegated));
253
if (*delegated == NULL) {
254
free_KRB5SignedPath(&sp);
255
return ENOMEM;
256
}
257
258
ret = copy_Principals(*delegated, sp.delegated);
259
if (ret) {
260
free_KRB5SignedPath(&sp);
261
free(*delegated);
262
*delegated = NULL;
263
return ret;
264
}
265
}
266
free_KRB5SignedPath(&sp);
267
268
*signedpath = 1;
269
}
270
271
return 0;
272
}
273
274
/*
275
*
276
*/
277
278
static krb5_error_code
279
check_PAC(krb5_context context,
280
krb5_kdc_configuration *config,
281
const krb5_principal client_principal,
282
const krb5_principal delegated_proxy_principal,
283
hdb_entry_ex *client,
284
hdb_entry_ex *server,
285
hdb_entry_ex *krbtgt,
286
const EncryptionKey *server_check_key,
287
const EncryptionKey *krbtgt_check_key,
288
const EncryptionKey *server_sign_key,
289
const EncryptionKey *krbtgt_sign_key,
290
EncTicketPart *tkt,
291
krb5_data *rspac,
292
int *signedpath)
293
{
294
AuthorizationData *ad = tkt->authorization_data;
295
unsigned i, j;
296
krb5_error_code ret;
297
298
if (ad == NULL || ad->len == 0)
299
return 0;
300
301
for (i = 0; i < ad->len; i++) {
302
AuthorizationData child;
303
304
if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
305
continue;
306
307
ret = decode_AuthorizationData(ad->val[i].ad_data.data,
308
ad->val[i].ad_data.length,
309
&child,
310
NULL);
311
if (ret) {
312
krb5_set_error_message(context, ret, "Failed to decode "
313
"IF_RELEVANT with %d", ret);
314
return ret;
315
}
316
for (j = 0; j < child.len; j++) {
317
318
if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
319
int signed_pac = 0;
320
krb5_pac pac;
321
322
/* Found PAC */
323
ret = krb5_pac_parse(context,
324
child.val[j].ad_data.data,
325
child.val[j].ad_data.length,
326
&pac);
327
free_AuthorizationData(&child);
328
if (ret)
329
return ret;
330
331
ret = krb5_pac_verify(context, pac, tkt->authtime,
332
client_principal,
333
server_check_key, krbtgt_check_key);
334
if (ret) {
335
krb5_pac_free(context, pac);
336
return ret;
337
}
338
339
ret = _kdc_pac_verify(context, client_principal,
340
delegated_proxy_principal,
341
client, server, krbtgt, &pac, &signed_pac);
342
if (ret) {
343
krb5_pac_free(context, pac);
344
return ret;
345
}
346
347
/*
348
* Only re-sign PAC if we could verify it with the PAC
349
* function. The no-verify case happens when we get in
350
* a PAC from cross realm from a Windows domain and
351
* that there is no PAC verification function.
352
*/
353
if (signed_pac) {
354
*signedpath = 1;
355
ret = _krb5_pac_sign(context, pac, tkt->authtime,
356
client_principal,
357
server_sign_key, krbtgt_sign_key, rspac);
358
}
359
krb5_pac_free(context, pac);
360
361
return ret;
362
}
363
}
364
free_AuthorizationData(&child);
365
}
366
return 0;
367
}
368
369
/*
370
*
371
*/
372
373
static krb5_error_code
374
check_tgs_flags(krb5_context context,
375
krb5_kdc_configuration *config,
376
KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
377
{
378
KDCOptions f = b->kdc_options;
379
380
if(f.validate){
381
if(!tgt->flags.invalid || tgt->starttime == NULL){
382
kdc_log(context, config, 0,
383
"Bad request to validate ticket");
384
return KRB5KDC_ERR_BADOPTION;
385
}
386
if(*tgt->starttime > kdc_time){
387
kdc_log(context, config, 0,
388
"Early request to validate ticket");
389
return KRB5KRB_AP_ERR_TKT_NYV;
390
}
391
/* XXX tkt = tgt */
392
et->flags.invalid = 0;
393
}else if(tgt->flags.invalid){
394
kdc_log(context, config, 0,
395
"Ticket-granting ticket has INVALID flag set");
396
return KRB5KRB_AP_ERR_TKT_INVALID;
397
}
398
399
if(f.forwardable){
400
if(!tgt->flags.forwardable){
401
kdc_log(context, config, 0,
402
"Bad request for forwardable ticket");
403
return KRB5KDC_ERR_BADOPTION;
404
}
405
et->flags.forwardable = 1;
406
}
407
if(f.forwarded){
408
if(!tgt->flags.forwardable){
409
kdc_log(context, config, 0,
410
"Request to forward non-forwardable ticket");
411
return KRB5KDC_ERR_BADOPTION;
412
}
413
et->flags.forwarded = 1;
414
et->caddr = b->addresses;
415
}
416
if(tgt->flags.forwarded)
417
et->flags.forwarded = 1;
418
419
if(f.proxiable){
420
if(!tgt->flags.proxiable){
421
kdc_log(context, config, 0,
422
"Bad request for proxiable ticket");
423
return KRB5KDC_ERR_BADOPTION;
424
}
425
et->flags.proxiable = 1;
426
}
427
if(f.proxy){
428
if(!tgt->flags.proxiable){
429
kdc_log(context, config, 0,
430
"Request to proxy non-proxiable ticket");
431
return KRB5KDC_ERR_BADOPTION;
432
}
433
et->flags.proxy = 1;
434
et->caddr = b->addresses;
435
}
436
if(tgt->flags.proxy)
437
et->flags.proxy = 1;
438
439
if(f.allow_postdate){
440
if(!tgt->flags.may_postdate){
441
kdc_log(context, config, 0,
442
"Bad request for post-datable ticket");
443
return KRB5KDC_ERR_BADOPTION;
444
}
445
et->flags.may_postdate = 1;
446
}
447
if(f.postdated){
448
if(!tgt->flags.may_postdate){
449
kdc_log(context, config, 0,
450
"Bad request for postdated ticket");
451
return KRB5KDC_ERR_BADOPTION;
452
}
453
if(b->from)
454
*et->starttime = *b->from;
455
et->flags.postdated = 1;
456
et->flags.invalid = 1;
457
}else if(b->from && *b->from > kdc_time + context->max_skew){
458
kdc_log(context, config, 0, "Ticket cannot be postdated");
459
return KRB5KDC_ERR_CANNOT_POSTDATE;
460
}
461
462
if(f.renewable){
463
if(!tgt->flags.renewable || tgt->renew_till == NULL){
464
kdc_log(context, config, 0,
465
"Bad request for renewable ticket");
466
return KRB5KDC_ERR_BADOPTION;
467
}
468
et->flags.renewable = 1;
469
ALLOC(et->renew_till);
470
_kdc_fix_time(&b->rtime);
471
*et->renew_till = *b->rtime;
472
}
473
if(f.renew){
474
time_t old_life;
475
if(!tgt->flags.renewable || tgt->renew_till == NULL){
476
kdc_log(context, config, 0,
477
"Request to renew non-renewable ticket");
478
return KRB5KDC_ERR_BADOPTION;
479
}
480
old_life = tgt->endtime;
481
if(tgt->starttime)
482
old_life -= *tgt->starttime;
483
else
484
old_life -= tgt->authtime;
485
et->endtime = *et->starttime + old_life;
486
if (et->renew_till != NULL)
487
et->endtime = min(*et->renew_till, et->endtime);
488
}
489
490
#if 0
491
/* checks for excess flags */
492
if(f.request_anonymous && !config->allow_anonymous){
493
kdc_log(context, config, 0,
494
"Request for anonymous ticket");
495
return KRB5KDC_ERR_BADOPTION;
496
}
497
#endif
498
return 0;
499
}
500
501
/*
502
* Determine if constrained delegation is allowed from this client to this server
503
*/
504
505
static krb5_error_code
506
check_constrained_delegation(krb5_context context,
507
krb5_kdc_configuration *config,
508
HDB *clientdb,
509
hdb_entry_ex *client,
510
hdb_entry_ex *server,
511
krb5_const_principal target)
512
{
513
const HDB_Ext_Constrained_delegation_acl *acl;
514
krb5_error_code ret;
515
size_t i;
516
517
/*
518
* constrained_delegation (S4U2Proxy) only works within
519
* the same realm. We use the already canonicalized version
520
* of the principals here, while "target" is the principal
521
* provided by the client.
522
*/
523
if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
524
ret = KRB5KDC_ERR_BADOPTION;
525
kdc_log(context, config, 0,
526
"Bad request for constrained delegation");
527
return ret;
528
}
529
530
if (clientdb->hdb_check_constrained_delegation) {
531
ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
532
if (ret == 0)
533
return 0;
534
} else {
535
/* if client delegates to itself, that ok */
536
if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
537
return 0;
538
539
ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
540
if (ret) {
541
krb5_clear_error_message(context);
542
return ret;
543
}
544
545
if (acl) {
546
for (i = 0; i < acl->len; i++) {
547
if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
548
return 0;
549
}
550
}
551
ret = KRB5KDC_ERR_BADOPTION;
552
}
553
kdc_log(context, config, 0,
554
"Bad request for constrained delegation");
555
return ret;
556
}
557
558
/*
559
* Determine if s4u2self is allowed from this client to this server
560
*
561
* For example, regardless of the principal being impersonated, if the
562
* 'client' and 'server' are the same, then it's safe.
563
*/
564
565
static krb5_error_code
566
check_s4u2self(krb5_context context,
567
krb5_kdc_configuration *config,
568
HDB *clientdb,
569
hdb_entry_ex *client,
570
krb5_const_principal server)
571
{
572
krb5_error_code ret;
573
574
/* if client does a s4u2self to itself, that ok */
575
if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
576
return 0;
577
578
if (clientdb->hdb_check_s4u2self) {
579
ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
580
if (ret == 0)
581
return 0;
582
} else {
583
ret = KRB5KDC_ERR_BADOPTION;
584
}
585
return ret;
586
}
587
588
/*
589
*
590
*/
591
592
static krb5_error_code
593
verify_flags (krb5_context context,
594
krb5_kdc_configuration *config,
595
const EncTicketPart *et,
596
const char *pstr)
597
{
598
if(et->endtime < kdc_time){
599
kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
600
return KRB5KRB_AP_ERR_TKT_EXPIRED;
601
}
602
if(et->flags.invalid){
603
kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
604
return KRB5KRB_AP_ERR_TKT_NYV;
605
}
606
return 0;
607
}
608
609
/*
610
*
611
*/
612
613
static krb5_error_code
614
fix_transited_encoding(krb5_context context,
615
krb5_kdc_configuration *config,
616
krb5_boolean check_policy,
617
const TransitedEncoding *tr,
618
EncTicketPart *et,
619
const char *client_realm,
620
const char *server_realm,
621
const char *tgt_realm)
622
{
623
krb5_error_code ret = 0;
624
char **realms, **tmp;
625
unsigned int num_realms;
626
size_t i;
627
628
switch (tr->tr_type) {
629
case DOMAIN_X500_COMPRESS:
630
break;
631
case 0:
632
/*
633
* Allow empty content of type 0 because that is was Microsoft
634
* generates in their TGT.
635
*/
636
if (tr->contents.length == 0)
637
break;
638
kdc_log(context, config, 0,
639
"Transited type 0 with non empty content");
640
return KRB5KDC_ERR_TRTYPE_NOSUPP;
641
default:
642
kdc_log(context, config, 0,
643
"Unknown transited type: %u", tr->tr_type);
644
return KRB5KDC_ERR_TRTYPE_NOSUPP;
645
}
646
647
ret = krb5_domain_x500_decode(context,
648
tr->contents,
649
&realms,
650
&num_realms,
651
client_realm,
652
server_realm);
653
if(ret){
654
krb5_warn(context, ret,
655
"Decoding transited encoding");
656
return ret;
657
}
658
659
/*
660
* If the realm of the presented tgt is neither the client nor the server
661
* realm, it is a transit realm and must be added to transited set.
662
*/
663
if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
664
if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
665
ret = ERANGE;
666
goto free_realms;
667
}
668
tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
669
if(tmp == NULL){
670
ret = ENOMEM;
671
goto free_realms;
672
}
673
realms = tmp;
674
realms[num_realms] = strdup(tgt_realm);
675
if(realms[num_realms] == NULL){
676
ret = ENOMEM;
677
goto free_realms;
678
}
679
num_realms++;
680
}
681
if(num_realms == 0) {
682
if(strcmp(client_realm, server_realm))
683
kdc_log(context, config, 0,
684
"cross-realm %s -> %s", client_realm, server_realm);
685
} else {
686
size_t l = 0;
687
char *rs;
688
for(i = 0; i < num_realms; i++)
689
l += strlen(realms[i]) + 2;
690
rs = malloc(l);
691
if(rs != NULL) {
692
*rs = '\0';
693
for(i = 0; i < num_realms; i++) {
694
if(i > 0)
695
strlcat(rs, ", ", l);
696
strlcat(rs, realms[i], l);
697
}
698
kdc_log(context, config, 0,
699
"cross-realm %s -> %s via [%s]",
700
client_realm, server_realm, rs);
701
free(rs);
702
}
703
}
704
if(check_policy) {
705
ret = krb5_check_transited(context, client_realm,
706
server_realm,
707
realms, num_realms, NULL);
708
if(ret) {
709
krb5_warn(context, ret, "cross-realm %s -> %s",
710
client_realm, server_realm);
711
goto free_realms;
712
}
713
et->flags.transited_policy_checked = 1;
714
}
715
et->transited.tr_type = DOMAIN_X500_COMPRESS;
716
ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
717
if(ret)
718
krb5_warn(context, ret, "Encoding transited encoding");
719
free_realms:
720
for(i = 0; i < num_realms; i++)
721
free(realms[i]);
722
free(realms);
723
return ret;
724
}
725
726
727
static krb5_error_code
728
tgs_make_reply(krb5_context context,
729
krb5_kdc_configuration *config,
730
KDC_REQ_BODY *b,
731
krb5_const_principal tgt_name,
732
const EncTicketPart *tgt,
733
const krb5_keyblock *replykey,
734
int rk_is_subkey,
735
const EncryptionKey *serverkey,
736
const krb5_keyblock *sessionkey,
737
krb5_kvno kvno,
738
AuthorizationData *auth_data,
739
hdb_entry_ex *server,
740
krb5_principal server_principal,
741
const char *server_name,
742
hdb_entry_ex *client,
743
krb5_principal client_principal,
744
const char *tgt_realm,
745
hdb_entry_ex *krbtgt,
746
krb5_enctype krbtgt_etype,
747
krb5_principals spp,
748
const krb5_data *rspac,
749
const METHOD_DATA *enc_pa_data,
750
const char **e_text,
751
krb5_data *reply)
752
{
753
KDC_REP rep;
754
EncKDCRepPart ek;
755
EncTicketPart et;
756
KDCOptions f = b->kdc_options;
757
krb5_error_code ret;
758
int is_weak = 0;
759
760
memset(&rep, 0, sizeof(rep));
761
memset(&et, 0, sizeof(et));
762
memset(&ek, 0, sizeof(ek));
763
764
rep.pvno = 5;
765
rep.msg_type = krb_tgs_rep;
766
767
et.authtime = tgt->authtime;
768
_kdc_fix_time(&b->till);
769
et.endtime = min(tgt->endtime, *b->till);
770
ALLOC(et.starttime);
771
*et.starttime = kdc_time;
772
773
ret = check_tgs_flags(context, config, b, tgt, &et);
774
if(ret)
775
goto out;
776
777
/* We should check the transited encoding if:
778
1) the request doesn't ask not to be checked
779
2) globally enforcing a check
780
3) principal requires checking
781
4) we allow non-check per-principal, but principal isn't marked as allowing this
782
5) we don't globally allow this
783
*/
784
785
#define GLOBAL_FORCE_TRANSITED_CHECK \
786
(config->trpolicy == TRPOLICY_ALWAYS_CHECK)
787
#define GLOBAL_ALLOW_PER_PRINCIPAL \
788
(config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
789
#define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
790
(config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
791
792
/* these will consult the database in future release */
793
#define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
794
#define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
795
796
ret = fix_transited_encoding(context, config,
797
!f.disable_transited_check ||
798
GLOBAL_FORCE_TRANSITED_CHECK ||
799
PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
800
!((GLOBAL_ALLOW_PER_PRINCIPAL &&
801
PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
802
GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
803
&tgt->transited, &et,
804
krb5_principal_get_realm(context, client_principal),
805
krb5_principal_get_realm(context, server->entry.principal),
806
tgt_realm);
807
if(ret)
808
goto out;
809
810
copy_Realm(&server_principal->realm, &rep.ticket.realm);
811
_krb5_principal2principalname(&rep.ticket.sname, server_principal);
812
copy_Realm(&tgt_name->realm, &rep.crealm);
813
/*
814
if (f.request_anonymous)
815
_kdc_make_anonymous_principalname (&rep.cname);
816
else */
817
818
copy_PrincipalName(&tgt_name->name, &rep.cname);
819
rep.ticket.tkt_vno = 5;
820
821
ek.caddr = et.caddr;
822
if(et.caddr == NULL)
823
et.caddr = tgt->caddr;
824
825
{
826
time_t life;
827
life = et.endtime - *et.starttime;
828
if(client && client->entry.max_life)
829
life = min(life, *client->entry.max_life);
830
if(server->entry.max_life)
831
life = min(life, *server->entry.max_life);
832
et.endtime = *et.starttime + life;
833
}
834
if(f.renewable_ok && tgt->flags.renewable &&
835
et.renew_till == NULL && et.endtime < *b->till &&
836
tgt->renew_till != NULL)
837
{
838
et.flags.renewable = 1;
839
ALLOC(et.renew_till);
840
*et.renew_till = *b->till;
841
}
842
if(et.renew_till){
843
time_t renew;
844
renew = *et.renew_till - et.authtime;
845
if(client && client->entry.max_renew)
846
renew = min(renew, *client->entry.max_renew);
847
if(server->entry.max_renew)
848
renew = min(renew, *server->entry.max_renew);
849
*et.renew_till = et.authtime + renew;
850
}
851
852
if(et.renew_till){
853
*et.renew_till = min(*et.renew_till, *tgt->renew_till);
854
*et.starttime = min(*et.starttime, *et.renew_till);
855
et.endtime = min(et.endtime, *et.renew_till);
856
}
857
858
*et.starttime = min(*et.starttime, et.endtime);
859
860
if(*et.starttime == et.endtime){
861
ret = KRB5KDC_ERR_NEVER_VALID;
862
goto out;
863
}
864
if(et.renew_till && et.endtime == *et.renew_till){
865
free(et.renew_till);
866
et.renew_till = NULL;
867
et.flags.renewable = 0;
868
}
869
870
et.flags.pre_authent = tgt->flags.pre_authent;
871
et.flags.hw_authent = tgt->flags.hw_authent;
872
et.flags.anonymous = tgt->flags.anonymous;
873
et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
874
875
if(rspac->length) {
876
/*
877
* No not need to filter out the any PAC from the
878
* auth_data since it's signed by the KDC.
879
*/
880
ret = _kdc_tkt_add_if_relevant_ad(context, &et,
881
KRB5_AUTHDATA_WIN2K_PAC, rspac);
882
if (ret)
883
goto out;
884
}
885
886
if (auth_data) {
887
unsigned int i = 0;
888
889
/* XXX check authdata */
890
891
if (et.authorization_data == NULL) {
892
et.authorization_data = calloc(1, sizeof(*et.authorization_data));
893
if (et.authorization_data == NULL) {
894
ret = ENOMEM;
895
krb5_set_error_message(context, ret, "malloc: out of memory");
896
goto out;
897
}
898
}
899
for(i = 0; i < auth_data->len ; i++) {
900
ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
901
if (ret) {
902
krb5_set_error_message(context, ret, "malloc: out of memory");
903
goto out;
904
}
905
}
906
907
/* Filter out type KRB5SignedPath */
908
ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
909
if (ret == 0) {
910
if (et.authorization_data->len == 1) {
911
free_AuthorizationData(et.authorization_data);
912
free(et.authorization_data);
913
et.authorization_data = NULL;
914
} else {
915
AuthorizationData *ad = et.authorization_data;
916
free_AuthorizationDataElement(&ad->val[ad->len - 1]);
917
ad->len--;
918
}
919
}
920
}
921
922
ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
923
if (ret)
924
goto out;
925
et.crealm = tgt_name->realm;
926
et.cname = tgt_name->name;
927
928
ek.key = et.key;
929
/* MIT must have at least one last_req */
930
ek.last_req.len = 1;
931
ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
932
if (ek.last_req.val == NULL) {
933
ret = ENOMEM;
934
goto out;
935
}
936
ek.nonce = b->nonce;
937
ek.flags = et.flags;
938
ek.authtime = et.authtime;
939
ek.starttime = et.starttime;
940
ek.endtime = et.endtime;
941
ek.renew_till = et.renew_till;
942
ek.srealm = rep.ticket.realm;
943
ek.sname = rep.ticket.sname;
944
945
_kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
946
et.endtime, et.renew_till);
947
948
/* Don't sign cross realm tickets, they can't be checked anyway */
949
{
950
char *r = get_krbtgt_realm(&ek.sname);
951
952
if (r == NULL || strcmp(r, ek.srealm) == 0) {
953
ret = _kdc_add_KRB5SignedPath(context,
954
config,
955
krbtgt,
956
krbtgt_etype,
957
client_principal,
958
NULL,
959
spp,
960
&et);
961
if (ret)
962
goto out;
963
}
964
}
965
966
if (enc_pa_data->len) {
967
rep.padata = calloc(1, sizeof(*rep.padata));
968
if (rep.padata == NULL) {
969
ret = ENOMEM;
970
goto out;
971
}
972
ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
973
if (ret)
974
goto out;
975
}
976
977
if (krb5_enctype_valid(context, et.key.keytype) != 0
978
&& _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
979
{
980
krb5_enctype_enable(context, et.key.keytype);
981
is_weak = 1;
982
}
983
984
985
/* It is somewhat unclear where the etype in the following
986
encryption should come from. What we have is a session
987
key in the passed tgt, and a list of preferred etypes
988
*for the new ticket*. Should we pick the best possible
989
etype, given the keytype in the tgt, or should we look
990
at the etype list here as well? What if the tgt
991
session key is DES3 and we want a ticket with a (say)
992
CAST session key. Should the DES3 etype be added to the
993
etype list, even if we don't want a session key with
994
DES3? */
995
ret = _kdc_encode_reply(context, config,
996
&rep, &et, &ek, et.key.keytype,
997
kvno,
998
serverkey, 0, replykey, rk_is_subkey,
999
e_text, reply);
1000
if (is_weak)
1001
krb5_enctype_disable(context, et.key.keytype);
1002
1003
out:
1004
free_TGS_REP(&rep);
1005
free_TransitedEncoding(&et.transited);
1006
if(et.starttime)
1007
free(et.starttime);
1008
if(et.renew_till)
1009
free(et.renew_till);
1010
if(et.authorization_data) {
1011
free_AuthorizationData(et.authorization_data);
1012
free(et.authorization_data);
1013
}
1014
free_LastReq(&ek.last_req);
1015
memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1016
free_EncryptionKey(&et.key);
1017
return ret;
1018
}
1019
1020
static krb5_error_code
1021
tgs_check_authenticator(krb5_context context,
1022
krb5_kdc_configuration *config,
1023
krb5_auth_context ac,
1024
KDC_REQ_BODY *b,
1025
const char **e_text,
1026
krb5_keyblock *key)
1027
{
1028
krb5_authenticator auth;
1029
size_t len = 0;
1030
unsigned char *buf;
1031
size_t buf_size;
1032
krb5_error_code ret;
1033
krb5_crypto crypto;
1034
1035
krb5_auth_con_getauthenticator(context, ac, &auth);
1036
if(auth->cksum == NULL){
1037
kdc_log(context, config, 0, "No authenticator in request");
1038
ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1039
goto out;
1040
}
1041
/*
1042
* according to RFC1510 it doesn't need to be keyed,
1043
* but according to the latest draft it needs to.
1044
*/
1045
if (
1046
#if 0
1047
!krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1048
||
1049
#endif
1050
!krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1051
kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
1052
auth->cksum->cksumtype);
1053
ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1054
goto out;
1055
}
1056
1057
/* XXX should not re-encode this */
1058
ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1059
if(ret){
1060
const char *msg = krb5_get_error_message(context, ret);
1061
kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1062
krb5_free_error_message(context, msg);
1063
goto out;
1064
}
1065
if(buf_size != len) {
1066
free(buf);
1067
kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1068
*e_text = "KDC internal error";
1069
ret = KRB5KRB_ERR_GENERIC;
1070
goto out;
1071
}
1072
ret = krb5_crypto_init(context, key, 0, &crypto);
1073
if (ret) {
1074
const char *msg = krb5_get_error_message(context, ret);
1075
free(buf);
1076
kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1077
krb5_free_error_message(context, msg);
1078
goto out;
1079
}
1080
ret = krb5_verify_checksum(context,
1081
crypto,
1082
KRB5_KU_TGS_REQ_AUTH_CKSUM,
1083
buf,
1084
len,
1085
auth->cksum);
1086
free(buf);
1087
krb5_crypto_destroy(context, crypto);
1088
if(ret){
1089
const char *msg = krb5_get_error_message(context, ret);
1090
kdc_log(context, config, 0,
1091
"Failed to verify authenticator checksum: %s", msg);
1092
krb5_free_error_message(context, msg);
1093
}
1094
out:
1095
free_Authenticator(auth);
1096
free(auth);
1097
return ret;
1098
}
1099
1100
/*
1101
*
1102
*/
1103
1104
static const char *
1105
find_rpath(krb5_context context, Realm crealm, Realm srealm)
1106
{
1107
const char *new_realm = krb5_config_get_string(context,
1108
NULL,
1109
"capaths",
1110
crealm,
1111
srealm,
1112
NULL);
1113
return new_realm;
1114
}
1115
1116
1117
static krb5_boolean
1118
need_referral(krb5_context context, krb5_kdc_configuration *config,
1119
const KDCOptions * const options, krb5_principal server,
1120
krb5_realm **realms)
1121
{
1122
const char *name;
1123
1124
if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1125
return FALSE;
1126
1127
if (server->name.name_string.len == 1)
1128
name = server->name.name_string.val[0];
1129
else if (server->name.name_string.len > 1)
1130
name = server->name.name_string.val[1];
1131
else
1132
return FALSE;
1133
1134
kdc_log(context, config, 0, "Searching referral for %s", name);
1135
1136
return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1137
}
1138
1139
static krb5_error_code
1140
tgs_parse_request(krb5_context context,
1141
krb5_kdc_configuration *config,
1142
KDC_REQ_BODY *b,
1143
const PA_DATA *tgs_req,
1144
hdb_entry_ex **krbtgt,
1145
krb5_enctype *krbtgt_etype,
1146
krb5_ticket **ticket,
1147
const char **e_text,
1148
const char *from,
1149
const struct sockaddr *from_addr,
1150
time_t **csec,
1151
int **cusec,
1152
AuthorizationData **auth_data,
1153
krb5_keyblock **replykey,
1154
int *rk_is_subkey)
1155
{
1156
static char failed[] = "<unparse_name failed>";
1157
krb5_ap_req ap_req;
1158
krb5_error_code ret;
1159
krb5_principal princ;
1160
krb5_auth_context ac = NULL;
1161
krb5_flags ap_req_options;
1162
krb5_flags verify_ap_req_flags;
1163
krb5_crypto crypto;
1164
Key *tkey;
1165
krb5_keyblock *subkey = NULL;
1166
unsigned usage;
1167
1168
*auth_data = NULL;
1169
*csec = NULL;
1170
*cusec = NULL;
1171
*replykey = NULL;
1172
1173
memset(&ap_req, 0, sizeof(ap_req));
1174
ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1175
if(ret){
1176
const char *msg = krb5_get_error_message(context, ret);
1177
kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1178
krb5_free_error_message(context, msg);
1179
goto out;
1180
}
1181
1182
if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1183
/* XXX check for ticket.sname == req.sname */
1184
kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1185
ret = KRB5KDC_ERR_POLICY; /* ? */
1186
goto out;
1187
}
1188
1189
_krb5_principalname2krb5_principal(context,
1190
&princ,
1191
ap_req.ticket.sname,
1192
ap_req.ticket.realm);
1193
1194
ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, krbtgt);
1195
1196
if(ret == HDB_ERR_NOT_FOUND_HERE) {
1197
char *p;
1198
ret = krb5_unparse_name(context, princ, &p);
1199
if (ret != 0)
1200
p = failed;
1201
krb5_free_principal(context, princ);
1202
kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
1203
if (ret == 0)
1204
free(p);
1205
ret = HDB_ERR_NOT_FOUND_HERE;
1206
goto out;
1207
} else if(ret){
1208
const char *msg = krb5_get_error_message(context, ret);
1209
char *p;
1210
ret = krb5_unparse_name(context, princ, &p);
1211
if (ret != 0)
1212
p = failed;
1213
krb5_free_principal(context, princ);
1214
kdc_log(context, config, 0,
1215
"Ticket-granting ticket not found in database: %s", msg);
1216
krb5_free_error_message(context, msg);
1217
if (ret == 0)
1218
free(p);
1219
ret = KRB5KRB_AP_ERR_NOT_US;
1220
goto out;
1221
}
1222
1223
if(ap_req.ticket.enc_part.kvno &&
1224
*ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1225
char *p;
1226
1227
ret = krb5_unparse_name (context, princ, &p);
1228
krb5_free_principal(context, princ);
1229
if (ret != 0)
1230
p = failed;
1231
kdc_log(context, config, 0,
1232
"Ticket kvno = %d, DB kvno = %d (%s)",
1233
*ap_req.ticket.enc_part.kvno,
1234
(*krbtgt)->entry.kvno,
1235
p);
1236
if (ret == 0)
1237
free (p);
1238
ret = KRB5KRB_AP_ERR_BADKEYVER;
1239
goto out;
1240
}
1241
1242
*krbtgt_etype = ap_req.ticket.enc_part.etype;
1243
1244
ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1245
ap_req.ticket.enc_part.etype, &tkey);
1246
if(ret){
1247
char *str = NULL, *p = NULL;
1248
1249
krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1250
krb5_unparse_name(context, princ, &p);
1251
kdc_log(context, config, 0,
1252
"No server key with enctype %s found for %s",
1253
str ? str : "<unknown enctype>",
1254
p ? p : "<unparse_name failed>");
1255
free(str);
1256
free(p);
1257
ret = KRB5KRB_AP_ERR_BADKEYVER;
1258
goto out;
1259
}
1260
1261
if (b->kdc_options.validate)
1262
verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1263
else
1264
verify_ap_req_flags = 0;
1265
1266
ret = krb5_verify_ap_req2(context,
1267
&ac,
1268
&ap_req,
1269
princ,
1270
&tkey->key,
1271
verify_ap_req_flags,
1272
&ap_req_options,
1273
ticket,
1274
KRB5_KU_TGS_REQ_AUTH);
1275
1276
krb5_free_principal(context, princ);
1277
if(ret) {
1278
const char *msg = krb5_get_error_message(context, ret);
1279
kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1280
krb5_free_error_message(context, msg);
1281
goto out;
1282
}
1283
1284
{
1285
krb5_authenticator auth;
1286
1287
ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1288
if (ret == 0) {
1289
*csec = malloc(sizeof(**csec));
1290
if (*csec == NULL) {
1291
krb5_free_authenticator(context, &auth);
1292
kdc_log(context, config, 0, "malloc failed");
1293
goto out;
1294
}
1295
**csec = auth->ctime;
1296
*cusec = malloc(sizeof(**cusec));
1297
if (*cusec == NULL) {
1298
krb5_free_authenticator(context, &auth);
1299
kdc_log(context, config, 0, "malloc failed");
1300
goto out;
1301
}
1302
**cusec = auth->cusec;
1303
krb5_free_authenticator(context, &auth);
1304
}
1305
}
1306
1307
ret = tgs_check_authenticator(context, config,
1308
ac, b, e_text, &(*ticket)->ticket.key);
1309
if (ret) {
1310
krb5_auth_con_free(context, ac);
1311
goto out;
1312
}
1313
1314
usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1315
*rk_is_subkey = 1;
1316
1317
ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1318
if(ret){
1319
const char *msg = krb5_get_error_message(context, ret);
1320
krb5_auth_con_free(context, ac);
1321
kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1322
krb5_free_error_message(context, msg);
1323
goto out;
1324
}
1325
if(subkey == NULL){
1326
usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1327
*rk_is_subkey = 0;
1328
1329
ret = krb5_auth_con_getkey(context, ac, &subkey);
1330
if(ret) {
1331
const char *msg = krb5_get_error_message(context, ret);
1332
krb5_auth_con_free(context, ac);
1333
kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1334
krb5_free_error_message(context, msg);
1335
goto out;
1336
}
1337
}
1338
if(subkey == NULL){
1339
krb5_auth_con_free(context, ac);
1340
kdc_log(context, config, 0,
1341
"Failed to get key for enc-authorization-data");
1342
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1343
goto out;
1344
}
1345
1346
*replykey = subkey;
1347
1348
if (b->enc_authorization_data) {
1349
krb5_data ad;
1350
1351
ret = krb5_crypto_init(context, subkey, 0, &crypto);
1352
if (ret) {
1353
const char *msg = krb5_get_error_message(context, ret);
1354
krb5_auth_con_free(context, ac);
1355
kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1356
krb5_free_error_message(context, msg);
1357
goto out;
1358
}
1359
ret = krb5_decrypt_EncryptedData (context,
1360
crypto,
1361
usage,
1362
b->enc_authorization_data,
1363
&ad);
1364
krb5_crypto_destroy(context, crypto);
1365
if(ret){
1366
krb5_auth_con_free(context, ac);
1367
kdc_log(context, config, 0,
1368
"Failed to decrypt enc-authorization-data");
1369
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1370
goto out;
1371
}
1372
ALLOC(*auth_data);
1373
if (*auth_data == NULL) {
1374
krb5_auth_con_free(context, ac);
1375
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1376
goto out;
1377
}
1378
ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1379
if(ret){
1380
krb5_auth_con_free(context, ac);
1381
free(*auth_data);
1382
*auth_data = NULL;
1383
kdc_log(context, config, 0, "Failed to decode authorization data");
1384
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1385
goto out;
1386
}
1387
}
1388
1389
krb5_auth_con_free(context, ac);
1390
1391
out:
1392
free_AP_REQ(&ap_req);
1393
1394
return ret;
1395
}
1396
1397
static krb5_error_code
1398
build_server_referral(krb5_context context,
1399
krb5_kdc_configuration *config,
1400
krb5_crypto session,
1401
krb5_const_realm referred_realm,
1402
const PrincipalName *true_principal_name,
1403
const PrincipalName *requested_principal,
1404
krb5_data *outdata)
1405
{
1406
PA_ServerReferralData ref;
1407
krb5_error_code ret;
1408
EncryptedData ed;
1409
krb5_data data;
1410
size_t size = 0;
1411
1412
memset(&ref, 0, sizeof(ref));
1413
1414
if (referred_realm) {
1415
ALLOC(ref.referred_realm);
1416
if (ref.referred_realm == NULL)
1417
goto eout;
1418
*ref.referred_realm = strdup(referred_realm);
1419
if (*ref.referred_realm == NULL)
1420
goto eout;
1421
}
1422
if (true_principal_name) {
1423
ALLOC(ref.true_principal_name);
1424
if (ref.true_principal_name == NULL)
1425
goto eout;
1426
ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1427
if (ret)
1428
goto eout;
1429
}
1430
if (requested_principal) {
1431
ALLOC(ref.requested_principal_name);
1432
if (ref.requested_principal_name == NULL)
1433
goto eout;
1434
ret = copy_PrincipalName(requested_principal,
1435
ref.requested_principal_name);
1436
if (ret)
1437
goto eout;
1438
}
1439
1440
ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1441
data.data, data.length,
1442
&ref, &size, ret);
1443
free_PA_ServerReferralData(&ref);
1444
if (ret)
1445
return ret;
1446
if (data.length != size)
1447
krb5_abortx(context, "internal asn.1 encoder error");
1448
1449
ret = krb5_encrypt_EncryptedData(context, session,
1450
KRB5_KU_PA_SERVER_REFERRAL,
1451
data.data, data.length,
1452
0 /* kvno */, &ed);
1453
free(data.data);
1454
if (ret)
1455
return ret;
1456
1457
ASN1_MALLOC_ENCODE(EncryptedData,
1458
outdata->data, outdata->length,
1459
&ed, &size, ret);
1460
free_EncryptedData(&ed);
1461
if (ret)
1462
return ret;
1463
if (outdata->length != size)
1464
krb5_abortx(context, "internal asn.1 encoder error");
1465
1466
return 0;
1467
eout:
1468
free_PA_ServerReferralData(&ref);
1469
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1470
return ENOMEM;
1471
}
1472
1473
static krb5_error_code
1474
tgs_build_reply(krb5_context context,
1475
krb5_kdc_configuration *config,
1476
KDC_REQ *req,
1477
KDC_REQ_BODY *b,
1478
hdb_entry_ex *krbtgt,
1479
krb5_enctype krbtgt_etype,
1480
const krb5_keyblock *replykey,
1481
int rk_is_subkey,
1482
krb5_ticket *ticket,
1483
krb5_data *reply,
1484
const char *from,
1485
const char **e_text,
1486
AuthorizationData **auth_data,
1487
const struct sockaddr *from_addr)
1488
{
1489
krb5_error_code ret;
1490
krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
1491
krb5_principal krbtgt_principal = NULL;
1492
char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
1493
hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1494
HDB *clientdb, *s4u2self_impersonated_clientdb;
1495
krb5_realm ref_realm = NULL;
1496
EncTicketPart *tgt = &ticket->ticket;
1497
krb5_principals spp = NULL;
1498
const EncryptionKey *ekey;
1499
krb5_keyblock sessionkey;
1500
krb5_kvno kvno;
1501
krb5_data rspac;
1502
const char *tgt_realm = /* Realm of TGT issuer */
1503
krb5_principal_get_realm(context, krbtgt->entry.principal);
1504
1505
hdb_entry_ex *krbtgt_out = NULL;
1506
1507
METHOD_DATA enc_pa_data;
1508
1509
PrincipalName *s;
1510
Realm r;
1511
int nloop = 0;
1512
EncTicketPart adtkt;
1513
char opt_str[128];
1514
int signedpath = 0;
1515
1516
Key *tkey_check;
1517
Key *tkey_sign;
1518
int flags = HDB_F_FOR_TGS_REQ;
1519
1520
memset(&sessionkey, 0, sizeof(sessionkey));
1521
memset(&adtkt, 0, sizeof(adtkt));
1522
krb5_data_zero(&rspac);
1523
memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1524
1525
s = b->sname;
1526
r = b->realm;
1527
1528
/*
1529
* Always to do CANON, see comment below about returned server principal (rsp).
1530
*/
1531
flags |= HDB_F_CANON;
1532
1533
if(b->kdc_options.enc_tkt_in_skey){
1534
Ticket *t;
1535
hdb_entry_ex *uu;
1536
krb5_principal p;
1537
Key *uukey;
1538
1539
if(b->additional_tickets == NULL ||
1540
b->additional_tickets->len == 0){
1541
ret = KRB5KDC_ERR_BADOPTION; /* ? */
1542
kdc_log(context, config, 0,
1543
"No second ticket present in request");
1544
goto out;
1545
}
1546
t = &b->additional_tickets->val[0];
1547
if(!get_krbtgt_realm(&t->sname)){
1548
kdc_log(context, config, 0,
1549
"Additional ticket is not a ticket-granting ticket");
1550
ret = KRB5KDC_ERR_POLICY;
1551
goto out;
1552
}
1553
_krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1554
ret = _kdc_db_fetch(context, config, p,
1555
HDB_F_GET_KRBTGT, t->enc_part.kvno,
1556
NULL, &uu);
1557
krb5_free_principal(context, p);
1558
if(ret){
1559
if (ret == HDB_ERR_NOENTRY)
1560
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1561
goto out;
1562
}
1563
ret = hdb_enctype2key(context, &uu->entry,
1564
t->enc_part.etype, &uukey);
1565
if(ret){
1566
_kdc_free_ent(context, uu);
1567
ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1568
goto out;
1569
}
1570
ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1571
_kdc_free_ent(context, uu);
1572
if(ret)
1573
goto out;
1574
1575
ret = verify_flags(context, config, &adtkt, spn);
1576
if (ret)
1577
goto out;
1578
1579
s = &adtkt.cname;
1580
r = adtkt.crealm;
1581
}
1582
1583
_krb5_principalname2krb5_principal(context, &sp, *s, r);
1584
ret = krb5_unparse_name(context, sp, &spn);
1585
if (ret)
1586
goto out;
1587
_krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1588
ret = krb5_unparse_name(context, cp, &cpn);
1589
if (ret)
1590
goto out;
1591
unparse_flags (KDCOptions2int(b->kdc_options),
1592
asn1_KDCOptions_units(),
1593
opt_str, sizeof(opt_str));
1594
if(*opt_str)
1595
kdc_log(context, config, 0,
1596
"TGS-REQ %s from %s for %s [%s]",
1597
cpn, from, spn, opt_str);
1598
else
1599
kdc_log(context, config, 0,
1600
"TGS-REQ %s from %s for %s", cpn, from, spn);
1601
1602
/*
1603
* Fetch server
1604
*/
1605
1606
server_lookup:
1607
ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1608
NULL, NULL, &server);
1609
1610
if(ret == HDB_ERR_NOT_FOUND_HERE) {
1611
kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1612
goto out;
1613
} else if(ret){
1614
const char *new_rlm, *msg;
1615
Realm req_rlm;
1616
krb5_realm *realms;
1617
1618
if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1619
if(nloop++ < 2) {
1620
new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1621
if(new_rlm) {
1622
kdc_log(context, config, 5, "krbtgt for realm %s "
1623
"not found, trying %s",
1624
req_rlm, new_rlm);
1625
krb5_free_principal(context, sp);
1626
free(spn);
1627
krb5_make_principal(context, &sp, r,
1628
KRB5_TGS_NAME, new_rlm, NULL);
1629
ret = krb5_unparse_name(context, sp, &spn);
1630
if (ret)
1631
goto out;
1632
1633
if (ref_realm)
1634
free(ref_realm);
1635
ref_realm = strdup(new_rlm);
1636
goto server_lookup;
1637
}
1638
}
1639
} else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1640
if (strcmp(realms[0], sp->realm) != 0) {
1641
kdc_log(context, config, 5,
1642
"Returning a referral to realm %s for "
1643
"server %s that was not found",
1644
realms[0], spn);
1645
krb5_free_principal(context, sp);
1646
free(spn);
1647
krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1648
realms[0], NULL);
1649
ret = krb5_unparse_name(context, sp, &spn);
1650
if (ret)
1651
goto out;
1652
1653
if (ref_realm)
1654
free(ref_realm);
1655
ref_realm = strdup(realms[0]);
1656
1657
krb5_free_host_realm(context, realms);
1658
goto server_lookup;
1659
}
1660
krb5_free_host_realm(context, realms);
1661
}
1662
msg = krb5_get_error_message(context, ret);
1663
kdc_log(context, config, 0,
1664
"Server not found in database: %s: %s", spn, msg);
1665
krb5_free_error_message(context, msg);
1666
if (ret == HDB_ERR_NOENTRY)
1667
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1668
goto out;
1669
}
1670
1671
/* the name returned to the client depend on what was asked for,
1672
* return canonical name if kdc_options.canonicalize was set, the
1673
* client wants the true name of the principal, if not it just
1674
* wants the name its asked for.
1675
*/
1676
1677
if (b->kdc_options.canonicalize)
1678
rsp = server->entry.principal;
1679
else
1680
rsp = sp;
1681
1682
1683
/*
1684
* Select enctype, return key and kvno.
1685
*/
1686
1687
{
1688
krb5_enctype etype;
1689
1690
if(b->kdc_options.enc_tkt_in_skey) {
1691
size_t i;
1692
ekey = &adtkt.key;
1693
for(i = 0; i < b->etype.len; i++)
1694
if (b->etype.val[i] == adtkt.key.keytype)
1695
break;
1696
if(i == b->etype.len) {
1697
kdc_log(context, config, 0,
1698
"Addition ticket have not matching etypes");
1699
krb5_clear_error_message(context);
1700
ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1701
goto out;
1702
}
1703
etype = b->etype.val[i];
1704
kvno = 0;
1705
} else {
1706
Key *skey;
1707
1708
ret = _kdc_find_etype(context,
1709
krb5_principal_is_krbtgt(context, sp) ?
1710
config->tgt_use_strongest_session_key :
1711
config->svc_use_strongest_session_key, FALSE,
1712
server, b->etype.val, b->etype.len, NULL,
1713
&skey);
1714
if(ret) {
1715
kdc_log(context, config, 0,
1716
"Server (%s) has no support for etypes", spn);
1717
goto out;
1718
}
1719
ekey = &skey->key;
1720
etype = skey->key.keytype;
1721
kvno = server->entry.kvno;
1722
}
1723
1724
ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1725
if (ret)
1726
goto out;
1727
}
1728
1729
/*
1730
* Check that service is in the same realm as the krbtgt. If it's
1731
* not the same, it's someone that is using a uni-directional trust
1732
* backward.
1733
*/
1734
1735
/*
1736
* Validate authoriation data
1737
*/
1738
1739
ret = hdb_enctype2key(context, &krbtgt->entry,
1740
krbtgt_etype, &tkey_check);
1741
if(ret) {
1742
kdc_log(context, config, 0,
1743
"Failed to find key for krbtgt PAC check");
1744
goto out;
1745
}
1746
1747
/* Now refetch the primary krbtgt, and get the current kvno (the
1748
* sign check may have been on an old kvno, and the server may
1749
* have been an incoming trust) */
1750
ret = krb5_make_principal(context, &krbtgt_principal,
1751
krb5_principal_get_comp_string(context,
1752
krbtgt->entry.principal,
1753
1),
1754
KRB5_TGS_NAME,
1755
krb5_principal_get_comp_string(context,
1756
krbtgt->entry.principal,
1757
1), NULL);
1758
if(ret) {
1759
kdc_log(context, config, 0,
1760
"Failed to generate krbtgt principal");
1761
goto out;
1762
}
1763
1764
ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1765
krb5_free_principal(context, krbtgt_principal);
1766
if (ret) {
1767
krb5_error_code ret2;
1768
char *ktpn, *ktpn2;
1769
ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1770
ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
1771
kdc_log(context, config, 0,
1772
"Request with wrong krbtgt: %s, %s not found in our database",
1773
(ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>");
1774
if(ret == 0)
1775
free(ktpn);
1776
if(ret2 == 0)
1777
free(ktpn2);
1778
ret = KRB5KRB_AP_ERR_NOT_US;
1779
goto out;
1780
}
1781
1782
/* The first realm is the realm of the service, the second is
1783
* krbtgt/<this>/@REALM component of the krbtgt DN the request was
1784
* encrypted to. The redirection via the krbtgt_out entry allows
1785
* the DB to possibly correct the case of the realm (Samba4 does
1786
* this) before the strcmp() */
1787
if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1788
krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1789
char *ktpn;
1790
ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1791
kdc_log(context, config, 0,
1792
"Request with wrong krbtgt: %s",
1793
(ret == 0) ? ktpn : "<unknown>");
1794
if(ret == 0)
1795
free(ktpn);
1796
ret = KRB5KRB_AP_ERR_NOT_US;
1797
}
1798
1799
ret = hdb_enctype2key(context, &krbtgt_out->entry,
1800
krbtgt_etype, &tkey_sign);
1801
if(ret) {
1802
kdc_log(context, config, 0,
1803
"Failed to find key for krbtgt PAC signature");
1804
goto out;
1805
}
1806
1807
ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1808
NULL, &clientdb, &client);
1809
if(ret == HDB_ERR_NOT_FOUND_HERE) {
1810
/* This is OK, we are just trying to find out if they have
1811
* been disabled or deleted in the meantime, missing secrets
1812
* is OK */
1813
} else if(ret){
1814
const char *krbtgt_realm, *msg;
1815
1816
/*
1817
* If the client belongs to the same realm as our krbtgt, it
1818
* should exist in the local database.
1819
*
1820
*/
1821
1822
krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1823
1824
if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1825
if (ret == HDB_ERR_NOENTRY)
1826
ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1827
kdc_log(context, config, 1, "Client no longer in database: %s",
1828
cpn);
1829
goto out;
1830
}
1831
1832
msg = krb5_get_error_message(context, ret);
1833
kdc_log(context, config, 1, "Client not found in database: %s", msg);
1834
krb5_free_error_message(context, msg);
1835
}
1836
1837
ret = check_PAC(context, config, cp, NULL,
1838
client, server, krbtgt,
1839
&tkey_check->key, &tkey_check->key,
1840
ekey, &tkey_sign->key,
1841
tgt, &rspac, &signedpath);
1842
if (ret) {
1843
const char *msg = krb5_get_error_message(context, ret);
1844
kdc_log(context, config, 0,
1845
"Verify PAC failed for %s (%s) from %s with %s",
1846
spn, cpn, from, msg);
1847
krb5_free_error_message(context, msg);
1848
goto out;
1849
}
1850
1851
/* also check the krbtgt for signature */
1852
ret = check_KRB5SignedPath(context,
1853
config,
1854
krbtgt,
1855
cp,
1856
tgt,
1857
&spp,
1858
&signedpath);
1859
if (ret) {
1860
const char *msg = krb5_get_error_message(context, ret);
1861
kdc_log(context, config, 0,
1862
"KRB5SignedPath check failed for %s (%s) from %s with %s",
1863
spn, cpn, from, msg);
1864
krb5_free_error_message(context, msg);
1865
goto out;
1866
}
1867
1868
/*
1869
* Process request
1870
*/
1871
1872
/* by default the tgt principal matches the client principal */
1873
tp = cp;
1874
tpn = cpn;
1875
1876
if (client) {
1877
const PA_DATA *sdata;
1878
int i = 0;
1879
1880
sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1881
if (sdata) {
1882
krb5_crypto crypto;
1883
krb5_data datack;
1884
PA_S4U2Self self;
1885
const char *str;
1886
1887
ret = decode_PA_S4U2Self(sdata->padata_value.data,
1888
sdata->padata_value.length,
1889
&self, NULL);
1890
if (ret) {
1891
kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1892
goto out;
1893
}
1894
1895
if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
1896
free_PA_S4U2Self(&self);
1897
kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
1898
ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1899
goto out;
1900
}
1901
1902
ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1903
if (ret)
1904
goto out;
1905
1906
ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1907
if (ret) {
1908
const char *msg = krb5_get_error_message(context, ret);
1909
free_PA_S4U2Self(&self);
1910
krb5_data_free(&datack);
1911
kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1912
krb5_free_error_message(context, msg);
1913
goto out;
1914
}
1915
1916
ret = krb5_verify_checksum(context,
1917
crypto,
1918
KRB5_KU_OTHER_CKSUM,
1919
datack.data,
1920
datack.length,
1921
&self.cksum);
1922
krb5_data_free(&datack);
1923
krb5_crypto_destroy(context, crypto);
1924
if (ret) {
1925
const char *msg = krb5_get_error_message(context, ret);
1926
free_PA_S4U2Self(&self);
1927
kdc_log(context, config, 0,
1928
"krb5_verify_checksum failed for S4U2Self: %s", msg);
1929
krb5_free_error_message(context, msg);
1930
goto out;
1931
}
1932
1933
ret = _krb5_principalname2krb5_principal(context,
1934
&tp,
1935
self.name,
1936
self.realm);
1937
free_PA_S4U2Self(&self);
1938
if (ret)
1939
goto out;
1940
1941
ret = krb5_unparse_name(context, tp, &tpn);
1942
if (ret)
1943
goto out;
1944
1945
ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
1946
NULL, &s4u2self_impersonated_clientdb,
1947
&s4u2self_impersonated_client);
1948
if (ret) {
1949
const char *msg;
1950
1951
/*
1952
* If the client belongs to the same realm as our krbtgt, it
1953
* should exist in the local database.
1954
*
1955
*/
1956
1957
if (ret == HDB_ERR_NOENTRY)
1958
ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1959
msg = krb5_get_error_message(context, ret);
1960
kdc_log(context, config, 2,
1961
"S4U2Self principal to impersonate %s not found in database: %s",
1962
tpn, msg);
1963
krb5_free_error_message(context, msg);
1964
goto out;
1965
}
1966
1967
free(s4u2self_impersonated_client->entry.pw_end);
1968
s4u2self_impersonated_client->entry.pw_end = NULL;
1969
1970
ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
1971
NULL, NULL, FALSE);
1972
if (ret)
1973
goto out;
1974
1975
/* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1976
if(rspac.data) {
1977
krb5_pac p = NULL;
1978
krb5_data_free(&rspac);
1979
ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
1980
if (ret) {
1981
kdc_log(context, config, 0, "PAC generation failed for -- %s",
1982
tpn);
1983
goto out;
1984
}
1985
if (p != NULL) {
1986
ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
1987
s4u2self_impersonated_client->entry.principal,
1988
ekey, &tkey_sign->key,
1989
&rspac);
1990
krb5_pac_free(context, p);
1991
if (ret) {
1992
kdc_log(context, config, 0, "PAC signing failed for -- %s",
1993
tpn);
1994
goto out;
1995
}
1996
}
1997
}
1998
1999
/*
2000
* Check that service doing the impersonating is
2001
* requesting a ticket to it-self.
2002
*/
2003
ret = check_s4u2self(context, config, clientdb, client, sp);
2004
if (ret) {
2005
kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
2006
"to impersonate to service "
2007
"(tried for user %s to service %s)",
2008
cpn, tpn, spn);
2009
goto out;
2010
}
2011
2012
/*
2013
* If the service isn't trusted for authentication to
2014
* delegation or if the impersonate client is disallowed
2015
* forwardable, remove the forwardable flag.
2016
*/
2017
2018
if (client->entry.flags.trusted_for_delegation &&
2019
s4u2self_impersonated_client->entry.flags.forwardable) {
2020
str = "[forwardable]";
2021
} else {
2022
b->kdc_options.forwardable = 0;
2023
str = "";
2024
}
2025
kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
2026
"service %s %s", cpn, tpn, spn, str);
2027
}
2028
}
2029
2030
/*
2031
* Constrained delegation
2032
*/
2033
2034
if (client != NULL
2035
&& b->additional_tickets != NULL
2036
&& b->additional_tickets->len != 0
2037
&& b->kdc_options.enc_tkt_in_skey == 0)
2038
{
2039
int ad_signedpath = 0;
2040
Key *clientkey;
2041
Ticket *t;
2042
2043
/*
2044
* Require that the KDC have issued the service's krbtgt (not
2045
* self-issued ticket with kimpersonate(1).
2046
*/
2047
if (!signedpath) {
2048
ret = KRB5KDC_ERR_BADOPTION;
2049
kdc_log(context, config, 0,
2050
"Constrained delegation done on service ticket %s/%s",
2051
cpn, spn);
2052
goto out;
2053
}
2054
2055
t = &b->additional_tickets->val[0];
2056
2057
ret = hdb_enctype2key(context, &client->entry,
2058
t->enc_part.etype, &clientkey);
2059
if(ret){
2060
ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2061
goto out;
2062
}
2063
2064
ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2065
if (ret) {
2066
kdc_log(context, config, 0,
2067
"failed to decrypt ticket for "
2068
"constrained delegation from %s to %s ", cpn, spn);
2069
goto out;
2070
}
2071
2072
ret = _krb5_principalname2krb5_principal(context,
2073
&tp,
2074
adtkt.cname,
2075
adtkt.crealm);
2076
if (ret)
2077
goto out;
2078
2079
ret = krb5_unparse_name(context, tp, &tpn);
2080
if (ret)
2081
goto out;
2082
2083
ret = _krb5_principalname2krb5_principal(context,
2084
&dp,
2085
t->sname,
2086
t->realm);
2087
if (ret)
2088
goto out;
2089
2090
ret = krb5_unparse_name(context, dp, &dpn);
2091
if (ret)
2092
goto out;
2093
2094
/* check that ticket is valid */
2095
if (adtkt.flags.forwardable == 0) {
2096
kdc_log(context, config, 0,
2097
"Missing forwardable flag on ticket for "
2098
"constrained delegation from %s (%s) as %s to %s ",
2099
cpn, dpn, tpn, spn);
2100
ret = KRB5KDC_ERR_BADOPTION;
2101
goto out;
2102
}
2103
2104
ret = check_constrained_delegation(context, config, clientdb,
2105
client, server, sp);
2106
if (ret) {
2107
kdc_log(context, config, 0,
2108
"constrained delegation from %s (%s) as %s to %s not allowed",
2109
cpn, dpn, tpn, spn);
2110
goto out;
2111
}
2112
2113
ret = verify_flags(context, config, &adtkt, tpn);
2114
if (ret) {
2115
goto out;
2116
}
2117
2118
krb5_data_free(&rspac);
2119
2120
/*
2121
* generate the PAC for the user.
2122
*
2123
* TODO: pass in t->sname and t->realm and build
2124
* a S4U_DELEGATION_INFO blob to the PAC.
2125
*/
2126
ret = check_PAC(context, config, tp, dp,
2127
client, server, krbtgt,
2128
&clientkey->key, &tkey_check->key,
2129
ekey, &tkey_sign->key,
2130
&adtkt, &rspac, &ad_signedpath);
2131
if (ret) {
2132
const char *msg = krb5_get_error_message(context, ret);
2133
kdc_log(context, config, 0,
2134
"Verify delegated PAC failed to %s for client"
2135
"%s (%s) as %s from %s with %s",
2136
spn, cpn, dpn, tpn, from, msg);
2137
krb5_free_error_message(context, msg);
2138
goto out;
2139
}
2140
2141
/*
2142
* Check that the KDC issued the user's ticket.
2143
*/
2144
ret = check_KRB5SignedPath(context,
2145
config,
2146
krbtgt,
2147
cp,
2148
&adtkt,
2149
NULL,
2150
&ad_signedpath);
2151
if (ret) {
2152
const char *msg = krb5_get_error_message(context, ret);
2153
kdc_log(context, config, 0,
2154
"KRB5SignedPath check from service %s failed "
2155
"for delegation to %s for client %s (%s)"
2156
"from %s failed with %s",
2157
spn, tpn, dpn, cpn, from, msg);
2158
krb5_free_error_message(context, msg);
2159
goto out;
2160
}
2161
2162
if (!ad_signedpath) {
2163
ret = KRB5KDC_ERR_BADOPTION;
2164
kdc_log(context, config, 0,
2165
"Ticket not signed with PAC nor SignedPath service %s failed "
2166
"for delegation to %s for client %s (%s)"
2167
"from %s",
2168
spn, tpn, dpn, cpn, from);
2169
goto out;
2170
}
2171
2172
kdc_log(context, config, 0, "constrained delegation for %s "
2173
"from %s (%s) to %s", tpn, cpn, dpn, spn);
2174
}
2175
2176
/*
2177
* Check flags
2178
*/
2179
2180
ret = kdc_check_flags(context, config,
2181
client, cpn,
2182
server, spn,
2183
FALSE);
2184
if(ret)
2185
goto out;
2186
2187
if((b->kdc_options.validate || b->kdc_options.renew) &&
2188
!krb5_principal_compare(context,
2189
krbtgt->entry.principal,
2190
server->entry.principal)){
2191
kdc_log(context, config, 0, "Inconsistent request.");
2192
ret = KRB5KDC_ERR_SERVER_NOMATCH;
2193
goto out;
2194
}
2195
2196
/* check for valid set of addresses */
2197
if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2198
ret = KRB5KRB_AP_ERR_BADADDR;
2199
kdc_log(context, config, 0, "Request from wrong address");
2200
goto out;
2201
}
2202
2203
/*
2204
* If this is an referral, add server referral data to the
2205
* auth_data reply .
2206
*/
2207
if (ref_realm) {
2208
PA_DATA pa;
2209
krb5_crypto crypto;
2210
2211
kdc_log(context, config, 0,
2212
"Adding server referral to %s", ref_realm);
2213
2214
ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2215
if (ret)
2216
goto out;
2217
2218
ret = build_server_referral(context, config, crypto, ref_realm,
2219
NULL, s, &pa.padata_value);
2220
krb5_crypto_destroy(context, crypto);
2221
if (ret) {
2222
kdc_log(context, config, 0,
2223
"Failed building server referral");
2224
goto out;
2225
}
2226
pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2227
2228
ret = add_METHOD_DATA(&enc_pa_data, &pa);
2229
krb5_data_free(&pa.padata_value);
2230
if (ret) {
2231
kdc_log(context, config, 0,
2232
"Add server referral METHOD-DATA failed");
2233
goto out;
2234
}
2235
}
2236
2237
/*
2238
*
2239
*/
2240
2241
ret = tgs_make_reply(context,
2242
config,
2243
b,
2244
tp,
2245
tgt,
2246
replykey,
2247
rk_is_subkey,
2248
ekey,
2249
&sessionkey,
2250
kvno,
2251
*auth_data,
2252
server,
2253
rsp,
2254
spn,
2255
client,
2256
cp,
2257
tgt_realm,
2258
krbtgt_out,
2259
krbtgt_etype,
2260
spp,
2261
&rspac,
2262
&enc_pa_data,
2263
e_text,
2264
reply);
2265
2266
out:
2267
if (tpn != cpn)
2268
free(tpn);
2269
free(spn);
2270
free(cpn);
2271
if (dpn)
2272
free(dpn);
2273
2274
krb5_data_free(&rspac);
2275
krb5_free_keyblock_contents(context, &sessionkey);
2276
if(krbtgt_out)
2277
_kdc_free_ent(context, krbtgt_out);
2278
if(server)
2279
_kdc_free_ent(context, server);
2280
if(client)
2281
_kdc_free_ent(context, client);
2282
if(s4u2self_impersonated_client)
2283
_kdc_free_ent(context, s4u2self_impersonated_client);
2284
2285
if (tp && tp != cp)
2286
krb5_free_principal(context, tp);
2287
if (cp)
2288
krb5_free_principal(context, cp);
2289
if (dp)
2290
krb5_free_principal(context, dp);
2291
if (sp)
2292
krb5_free_principal(context, sp);
2293
if (ref_realm)
2294
free(ref_realm);
2295
free_METHOD_DATA(&enc_pa_data);
2296
2297
free_EncTicketPart(&adtkt);
2298
2299
return ret;
2300
}
2301
2302
/*
2303
*
2304
*/
2305
2306
krb5_error_code
2307
_kdc_tgs_rep(krb5_context context,
2308
krb5_kdc_configuration *config,
2309
KDC_REQ *req,
2310
krb5_data *data,
2311
const char *from,
2312
struct sockaddr *from_addr,
2313
int datagram_reply)
2314
{
2315
AuthorizationData *auth_data = NULL;
2316
krb5_error_code ret;
2317
int i = 0;
2318
const PA_DATA *tgs_req;
2319
2320
hdb_entry_ex *krbtgt = NULL;
2321
krb5_ticket *ticket = NULL;
2322
const char *e_text = NULL;
2323
krb5_enctype krbtgt_etype = ETYPE_NULL;
2324
2325
krb5_keyblock *replykey = NULL;
2326
int rk_is_subkey = 0;
2327
time_t *csec = NULL;
2328
int *cusec = NULL;
2329
2330
if(req->padata == NULL){
2331
ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2332
kdc_log(context, config, 0,
2333
"TGS-REQ from %s without PA-DATA", from);
2334
goto out;
2335
}
2336
2337
tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2338
2339
if(tgs_req == NULL){
2340
ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2341
2342
kdc_log(context, config, 0,
2343
"TGS-REQ from %s without PA-TGS-REQ", from);
2344
goto out;
2345
}
2346
ret = tgs_parse_request(context, config,
2347
&req->req_body, tgs_req,
2348
&krbtgt,
2349
&krbtgt_etype,
2350
&ticket,
2351
&e_text,
2352
from, from_addr,
2353
&csec, &cusec,
2354
&auth_data,
2355
&replykey,
2356
&rk_is_subkey);
2357
if (ret == HDB_ERR_NOT_FOUND_HERE) {
2358
/* kdc_log() is called in tgs_parse_request() */
2359
goto out;
2360
}
2361
if (ret) {
2362
kdc_log(context, config, 0,
2363
"Failed parsing TGS-REQ from %s", from);
2364
goto out;
2365
}
2366
2367
ret = tgs_build_reply(context,
2368
config,
2369
req,
2370
&req->req_body,
2371
krbtgt,
2372
krbtgt_etype,
2373
replykey,
2374
rk_is_subkey,
2375
ticket,
2376
data,
2377
from,
2378
&e_text,
2379
&auth_data,
2380
from_addr);
2381
if (ret) {
2382
kdc_log(context, config, 0,
2383
"Failed building TGS-REP to %s", from);
2384
goto out;
2385
}
2386
2387
/* */
2388
if (datagram_reply && data->length > config->max_datagram_reply_length) {
2389
krb5_data_free(data);
2390
ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2391
e_text = "Reply packet too large";
2392
}
2393
2394
out:
2395
if (replykey)
2396
krb5_free_keyblock(context, replykey);
2397
if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2398
krb5_mk_error(context,
2399
ret,
2400
NULL,
2401
NULL,
2402
NULL,
2403
NULL,
2404
csec,
2405
cusec,
2406
data);
2407
ret = 0;
2408
}
2409
free(csec);
2410
free(cusec);
2411
if (ticket)
2412
krb5_free_ticket(context, ticket);
2413
if(krbtgt)
2414
_kdc_free_ent(context, krbtgt);
2415
2416
if (auth_data) {
2417
free_AuthorizationData(auth_data);
2418
free(auth_data);
2419
}
2420
2421
return ret;
2422
}
2423
2424