~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/krb5/rd_req.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 - 2007 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 <krb5_locl.h>
 
35
 
 
36
RCSID("$Id$");
 
37
 
 
38
static krb5_error_code
 
39
decrypt_tkt_enc_part (krb5_context context,
 
40
                      krb5_keyblock *key,
 
41
                      EncryptedData *enc_part,
 
42
                      EncTicketPart *decr_part)
 
43
{
 
44
    krb5_error_code ret;
 
45
    krb5_data plain;
 
46
    size_t len;
 
47
    krb5_crypto crypto;
 
48
 
 
49
    ret = krb5_crypto_init(context, key, 0, &crypto);
 
50
    if (ret)
 
51
        return ret;
 
52
    ret = krb5_decrypt_EncryptedData (context,
 
53
                                      crypto,
 
54
                                      KRB5_KU_TICKET,
 
55
                                      enc_part,
 
56
                                      &plain);
 
57
    krb5_crypto_destroy(context, crypto);
 
58
    if (ret)
 
59
        return ret;
 
60
 
 
61
    ret = krb5_decode_EncTicketPart(context, plain.data, plain.length,
 
62
                                    decr_part, &len);
 
63
    krb5_data_free (&plain);
 
64
    return ret;
 
65
}
 
66
 
 
67
static krb5_error_code
 
68
decrypt_authenticator (krb5_context context,
 
69
                       EncryptionKey *key,
 
70
                       EncryptedData *enc_part,
 
71
                       Authenticator *authenticator,
 
72
                       krb5_key_usage usage)
 
73
{
 
74
    krb5_error_code ret;
 
75
    krb5_data plain;
 
76
    size_t len;
 
77
    krb5_crypto crypto;
 
78
 
 
79
    ret = krb5_crypto_init(context, key, 0, &crypto);
 
80
    if (ret)
 
81
        return ret;
 
82
    ret = krb5_decrypt_EncryptedData (context,
 
83
                                      crypto,
 
84
                                      usage /* KRB5_KU_AP_REQ_AUTH */,
 
85
                                      enc_part,
 
86
                                      &plain);
 
87
    /* for backwards compatibility, also try the old usage */
 
88
    if (ret && usage == KRB5_KU_TGS_REQ_AUTH)
 
89
        ret = krb5_decrypt_EncryptedData (context,
 
90
                                          crypto,
 
91
                                          KRB5_KU_AP_REQ_AUTH,
 
92
                                          enc_part,
 
93
                                          &plain);
 
94
    krb5_crypto_destroy(context, crypto);
 
95
    if (ret)
 
96
        return ret;
 
97
 
 
98
    ret = krb5_decode_Authenticator(context, plain.data, plain.length,
 
99
                                    authenticator, &len);
 
100
    krb5_data_free (&plain);
 
101
    return ret;
 
102
}
 
103
 
 
104
krb5_error_code KRB5_LIB_FUNCTION
 
105
krb5_decode_ap_req(krb5_context context,
 
106
                   const krb5_data *inbuf,
 
107
                   krb5_ap_req *ap_req)
 
108
{
 
109
    krb5_error_code ret;
 
110
    size_t len;
 
111
    ret = decode_AP_REQ(inbuf->data, inbuf->length, ap_req, &len);
 
112
    if (ret)
 
113
        return ret;
 
114
    if (ap_req->pvno != 5){
 
115
        free_AP_REQ(ap_req);
 
116
        krb5_clear_error_message (context);
 
117
        return KRB5KRB_AP_ERR_BADVERSION;
 
118
    }
 
119
    if (ap_req->msg_type != krb_ap_req){
 
120
        free_AP_REQ(ap_req);
 
121
        krb5_clear_error_message (context);
 
122
        return KRB5KRB_AP_ERR_MSG_TYPE;
 
123
    }
 
124
    if (ap_req->ticket.tkt_vno != 5){
 
125
        free_AP_REQ(ap_req);
 
126
        krb5_clear_error_message (context);
 
127
        return KRB5KRB_AP_ERR_BADVERSION;
 
128
    }
 
129
    return 0;
 
130
}
 
131
 
 
132
static krb5_error_code
 
133
check_transited(krb5_context context, Ticket *ticket, EncTicketPart *enc)
 
