~ubuntu-branches/ubuntu/precise/krb5/precise-updates

« back to all changes in this revision

Viewing changes to src/kdc/do_as_req.c

  • Committer: Package Import Robot
  • Author(s): Sam Hartman
  • Date: 2011-12-01 19:34:41 UTC
  • mfrom: (28.1.14 sid)
  • Revision ID: package-import@ubuntu.com-20111201193441-9tipg3aru1jsidyv
Tags: 1.10+dfsg~alpha1-6
* Fix segfault with unknown hostnames in krb5_sname_to_principal,
  Closes: #650671
* Indicate that this library breaks libsmbclient versions that depend on
  krb5_locate_kdc, Closes: #650603, #650611

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 
2
/* kdc/do_as_req.c */
2
3
/*
3
 
 * kdc/do_as_req.c
4
 
 *
5
4
 * Portions Copyright (C) 2007 Apple Inc.
6
5
 * Copyright 1990,1991,2007,2008,2009 by the Massachusetts Institute of Technology.
7
6
 * All Rights Reserved.
85
84
 
86
85
static krb5_error_code
87
86
prepare_error_as(struct kdc_request_state *, krb5_kdc_req *,
88
 
                 int, krb5_data *, krb5_principal, krb5_data **,
89
 
                 const char *);
 
87
                 int, krb5_pa_data **, krb5_boolean, krb5_principal,
 
88
                 krb5_data **, const char *);
90
89
 
91
90
/* Determine the key-expiration value according to RFC 4120 section 5.4.2. */
92
91
static krb5_timestamp
99
98
    return min(entry->expiration, entry->pw_expiration);
100
99
}
101
100
 
102
 
/*ARGSUSED*/
103
 
krb5_error_code
104
 
process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
105
 
               const krb5_fulladdr *from, krb5_data **response)
106
 
{
107
 
    krb5_db_entry *client = NULL, *server = NULL;
108
 
    krb5_kdc_rep reply;
 
101
struct as_req_state {
 
102
    loop_respond_fn respond;
 
103
    void *arg;
 
104
 
 
105
    krb5_enc_tkt_part enc_tkt_reply;
109
106
    krb5_enc_kdc_rep_part reply_encpart;
110
107
    krb5_ticket ticket_reply;
111
 
    krb5_enc_tkt_part enc_tkt_reply;
112
 
    krb5_error_code errcode;
113
 
    krb5_timestamp kdc_time, authtime = 0;
 
108
    krb5_keyblock server_keyblock;
 
109
    krb5_keyblock client_keyblock;
 
110
    krb5_db_entry *client;
 
111
    krb5_db_entry *server;
 
112
    krb5_kdc_req *request;
 
113
    struct krb5_kdcpreauth_rock_st rock;
 
114
    const char *status;
 
115
    krb5_pa_data **e_data;
 
116
    krb5_boolean typed_e_data;
 
117
    krb5_kdc_rep reply;
 
118
    krb5_timestamp kdc_time;
 
119
    krb5_timestamp authtime;
114
120
    krb5_keyblock session_key;
115
 
    const char *status;
116
 
    krb5_key_data *server_key, *client_key;
117
 
    krb5_keyblock server_keyblock, client_keyblock;
118
 
    krb5_enctype useenctype;
119
 
    krb5_data e_data;
 
121
    unsigned int c_flags;
 
122
    krb5_data *req_pkt;
 
123
    struct kdc_request_state *rstate;
 
124
    char *sname, *cname;
 
125
    void *pa_context;
 
126
    const krb5_fulladdr *from;
 
127
 
 
128
    krb5_error_code preauth_err;
 
129
};
 
130
 
 
131
static void
 
132
finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
 
133
{
 
134
    krb5_key_data *server_key;
 
135
    krb5_key_data *client_key;
 
136
    krb5_keyblock *as_encrypting_key = NULL;
 
137
    krb5_data *response = NULL;
 
138
    const char *emsg = 0;
 
139
    int did_log = 0;
120
140
    register int i;
 
141
    krb5_enctype useenctype;
 
142
    loop_respond_fn oldrespond;
 
143
    void *oldarg;
 
144
 
 
145
    assert(state);
 
146
    oldrespond = state->respond;
 
147
    oldarg = state->arg;
 
148
 
 
149
    if (errcode)
 
150
        goto egress;
 
151
 
 
152
    if ((errcode = validate_forwardable(state->request, *state->client,
 
153
                                        *state->server, state->kdc_time,
 
154
                                        &state->status))) {
 
155
        errcode += ERROR_TABLE_BASE_krb5;
 
156
        goto egress;
 
157
    }
 
158
 
 
159
    state->ticket_reply.enc_part2 = &state->enc_tkt_reply;
 
160
 
 
161
    /*
 
162
     * Find the server key
 
163
     */
 
164
    if ((errcode = krb5_dbe_find_enctype(kdc_context, state->server,
 
165
                                         -1, /* ignore keytype   */
 
166
                                         -1, /* Ignore salttype  */
 
167
                                         0,  /* Get highest kvno */
 
168
                                         &server_key))) {
 
169
        state->status = "FINDING_SERVER_KEY";
 
170
        goto egress;
 
171
    }
 
172
 
 
173
    /*
 
174
     * Convert server->key into a real key
 
175
     * (it may be encrypted in the database)
 
176
     *
 
177
     *  server_keyblock is later used to generate auth data signatures
 
178
     */
 
179
    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
 
180
                                             server_key,
 
181
                                             &state->server_keyblock,
 
182
                                             NULL))) {
 
183
        state->status = "DECRYPT_SERVER_KEY";
 
184
        goto egress;
 
185
    }
 
186
 
 
187
    /*
 
188
     * Find the appropriate client key.  We search in the order specified
 
189
     * by request keytype list.
 
190
     */
 
191
    client_key = NULL;
 
192
    for (i = 0; i < state->request->nktypes; i++) {
 
193
        useenctype = state->request->ktype[i];
 
194
        if (!krb5_c_valid_enctype(useenctype))
 
195
            continue;
 
196
 
 
197
        if (!krb5_dbe_find_enctype(kdc_context, state->client,
 
198
                                   useenctype, -1, 0, &client_key))
 
199
            break;
 
200
    }
 
201
    if (!(client_key)) {
 
202
        /* Cannot find an appropriate key */
 
203
        state->status = "CANT_FIND_CLIENT_KEY";
 
204
        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
 
205
        goto egress;
 
206
    }
 
207
    state->rock.client_key = client_key;
 
208
 
 
209
    /* convert client.key_data into a real key */
 
210
    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
 
211
                                             client_key,
 
212
                                             &state->client_keyblock,
 
213
                                             NULL))) {
 
214
        state->status = "DECRYPT_CLIENT_KEY";
 
215
        goto egress;
 
216
    }
 
217
    state->client_keyblock.enctype = useenctype;
 
