~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/kdc/krb5tgs.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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