134
{
 
135
    char **realms;
 
136
    unsigned int num_realms;
 
137
    krb5_error_code ret;
 
138
        
 
139
    /*
 
140
     * Windows 2000 and 2003 uses this inside their TGT so it's normaly
 
141
     * not seen by others, however, samba4 joined with a Windows AD as
 
142
     * a Domain Controller gets exposed to this.
 
143
     */
 
144
    if(enc->transited.tr_type == 0 && enc->transited.contents.length == 0)
 
145
        return 0;
 
146
 
 
147
    if(enc->transited.tr_type != DOMAIN_X500_COMPRESS)
 
148
        return KRB5KDC_ERR_TRTYPE_NOSUPP;
 
149
 
 
150
    if(enc->transited.contents.length == 0)
 
151
        return 0;
 
152
 
 
153
    ret = krb5_domain_x500_decode(context, enc->transited.contents,
 
154
                                  &realms, &num_realms,
 
155
                                  enc->crealm,
 
156
                                  ticket->realm);
 
157
    if(ret)
 
158
        return ret;
 
159
    ret = krb5_check_transited(context, enc->crealm,
 
160
                               ticket->realm,
 
161
                               realms, num_realms, NULL);
 
162
    free(realms);
 
163
    return ret;
 
164
}
 
165
 
 
166
static krb5_error_code
 
167
find_etypelist(krb5_context context,
 
168
               krb5_auth_context auth_context,
 
169
               EtypeList *etypes)
 
170
{
 
171
    krb5_error_code ret;
 
172
    krb5_authdata *ad;
 
173
    krb5_authdata adIfRelevant;
 
174
    unsigned i;
 
175
 
 
176
    adIfRelevant.len = 0;
 
177
 
 
178
    etypes->len = 0;
 
179
    etypes->val = NULL;
 
180
 
 
181
    ad = auth_context->authenticator->authorization_data;
 
182
    if (ad == NULL)
 
183
        return 0;
 
184
 
 
185
    for (i = 0; i < ad->len; i++) {
 
186
        if (ad->val[i].ad_type == KRB5_AUTHDATA_IF_RELEVANT) {
 
187
            ret = decode_AD_IF_RELEVANT(ad->val[i].ad_data.data,
 
188
                                        ad->val[i].ad_data.length,
 
189
                                        &adIfRelevant,
 
190
                                        NULL);
 
191
            if (ret)
 
192
                return ret;
 
193
 
 
194
            if (adIfRelevant.len == 1 &&
 
195
                adIfRelevant.val[0].ad_type ==
 
196
                        KRB5_AUTHDATA_GSS_API_ETYPE_NEGOTIATION) {
 
197
                break;
 
198
            }
 
199
            free_AD_IF_RELEVANT(&adIfRelevant);
 
200
            adIfRelevant.len = 0;
 
201
        }
 
202
    }
 
203
 
 
204
    if (adIfRelevant.len == 0)
 
205
        return 0;
 
206
 
 
207
    ret = decode_EtypeList(adIfRelevant.val[0].ad_data.data,
 
208
                           adIfRelevant.val[0].ad_data.length,
 
209
                           etypes,
 
210
                           NULL);
 
211
    if (ret)
 
212
        krb5_clear_error_message(context);
 
213
 
 
214
    free_AD_IF_RELEVANT(&adIfRelevant);
 
215
 
 
216
    return ret;
 
217
}
 
218
 
 
219
krb5_error_code KRB5_LIB_FUNCTION
 
220
krb5_decrypt_ticket(krb5_context context,
 
221
                    Ticket *ticket,
 
222
                    krb5_keyblock *key,
 
223
                    EncTicketPart *out,
 
224
                    krb5_flags flags)
 