218
 
 
219
    /* Start assembling the response */
 
220
    state->reply.msg_type = KRB5_AS_REP;
 
221
    state->reply.client = state->enc_tkt_reply.client; /* post canonization */
 
222
    state->reply.ticket = &state->ticket_reply;
 
223
    state->reply_encpart.session = &state->session_key;
 
224
    if ((errcode = fetch_last_req_info(state->client,
 
225
                                       &state->reply_encpart.last_req))) {
 
226
        state->status = "FETCH_LAST_REQ";
 
227
        goto egress;
 
228
    }
 
229
    state->reply_encpart.nonce = state->request->nonce;
 
230
    state->reply_encpart.key_exp = get_key_exp(state->client);
 
231
    state->reply_encpart.flags = state->enc_tkt_reply.flags;
 
232
    state->reply_encpart.server = state->ticket_reply.server;
 
233
 
 
234
    /* copy the time fields EXCEPT for authtime; it's location
 
235
     *  is used for ktime
 
236
     */
 
237
    state->reply_encpart.times = state->enc_tkt_reply.times;
 
238
    state->reply_encpart.times.authtime = state->authtime = state->kdc_time;
 
239
 
 
240
    state->reply_encpart.caddrs = state->enc_tkt_reply.caddrs;
 
241
    state->reply_encpart.enc_padata = NULL;
 
242
 
 
243
    /* Fetch the padata info to be returned (do this before
 
244
     *  authdata to handle possible replacement of reply key
 
245
     */
 
246
    errcode = return_padata(kdc_context, &state->rock, state->req_pkt,
 
247
                            state->request, &state->reply,
 
248
                            &state->client_keyblock, &state->pa_context);
 
249
    if (errcode) {
 
250
        state->status = "KDC_RETURN_PADATA";
 
251
        goto egress;
 
252
    }
 
253
 
 
254
#if APPLE_PKINIT
 
255
    asReqDebug("process_as_req reply realm %s name %s\n",
 
256
               reply.client->realm.data, reply.client->data->data);
 
257
#endif /* APPLE_PKINIT */
 
258
 
 
259
 
 
260
 
 
261
    errcode = handle_authdata(kdc_context,
 
262
                              state->c_flags,
 
263
                              state->client,
 
264
                              state->server,
 
265
                              state->server,
 
266
                              &state->client_keyblock,
 
267
                              &state->server_keyblock,
 
268
                              &state->server_keyblock,
 
269
                              state->req_pkt,
 
270
                              state->request,
 
271
                              NULL, /* for_user_princ */
 
272
                              NULL, /* enc_tkt_request */
 
273
                              &state->enc_tkt_reply);
 
274
    if (errcode) {
 
275
        krb5_klog_syslog(LOG_INFO, _("AS_REQ : handle_authdata (%d)"),
 
276
                         errcode);
 
277
        state->status = "HANDLE_AUTHDATA";
 
278
        goto egress;
 
279
    }
 
280
 
 
281
    errcode = krb5_encrypt_tkt_part(kdc_context, &state->server_keyblock,
 
282
                                    &state->ticket_reply);
 
283
    if (errcode) {
 
284
        state->status = "ENCRYPTING_TICKET";
 
285
        goto egress;
 
286
    }
 
287
    state->ticket_reply.enc_part.kvno = server_key->key_data_kvno;
 
288
    errcode = kdc_fast_response_handle_padata(state->rstate,
 
289
                                              state->request,
 
290
                                              &state->reply,
 
291
                                              state->client_keyblock.enctype);
 
292
    if (errcode) {
 
293
        state->status = "fast response handling";
 
294
        goto egress;
 
295
    }
 
296
 
 
297
    /* now encode/encrypt the response */
 
298
 
 
299
    state->reply.enc_part.enctype = state->client_keyblock.enctype;
 
300
 
 
301
    errcode = kdc_fast_handle_reply_key(state->rstate, &state->client_keyblock,
 
302
                                        &as_encrypting_key);
 
303
    if (errcode) {
 
304
        state->status = "generating reply key";
 
305
        goto egress;
 
306
    }
 
307
    errcode = return_enc_padata(kdc_context, state->req_pkt, state->request,
 
308
                                as_encrypting_key, state->server,
 
309
                                &state->reply_encpart, FALSE);
 
310
    if (errcode) {
 
311
        state->status = "KDC_RETURN_ENC_PADATA";
 
312
        goto egress;
 
313
    }
 
314
 
 
315
    errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP,
 
316
                                  &state->reply_encpart, 0,
 
317
                                  as_encrypting_key,
 
318
                                  &state->reply, &response);
 
319
    state->reply.enc_part.kvno = client_key->key_data_kvno;
 
320
    if (errcode) {
 
321
        state->status = "ENCODE_KDC_REP";
 
322
        goto egress;
 
323
    }
 
324
 
 
325
    /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
 
326
       can use them in raw form if needed.  But, we don't... */
 
327
    memset(state->reply.enc_part.ciphertext.data, 0,
 
328
           state->reply.enc_part.ciphertext.length);
 
329
    free(state->reply.enc_part.ciphertext.data);
 
330
 
 
331
    log_as_req(state->from, state->request, &state->reply,
 
332
               state->client, state->cname, state->server,
 
333
               state->sname, state->authtime, 0, 0, 0);
 
334
    did_log = 1;
 
335
 
 
336
egress:
 
337
    if (errcode != 0)
 
338
        assert (state->status != 0);
 
339
    free_padata_context(kdc_context, state->pa_context);
 
340
    if (as_encrypting_key)
 
341
        krb5_free_keyblock(kdc_context, as_encrypting_key);
 
342
    if (errcode)
 
343
        emsg = krb5_get_error_message(kdc_context, errcode);
 
344
 
 
345
    if (state->status) {
 
346
        log_as_req(state->from, state->request, &state->reply, state->client,
 
347
                   state->cname, state->server, state->sname, state->authtime,
 
348
                   state->status, errcode, emsg);
 
349
        did_log = 1;
 
350
    }
 
351
    if (errcode) {
 
352
        if (state->status == 0) {
 
353
            state->status = emsg;
 
354
        }
 
355
        if (errcode != KRB5KDC_ERR_DISCARD) {
 
356
            errcode -= ERROR_TABLE_BASE_krb5;
 
357
            if (errcode < 0 || errcode > 128)
 
358
                errcode = KRB_ERR_GENERIC;
 
359
 
 
360
            errcode = prepare_error_as(state->rstate, state->request,
 
361
                                       errcode, state->e_data,
 
362
                                       state->typed_e_data,
 
363
                                       ((state->client != NULL) ?
 
364
                                        state->client->princ : NULL),
 
365
                                       &response, state->status);
 
366
            state->status = 0;
 
367
        }
 
368
    }
 
369
 
 
370
    if (emsg)
 
371
        krb5_free_error_message(kdc_context, emsg);
 
