1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
4 * Portions Copyright (C) 2007 Apple Inc.
5 * Copyright 1990,1991,2007,2008,2009 by the Massachusetts Institute of Technology.
8 * Export of this software from the United States of America may
9 * require a specific license from the United States Government.
10 * It is the responsibility of any person or organization contemplating
11 * export to obtain such a license before exporting.
13 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14 * distribute this software and its documentation for any purpose and
15 * without fee is hereby granted, provided that the above copyright
16 * notice appear in all copies and that both that copyright notice and
17 * this permission notice appear in supporting documentation, and that
18 * the name of M.I.T. not be used in advertising or publicity pertaining
19 * to distribution of the software without specific, written prior
20 * permission. Furthermore if you modify this software you must label
21 * your software as modified software and not distribute it in such a
22 * fashion that it might be confused with the original M.I.T. software.
23 * M.I.T. makes no representations about the suitability of
24 * this software for any purpose. It is provided "as is" without express
25 * or implied warranty.
28 * KDC Routines to deal with AS_REQ's
31 * Copyright (c) 2006-2008, Novell, Inc.
32 * All rights reserved.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions are met:
37 * * Redistributions of source code must retain the above copyright notice,
38 * this list of conditions and the following disclaimer.
39 * * Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * * The copyright holder's name is not used to endorse or promote products
43 * derived from this software without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
46 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
49 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55 * POSSIBILITY OF SUCH DAMAGE.
62 #ifdef HAVE_NETINET_IN_H
63 #include <sys/types.h>
64 #include <netinet/in.h>
66 #include <arpa/inet.h>
68 #endif /* HAVE_NETINET_IN_H */
73 #include "adm_proto.h"
77 #define AS_REQ_DEBUG 0
79 #define asReqDebug(args...) printf(args)
81 #define asReqDebug(args...)
83 #endif /* APPLE_PKINIT */
85 static krb5_error_code
86 prepare_error_as(struct kdc_request_state *, krb5_kdc_req *,
87 int, krb5_pa_data **, krb5_boolean, krb5_principal,
88 krb5_data **, const char *);
90 /* Determine the key-expiration value according to RFC 4120 section 5.4.2. */
92 get_key_exp(krb5_db_entry *entry)
94 if (entry->expiration == 0)
95 return entry->pw_expiration;
96 if (entry->pw_expiration == 0)
97 return entry->expiration;
98 return min(entry->expiration, entry->pw_expiration);
101 struct as_req_state {
102 loop_respond_fn respond;
105 krb5_principal_data client_princ;
106 krb5_enc_tkt_part enc_tkt_reply;
107 krb5_enc_kdc_rep_part reply_encpart;
108 krb5_ticket ticket_reply;
109 krb5_keyblock server_keyblock;
110 krb5_keyblock client_keyblock;
111 krb5_db_entry *client;
112 krb5_db_entry *server;
113 krb5_kdc_req *request;
114 struct krb5_kdcpreauth_rock_st rock;
116 krb5_pa_data **e_data;
117 krb5_boolean typed_e_data;
119 krb5_timestamp kdc_time;
120 krb5_timestamp authtime;
121 krb5_keyblock session_key;
122 unsigned int c_flags;
124 krb5_data *inner_body;
125 struct kdc_request_state *rstate;
128 const krb5_fulladdr *from;
130 krb5_error_code preauth_err;
134 finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
136 krb5_key_data *server_key;
137 krb5_key_data *client_key;
138 krb5_keyblock *as_encrypting_key = NULL;
139 krb5_data *response = NULL;
140 const char *emsg = 0;
143 krb5_enctype useenctype;
144 loop_respond_fn oldrespond;
148 oldrespond = state->respond;
154 if ((errcode = validate_forwardable(state->request, *state->client,
155 *state->server, state->kdc_time,
157 errcode += ERROR_TABLE_BASE_krb5;
161 state->ticket_reply.enc_part2 = &state->enc_tkt_reply;
164 * Find the server key
166 if ((errcode = krb5_dbe_find_enctype(kdc_context, state->server,
167 -1, /* ignore keytype */
168 -1, /* Ignore salttype */
169 0, /* Get highest kvno */
171 state->status = "FINDING_SERVER_KEY";
176 * Convert server->key into a real key
177 * (it may be encrypted in the database)
179 * server_keyblock is later used to generate auth data signatures
181 if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
183 &state->server_keyblock,
185 state->status = "DECRYPT_SERVER_KEY";
190 * Find the appropriate client key. We search in the order specified
191 * by request keytype list.
194 for (i = 0; i < state->request->nktypes; i++) {
195 useenctype = state->request->ktype[i];
196 if (!krb5_c_valid_enctype(useenctype))
199 if (!krb5_dbe_find_enctype(kdc_context, state->client,
200 useenctype, -1, 0, &client_key))
204 /* Cannot find an appropriate key */
205 state->status = "CANT_FIND_CLIENT_KEY";
206 errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
209 state->rock.client_key = client_key;
211 /* convert client.key_data into a real key */
212 if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
214 &state->client_keyblock,
216 state->status = "DECRYPT_CLIENT_KEY";
219 state->client_keyblock.enctype = useenctype;
221 /* Start assembling the response */
222 state->reply.msg_type = KRB5_AS_REP;
223 state->reply.client = state->enc_tkt_reply.client; /* post canonization */
224 state->reply.ticket = &state->ticket_reply;
225 state->reply_encpart.session = &state->session_key;
226 if ((errcode = fetch_last_req_info(state->client,
227 &state->reply_encpart.last_req))) {
228 state->status = "FETCH_LAST_REQ";
231 state->reply_encpart.nonce = state->request->nonce;
232 state->reply_encpart.key_exp = get_key_exp(state->client);
233 state->reply_encpart.flags = state->enc_tkt_reply.flags;
234 state->reply_encpart.server = state->ticket_reply.server;
236 /* copy the time fields EXCEPT for authtime; it's location
239 state->reply_encpart.times = state->enc_tkt_reply.times;
240 state->reply_encpart.times.authtime = state->authtime = state->kdc_time;
242 state->reply_encpart.caddrs = state->enc_tkt_reply.caddrs;
243 state->reply_encpart.enc_padata = NULL;
245 /* Fetch the padata info to be returned (do this before
246 * authdata to handle possible replacement of reply key
248 errcode = return_padata(kdc_context, &state->rock, state->req_pkt,
249 state->request, &state->reply,
250 &state->client_keyblock, &state->pa_context);
252 state->status = "KDC_RETURN_PADATA";
257 asReqDebug("process_as_req reply realm %s name %s\n",
258 reply.client->realm.data, reply.client->data->data);
259 #endif /* APPLE_PKINIT */
263 errcode = handle_authdata(kdc_context,
268 &state->client_keyblock,
269 &state->server_keyblock,
270 &state->server_keyblock,
273 NULL, /* for_user_princ */
274 NULL, /* enc_tkt_request */
275 &state->enc_tkt_reply);
277 krb5_klog_syslog(LOG_INFO, _("AS_REQ : handle_authdata (%d)"),
279 state->status = "HANDLE_AUTHDATA";
283 errcode = krb5_encrypt_tkt_part(kdc_context, &state->server_keyblock,
284 &state->ticket_reply);
286 state->status = "ENCRYPTING_TICKET";
289 state->ticket_reply.enc_part.kvno = server_key->key_data_kvno;
290 errcode = kdc_fast_response_handle_padata(state->rstate,
293 state->client_keyblock.enctype);
295 state->status = "fast response handling";
299 /* now encode/encrypt the response */
301 state->reply.enc_part.enctype = state->client_keyblock.enctype;
303 errcode = kdc_fast_handle_reply_key(state->rstate, &state->client_keyblock,
306 state->status = "generating reply key";
309 errcode = return_enc_padata(kdc_context, state->req_pkt, state->request,
310 as_encrypting_key, state->server,
311 &state->reply_encpart, FALSE);
313 state->status = "KDC_RETURN_ENC_PADATA";
317 errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP,
318 &state->reply_encpart, 0,
320 &state->reply, &response);
321 state->reply.enc_part.kvno = client_key->key_data_kvno;
323 state->status = "ENCODE_KDC_REP";
327 /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
328 can use them in raw form if needed. But, we don't... */
329 memset(state->reply.enc_part.ciphertext.data, 0,
330 state->reply.enc_part.ciphertext.length);
331 free(state->reply.enc_part.ciphertext.data);
333 log_as_req(state->from, state->request, &state->reply,
334 state->client, state->cname, state->server,
335 state->sname, state->authtime, 0, 0, 0);
340 assert (state->status != 0);
341 free_padata_context(kdc_context, state->pa_context);
342 if (as_encrypting_key)
343 krb5_free_keyblock(kdc_context, as_encrypting_key);
345 emsg = krb5_get_error_message(kdc_context, errcode);
348 log_as_req(state->from, state->request, &state->reply, state->client,
349 state->cname, state->server, state->sname, state->authtime,
350 state->status, errcode, emsg);
354 if (state->status == 0) {
355 state->status = emsg;
357 if (errcode != KRB5KDC_ERR_DISCARD) {
358 errcode -= ERROR_TABLE_BASE_krb5;
359 if (errcode < 0 || errcode > 128)
360 errcode = KRB_ERR_GENERIC;
362 errcode = prepare_error_as(state->rstate, state->request,
363 errcode, state->e_data,
365 ((state->client != NULL) ?
366 state->client->princ : NULL),
367 &response, state->status);
373 krb5_free_error_message(kdc_context, emsg);
374 if (state->enc_tkt_reply.authorization_data != NULL)
375 krb5_free_authdata(kdc_context,
376 state->enc_tkt_reply.authorization_data);
377 if (state->server_keyblock.contents != NULL)
378 krb5_free_keyblock_contents(kdc_context, &state->server_keyblock);
379 if (state->client_keyblock.contents != NULL)
380 krb5_free_keyblock_contents(kdc_context, &state->client_keyblock);
381 if (state->reply.padata != NULL)
382 krb5_free_pa_data(kdc_context, state->reply.padata);
383 if (state->reply_encpart.enc_padata)
384 krb5_free_pa_data(kdc_context, state->reply_encpart.enc_padata);
386 if (state->cname != NULL)
388 if (state->sname != NULL)
390 krb5_db_free_principal(kdc_context, state->client);
391 krb5_db_free_principal(kdc_context, state->server);
392 if (state->session_key.contents != NULL)
393 krb5_free_keyblock_contents(kdc_context, &state->session_key);
394 if (state->ticket_reply.enc_part.ciphertext.data != NULL) {
395 memset(state->ticket_reply.enc_part.ciphertext.data , 0,
396 state->ticket_reply.enc_part.ciphertext.length);
397 free(state->ticket_reply.enc_part.ciphertext.data);
400 krb5_free_pa_data(kdc_context, state->e_data);
401 krb5_free_data(kdc_context, state->inner_body);
402 kdc_free_rstate(state->rstate);
403 krb5_free_kdc_req(kdc_context, state->request);
404 assert(did_log != 0);
407 (*oldrespond)(oldarg, errcode, response);
411 finish_missing_required_preauth(void *arg)
413 struct as_req_state *state = (struct as_req_state *)arg;
415 finish_process_as_req(state, state->preauth_err);
419 finish_preauth(void *arg, krb5_error_code code)
421 struct as_req_state *state = arg;
422 krb5_error_code real_code = code;
426 code = KRB5KRB_ERR_GENERIC;
427 state->status = "PREAUTH_FAILED";
428 if (real_code == KRB5KDC_ERR_PREAUTH_FAILED) {
429 state->preauth_err = code;
430 get_preauth_hint_list(state->request, &state->rock, &state->e_data,
431 finish_missing_required_preauth, state);
436 * Final check before handing out ticket: If the client requires
437 * preauthentication, verify that the proper kind of
438 * preauthentication was carried out.
440 state->status = missing_required_preauth(state->client, state->server,
441 &state->enc_tkt_reply);
443 state->preauth_err = KRB5KDC_ERR_PREAUTH_REQUIRED;
444 get_preauth_hint_list(state->request, &state->rock, &state->e_data,
445 finish_missing_required_preauth, state);
450 finish_process_as_req(state, code);
455 process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
456 const krb5_fulladdr *from, verto_ctx *vctx,
457 loop_respond_fn respond, void *arg)
459 krb5_error_code errcode;
460 krb5_timestamp rtime;
461 unsigned int s_flags = 0;
462 krb5_data encoded_req_body;
463 krb5_enctype useenctype;
464 struct as_req_state *state;
466 state = malloc(sizeof(*state));
468 (*respond)(arg, ENOMEM, NULL);
471 state->session_key.contents = 0;
472 state->enc_tkt_reply.authorization_data = NULL;
473 state->reply.padata = 0;
474 memset(&state->reply, 0, sizeof(state->reply));
475 state->respond = respond;
477 state->ticket_reply.enc_part.ciphertext.data = 0;
478 state->server_keyblock.contents = NULL;
479 state->client_keyblock.contents = NULL;
480 state->reply_encpart.enc_padata = 0;
481 state->client = NULL;
482 state->server = NULL;
483 state->request = request;
484 state->e_data = NULL;
485 state->typed_e_data = FALSE;
488 state->req_pkt = req_pkt;
489 state->rstate = NULL;
492 state->pa_context = NULL;
494 memset(&state->rock, 0, sizeof(state->rock));
497 asReqDebug("process_as_req top realm %s name %s\n",
498 request->client->realm.data, request->client->data->data);
499 #endif /* APPLE_PKINIT */
501 if (state->request->msg_type != KRB5_AS_REQ) {
502 state->status = "msg_type mismatch";
503 errcode = KRB5_BADMSGTYPE;
506 errcode = kdc_make_rstate(&state->rstate);
508 state->status = "constructing state";
511 if (fetch_asn1_field((unsigned char *) req_pkt->data,
512 1, 4, &encoded_req_body) != 0) {
513 errcode = ASN1_BAD_ID;
514 state->status = "Finding req_body";
517 errcode = kdc_find_fast(&state->request, &encoded_req_body, NULL, NULL,
518 state->rstate, &state->inner_body);
520 state->status = "error decoding FAST";
523 if (state->inner_body == NULL) {
524 /* Not a FAST request; copy the encoded request body. */
525 errcode = krb5_copy_data(kdc_context, &encoded_req_body,
528 state->status = "storing req body";
532 state->rock.request = state->request;
533 state->rock.inner_body = state->inner_body;
534 state->rock.rstate = state->rstate;
535 state->rock.vctx = vctx;
536 if (!state->request->client) {
537 state->status = "NULL_CLIENT";
538 errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
541 if ((errcode = krb5_unparse_name(kdc_context,
542 state->request->client,
544 state->status = "UNPARSING_CLIENT";
547 limit_string(state->cname);
548 if (!state->request->server) {
549 state->status = "NULL_SERVER";
550 errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
553 if ((errcode = krb5_unparse_name(kdc_context,
554 state->request->server,
556 state->status = "UNPARSING_SERVER";
559 limit_string(state->sname);
562 * We set KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY as a hint
563 * to the backend to return naming information in lieu
564 * of cross realm TGS entries.
566 setflag(state->c_flags, KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY);
568 * Note that according to the referrals draft we should
569 * always canonicalize enterprise principal names.
571 if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) ||
572 state->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
573 setflag(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE);
574 setflag(state->c_flags, KRB5_KDB_FLAG_ALIAS_OK);
576 if (include_pac_p(kdc_context, state->request)) {
577 setflag(state->c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
579 errcode = krb5_db_get_principal(kdc_context, state->request->client,
580 state->c_flags, &state->client);
581 if (errcode == KRB5_KDB_NOENTRY) {
582 state->status = "CLIENT_NOT_FOUND";
584 errcode = KRB5KRB_ERR_GENERIC;
586 errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
588 } else if (errcode) {
589 state->status = "LOOKING_UP_CLIENT";
592 state->rock.client = state->client;
595 * If the backend returned a principal that is not in the local
596 * realm, then we need to refer the client to that realm.
598 if (!is_local_principal(state->client->princ)) {
599 /* Entry is a referral to another realm */
600 state->status = "REFERRAL";
601 errcode = KRB5KDC_ERR_WRONG_REALM;
607 * Turn off canonicalization if client is marked DES only
608 * (unless enterprise principal name was requested)
610 if (isflagset(client->attributes, KRB5_KDB_NON_MS_PRINCIPAL) &&
611 krb5_princ_type(kdc_context,
612 request->client) != KRB5_NT_ENTERPRISE_PRINCIPAL) {
613 clear(c_flags, KRB5_KDB_FLAG_CANONICALIZE);
618 setflag(s_flags, KRB5_KDB_FLAG_ALIAS_OK);
619 if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) {
620 setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
622 errcode = krb5_db_get_principal(kdc_context, state->request->server,
623 s_flags, &state->server);
624 if (errcode == KRB5_KDB_NOENTRY) {
625 state->status = "SERVER_NOT_FOUND";
626 errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
628 } else if (errcode) {
629 state->status = "LOOKING_UP_SERVER";
633 if ((errcode = krb5_timeofday(kdc_context, &state->kdc_time))) {
634 state->status = "TIMEOFDAY";
637 state->authtime = state->kdc_time; /* for audit_as_request() */
639 if ((errcode = validate_as_request(state->request, *state->client,
640 *state->server, state->kdc_time,
641 &state->status, &state->e_data))) {
643 state->status = "UNKNOWN_REASON";
644 errcode += ERROR_TABLE_BASE_krb5;
649 * Select the keytype for the ticket session key.
651 if ((useenctype = select_session_keytype(kdc_context, state->server,
652 state->request->nktypes,
653 state->request->ktype)) == 0) {
654 /* unsupported ktype */
655 state->status = "BAD_ENCRYPTION_TYPE";
656 errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
660 if ((errcode = krb5_c_make_random_key(kdc_context, useenctype,
661 &state->session_key))) {
662 state->status = "RANDOM_KEY_FAILED";
667 * Canonicalization is only effective if we are issuing a TGT
668 * (the intention is to allow support for Windows "short" realm
669 * aliases, nothing more).
671 if (isflagset(s_flags, KRB5_KDB_FLAG_CANONICALIZE) &&
672 krb5_is_tgs_principal(state->request->server) &&
673 krb5_is_tgs_principal(state->server->princ)) {
674 state->ticket_reply.server = state->server->princ;
676 state->ticket_reply.server = state->request->server;
679 state->enc_tkt_reply.flags = 0;
680 state->enc_tkt_reply.times.authtime = state->authtime;
682 setflag(state->enc_tkt_reply.flags, TKT_FLG_INITIAL);
683 setflag(state->enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP);
686 * It should be noted that local policy may affect the
687 * processing of any of these flags. For example, some
688 * realms may refuse to issue renewable tickets
691 if (isflagset(state->request->kdc_options, KDC_OPT_FORWARDABLE))
692 setflag(state->enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
694 if (isflagset(state->request->kdc_options, KDC_OPT_PROXIABLE))
695 setflag(state->enc_tkt_reply.flags, TKT_FLG_PROXIABLE);
697 if (isflagset(state->request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
698 setflag(state->enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
700 state->enc_tkt_reply.session = &state->session_key;
701 if (isflagset(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
702 state->client_princ = *(state->client->princ);
704 state->client_princ = *(state->request->client);
705 /* The realm is always canonicalized */
706 state->client_princ.realm = state->client->princ->realm;
708 state->enc_tkt_reply.client = &state->client_princ;
709 state->enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
710 state->enc_tkt_reply.transited.tr_contents = empty_string;
712 if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED)) {
713 setflag(state->enc_tkt_reply.flags, TKT_FLG_POSTDATED);
714 setflag(state->enc_tkt_reply.flags, TKT_FLG_INVALID);
715 state->enc_tkt_reply.times.starttime = state->request->from;
717 state->enc_tkt_reply.times.starttime = state->kdc_time;
719 kdc_get_ticket_endtime(kdc_context, state->enc_tkt_reply.times.starttime,
720 kdc_infinity, state->request->till, state->client,
721 state->server, &state->enc_tkt_reply.times.endtime);
723 if (isflagset(state->request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
724 !isflagset(state->client->attributes, KRB5_KDB_DISALLOW_RENEWABLE) &&
725 (state->enc_tkt_reply.times.endtime < state->request->till)) {
727 /* we set the RENEWABLE option for later processing */
729 setflag(state->request->kdc_options, KDC_OPT_RENEWABLE);
730 state->request->rtime = state->request->till;
732 rtime = (state->request->rtime == 0) ? kdc_infinity :
733 state->request->rtime;
735 if (isflagset(state->request->kdc_options, KDC_OPT_RENEWABLE)) {
737 * XXX Should we squelch the output renew_till to be no
738 * earlier than the endtime of the ticket?
740 setflag(state->enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
741 state->enc_tkt_reply.times.renew_till =
742 min(rtime, state->enc_tkt_reply.times.starttime +
743 min(state->client->max_renewable_life,
744 min(state->server->max_renewable_life,
745 max_renewable_life_for_realm)));
747 state->enc_tkt_reply.times.renew_till = 0; /* XXX */
750 * starttime is optional, and treated as authtime if not present.
751 * so we can nuke it if it matches
753 if (state->enc_tkt_reply.times.starttime ==
754 state->enc_tkt_reply.times.authtime)
755 state->enc_tkt_reply.times.starttime = 0;
757 state->enc_tkt_reply.caddrs = state->request->addresses;
758 state->enc_tkt_reply.authorization_data = 0;
760 /* If anonymous requests are being used, adjust the realm of the client
762 if (isflagset(state->request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) {
763 if (!krb5_principal_compare_any_realm(kdc_context,
764 state->request->client,
765 krb5_anonymous_principal())) {
766 errcode = KRB5KDC_ERR_BADOPTION;
767 state->status = "Anonymous requested but anonymous "
768 "principal not used.";
771 setflag(state->enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
772 krb5_free_principal(kdc_context, state->request->client);
773 errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
774 &state->request->client);
776 state->status = "Copying anonymous principal";
779 state->enc_tkt_reply.client = state->request->client;
780 setflag(state->client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH);
784 * Check the preauthentication if it is there.
786 if (state->request->padata) {
787 check_padata(kdc_context, &state->rock, state->req_pkt,
788 state->request, &state->enc_tkt_reply, &state->pa_context,
789 &state->e_data, &state->typed_e_data, finish_preauth,
792 finish_preauth(state, 0);
796 finish_process_as_req(state, errcode);
799 static krb5_error_code
800 prepare_error_as (struct kdc_request_state *rstate, krb5_kdc_req *request,
801 int error, krb5_pa_data **e_data, krb5_boolean typed_e_data,
802 krb5_principal canon_client, krb5_data **response,
806 krb5_error_code retval;
807 krb5_data *scratch = NULL, *e_data_asn1 = NULL, *fast_edata = NULL;
809 errpkt.ctime = request->nonce;
812 retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec);
815 errpkt.error = error;
816 errpkt.server = request->server;
817 errpkt.client = (error == KRB5KDC_ERR_WRONG_REALM) ? canon_client :
819 errpkt.text = string2data((char *)status);
821 if (e_data != NULL) {
823 retval = encode_krb5_typed_data((const krb5_typed_data **)e_data,
826 retval = encode_krb5_padata_sequence(e_data, &e_data_asn1);
829 errpkt.e_data = *e_data_asn1;
831 errpkt.e_data = empty_data();
833 retval = kdc_fast_handle_error(kdc_context, rstate, request, e_data,
834 &errpkt, &fast_edata);
837 if (fast_edata != NULL)
838 errpkt.e_data = *fast_edata;
840 scratch = k5alloc(sizeof(*scratch), &retval);
843 retval = krb5_mk_error(kdc_context, &errpkt, scratch);
851 krb5_free_data(kdc_context, fast_edata);
852 krb5_free_data(kdc_context, e_data_asn1);