225
{
 
226
    EncTicketPart t;
 
227
    krb5_error_code ret;
 
228
    ret = decrypt_tkt_enc_part (context, key, &ticket->enc_part, &t);
 
229
    if (ret)
 
230
        return ret;
 
231
 
 
232
    {
 
233
        krb5_timestamp now;
 
234
        time_t start = t.authtime;
 
235
 
 
236
        krb5_timeofday (context, &now);
 
237
        if(t.starttime)
 
238
            start = *t.starttime;
 
239
        if(start - now > context->max_skew
 
240
           || (t.flags.invalid
 
241
               && !(flags & KRB5_VERIFY_AP_REQ_IGNORE_INVALID))) {
 
242
            free_EncTicketPart(&t);
 
243
            krb5_clear_error_message (context);
 
244
            return KRB5KRB_AP_ERR_TKT_NYV;
 
245
        }
 
246
        if(now - t.endtime > context->max_skew) {
 
247
            free_EncTicketPart(&t);
 
248
            krb5_clear_error_message (context);
 
249
            return KRB5KRB_AP_ERR_TKT_EXPIRED;
 
250
        }
 
251
        
 
252
        if(!t.flags.transited_policy_checked) {
 
253
            ret = check_transited(context, ticket, &t);
 
254
            if(ret) {
 
255
                free_EncTicketPart(&t);
 
256
                return ret;
 
257
            }
 
258
        }
 
259
    }
 
260
 
 
261
    if(out)
 
262
        *out = t;
 
263
    else
 
264
        free_EncTicketPart(&t);
 
265
    return 0;
 
266
}
 
267
 
 
268
krb5_error_code KRB5_LIB_FUNCTION
 
269
krb5_verify_authenticator_checksum(krb5_context context,
 
270
                                   krb5_auth_context ac,
 
271
                                   void *data,
 
272
                                   size_t len)
 
273
{
 
274
    krb5_error_code ret;
 
275
    krb5_keyblock *key;
 
276
    krb5_authenticator authenticator;
 
277
    krb5_crypto crypto;
 
278
 
 
279
    ret = krb5_auth_con_getauthenticator (context,
 
280
                                      ac,
 
281
                                      &authenticator);
 
282
    if(ret)
 
283
        return ret;
 
284
    if(authenticator->cksum == NULL) {
 
285
        krb5_free_authenticator(context, &authenticator);
 
286
        return -17;
 
287
    }
 
288
    ret = krb5_auth_con_getkey(context, ac, &key);
 
289
    if(ret) {
 
290
        krb5_free_authenticator(context, &authenticator);
 
291
        return ret;
 
292
    }
 
293
    ret = krb5_crypto_init(context, key, 0, &crypto);
 
294
    if(ret)
 
295
        goto out;
 
296
    ret = krb5_verify_checksum (context,
 
297
                                crypto,
 
298
                                KRB5_KU_AP_REQ_AUTH_CKSUM,
 
299
                                data,
 
300
                                len,
 
301
                                authenticator->cksum);
 
302
    krb5_crypto_destroy(context, crypto);
 
303
out:
 
304
    krb5_free_authenticator(context, &authenticator);
 
305
    krb5_free_keyblock(context, key);
 
306
    return ret;
 
307
}
 
308
 
 
309
 
 
310
krb5_error_code KRB5_LIB_FUNCTION
 
311
krb5_verify_ap_req(krb5_context context,
 
312
                   krb5_auth_context *auth_context,
 
313
                   krb5_ap_req *ap_req,
 
314
                   krb5_const_principal server,
 
315
                   krb5_keyblock *keyblock,
 
316
                   krb5_flags flags,
 
317
                   krb5_flags *ap_req_options,
 
318
                   krb5_ticket **ticket)
 
319
{
 
320
    return krb5_verify_ap_req2 (context,
 
321
                                auth_context,
 
322
                                ap_req,
 
323
                                server,
 
324
                                keyblock,
 
325
                                flags,
 
326
                                ap_req_options,
 
327
                                ticket,
 
328
                                KRB5_KU_AP_REQ_AUTH);
 
329
}
 
330
 
 
331
krb5_error_code KRB5_LIB_FUNCTION
 
332
krb5_verify_ap_req2(krb5_context context,
 
333
                    krb5_auth_context *auth_context,
 
334
                    krb5_ap_req *ap_req,
 
335
                    krb5_const_principal server,
 
336
                    krb5_keyblock *keyblock,
 
337
                    krb5_flags flags,
 
338
                    krb5_flags *ap_req_options,
 
339
                    krb5_ticket **ticket,
 
340
                    krb5_key_usage usage)
 