372
    if (state->enc_tkt_reply.authorization_data != NULL)
 
373
        krb5_free_authdata(kdc_context,
 
374
                           state->enc_tkt_reply.authorization_data);
 
375
    if (state->server_keyblock.contents != NULL)
 
376
        krb5_free_keyblock_contents(kdc_context, &state->server_keyblock);
 
377
    if (state->client_keyblock.contents != NULL)
 
378
        krb5_free_keyblock_contents(kdc_context, &state->client_keyblock);
 
379
    if (state->reply.padata != NULL)
 
380
        krb5_free_pa_data(kdc_context, state->reply.padata);
 
381
    if (state->reply_encpart.enc_padata)
 
382
        krb5_free_pa_data(kdc_context, state->reply_encpart.enc_padata);
 
383
 
 
384
    if (state->cname != NULL)
 
385
        free(state->cname);
 
386
    if (state->sname != NULL)
 
387
        free(state->sname);
 
388
    krb5_db_free_principal(kdc_context, state->client);
 
389
    krb5_db_free_principal(kdc_context, state->server);
 
390
    if (state->session_key.contents != NULL)
 
391
        krb5_free_keyblock_contents(kdc_context, &state->session_key);
 
392
    if (state->ticket_reply.enc_part.ciphertext.data != NULL) {
 
393
        memset(state->ticket_reply.enc_part.ciphertext.data , 0,
 
394
               state->ticket_reply.enc_part.ciphertext.length);
 
395
        free(state->ticket_reply.enc_part.ciphertext.data);
 
396
    }
 
397
 
 
398
    krb5_free_pa_data(kdc_context, state->e_data);
 
399
    kdc_free_rstate(state->rstate);
 
400
    krb5_free_kdc_req(kdc_context, state->request);
 
401
    assert(did_log != 0);
 
402
 
 
403
    free(state);
 
404
    (*oldrespond)(oldarg, errcode, response);
 
405
}
 
406
 
 
407
static void
 
408
finish_missing_required_preauth(void *arg)
 
409
{
 
410
    struct as_req_state *state = (struct as_req_state *)arg;
 
411
 
 
412
    finish_process_as_req(state, state->preauth_err);
 
413
}
 
414
 
 
415
static void
 
416
finish_preauth(void *arg, krb5_error_code code)
 
417
{
 
418
    struct as_req_state *state = arg;
 
419
    krb5_error_code real_code = code;
 
420
 
 
421
    if (code) {
 
422
        if (vague_errors)
 
423
            code = KRB5KRB_ERR_GENERIC;
 
424
        state->status = "PREAUTH_FAILED";
 
425
        if (real_code == KRB5KDC_ERR_PREAUTH_FAILED) {
 
426
            state->preauth_err = code;
 
427
            get_preauth_hint_list(state->request, &state->rock, &state->e_data,
 
428
                                  finish_missing_required_preauth, state);
 
429
            return;
 
430
        }
 
431
    } else {
 
432
        /*
 
433
         * Final check before handing out ticket: If the client requires
 
434
         * preauthentication, verify that the proper kind of
 
435
         * preauthentication was carried out.
 
436
         */
 
437
        state->status = missing_required_preauth(state->client, state->server,
 
438
                                                 &state->enc_tkt_reply);
 
439
        if (state->status) {
 
440
            state->preauth_err = KRB5KDC_ERR_PREAUTH_REQUIRED;
 
441
            get_preauth_hint_list(state->request, &state->rock, &state->e_data,
 
442
                                  finish_missing_required_preauth, state);
 
443
            return;
 
444
        }
 
445
    }
 
446
 
 
447
    finish_process_as_req(state, code);
 
448
}
 
449
 
 
450
/*ARGSUSED*/
 
451
void
 
452
process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
 
453
               const krb5_fulladdr *from, loop_respond_fn respond, void *arg)
 
454
{
 
455
    krb5_error_code errcode;
121
456
    krb5_timestamp rtime;
122
 
    char *cname = 0, *sname = 0;
123
 
    unsigned int c_flags = 0, s_flags = 0;
 
457
    unsigned int s_flags = 0;
124
458
    krb5_principal_data client_princ;
125
 
    void *pa_context = NULL;
126
 
    int did_log = 0;
127
 
    const char *emsg = 0;
128
 
    struct kdc_request_state *state = NULL;
129
459
    krb5_data encoded_req_body;
130
 
    krb5_keyblock *as_encrypting_key = NULL;
 
460
    krb5_enctype useenctype;
 
461
    struct as_req_state *state;
131
462
 
 
463
    state = malloc(sizeof(*state));
 
464
    if (!state) {
 
465
        (*respond)(arg, ENOMEM, NULL);
 
466
        return;
 
467
    }
 
468
    state->session_key.contents = 0;
 
469
    state->enc_tkt_reply.authorization_data = NULL;
 
470
    state->reply.padata = 0;
 
471
    memset(&state->reply, 0, sizeof(state->reply));
 
472
    state->respond = respond;
 
473
    state->arg = arg;
 
474
    state->ticket_reply.enc_part.ciphertext.data = 0;
 
475
    state->server_keyblock.contents = NULL;
 
476
    state->client_keyblock.contents = NULL;
 
477
    state->reply_encpart.enc_padata = 0;
 
478
    state->client = NULL;
 
479
    state->server = NULL;
 
480
    state->request = request;
 
481
    state->e_data = NULL;
 
482
    state->typed_e_data = FALSE;
 
483
    state->authtime = 0;
 
484
    state->c_flags = 0;
 
485
    state->req_pkt = req_pkt;
 
486
    state->rstate = NULL;
 
487
    state->sname = 0;
 
488
    state->cname = 0;
 
489
    state->pa_context = NULL;
 
490
    state->from = from;
 
491
    memset(&state->rock, 0, sizeof(state->rock));
132
492
 
133
493
#if APPLE_PKINIT
134
494
    asReqDebug("process_as_req top realm %s name %s\n",
135
495
               request->client->realm.data, request->client->data->data);
136
496
#endif /* APPLE_PKINIT */
137
497
 
138
 
    ticket_reply.enc_part.ciphertext.data = 0;
139
 
    e_data.data = 0;
140
 
    server_keyblock.contents = NULL;
141
 
    client_keyblock.contents = NULL;
142
 
    reply.padata = 0;
143
 
    reply_encpart.enc_padata = 0;
144
 
    memset(&reply, 0, sizeof(reply));
145
 
 
146
 
    session_key.contents = 0;
147
 
    enc_tkt_reply.authorization_data = NULL;
148
 
 
149
 
    if (request->msg_type != KRB5_AS_REQ) {
150
 
        status = "msg_type mismatch";
 
498
    if (state->request->msg_type != KRB5_AS_REQ) {
 
499
        state->status = "msg_type mismatch";
151
500
        errcode = KRB5_BADMSGTYPE;
152
501
        goto errout;
153
502
    }
154
 
    errcode = kdc_make_rstate(&state);
 
503
    errcode = kdc_make_rstate(&state->rstate);
155
504
    if (errcode != 0) {
156
 
        status = "constructing state";
 
505
        state->status = "constructing state";
157
506
        goto errout;
158
507
    }
159
508
    if (fetch_asn1_field((unsigned char *) req_pkt->data,
160
509
                         1, 4, &encoded_req_body) != 0) {
161
510
        errcode = ASN1_BAD_ID;
162
 
        status = "Finding req_body";
 
511
        state->status = "Finding req_body";
163
512
        goto errout;
164
513
    }
165
 
    errcode = kdc_find_fast(&request, &encoded_req_body,
166
 
                            NULL /*TGS key*/, NULL, state);
 
514
    errcode = kdc_find_fast(&state->request, &encoded_req_body,
 
515
                            NULL /*TGS key*/, NULL, state->rstate);
167
516
    if (errcode) {
168
 
        status = "error decoding FAST";
 
517
        state->status = "error decoding FAST";
169
518
        goto errout;
170
519
    }
171
 
    request->kdc_state = state;
172
 
    if (!request->client) {
173
 
        status = "NULL_CLIENT";
 
520
    state->rock.request = state->request;
 
521
    state->rock.rstate = state->rstate;
 
522
    if (!state->request->client) {
 
523
        state->status = "NULL_CLIENT";
174
524
        errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
175
525
        goto errout;
176
526
    }
177
 
    if ((errcode = krb5_unparse_name(kdc_context, request->client, &cname))) {
178
 
        status = "UNPARSING_CLIENT";
 
527
    if ((errcode = krb5_unparse_name(kdc_context,
 
528
                                     state->request->client,
 
529
                                     &state->cname))) {
 
530
        state->status = "UNPARSING_CLIENT";
179
531
        goto errout;
180
532
    }
181
 
    limit_string(cname);
182
 
    if (!request->server) {
183
 
        status = "NULL_SERVER";
 
533
    limit_string(state->cname);
 
534
    if (!state->request->server) {
 
535
        state->status = "NULL_SERVER";
184
536
        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
185
537
        goto errout;
186
538
    }
187
 
    if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
188
 
        status = "UNPARSING_SERVER";
 
539
    if ((errcode = krb5_unparse_name(kdc_context,
 
540
                                     state->request->server,
 
541
                                     &state->sname))) {
 
542
        state->status = "UNPARSING_SERVER";
189
543
        goto errout;
190
544
    }
191
 
    limit_string(sname);
 
545
    limit_string(state->sname);
192
546
 
193
547
    /*
194
548
     * We set KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY as a hint
195
549
     * to the backend to return naming information in lieu
196
550
     * of cross realm TGS entries.
197
551
     */
198
 
    setflag(c_flags, KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY);
 
552
    setflag(state->c_flags, KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY);
199
553
    /*
200
554
     * Note that according to the referrals draft we should
201
555
     * always canonicalize enterprise principal names.
202
556
     */
203
 
    if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE) ||
204
 
        krb5_princ_type(kdc_context,
205
 
                        request->client) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
206
 
        setflag(c_flags, KRB5_KDB_FLAG_CANONICALIZE);
207
 
        setflag(c_flags, KRB5_KDB_FLAG_ALIAS_OK);
208
 
    }
209
 
    if (include_pac_p(kdc_context, request)) {
210
 
        setflag(c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
211
 
    }
212
 
    errcode = krb5_db_get_principal(kdc_context, request->client,
213
 
                                    c_flags, &client);
 
557
    if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) ||
 
558
        state->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
 
559
        setflag(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE);
 
560
        setflag(state->c_flags, KRB5_KDB_FLAG_ALIAS_OK);
 
561
    }
 
562
    if (include_pac_p(kdc_context, state->request)) {
 
563
        setflag(state->c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
 
564
    }
 
565
    errcode = krb5_db_get_principal(kdc_context, state->request->client,
 
566
                                    state->c_flags, &state->client);
214
567
    if (errcode == KRB5_KDB_NOENTRY) {
215
 
        status = "CLIENT_NOT_FOUND";
 
568
        state->status = "CLIENT_NOT_FOUND";
216
569
        if (vague_errors)
217
570
            errcode = KRB5KRB_ERR_GENERIC;
218
571
        else
219
572
            errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
220
573
        goto errout;
221
574
    } else if (errcode) {
222
 
        status = "LOOKING_UP_CLIENT";
 
575
        state->status = "LOOKING_UP_CLIENT";
223
576
        goto errout;
224
577
    }
 
578
    state->rock.client = state->client;
225
579
 
226
580
    /*
227
581
     * If the backend returned a principal that is not in the local
228
582
     * realm, then we need to refer the client to that realm.
229
583
     */
230
 
    if (!is_local_principal(client->princ)) {
 
584
    if (!is_local_principal(state->client->princ)) {
231
585
        /* Entry is a referral to another realm */
232
 
        status = "REFERRAL";
 
586
        state->status = "REFERRAL";
233
587
        errcode = KRB5KDC_ERR_WRONG_REALM;
234
588
        goto errout;
235
589
    }
248
602
 
249
603
    s_flags = 0;
250
604
    setflag(s_flags, KRB5_KDB_FLAG_ALIAS_OK);
251
 
    if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE)) {
 
605
    if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) {
252
606
        setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
253
607
    }
254
 
    errcode = krb5_db_get_principal(kdc_context, request->server,
255
 
                                    s_flags, &server);
 
608
    errcode = krb5_db_get_principal(kdc_context, state->request->server,
 
609
                                    s_flags, &state->server);
256
610
    if (errcode == KRB5_KDB_NOENTRY) {
257
 
        status = "SERVER_NOT_FOUND";
 
611
        state->status = "SERVER_NOT_FOUND";
258
612
        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
259
613
        goto errout;
260
614
    } else if (errcode) {
261
 
        status = "LOOKING_UP_SERVER";
262
 
        goto errout;
263
 
    }
264
 
 
265
 
    if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) {
266
 
        status = "TIMEOFDAY";
267
 
        goto errout;
268
 
    }
269
 
    authtime = kdc_time; /* for audit_as_request() */
270
 
 
271
 
    if ((errcode = validate_as_request(request, *client, *server,
272
 
                                       kdc_time, &status, &e_data))) {
273
 
        if (!status)
274
 
            status = "UNKNOWN_REASON";
 
615
        state->status = "LOOKING_UP_SERVER";
 
616
        goto errout;
 
617
    }
 
618
 
 
619
    if ((errcode = krb5_timeofday(kdc_context, &state->kdc_time))) {
 
620
        state->status = "TIMEOFDAY";
 
621
        goto errout;
 
622
    }
 
623
    state->authtime = state->kdc_time; /* for audit_as_request() */
 
624
 
 
625
    if ((errcode = validate_as_request(state->request, *state->client,
 
626
                                       *state->server, state->kdc_time,
 
627
                                       &state->status, &state->e_data))) {
 
628
        if (!state->status)
 
629
            state->status = "UNKNOWN_REASON";
275
630
        errcode += ERROR_TABLE_BASE_krb5;
276
631
        goto errout;
277
632
    }
279
634
    /*
280
635
     * Select the keytype for the ticket session key.
281
636
     */
282
 
    if ((useenctype = select_session_keytype(kdc_context, server,
283
 
                                             request->nktypes,
284
 
                                             request->ktype)) == 0) {
 
637
    if ((useenctype = select_session_keytype(kdc_context, state->server,
 
638
                                             state->request->nktypes,
 
639
                                             state->request->ktype)) == 0) {
285
640
        /* unsupported ktype */
286
 
        status = "BAD_ENCRYPTION_TYPE";
 
641
        state->status = "BAD_ENCRYPTION_TYPE";
287
642
        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
288
643
        goto errout;
289
644
    }
290
645
 
291
646
    if ((errcode = krb5_c_make_random_key(kdc_context, useenctype,
292
 
                                          &session_key))) {
293
 
        status = "RANDOM_KEY_FAILED";
 
647
                                          &state->session_key))) {
 
648
        state->status = "RANDOM_KEY_FAILED";
294
649
        goto errout;
295
650
    }