341
{
 
342
    krb5_ticket *t;
 
343
    krb5_auth_context ac;
 
344
    krb5_error_code ret;
 
345
    EtypeList etypes;
 
346
 
 
347
    if (ticket)
 
348
        *ticket = NULL;
 
349
 
 
350
    if (auth_context && *auth_context) {
 
351
        ac = *auth_context;
 
352
    } else {
 
353
        ret = krb5_auth_con_init (context, &ac);
 
354
        if (ret)
 
355
            return ret;
 
356
    }
 
357
 
 
358
    t = calloc(1, sizeof(*t));
 
359
    if (t == NULL) {
 
360
        ret = ENOMEM;
 
361
        krb5_clear_error_message (context);
 
362
        goto out;
 
363
    }
 
364
 
 
365
    if (ap_req->ap_options.use_session_key && ac->keyblock){
 
366
        ret = krb5_decrypt_ticket(context, &ap_req->ticket,
 
367
                                  ac->keyblock,
 
368
                                  &t->ticket,
 
369
                                  flags);
 
370
        krb5_free_keyblock(context, ac->keyblock);
 
371
        ac->keyblock = NULL;
 
372
    }else
 
373
        ret = krb5_decrypt_ticket(context, &ap_req->ticket,
 
374
                                  keyblock,
 
375
                                  &t->ticket,
 
376
                                  flags);
 
377
 
 
378
    if(ret)
 
379
        goto out;
 
380
 
 
381
    ret = _krb5_principalname2krb5_principal(context,
 
382
                                             &t->server,
 
383
                                             ap_req->ticket.sname,
 
384
                                             ap_req->ticket.realm);
 
385
    if (ret) goto out;
 
386
    ret = _krb5_principalname2krb5_principal(context,
 
387
                                             &t->client,
 
388
                                             t->ticket.cname,
 
389
                                             t->ticket.crealm);
 
390
    if (ret) goto out;
 
391
 
 
392
    ret = decrypt_authenticator (context,
 
393
                                 &t->ticket.key,
 
394
                                 &ap_req->authenticator,
 
395
                                 ac->authenticator,
 
396
                                 usage);
 
397
    if (ret)
 
398
        goto out;
 
399
 
 
400
    {
 
401
        krb5_principal p1, p2;
 
402
        krb5_boolean res;
 
403
        
 
404
        _krb5_principalname2krb5_principal(context,
 
405
                                           &p1,
 
406
                                           ac->authenticator->cname,
 
407
                                           ac->authenticator->crealm);
 
408
        _krb5_principalname2krb5_principal(context,
 
409
                                           &p2,
 
410
                                           t->ticket.cname,
 
411
                                           t->ticket.crealm);
 
412
        res = krb5_principal_compare (context, p1, p2);
 
413
        krb5_free_principal (context, p1);
 
414
        krb5_free_principal (context, p2);
 
415
        if (!res) {
 
416
            ret = KRB5KRB_AP_ERR_BADMATCH;
 
417
            krb5_clear_error_message (context);
 
418
            goto out;
 
419
        }
 
420
    }
 
421
 
 
422
    /* check addresses */
 
423
 
 
424
    if (t->ticket.caddr
 
425
        && ac->remote_address
 
426
        && !krb5_address_search (context,
 
427
                                 ac->remote_address,
 
428
                                 t->ticket.caddr)) {
 
429
        ret = KRB5KRB_AP_ERR_BADADDR;
 
430
        krb5_clear_error_message (context);
 
431
        goto out;
 
432
    }
 
433
 
 
434
    /* check timestamp in authenticator */
 
435
    {
 
436
        krb5_timestamp now;
 
437
 
 
438
        krb5_timeofday (context, &now);
 
439
 
 
440
        if (abs(ac->authenticator->ctime - now) > context->max_skew) {
 
441
            ret = KRB5KRB_AP_ERR_SKEW;
 
442
            krb5_clear_error_message (context);
 
443
            goto out;
 
444
        }
 
445
    }
 
446
 
 
447
    if (ac->authenticator->seq_number)
 
448
        krb5_auth_con_setremoteseqnumber(context, ac,
 
449
                                         *ac->authenticator->seq_number);
 
450
 
 
451
    /* XXX - Xor sequence numbers */
 
452
 
 
453
    if (ac->authenticator->subkey) {
 
454
        ret = krb5_auth_con_setremotesubkey(context, ac,
 
455
                                            ac->authenticator->subkey);
 
456
        if (ret)
 
457
            goto out;
 
458
    }
 
459
 
 
460
    ret = find_etypelist(context, ac, &etypes);
 
461
    if (ret)
 
462
        goto out;
 
463
 
 
464
    ac->keytype = ETYPE_NULL;
 
465
 
 
466
    if (etypes.val) {
 
467
        int i;
 
468
 
 
469
        for (i = 0; i < etypes.len; i++) {
 
470
            if (krb5_enctype_valid(context, etypes.val[i]) == 0) {
 
471
                ac->keytype = etypes.val[i];
 
472
                break;
 
473
            }
 
474
        }
 
475
    }
 
476
 
 
477
    /* save key */
 
478
    ret = krb5_copy_keyblock(context, &t->ticket.key, &ac->keyblock);
 
479
    if (ret) goto out;
 
480
 
 
481
    if (ap_req_options) {
 
482
        *ap_req_options = 0;
 
483
        if (ac->keytype != ETYPE_NULL)
 
484
            *ap_req_options |= AP_OPTS_USE_SUBKEY;
 
485
        if (ap_req->ap_options.use_session_key)
 
486
            *ap_req_options |= AP_OPTS_USE_SESSION_KEY;
 
487
        if (ap_req->ap_options.mutual_required)
 
488
            *ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
 
489
    }
 
490
 
 
491
    if(ticket)
 
492
        *ticket = t;
 
493
    else
 
494
        krb5_free_ticket (context, t);
 
495
    if (auth_context) {
 
496
        if (*auth_context == NULL)
 
497
            *auth_context = ac;
 
498
    } else
 
499
        krb5_auth_con_free (context, ac);
 
500
    free_EtypeList(&etypes);
 
501
    return 0;
 
502
 out:
 
503
    if (t)
 
504
        krb5_free_ticket (context, t);
 
505
    if (auth_context == NULL || *auth_context == NULL)
 
506
        krb5_auth_con_free (context, ac);
 
507
    return ret;
 
508
}
 
509
                
 
510
/*
 
511
 *
 
512
 */
 
513
 
 
514
struct krb5_rd_req_in_ctx_data {
 
515
    krb5_keytab keytab;
 
516
    krb5_keyblock *keyblock;
 
517
    krb5_boolean check_pac;
 
518
};
 
519
 
 
520
struct krb5_rd_req_out_ctx_data {
 
521
    krb5_keyblock *keyblock;
 
522
    krb5_flags ap_req_options;
 
523
    krb5_ticket *ticket;
 
524
};
 
525
 
 
526
/*
 
527
 *
 
528
 */
 
529
 
 
530
krb5_error_code KRB5_LIB_FUNCTION
 
531
krb5_rd_req_in_ctx_alloc(krb5_context context, krb5_rd_req_in_ctx *ctx)
 
532
{
 
533
    *ctx = calloc(1, sizeof(**ctx));
 
534
    if (*ctx == NULL) {
 
535
        krb5_set_error_message(context, ENOMEM,
 
536
                               N_("malloc: out of memory", ""));
 
537
        return ENOMEM;
 
538
    }
 
539
    (*ctx)->check_pac = (context->flags & KRB5_CTX_F_CHECK_PAC) ? 1 : 0;
 
540
    return 0;
 
541
}
 
542
 
 
543
krb5_error_code KRB5_LIB_FUNCTION
 
544
krb5_rd_req_in_set_keytab(krb5_context context,
 
545
                          krb5_rd_req_in_ctx in,
 
546
                          krb5_keytab keytab)
 
547
{
 
548
    in->keytab = keytab; /* XXX should make copy */
 
549
    return 0;
 
550
}
 
551
 
 
552
/**
 
553
 * Set if krb5_rq_red() is going to check the Windows PAC or not
 
554
 *
 
555
 * @param context Keberos 5 context.
 
556
 * @param in krb5_rd_req_in_ctx to check the option on.
 
557
 * @param flag flag to select if to check the pac (TRUE) or not (FALSE).
 
558
 *
 
559
 * @return Kerberos 5 error code, see krb5_get_error_message().
 
560
 *
 
561
 * @ingroup krb5
 
562
 */
 
563
 
 
564
krb5_error_code KRB5_LIB_FUNCTION
 