296
651
 
300
655
     * aliases, nothing more).
301
656
     */
302
657
    if (isflagset(s_flags, KRB5_KDB_FLAG_CANONICALIZE) &&
303
 
        krb5_is_tgs_principal(request->server) &&
304
 
        krb5_is_tgs_principal(server->princ)) {
305
 
        ticket_reply.server = server->princ;
 
658
        krb5_is_tgs_principal(state->request->server) &&
 
659
        krb5_is_tgs_principal(state->server->princ)) {
 
660
        state->ticket_reply.server = state->server->princ;
306
661
    } else {
307
 
        ticket_reply.server = request->server;
 
662
        state->ticket_reply.server = state->request->server;
308
663
    }
309
664
 
310
 
    enc_tkt_reply.flags = 0;
311
 
    enc_tkt_reply.times.authtime = authtime;
 
665
    state->enc_tkt_reply.flags = 0;
 
666
    state->enc_tkt_reply.times.authtime = state->authtime;
312
667
 
313
 
    setflag(enc_tkt_reply.flags, TKT_FLG_INITIAL);
314
 
    setflag(enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP);
 
668
    setflag(state->enc_tkt_reply.flags, TKT_FLG_INITIAL);
 
669
    setflag(state->enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP);
315
670
 
316
671
    /*
317
672
     * It should be noted that local policy may affect the
319
674
     * realms may refuse to issue renewable tickets
320
675
     */
321
676
 
322
 
    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE))
323
 
        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
324
 
 
325
 
    if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE))
326
 
        setflag(enc_tkt_reply.flags, TKT_FLG_PROXIABLE);
327
 
 
328
 
    if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