565
krb5_rd_req_in_set_pac_check(krb5_context context,
 
566
                             krb5_rd_req_in_ctx in,
 
567
                             krb5_boolean flag)
 
568
{
 
569
    in->check_pac = flag;
 
570
    return 0;
 
571
}
 
572
 
 
573
 
 
574
krb5_error_code KRB5_LIB_FUNCTION
 
575
krb5_rd_req_in_set_keyblock(krb5_context context,
 
576
                            krb5_rd_req_in_ctx in,
 
577
                            krb5_keyblock *keyblock)
 
578
{
 
579
    in->keyblock = keyblock; /* XXX should make copy */
 
580
    return 0;
 
581
}
 
582
 
 
583
krb5_error_code KRB5_LIB_FUNCTION
 
584
krb5_rd_req_out_get_ap_req_options(krb5_context context,
 
585
                                   krb5_rd_req_out_ctx out,
 
586
                                   krb5_flags *ap_req_options)
 
587
{
 
588
    *ap_req_options = out->ap_req_options;
 
589
    return 0;
 
590
}
 
591
 
 
592
krb5_error_code KRB5_LIB_FUNCTION
 
593
krb5_rd_req_out_get_ticket(krb5_context context,
 
594
                            krb5_rd_req_out_ctx out,
 
595
                            krb5_ticket **ticket)
 
596
{
 
597
    return krb5_copy_ticket(context, out->ticket, ticket);
 
598
}
 
599
 
 
600
krb5_error_code KRB5_LIB_FUNCTION
 
601
krb5_rd_req_out_get_keyblock(krb5_context context,
 
602
                            krb5_rd_req_out_ctx out,
 
603
                            krb5_keyblock **keyblock)
 
604
{
 
605
    return krb5_copy_keyblock(context, out->keyblock, keyblock);
 
606
}
 
607
 
 
608
void  KRB5_LIB_FUNCTION
 
609
krb5_rd_req_in_ctx_free(krb5_context context, krb5_rd_req_in_ctx ctx)
 
610
{
 
611
    free(ctx);
 
612
}
 
613
 
 
614
krb5_error_code KRB5_LIB_FUNCTION
 
615
_krb5_rd_req_out_ctx_alloc(krb5_context context, krb5_rd_req_out_ctx *ctx)
 
616
{
 
617
    *ctx = calloc(1, sizeof(**ctx));
 
618
    if (*ctx == NULL) {
 
619
        krb5_set_error_message(context, ENOMEM,
 
620
                               N_("malloc: out of memory", ""));
 
621
        return ENOMEM;
 
622
    }
 
623
    return 0;
 
624
}
 
625
 
 
626
void  KRB5_LIB_FUNCTION
 
627
krb5_rd_req_out_ctx_free(krb5_context context, krb5_rd_req_out_ctx ctx)
 
628
{
 
629
    krb5_free_keyblock(context, ctx->keyblock);
 
630
    free(ctx);
 
631
}
 
632
 
 
633
/*
 
634
 *
 
635
 */
 
636
 
 
637
krb5_error_code KRB5_LIB_FUNCTION
 
638
krb5_rd_req(krb5_context context,
 
639
            krb5_auth_context *auth_context,
 
640
            const krb5_data *inbuf,
 
641
            krb5_const_principal server,
 
642
            krb5_keytab keytab,
 
643
            krb5_flags *ap_req_options,
 
644
            krb5_ticket **ticket)
 
645
{
 
646
    krb5_error_code ret;
 
647
    krb5_rd_req_in_ctx in;
 
648
    krb5_rd_req_out_ctx out;
 
649
 
 
650
    ret = krb5_rd_req_in_ctx_alloc(context, &in);
 
651
    if (ret)
 
652
        return ret;
 
653
 
 
654
    ret = krb5_rd_req_in_set_keytab(context, in, keytab);
 
655
    if (ret) {
 
656
        krb5_rd_req_in_ctx_free(context, in);
 
657
        return ret;
 
658
    }
 
659
 
 
660
    ret = krb5_rd_req_ctx(context, auth_context, inbuf, server, in, &out);
 
661
    krb5_rd_req_in_ctx_free(context, in);
 
662
    if (ret)
 
663
        return ret;
 
664
 
 
665
    if (ap_req_options)
 
666
        *ap_req_options = out->ap_req_options;
 
667
    if (ticket) {
 
668
        ret = krb5_copy_ticket(context, out->ticket, ticket);
 
669
        if (ret)
 
670
            goto out;
 
671
    }
 
672
 
 
673
out:
 
674
    krb5_rd_req_out_ctx_free(context, out);
 
675
    return ret;
 
676
}
 
677
 
 
678
/*
 
679
 *
 
680
 */
 
681
 
 
682
krb5_error_code KRB5_LIB_FUNCTION
 
683
krb5_rd_req_with_keyblock(krb5_context context,
 
684
                          krb5_auth_context *auth_context,
 
685
                          const krb5_data *inbuf,
 
686
                          krb5_const_principal server,
 
687
                          krb5_keyblock *keyblock,
 
688
                          krb5_flags *ap_req_options,
 
689
                          krb5_ticket **ticket)
 
690
{
 
691
    krb5_error_code ret;
 
692
    krb5_rd_req_in_ctx in;
 
693
    krb5_rd_req_out_ctx out;
 
694
 
 
695
    ret = krb5_rd_req_in_ctx_alloc(context, &in);
 
696
    if (ret)
 
697
        return ret;
 
698
 
 
699
    ret = krb5_rd_req_in_set_keyblock(context, in, keyblock);
 
700
    if (ret) {
 
701
        krb5_rd_req_in_ctx_free(context, in);
 
702
        return ret;
 
703
    }
 
704
 
 
705
    ret = krb5_rd_req_ctx(context, auth_context, inbuf, server, in, &out);
 
706
    krb5_rd_req_in_ctx_free(context, in);
 
707
    if (ret)
 
708
        return ret;
 
709
 
 
710
    if (ap_req_options)
 
711
        *ap_req_options = out->ap_req_options;
 
712
    if (ticket) {
 
713
        ret = krb5_copy_ticket(context, out->ticket, ticket);
 
714
        if (ret)
 
715
            goto out;
 
716
    }
 
717
 
 
718
out:
 
719
    krb5_rd_req_out_ctx_free(context, out);
 
720
    return ret;
 
721
}
 
722
 
 
723
/*
 
724
 *
 
725
 */
 
726
 
 
727
static krb5_error_code
 
728
get_key_from_keytab(krb5_context context,
 
729
                    krb5_auth_context *auth_context,
 
730
                    krb5_ap_req *ap_req,
 
731
                    krb5_const_principal server,
 
732
                    krb5_keytab keytab,
 
733
                    krb5_keyblock **out_key)
 
734
{
 
735
    krb5_keytab_entry entry;
 
736
    krb5_error_code ret;
 
737
    int kvno;
 
738
    krb5_keytab real_keytab;
 
739
 
 
740
    if(keytab == NULL)
 
741
        krb5_kt_default(context, &real_keytab);
 
742
    else
 
743
        real_keytab = keytab;
 
744
 
 
745
    if (ap_req->ticket.enc_part.kvno)
 
746
        kvno = *ap_req->ticket.enc_part.kvno;
 
747
    else
 
748
        kvno = 0;
 
749
 
 
750
    ret = krb5_kt_get_entry (context,
 
751
                             real_keytab,
 
752
                             server,
 
753
                             kvno,
 
754
                             ap_req->ticket.enc_part.etype,
 
755
                             &entry);
 
756
    if(ret)
 
757
        goto out;
 
758
    ret = krb5_copy_keyblock(context, &entry.keyblock, out_key);
 
759
    krb5_kt_free_entry (context, &entry);
 
760
out:
 
761
    if(keytab == NULL)
 
762
        krb5_kt_close(context, real_keytab);
 
763
 
 
764
    return ret;
 
765
}
 
766
 
 
767
/*
 
768
 *
 
769
 */
 
770
 
 
771
krb5_error_code KRB5_LIB_FUNCTION
 
772
krb5_rd_req_ctx(krb5_context context,
 
773
                krb5_auth_context *auth_context,
 
774
                const krb5_data *inbuf,
 
775
                krb5_const_principal server,
 
776
                krb5_rd_req_in_ctx inctx,
 
777
                krb5_rd_req_out_ctx *outctx)
 