329
 
        setflag(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
330
 
 
331
 
    enc_tkt_reply.session = &session_key;
332
 
    if (isflagset(c_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
333
 
        client_princ = *(client->princ);
 
677
    if (isflagset(state->request->kdc_options, KDC_OPT_FORWARDABLE))
 
678
        setflag(state->enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
 
679
 
 
680
    if (isflagset(state->request->kdc_options, KDC_OPT_PROXIABLE))
 
681
        setflag(state->enc_tkt_reply.flags, TKT_FLG_PROXIABLE);
 
682
 
 
683
    if (isflagset(state->request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
 
684
        setflag(state->enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
 
685
 
 
686
    state->enc_tkt_reply.session = &state->session_key;
 
687
    if (isflagset(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
 
688
        client_princ = *(state->client->princ);
334
689
    } else {
335
 
        client_princ = *(request->client);
 
690
        client_princ = *(state->request->client);
336
691
        /* The realm is always canonicalized */
337
 
        client_princ.realm = *(krb5_princ_realm(context, client->princ));
 
692
        client_princ.realm = state->client->princ->realm;
338
693
    }
339
 
    enc_tkt_reply.client = &client_princ;
340
 
    enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
341
 
    enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */
 
694
    state->enc_tkt_reply.client = &client_princ;
 
695
    state->enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
 
696
    state->enc_tkt_reply.transited.tr_contents = empty_string;
342
697
 
343
 
    if (isflagset(request->kdc_options, KDC_OPT_POSTDATED)) {
344
 
        setflag(enc_tkt_reply.flags, TKT_FLG_POSTDATED);
345
 
        setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
346
 
        enc_tkt_reply.times.starttime = request->from;
 
698
    if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED)) {
 
699
        setflag(state->enc_tkt_reply.flags, TKT_FLG_POSTDATED);
 
700
        setflag(state->enc_tkt_reply.flags, TKT_FLG_INVALID);
 
701
        state->enc_tkt_reply.times.starttime = state->request->from;
347
702
    } else
348
 
        enc_tkt_reply.times.starttime = kdc_time;
349
 
 
350
 
    kdc_get_ticket_endtime(kdc_context,
351
 
                           enc_tkt_reply.times.starttime,
352
 
                           kdc_infinity,
353
 
                           request->till,
354
 
                           client,
355
 
                           server,
356
 
                           &enc_tkt_reply.times.endtime);
357
 
 
358
 
    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
359
 
        !isflagset(client->attributes, KRB5_KDB_DISALLOW_RENEWABLE) &&
360
 
        (enc_tkt_reply.times.endtime < request->till)) {
 
703
        state->enc_tkt_reply.times.starttime = state->kdc_time;
 
704
 
 
705
    kdc_get_ticket_endtime(kdc_context, state->enc_tkt_reply.times.starttime,
 
706
                           kdc_infinity, state->request->till, state->client,
 
707
                           state->server, &state->enc_tkt_reply.times.endtime);
 
708
 
 
709
    if (isflagset(state->request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
 
710
        !isflagset(state->client->attributes, KRB5_KDB_DISALLOW_RENEWABLE) &&
 
711
        (state->enc_tkt_reply.times.endtime < state->request->till)) {
361
712
 
362
713
        /* we set the RENEWABLE option for later processing */
363
714
 
364
 
        setflag(request->kdc_options, KDC_OPT_RENEWABLE);
365
 
        request->rtime = request->till;
 
715
        setflag(state->request->kdc_options, KDC_OPT_RENEWABLE);
 
716
        state->request->rtime = state->request->till;
366
717
    }
367
 
    rtime = (request->rtime == 0) ? kdc_infinity : request->rtime;
 
718
    rtime = (state->request->rtime == 0) ? kdc_infinity :
 
719
        state->request->rtime;
368
720
 
369
 
    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) {
 
721
    if (isflagset(state->request->kdc_options, KDC_OPT_RENEWABLE)) {
370
722
        /*
371
723
         * XXX Should we squelch the output renew_till to be no
372
724
         * earlier than the endtime of the ticket?
373
725
         */
374
 
        setflag(enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
375
 
        enc_tkt_reply.times.renew_till =
376
 
            min(rtime, enc_tkt_reply.times.starttime +
377
 
                min(client->max_renewable_life,
378
 
                    min(server->max_renewable_life,
 
726
        setflag(state->enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
 
727
        state->enc_tkt_reply.times.renew_till =
 
728
            min(rtime, state->enc_tkt_reply.times.starttime +
 
729
                min(state->client->max_renewable_life,
 
730
                    min(state->server->max_renewable_life,
379
731
                        max_renewable_life_for_realm)));
380
732
    } else
381
 
        enc_tkt_reply.times.renew_till = 0; /* XXX */
 
733
        state->enc_tkt_reply.times.renew_till = 0; /* XXX */
382
734
 
383
735
    /*
384
736
     * starttime is optional, and treated as authtime if not present.
385
737
     * so we can nuke it if it matches
386
738
     */
387
 
    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
388
 
        enc_tkt_reply.times.starttime = 0;
 
739
    if (state->enc_tkt_reply.times.starttime ==
 
740
        state->enc_tkt_reply.times.authtime)
 
741
        state->enc_tkt_reply.times.starttime = 0;
389
742
 
390
 
    enc_tkt_reply.caddrs = request->addresses;
391
 
    enc_tkt_reply.authorization_data = 0;
 
743
    state->enc_tkt_reply.caddrs = state->request->addresses;
 
744
    state->enc_tkt_reply.authorization_data = 0;
392
745
 
393
746
    /* If anonymous requests are being used, adjust the realm of the client
394
747
     * principal. */
395
 
    if (isflagset(request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) {
396
 
        if (!krb5_principal_compare_any_realm(kdc_context, request->client,
 
748
    if (isflagset(state->request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) {
 
749
        if (!krb5_principal_compare_any_realm(kdc_context,
 
750
                                              state->request->client,
397
751
                                              krb5_anonymous_principal())) {
398
752
            errcode = KRB5KDC_ERR_BADOPTION;
399
 
            status = "Anonymous requested but anonymous principal not used.";
 
753
            state->status = "Anonymous requested but anonymous "
 
754
                "principal not used.";
400
755
            goto errout;
401
756
        }
402
 
        setflag(enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
403
 
        krb5_free_principal(kdc_context, request->client);
 
757
        setflag(state->enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
 
758
        krb5_free_principal(kdc_context, state->request->client);
404
759
        errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
405
 
                                      &request->client);
 
760
                                      &state->request->client);
406
761
        if (errcode) {
407
 
            status = "Copying anonymous principal";
 
762
            state->status = "Copying anonymous principal";
408
763
            goto errout;
409
764
        }
410
 
        enc_tkt_reply.client = request->client;
411
 
        setflag(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH);
 
765
        state->enc_tkt_reply.client = state->request->client;
 
766
        setflag(state->client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH);
412
767
    }
 
768
 
413
769
    /*
414
770
     * Check the preauthentication if it is there.
415
771
     */
416
 
    if (request->padata) {
417
 
        errcode = check_padata(kdc_context, client, req_pkt, request,
418
 
                               &enc_tkt_reply, &pa_context, &e_data);
419
 
        if (errcode) {
420
 
            if (errcode == KRB5KDC_ERR_PREAUTH_FAILED)
421
 
                get_preauth_hint_list(request, client, server, &e_data);
422
 
 
423
 
            status = "PREAUTH_FAILED";
424
 
            if (vague_errors)
425
 
                errcode = KRB5KRB_ERR_GENERIC;
426
 
            goto errout;
427
 
        }
428
 
    }
429
 
 
430
 
    /*
431
 
     * Final check before handing out ticket: If the client requires
432
 
     * preauthentication, verify that the proper kind of
433
 
     * preauthentication was carried out.
434
 
     */
435
 
    status = missing_required_preauth(client, server, &enc_tkt_reply);
436
 
    if (status) {
437
 
        errcode = KRB5KDC_ERR_PREAUTH_REQUIRED;
438
 
        get_preauth_hint_list(request, client, server, &e_data);
439
 
        goto errout;
440
 
    }
441
 
 
442
 
    if ((errcode = validate_forwardable(request, *client, *server,
443
 
                                        kdc_time, &status))) {
444
 
        errcode += ERROR_TABLE_BASE_krb5;
445
 
        goto errout;
446
 
    }
447
 
 
448
 
    ticket_reply.enc_part2 = &enc_tkt_reply;
449
 
 
450
 
    /*
451
 
     * Find the server key
452
 
     */
453
 
    if ((errcode = krb5_dbe_find_enctype(kdc_context, server,
454
 
                                         -1, /* ignore keytype   */
455
 
                                         -1, /* Ignore salttype  */
456
 
                                         0,  /* Get highest kvno */
457
 
                                         &server_key))) {
458
 
        status = "FINDING_SERVER_KEY";
459
 
        goto errout;
460
 
    }
461
 
 
462
 
    /*
463
 
     * Convert server->key into a real key
464
 
     * (it may be encrypted in the database)
465
 
     *
466
 
     *  server_keyblock is later used to generate auth data signatures
467
 
     */
468
 
    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
469
 
                                             server_key, &server_keyblock,
470
 
                                             NULL))) {
471
 
        status = "DECRYPT_SERVER_KEY";
472
 
        goto errout;
473
 
    }
474
 
 
475
 
    /*
476
 
     * Find the appropriate client key.  We search in the order specified
477
 
     * by request keytype list.
478
 
     */
479
 
    client_key = (krb5_key_data *) NULL;
480
 
    for (i = 0; i < request->nktypes; i++) {
481
 
        useenctype = request->ktype[i];
482
 
        if (!krb5_c_valid_enctype(useenctype))
483
 
            continue;
484
 
 
485
 
        if (!krb5_dbe_find_enctype(kdc_context, client, useenctype, -1,
486
 
                                   0, &client_key))
487
 
            break;
488
 
    }
489
 
    if (!(client_key)) {
490
 
        /* Cannot find an appropriate key */
491
 
        status = "CANT_FIND_CLIENT_KEY";
492
 
        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
493
 
        goto errout;
494
 
    }
495
 
 
496
 
    /* convert client.key_data into a real key */
497
 
    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
498
 
                                             client_key, &client_keyblock,
499
 
                                             NULL))) {
500
 
        status = "DECRYPT_CLIENT_KEY";
501
 
        goto errout;
502
 
    }
503
 
    client_keyblock.enctype = useenctype;
504
 
 
505
 
    /* Start assembling the response */
506
 
    reply.msg_type = KRB5_AS_REP;
507
 
    reply.client = enc_tkt_reply.client; /* post canonicalization */
508
 
    reply.ticket = &ticket_reply;
509
 
    reply_encpart.session = &session_key;
510
 
    if ((errcode = fetch_last_req_info(client, &reply_encpart.last_req))) {
511
 
        status = "FETCH_LAST_REQ";
512
 
        goto errout;
513
 
    }
514
 
    reply_encpart.nonce = request->nonce;
515
 
    reply_encpart.key_exp = get_key_exp(client);
516
 
    reply_encpart.flags = enc_tkt_reply.flags;
517
 
    reply_encpart.server = ticket_reply.server;
518
 
 
519
 
    /* copy the time fields EXCEPT for authtime; it's location
520
 
     *  is used for ktime
521
 
     */
522
 
    reply_encpart.times = enc_tkt_reply.times;
523
 
    reply_encpart.times.authtime = authtime = kdc_time;
524
 
 
525
 
    reply_encpart.caddrs = enc_tkt_reply.caddrs;
526
 
    reply_encpart.enc_padata = NULL;
527
 
 
528
 
    /* Fetch the padata info to be returned (do this before
529
 
     *  authdata to handle possible replacement of reply key
530
 
     */
531
 
    errcode = return_padata(kdc_context, client, req_pkt, request,
532
 
                            &reply, client_key, &client_keyblock, &pa_context);
533
 
    if (errcode) {
534
 
        status = "KDC_RETURN_PADATA";
535
 
        goto errout;
536
 
    }
537
 
 
538
 
#if APPLE_PKINIT
539
 
    asReqDebug("process_as_req reply realm %s name %s\n",
540
 
               reply.client->realm.data, reply.client->data->data);
541
 
#endif /* APPLE_PKINIT */
542
 
 
543
 
 
544
 
 
545
 
    errcode = handle_authdata(kdc_context,
546
 
                              c_flags,
547
 
                              client,
548
 
                              server,
549
 
                              server,
550
 
                              &client_keyblock,
551
 
                              &server_keyblock,
552
 
                              &server_keyblock,
553
 
                              req_pkt,
554
 
                              request,
555
 
                              NULL, /* for_user_princ */
556
 
                              NULL, /* enc_tkt_request */
557
 
                              &enc_tkt_reply);
558
 
    if (errcode) {
559
 
        krb5_klog_syslog(LOG_INFO, "AS_REQ : handle_authdata (%d)", errcode);
560
 
        status = "HANDLE_AUTHDATA";
561
 
        goto errout;
562
 
    }
563
 
 
564
 
    errcode = krb5_encrypt_tkt_part(kdc_context, &server_keyblock,
565
 
                                    &ticket_reply);
566
 
    if (errcode) {
567
 
        status = "ENCRYPTING_TICKET";
568
 
        goto errout;
569
 
    }
570
 
    ticket_reply.enc_part.kvno = server_key->key_data_kvno;
571
 
    errcode = kdc_fast_response_handle_padata(state, request, &reply,
572
 
                                              client_keyblock.enctype);
573
 
    if (errcode) {
574
 
        status = "fast response handling";
575
 
        goto errout;
576
 
    }
577
 
 
578
 
    /* now encode/encrypt the response */
579
 
 
580
 
    reply.enc_part.enctype = client_keyblock.enctype;
581
 
 
582
 
    errcode = kdc_fast_handle_reply_key(state, &client_keyblock,
583
 
                                        &as_encrypting_key);
584
 
    if (errcode) {
585
 
        status = "generating reply key";
586
 
        goto errout;
587
 
    }
588
 
    errcode = return_enc_padata(kdc_context, req_pkt, request,
589
 
                                as_encrypting_key, server, &reply_encpart,
590
 
                                FALSE);
591
 
    if (errcode) {
592
 
        status = "KDC_RETURN_ENC_PADATA";
593
 
        goto errout;
594
 
    }
595
 
 
596
 
    errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart,
597
 
                                  0, as_encrypting_key,  &reply, response);
598
 
    reply.enc_part.kvno = client_key->key_data_kvno;
599
 
    if (errcode) {
600
 
        status = "ENCODE_KDC_REP";
601
 
        goto errout;
602
 
    }
603
 
 
604
 
    /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
605
 
       can use them in raw form if needed.  But, we don't... */
606
 
    memset(reply.enc_part.ciphertext.data, 0, reply.enc_part.ciphertext.length);
607
 
    free(reply.enc_part.ciphertext.data);
608
 
 
609
 
    log_as_req(from, request, &reply, client, cname, server, sname,
610
 
               authtime, 0, 0, 0);
611
 
    did_log = 1;
612
 
 
613
 
    goto egress;
 
772
    if (state->request->padata) {
 
773
        check_padata(kdc_context, &state->rock, state->req_pkt,
 
774
                     state->request, &state->enc_tkt_reply, &state->pa_context,
 
775
                     &state->e_data, &state->typed_e_data, finish_preauth,
 
776
                     state);
 
777
    } else
 
778
        finish_preauth(state, 0);
 
779
    return;
614
780
 
615
781
errout:
616
 
    assert (status != 0);
617
 
    /* fall through */
618
 
 
619
 
egress:
620
 
    if (pa_context)
621
 
        free_padata_context(kdc_context, &pa_context);
622
 
    if (as_encrypting_key)
623
 
        krb5_free_keyblock(kdc_context, as_encrypting_key);
624
 
    if (errcode)
625
 
        emsg = krb5_get_error_message(kdc_context, errcode);
626
 
 
627
 
    if (status) {
628
 
        log_as_req(from, request, &reply, client, cname, server, sname,
629
 
                   authtime, status, errcode, emsg);
630
 
        did_log = 1;
631
 
    }
632
 
    if (errcode) {
633
 
        if (status == 0) {
634
 
            status = emsg;
635
 
        }
636
 
        if (errcode == KRB5KDC_ERR_DISCARD)
637
 
            goto discard;
638
 
        errcode -= ERROR_TABLE_BASE_krb5;
639
 
        if (errcode < 0 || errcode > 128)
640
 
            errcode = KRB_ERR_GENERIC;
641
 
 
642
 
        errcode = prepare_error_as(state, request, errcode, &e_data,
643
 
                                   (client != NULL) ? client->princ : NULL,
644
 
                                   response, status);
645
 
        status = 0;
646
 
    }
647
 
 
648
 
discard: if (emsg)
649
 
        krb5_free_error_message(kdc_context, emsg);
650
 
    if (enc_tkt_reply.authorization_data != NULL)
651
 
        krb5_free_authdata(kdc_context, enc_tkt_reply.authorization_data);
652
 
    if (server_keyblock.contents != NULL)
653
 
        krb5_free_keyblock_contents(kdc_context, &server_keyblock);
654
 
    if (client_keyblock.contents != NULL)
655
 
        krb5_free_keyblock_contents(kdc_context, &client_keyblock);
656
 
    if (reply.padata != NULL)
657
 
        krb5_free_pa_data(kdc_context, reply.padata);
658
 
    if (reply_encpart.enc_padata)
659
 
        krb5_free_pa_data(kdc_context, reply_encpart.enc_padata);
660
 
 
661
 
    if (cname != NULL)
662
 
        free(cname);
663
 
    if (sname != NULL)
664
 
        free(sname);
665
 
    krb5_db_free_principal(kdc_context, client);
666
 
    krb5_db_free_principal(kdc_context, server);
667
 
    if (session_key.contents != NULL)
668
 
        krb5_free_keyblock_contents(kdc_context, &session_key);
669
 
    if (ticket_reply.enc_part.ciphertext.data != NULL) {
670
 
        memset(ticket_reply.enc_part.ciphertext.data , 0,
671
 
               ticket_reply.enc_part.ciphertext.length);
672
 
        free(ticket_reply.enc_part.ciphertext.data);
673
 
    }
674
 
 
675
 
    krb5_free_data_contents(kdc_context, &e_data);
676
 
    kdc_free_rstate(state);
677
 
    request->kdc_state = NULL;
678
 
    krb5_free_kdc_req(kdc_context, request);
679
 
    assert(did_log != 0);
680
 
 
681
 
    return errcode;
 
782
    finish_process_as_req(state, errcode);
682
783
}
683
784
 
684
785
static krb5_error_code
685
786
prepare_error_as (struct kdc_request_state *rstate, krb5_kdc_req *request,
686
 
                  int error, krb5_data *e_data,
 
787
                  int error, krb5_pa_data **e_data, krb5_boolean typed_e_data,
687
788
                  krb5_principal canon_client, krb5_data **response,
688
789
                  const char *status)
689
790
{
690
791
    krb5_error errpkt;
691
792
    krb5_error_code retval;
692
 
    krb5_data *scratch;
693
 
    krb5_pa_data **pa = NULL;
694
 
    krb5_typed_data **td = NULL;
695
 
    size_t size;
 
793
    krb5_data *scratch = NULL, *e_data_asn1 = NULL, *fast_edata = NULL;
696
794
 
697
795
    errpkt.ctime = request->nonce;
698
796
    errpkt.cusec = 0;
699
797
 
700
 
    if ((retval = krb5_us_timeofday(kdc_context, &errpkt.stime,
701
 
                                    &errpkt.susec)))
702
 
        return(retval);
 
798
    retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec);
 
799
    if (retval)
 
800
        return retval;
703
801
    errpkt.error = error;
704
802
    errpkt.server = request->server;
705
 
 
706
 
    if (error == KRB5KDC_ERR_WRONG_REALM)
707
 
        errpkt.client = canon_client;
708
 
    else
709
 
        errpkt.client = request->client;
710
 
    errpkt.text.length = strlen(status);
711
 
    if (!(errpkt.text.data = strdup(status)))
712
 
        return ENOMEM;
713
 
 
714
 
    if (!(scratch = (krb5_data *)malloc(sizeof(*scratch)))) {
715
 
        free(errpkt.text.data);
716
 
        return ENOMEM;
717
 
    }
718
 
    if (e_data  != NULL&& e_data->data != NULL) {
719
 
        errpkt.e_data = *e_data;
720
 
    } else {
721
 
        errpkt.e_data.length = 0;
722
 
        errpkt.e_data.data = NULL;
723
 
    }
724
 
    /*We need to try and produce a padata sequence for FAST*/
725
 
    retval = decode_krb5_padata_sequence(e_data, &pa);
726
 
    if (retval != 0) {
727
 
        retval = decode_krb5_typed_data(e_data, &td);
728
 
        if (retval == 0) {
729
 
            for (size =0; td[size]; size++);
730
 
            pa = calloc(size+1, sizeof(*pa));
731
 
            if (pa == NULL)
732
 
                retval = ENOMEM;
733
 
            else
734
 
                for (size = 0; td[size]; size++) {
735
 
                    krb5_pa_data *pad = malloc(sizeof(krb5_pa_data ));
736
 
                    if (pad == NULL) {
737
 
                        retval = ENOMEM;
738
 
                        break;
739
 
                    }
740
 
                    pad->pa_type = td[size]->type;
741
 
                    pad->contents = td[size]->data;
742
 
                    pad->length = td[size]->length;
743
 
                    pa[size] = pad;
744
 
                    td[size]->data = NULL;
745
 
                    td[size]->length = 0;
746
 
                }
747
 
            krb5_free_typed_data(kdc_context, td);
748
 
        }
749
 
    }
750
 
    retval = kdc_fast_handle_error(kdc_context, rstate,
751
 
                                   request, pa, &errpkt);
752
 
    if (retval == 0)
753
 
        retval = krb5_mk_error(kdc_context, &errpkt, scratch);
754
 
 
755
 
    free(errpkt.text.data);
756
 
    if (retval)
757
 
        free(scratch);
758
 
    else
759
 
        *response = scratch;
760
 
    krb5_free_pa_data(kdc_context, pa);
761
 
 
 
803
    errpkt.client = (error == KRB5KDC_ERR_WRONG_REALM) ? canon_client :
 
804
        request->client;
 
805
    errpkt.text = string2data((char *)status);
 
806
 
 
807
    if (e_data != NULL) {
 
808
        if (typed_e_data) {
 
809
            retval = encode_krb5_typed_data((const krb5_typed_data **)e_data,
 
810
                                            &e_data_asn1);
 
811
        } else
 
812
            retval = encode_krb5_padata_sequence(e_data, &e_data_asn1);
 
813
        if (retval)
 
814
            goto cleanup;
 
815
        errpkt.e_data = *e_data_asn1;
 
816
    } else
 
817
        errpkt.e_data = empty_data();
 
818
 
 
819
    retval = kdc_fast_handle_error(kdc_context, rstate, request, e_data,
 
820
                                   &errpkt, &fast_edata);
 
821
    if (retval)
 
822
        goto cleanup;
 
823
    if (fast_edata != NULL)
 
824
        errpkt.e_data = *fast_edata;
 
825
 
 
826
    scratch = k5alloc(sizeof(*scratch), &retval);
 
827
    if (scratch == NULL)
 
828
        goto cleanup;
 
829
    retval = krb5_mk_error(kdc_context, &errpkt, scratch);
 
830
    if (retval)
 
831
        goto cleanup;
 
832
 
 
833
    *response = scratch;
 
834
    scratch = NULL;
 
835
 
 
836
cleanup:
 
837
    krb5_free_data(kdc_context, fast_edata);
 
838
    krb5_free_data(kdc_context, e_data_asn1);
 
839
    free(scratch);
762
840
    return retval;
763
841
}