778
{
 
779
    krb5_error_code ret;
 
780
    krb5_ap_req ap_req;
 
781
    krb5_principal service = NULL;
 
782
    krb5_rd_req_out_ctx o = NULL;
 
783
 
 
784
    ret = _krb5_rd_req_out_ctx_alloc(context, &o);
 
785
    if (ret)
 
786
        goto out;
 
787
 
 
788
    if (*auth_context == NULL) {
 
789
        ret = krb5_auth_con_init(context, auth_context);
 
790
        if (ret)
 
791
            goto out;
 
792
    }
 
793
 
 
794
    ret = krb5_decode_ap_req(context, inbuf, &ap_req);
 
795
    if(ret)
 
796
        goto out;
 
797
 
 
798
    if(server == NULL){
 
799
        ret = _krb5_principalname2krb5_principal(context,
 
800
                                                 &service,
 
801
                                                 ap_req.ticket.sname,
 
802
                                                 ap_req.ticket.realm);
 
803
        if (ret)
 
804
            goto out;
 
805
        server = service;
 
806
    }
 
807
    if (ap_req.ap_options.use_session_key &&
 
808
        (*auth_context)->keyblock == NULL) {
 
809
        ret = KRB5KRB_AP_ERR_NOKEY;
 
810
        krb5_set_error_message(context, ret,
 
811
                               N_("krb5_rd_req: user to user auth "
 
812
                                  "without session key given", ""));
 
813
        goto out;
 
814
    }
 
815
 
 
816
    if((*auth_context)->keyblock){
 
817
        ret = krb5_copy_keyblock(context,
 
818
                                 (*auth_context)->keyblock,
 
819
                                 &o->keyblock);
 
820
        if (ret)
 
821
            goto out;
 
822
    } else if(inctx->keyblock){
 
823
        ret = krb5_copy_keyblock(context,
 
824
                                 inctx->keyblock,
 
825
                                 &o->keyblock);
 
826
        if (ret)
 
827
            goto out;
 
828
    } else {
 
829
        krb5_keytab keytab = NULL;
 
830
 
 
831
        if (inctx && inctx->keytab)
 
832
            keytab = inctx->keytab;
 
833
 
 
834
        ret = get_key_from_keytab(context,
 
835
                                  auth_context,
 
836
                                  &ap_req,
 
837
                                  server,
 
838
                                  keytab,
 
839
                                  &o->keyblock);
 
840
        if(ret)
 
841
            goto out;
 
842
    }
 
843
 
 
844
    ret = krb5_verify_ap_req2(context,
 
845
                              auth_context,
 
846
                              &ap_req,
 
847
                              server,
 
848
                              o->keyblock,
 
849
                              0,
 
850
                              &o->ap_req_options,
 
851
                              &o->ticket,
 
852
                              KRB5_KU_AP_REQ_AUTH);
 
853
 
 
854
    if (ret)
 
855
        goto out;
 
856
 
 
857
    /* If there is a PAC, verify its server signature */
 
858
    if (inctx->check_pac) {
 
859
        krb5_pac pac;
 
860
        krb5_data data;
 
861
 
 
862
        ret = krb5_ticket_get_authorization_data_type(context,
 
863
                                                      o->ticket,
 
864
                                                      KRB5_AUTHDATA_WIN2K_PAC,
 
865
                                                      &data);
 
866
        if (ret == 0) {
 
867
            ret = krb5_pac_parse(context, data.data, data.length, &pac);
 
868
            krb5_data_free(&data);
 
869
            if (ret)
 
870
                goto out;
 
871
        
 
872
            ret = krb5_pac_verify(context,
 
873
                                  pac,
 
874
                                  o->ticket->ticket.authtime,
 
875
                                  o->ticket->client,
 
876
                                  o->keyblock,
 
877
                                  NULL);
 
878
            krb5_pac_free(context, pac);
 
879
            if (ret)
 
880
                goto out;
 
881
        }
 
882
        ret = 0;
 
883
    }
 
884
out:
 
885
    if (ret || outctx == NULL) {
 
886
        krb5_rd_req_out_ctx_free(context, o);
 
887
    } else
 
888
        *outctx = o;
 
889
 
 
890
    free_AP_REQ(&ap_req);
 
891
    if(service)
 
892
        krb5_free_principal(context, service);
 
893
    return ret;
 
894
}