Imported Upstream version 1.20.1
[platform/upstream/krb5.git] / src / kdc / do_as_req.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* kdc/do_as_req.c */
3 /*
4  * Portions Copyright (C) 2007 Apple Inc.
5  * Copyright 1990, 1991, 2007, 2008, 2009, 2013, 2014 by the
6  * Massachusetts Institute of Technology.  All Rights Reserved.
7  *
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.
12  *
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.
26  *
27  *
28  * KDC Routines to deal with AS_REQ's
29  */
30 /*
31  * Copyright (c) 2006-2008, Novell, Inc.
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions are met:
36  *
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.
44  *
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.
56  */
57
58 #include "k5-int.h"
59 #include "com_err.h"
60
61 #include <syslog.h>
62 #ifdef HAVE_NETINET_IN_H
63 #include <sys/types.h>
64 #include <netinet/in.h>
65 #ifndef hpux
66 #include <arpa/inet.h>
67 #endif  /* hpux */
68 #endif /* HAVE_NETINET_IN_H */
69
70 #include "kdc_util.h"
71 #include "kdc_audit.h"
72 #include "policy.h"
73 #include <kadm5/admin.h>
74 #include "adm_proto.h"
75 #include "extern.h"
76
77 static krb5_error_code
78 prepare_error_as(struct kdc_request_state *, krb5_kdc_req *, krb5_db_entry *,
79                  krb5_keyblock *, int, krb5_pa_data **, krb5_boolean,
80                  krb5_principal, krb5_data **, const char *);
81
82 /* Determine the key-expiration value according to RFC 4120 section 5.4.2. */
83 static krb5_timestamp
84 get_key_exp(krb5_db_entry *entry)
85 {
86     if (entry->expiration == 0)
87         return entry->pw_expiration;
88     if (entry->pw_expiration == 0)
89         return entry->expiration;
90     return ts_min(entry->expiration, entry->pw_expiration);
91 }
92
93 /*
94  * Find the key in client for the most preferred enctype in req_enctypes.  Fill
95  * in *kb_out with the decrypted keyblock (which the caller must free) and set
96  * *kd_out to an alias to that key data entry.  Set *kd_out to NULL and leave
97  * *kb_out zeroed if no key is found for any of the requested enctypes.
98  * kb_out->enctype may differ from the enctype of *kd_out for DES enctypes; in
99  * this case, kb_out->enctype is the requested enctype used to match the key
100  * data entry.
101  */
102 static krb5_error_code
103 select_client_key(krb5_context context, krb5_db_entry *client,
104                   krb5_enctype *req_enctypes, int n_req_enctypes,
105                   krb5_keyblock *kb_out, krb5_key_data **kd_out)
106 {
107     krb5_error_code ret;
108     krb5_key_data *kd;
109     krb5_enctype etype;
110     int i;
111
112     memset(kb_out, 0, sizeof(*kb_out));
113     *kd_out = NULL;
114
115     for (i = 0; i < n_req_enctypes; i++) {
116         etype = req_enctypes[i];
117         if (!krb5_c_valid_enctype(etype))
118             continue;
119         if (krb5_dbe_find_enctype(context, client, etype, -1, 0, &kd) == 0) {
120             /* Decrypt the client key data and set its enctype to the request
121              * enctype (which may differ from the key data enctype for DES). */
122             ret = krb5_dbe_decrypt_key_data(context, NULL, kd, kb_out, NULL);
123             if (ret)
124                 return ret;
125             kb_out->enctype = etype;
126             *kd_out = kd;
127             return 0;
128         }
129     }
130     return 0;
131 }
132
133 static krb5_error_code
134 lookup_client(krb5_context context, krb5_kdc_req *req, unsigned int flags,
135               krb5_db_entry **entry_out)
136 {
137     krb5_pa_data *pa;
138     krb5_data cert;
139
140     *entry_out = NULL;
141     pa = krb5int_find_pa_data(context, req->padata, KRB5_PADATA_S4U_X509_USER);
142     if (pa != NULL && pa->length != 0 &&
143         req->client->type == KRB5_NT_X500_PRINCIPAL) {
144         cert = make_data(pa->contents, pa->length);
145         flags |= KRB5_KDB_FLAG_REFERRAL_OK;
146         return krb5_db_get_s4u_x509_principal(context, &cert, req->client,
147                                               flags, entry_out);
148     } else {
149         return krb5_db_get_principal(context, req->client, flags, entry_out);
150     }
151 }
152
153 struct as_req_state {
154     loop_respond_fn respond;
155     void *arg;
156
157     krb5_principal_data client_princ;
158     krb5_enc_tkt_part enc_tkt_reply;
159     krb5_enc_kdc_rep_part reply_encpart;
160     krb5_ticket ticket_reply;
161     krb5_keyblock local_tgt_key;
162     krb5_keyblock server_keyblock;
163     krb5_keyblock client_keyblock;
164     krb5_db_entry *client;
165     krb5_db_entry *server;
166     krb5_db_entry *local_tgt;
167     krb5_db_entry *local_tgt_storage;
168     krb5_key_data *client_key;
169     krb5_kdc_req *request;
170     struct krb5_kdcpreauth_rock_st rock;
171     const char *status;
172     krb5_pa_data **e_data;
173     krb5_boolean typed_e_data;
174     krb5_kdc_rep reply;
175     krb5_timestamp kdc_time;
176     krb5_keyblock session_key;
177     unsigned int c_flags;
178     krb5_data *req_pkt;
179     krb5_data *inner_body;
180     struct kdc_request_state *rstate;
181     char *sname, *cname;
182     void *pa_context;
183     const krb5_fulladdr *local_addr;
184     const krb5_fulladdr *remote_addr;
185     krb5_data **auth_indicators;
186
187     krb5_error_code preauth_err;
188
189     kdc_realm_t *active_realm;
190     krb5_audit_state *au_state;
191 };
192
193 static void
194 finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
195 {
196     krb5_keyblock *as_encrypting_key = NULL;
197     krb5_data *response = NULL;
198     const char *emsg = 0;
199     int did_log = 0;
200     loop_respond_fn oldrespond;
201     void *oldarg;
202     kdc_realm_t *kdc_active_realm = state->active_realm;
203     krb5_audit_state *au_state = state->au_state;
204     krb5_keyblock *replaced_reply_key = NULL;
205
206     assert(state);
207     oldrespond = state->respond;
208     oldarg = state->arg;
209
210     if (errcode)
211         goto egress;
212
213     au_state->stage = ENCR_REP;
214
215     state->ticket_reply.enc_part2 = &state->enc_tkt_reply;
216
217     errcode = check_kdcpolicy_as(kdc_context, state->request, state->client,
218                                  state->server, state->auth_indicators,
219                                  state->kdc_time, &state->enc_tkt_reply.times,
220                                  &state->status);
221     if (errcode)
222         goto egress;
223
224     errcode = get_first_current_key(kdc_context, state->server,
225                                     &state->server_keyblock);
226     if (errcode) {
227         state->status = "FINDING_SERVER_KEY";
228         goto egress;
229     }
230
231     /* Start assembling the response */
232     state->reply.msg_type = KRB5_AS_REP;
233     state->reply.client = state->enc_tkt_reply.client; /* post canonization */
234     state->reply.ticket = &state->ticket_reply;
235     state->reply_encpart.session = &state->session_key;
236     if ((errcode = fetch_last_req_info(state->client,
237                                        &state->reply_encpart.last_req)))
238         goto egress;
239     state->reply_encpart.nonce = state->request->nonce;
240     state->reply_encpart.key_exp = get_key_exp(state->client);
241     state->reply_encpart.flags = state->enc_tkt_reply.flags;
242     state->reply_encpart.server = state->ticket_reply.server;
243     state->reply_encpart.times = state->enc_tkt_reply.times;
244     state->reply_encpart.caddrs = state->enc_tkt_reply.caddrs;
245     state->reply_encpart.enc_padata = NULL;
246
247     /* Fetch the padata info to be returned (do this before
248      *  authdata to handle possible replacement of reply key
249      */
250     errcode = return_padata(kdc_context, &state->rock, state->req_pkt,
251                             state->request, &state->reply,
252                             &state->client_keyblock, &state->pa_context);
253     if (errcode) {
254         state->status = "KDC_RETURN_PADATA";
255         goto egress;
256     }
257
258     /* If we didn't find a client long-term key and no preauth mechanism
259      * replaced the reply key, error out now. */
260     if (state->client_keyblock.enctype == ENCTYPE_NULL) {
261         state->status = "CANT_FIND_CLIENT_KEY";
262         errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
263         goto egress;
264     }
265
266     if (state->rock.replaced_reply_key)
267         replaced_reply_key = &state->client_keyblock;
268
269     errcode = handle_authdata(kdc_active_realm, state->c_flags, state->client,
270                               state->server, NULL, state->local_tgt,
271                               &state->local_tgt_key, &state->client_keyblock,
272                               &state->server_keyblock, NULL,
273                               replaced_reply_key, state->req_pkt,
274                               state->request, NULL, NULL, NULL,
275                               &state->auth_indicators, &state->enc_tkt_reply);
276     if (errcode) {
277         krb5_klog_syslog(LOG_INFO, _("AS_REQ : handle_authdata (%d)"),
278                          errcode);
279         state->status = "HANDLE_AUTHDATA";
280         goto egress;
281     }
282
283     errcode = check_indicators(kdc_context, state->server,
284                                state->auth_indicators);
285     if (errcode) {
286         state->status = "HIGHER_AUTHENTICATION_REQUIRED";
287         goto egress;
288     }
289
290     errcode = krb5_encrypt_tkt_part(kdc_context, &state->server_keyblock,
291                                     &state->ticket_reply);
292     if (errcode)
293         goto egress;
294
295     errcode = kau_make_tkt_id(kdc_context, &state->ticket_reply,
296                               &au_state->tkt_out_id);
297     if (errcode)
298         goto egress;
299
300     state->ticket_reply.enc_part.kvno = current_kvno(state->server);
301     errcode = kdc_fast_response_handle_padata(state->rstate,
302                                               state->request,
303                                               &state->reply,
304                                               state->client_keyblock.enctype);
305     if (errcode)
306         goto egress;
307
308     /* now encode/encrypt the response */
309
310     state->reply.enc_part.enctype = state->client_keyblock.enctype;
311
312     errcode = kdc_fast_handle_reply_key(state->rstate, &state->client_keyblock,
313                                         &as_encrypting_key);
314     if (errcode)
315         goto egress;
316     errcode = return_enc_padata(kdc_context, state->req_pkt, state->request,
317                                 as_encrypting_key, state->server,
318                                 &state->reply_encpart, FALSE);
319     if (errcode) {
320         state->status = "KDC_RETURN_ENC_PADATA";
321         goto egress;
322     }
323
324     if (kdc_fast_hide_client(state->rstate))
325         state->reply.client = (krb5_principal)krb5_anonymous_principal();
326     errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP,
327                                   &state->reply_encpart, 0,
328                                   as_encrypting_key,
329                                   &state->reply, &response);
330     if (state->client_key != NULL)
331         state->reply.enc_part.kvno = state->client_key->key_data_kvno;
332     if (errcode)
333         goto egress;
334
335     /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
336        can use them in raw form if needed.  But, we don't... */
337     memset(state->reply.enc_part.ciphertext.data, 0,
338            state->reply.enc_part.ciphertext.length);
339     free(state->reply.enc_part.ciphertext.data);
340
341     log_as_req(kdc_context, state->local_addr, state->remote_addr,
342                state->request, &state->reply, state->client, state->cname,
343                state->server, state->sname, state->kdc_time, 0, 0, 0);
344     did_log = 1;
345
346 egress:
347     if (errcode != 0 && state->status == NULL)
348         state->status = "UNKNOWN_REASON";
349
350     au_state->status = state->status;
351     au_state->reply = &state->reply;
352     kau_as_req(kdc_context,
353               (errcode || state->preauth_err) ? FALSE : TRUE, au_state);
354     kau_free_kdc_req(au_state);
355
356     free_padata_context(kdc_context, state->pa_context);
357     if (as_encrypting_key)
358         krb5_free_keyblock(kdc_context, as_encrypting_key);
359     if (errcode)
360         emsg = krb5_get_error_message(kdc_context, errcode);
361
362     if (state->status) {
363         log_as_req(kdc_context, state->local_addr, state->remote_addr,
364                    state->request, &state->reply, state->client,
365                    state->cname, state->server, state->sname, state->kdc_time,
366                    state->status, errcode, emsg);
367         did_log = 1;
368     }
369     if (errcode) {
370         if (state->status == 0) {
371             state->status = emsg;
372         }
373         if (errcode != KRB5KDC_ERR_DISCARD) {
374             errcode -= ERROR_TABLE_BASE_krb5;
375             if (errcode < 0 || errcode > KRB_ERR_MAX)
376                 errcode = KRB_ERR_GENERIC;
377
378             errcode = prepare_error_as(state->rstate, state->request,
379                                        state->local_tgt, &state->local_tgt_key,
380                                        errcode, state->e_data,
381                                        state->typed_e_data,
382                                        ((state->client != NULL) ?
383                                         state->client->princ : NULL),
384                                        &response, state->status);
385             state->status = 0;
386         }
387     }
388
389     if (emsg)
390         krb5_free_error_message(kdc_context, emsg);
391     if (state->enc_tkt_reply.authorization_data != NULL)
392         krb5_free_authdata(kdc_context,
393                            state->enc_tkt_reply.authorization_data);
394     if (state->local_tgt_key.contents != NULL)
395         krb5_free_keyblock_contents(kdc_context, &state->local_tgt_key);
396     if (state->server_keyblock.contents != NULL)
397         krb5_free_keyblock_contents(kdc_context, &state->server_keyblock);
398     if (state->client_keyblock.contents != NULL)
399         krb5_free_keyblock_contents(kdc_context, &state->client_keyblock);
400     if (state->reply.padata != NULL)
401         krb5_free_pa_data(kdc_context, state->reply.padata);
402     if (state->reply_encpart.enc_padata)
403         krb5_free_pa_data(kdc_context, state->reply_encpart.enc_padata);
404
405     if (state->cname != NULL)
406         free(state->cname);
407     if (state->sname != NULL)
408         free(state->sname);
409     krb5_db_free_principal(kdc_context, state->client);
410     krb5_db_free_principal(kdc_context, state->server);
411     krb5_db_free_principal(kdc_context, state->local_tgt_storage);
412     if (state->session_key.contents != NULL)
413         krb5_free_keyblock_contents(kdc_context, &state->session_key);
414     if (state->ticket_reply.enc_part.ciphertext.data != NULL) {
415         memset(state->ticket_reply.enc_part.ciphertext.data , 0,
416                state->ticket_reply.enc_part.ciphertext.length);
417         free(state->ticket_reply.enc_part.ciphertext.data);
418     }
419
420     krb5_free_pa_data(kdc_context, state->e_data);
421     krb5_free_data(kdc_context, state->inner_body);
422     kdc_free_rstate(state->rstate);
423     krb5_free_kdc_req(kdc_context, state->request);
424     k5_free_data_ptr_list(state->auth_indicators);
425     assert(did_log != 0);
426
427     free(state);
428     (*oldrespond)(oldarg, errcode, response);
429 }
430
431 static void
432 finish_missing_required_preauth(void *arg)
433 {
434     struct as_req_state *state = (struct as_req_state *)arg;
435
436     finish_process_as_req(state, state->preauth_err);
437 }
438
439 static void
440 finish_preauth(void *arg, krb5_error_code code)
441 {
442     struct as_req_state *state = arg;
443     krb5_error_code real_code = code;
444
445     if (code) {
446         if (vague_errors)
447             code = KRB5KRB_ERR_GENERIC;
448         state->status = "PREAUTH_FAILED";
449         if (real_code == KRB5KDC_ERR_PREAUTH_FAILED) {
450             state->preauth_err = code;
451             get_preauth_hint_list(state->request, &state->rock, &state->e_data,
452                                   finish_missing_required_preauth, state);
453             return;
454         }
455     } else {
456         /*
457          * Final check before handing out ticket: If the client requires
458          * preauthentication, verify that the proper kind of
459          * preauthentication was carried out.
460          */
461         state->status = missing_required_preauth(state->client, state->server,
462                                                  &state->enc_tkt_reply);
463         if (state->status) {
464             state->preauth_err = KRB5KDC_ERR_PREAUTH_REQUIRED;
465             get_preauth_hint_list(state->request, &state->rock, &state->e_data,
466                                   finish_missing_required_preauth, state);
467             return;
468         }
469     }
470
471     finish_process_as_req(state, code);
472 }
473
474 /*ARGSUSED*/
475 void
476 process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
477                const krb5_fulladdr *local_addr,
478                const krb5_fulladdr *remote_addr, kdc_realm_t *kdc_active_realm,
479                verto_ctx *vctx, loop_respond_fn respond, void *arg)
480 {
481     krb5_error_code errcode;
482     krb5_data encoded_req_body;
483     krb5_enctype useenctype;
484     struct as_req_state *state;
485     krb5_audit_state *au_state = NULL;
486
487     state = k5alloc(sizeof(*state), &errcode);
488     if (state == NULL) {
489         (*respond)(arg, errcode, NULL);
490         return;
491     }
492     state->respond = respond;
493     state->arg = arg;
494     state->request = request;
495     state->req_pkt = req_pkt;
496     state->local_addr = local_addr;
497     state->remote_addr = remote_addr;
498     state->active_realm = kdc_active_realm;
499
500     errcode = kdc_make_rstate(kdc_active_realm, &state->rstate);
501     if (errcode != 0) {
502         (*respond)(arg, errcode, NULL);
503         free(state);
504         return;
505     }
506
507     /* Initialize audit state. */
508     errcode = kau_init_kdc_req(kdc_context, state->request, remote_addr,
509                                &au_state);
510     if (errcode) {
511         (*respond)(arg, errcode, NULL);
512         kdc_free_rstate(state->rstate);
513         free(state);
514         return;
515     }
516     state->au_state = au_state;
517
518     if (state->request->msg_type != KRB5_AS_REQ) {
519         state->status = "VALIDATE_MESSAGE_TYPE";
520         errcode = KRB5_BADMSGTYPE;
521         goto errout;
522     }
523
524     /* Seed the audit trail with the request ID and basic information. */
525     kau_as_req(kdc_context, TRUE, au_state);
526
527     errcode = krb5_timeofday(kdc_context, &state->kdc_time);
528     if (errcode)
529         goto errout;
530
531     if (fetch_asn1_field((unsigned char *) req_pkt->data,
532                          1, 4, &encoded_req_body) != 0) {
533         errcode = ASN1_BAD_ID;
534         goto errout;
535     }
536     errcode = kdc_find_fast(&state->request, &encoded_req_body, NULL, NULL,
537                             state->rstate, &state->inner_body);
538     if (errcode) {
539         state->status = "FIND_FAST";
540         goto errout;
541     }
542     if (state->inner_body == NULL) {
543         /* Not a FAST request; copy the encoded request body. */
544         errcode = krb5_copy_data(kdc_context, &encoded_req_body,
545                                  &state->inner_body);
546         if (errcode)
547             goto errout;
548     }
549     au_state->request = state->request;
550     state->rock.request = state->request;
551     state->rock.inner_body = state->inner_body;
552     state->rock.rstate = state->rstate;
553     state->rock.vctx = vctx;
554     state->rock.auth_indicators = &state->auth_indicators;
555     state->rock.send_freshness_token = FALSE;
556     if (!state->request->client) {
557         state->status = "NULL_CLIENT";
558         errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
559         goto errout;
560     }
561     if ((errcode = krb5_unparse_name(kdc_context,
562                                      state->request->client,
563                                      &state->cname)))
564         goto errout;
565     limit_string(state->cname);
566
567     if (!state->request->server) {
568         state->status = "NULL_SERVER";
569         errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
570         goto errout;
571     }
572     if ((errcode = krb5_unparse_name(kdc_context,
573                                      state->request->server,
574                                      &state->sname)))
575         goto errout;
576     limit_string(state->sname);
577
578     setflag(state->c_flags, KRB5_KDB_FLAG_CLIENT);
579     if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) ||
580         state->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL)
581         setflag(state->c_flags, KRB5_KDB_FLAG_REFERRAL_OK);
582     errcode = lookup_client(kdc_context, state->request, state->c_flags,
583                             &state->client);
584     if (errcode == KRB5_KDB_CANTLOCK_DB)
585         errcode = KRB5KDC_ERR_SVC_UNAVAILABLE;
586     if (errcode == KRB5_KDB_NOENTRY) {
587         state->status = "CLIENT_NOT_FOUND";
588         if (vague_errors)
589             errcode = KRB5KRB_ERR_GENERIC;
590         else
591             errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
592         goto errout;
593     } else if (errcode) {
594         state->status = "LOOKING_UP_CLIENT";
595         goto errout;
596     }
597     state->rock.client = state->client;
598
599     au_state->stage = SRVC_PRINC;
600
601     errcode = krb5_db_get_principal(kdc_context, state->request->server, 0,
602                                     &state->server);
603     if (errcode == KRB5_KDB_CANTLOCK_DB)
604         errcode = KRB5KDC_ERR_SVC_UNAVAILABLE;
605     if (errcode == KRB5_KDB_NOENTRY) {
606         state->status = "SERVER_NOT_FOUND";
607         errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
608         goto errout;
609     } else if (errcode) {
610         state->status = "LOOKING_UP_SERVER";
611         goto errout;
612     }
613
614     /* If the KDB module returned a different realm for the client and server,
615      * we need to issue a client realm referral. */
616     if (!data_eq(state->server->princ->realm, state->client->princ->realm)) {
617         state->status = "REFERRAL";
618         au_state->cl_realm = &state->client->princ->realm;
619         errcode = KRB5KDC_ERR_WRONG_REALM;
620         goto errout;
621     }
622
623     errcode = get_local_tgt(kdc_context, &state->request->server->realm,
624                             state->server, &state->local_tgt,
625                             &state->local_tgt_storage, &state->local_tgt_key);
626     if (errcode) {
627         state->status = "GET_LOCAL_TGT";
628         goto errout;
629     }
630     state->rock.local_tgt = state->local_tgt;
631     state->rock.local_tgt_key = &state->local_tgt_key;
632
633     au_state->stage = VALIDATE_POL;
634
635     if ((errcode = validate_as_request(kdc_active_realm,
636                                        state->request, state->client,
637                                        state->server, state->kdc_time,
638                                        &state->status, &state->e_data))) {
639         errcode += ERROR_TABLE_BASE_krb5;
640         goto errout;
641     }
642
643     au_state->stage = ISSUE_TKT;
644
645     /*
646      * Select the keytype for the ticket session key.
647      */
648     if ((useenctype = select_session_keytype(kdc_active_realm, state->server,
649                                              state->request->nktypes,
650                                              state->request->ktype)) == 0) {
651         /* unsupported ktype */
652         state->status = "BAD_ENCRYPTION_TYPE";
653         errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
654         goto errout;
655     }
656
657     if ((errcode = krb5_c_make_random_key(kdc_context, useenctype,
658                                           &state->session_key)))
659         goto errout;
660
661     /*
662      * Canonicalization is only effective if we are issuing a TGT
663      * (the intention is to allow support for Windows "short" realm
664      * aliases, nothing more).
665      */
666     if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) &&
667         krb5_is_tgs_principal(state->request->server) &&
668         krb5_is_tgs_principal(state->server->princ)) {
669         state->ticket_reply.server = state->server->princ;
670     } else {
671         state->ticket_reply.server = state->request->server;
672     }
673
674     /* Copy options that request the corresponding ticket flags. */
675     state->enc_tkt_reply.flags = get_ticket_flags(state->request->kdc_options,
676                                                   state->client, state->server,
677                                                   NULL);
678     state->enc_tkt_reply.times.authtime = state->kdc_time;
679
680     /*
681      * It should be noted that local policy may affect the
682      * processing of any of these flags.  For example, some
683      * realms may refuse to issue renewable tickets
684      */
685
686     state->enc_tkt_reply.session = &state->session_key;
687     if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) {
688         state->client_princ = *(state->client->princ);
689     } else {
690         state->client_princ = *(state->request->client);
691         /* The realm is always canonicalized */
692         state->client_princ.realm = state->client->princ->realm;
693     }
694     state->enc_tkt_reply.client = &state->client_princ;
695     state->enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
696     state->enc_tkt_reply.transited.tr_contents = empty_string;
697
698     if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED))
699         state->enc_tkt_reply.times.starttime = state->request->from;
700     else
701         state->enc_tkt_reply.times.starttime = state->kdc_time;
702
703     kdc_get_ticket_endtime(kdc_active_realm,
704                            state->enc_tkt_reply.times.starttime,
705                            kdc_infinity, state->request->till, state->client,
706                            state->server, &state->enc_tkt_reply.times.endtime);
707
708     kdc_get_ticket_renewtime(kdc_active_realm, state->request, NULL,
709                              state->client, state->server,
710                              &state->enc_tkt_reply);
711
712     /*
713      * starttime is optional, and treated as authtime if not present.
714      * so we can nuke it if it matches
715      */
716     if (state->enc_tkt_reply.times.starttime ==
717         state->enc_tkt_reply.times.authtime)
718         state->enc_tkt_reply.times.starttime = 0;
719
720     state->enc_tkt_reply.caddrs = state->request->addresses;
721     state->enc_tkt_reply.authorization_data = 0;
722
723     /* If anonymous requests are being used, adjust the realm of the client
724      * principal. */
725     if (isflagset(state->request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) {
726         if (!krb5_principal_compare_any_realm(kdc_context,
727                                               state->request->client,
728                                               krb5_anonymous_principal())) {
729             errcode = KRB5KDC_ERR_BADOPTION;
730             /* Anonymous requested but anonymous principal not used.*/
731             state->status = "VALIDATE_ANONYMOUS_PRINCIPAL";
732             goto errout;
733         }
734         krb5_free_principal(kdc_context, state->request->client);
735         state->request->client = NULL;
736         errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
737                                       &state->request->client);
738         if (errcode)
739             goto errout;
740         state->enc_tkt_reply.client = state->request->client;
741         setflag(state->client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH);
742     }
743
744     errcode = select_client_key(kdc_context, state->client,
745                                 state->request->ktype, state->request->nktypes,
746                                 &state->client_keyblock, &state->client_key);
747     if (errcode) {
748         state->status = "DECRYPT_CLIENT_KEY";
749         goto errout;
750     }
751     if (state->client_key != NULL)
752         state->rock.client_key = state->client_key;
753     state->rock.client_keyblock = &state->client_keyblock;
754
755     errcode = kdc_fast_read_cookie(kdc_context, state->rstate, state->request,
756                                    state->local_tgt, &state->local_tgt_key);
757     if (errcode) {
758         state->status = "READ_COOKIE";
759         goto errout;
760     }
761
762     /*
763      * Check the preauthentication if it is there.
764      */
765     if (state->request->padata) {
766         check_padata(kdc_context, &state->rock, state->req_pkt,
767                      state->request, &state->enc_tkt_reply, &state->pa_context,
768                      &state->e_data, &state->typed_e_data, finish_preauth,
769                      state);
770     } else
771         finish_preauth(state, 0);
772     return;
773
774 errout:
775     finish_process_as_req(state, errcode);
776 }
777
778 static krb5_error_code
779 prepare_error_as(struct kdc_request_state *rstate, krb5_kdc_req *request,
780                  krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
781                  int error, krb5_pa_data **e_data_in,
782                  krb5_boolean typed_e_data, krb5_principal canon_client,
783                  krb5_data **response, const char *status)
784 {
785     krb5_error errpkt;
786     krb5_error_code retval;
787     krb5_data *scratch = NULL, *e_data_asn1 = NULL, *fast_edata = NULL;
788     krb5_pa_data **e_data = NULL, *cookie = NULL;
789     kdc_realm_t *kdc_active_realm = rstate->realm_data;
790     size_t count;
791
792     errpkt.magic = KV5M_ERROR;
793
794     if (e_data_in != NULL) {
795         /* Add a PA-FX-COOKIE to e_data_in.  e_data is a shallow copy
796          * containing aliases. */
797         for (count = 0; e_data_in[count] != NULL; count++);
798         e_data = calloc(count + 2, sizeof(*e_data));
799         if (e_data == NULL)
800             return ENOMEM;
801         memcpy(e_data, e_data_in, count * sizeof(*e_data));
802         retval = kdc_fast_make_cookie(kdc_context, rstate, local_tgt,
803                                       local_tgt_key, request->client,
804                                       &cookie);
805         e_data[count] = cookie;
806     }
807
808     errpkt.ctime = 0;
809     errpkt.cusec = 0;
810
811     retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec);
812     if (retval)
813         goto cleanup;
814     errpkt.error = error;
815     errpkt.server = request->server;
816     errpkt.client = (error == KDC_ERR_WRONG_REALM) ? canon_client :
817         request->client;
818     errpkt.text = string2data((char *)status);
819
820     if (e_data != NULL) {
821         if (typed_e_data)
822             retval = encode_krb5_typed_data(e_data, &e_data_asn1);
823         else
824             retval = encode_krb5_padata_sequence(e_data, &e_data_asn1);
825         if (retval)
826             goto cleanup;
827         errpkt.e_data = *e_data_asn1;
828     } else
829         errpkt.e_data = empty_data();
830
831     retval = kdc_fast_handle_error(kdc_context, rstate, request, e_data,
832                                    &errpkt, &fast_edata);
833     if (retval)
834         goto cleanup;
835     if (fast_edata != NULL)
836         errpkt.e_data = *fast_edata;
837
838     scratch = k5alloc(sizeof(*scratch), &retval);
839     if (scratch == NULL)
840         goto cleanup;
841     if (kdc_fast_hide_client(rstate) && errpkt.client != NULL)
842         errpkt.client = (krb5_principal)krb5_anonymous_principal();
843     retval = krb5_mk_error(kdc_context, &errpkt, scratch);
844     if (retval)
845         goto cleanup;
846
847     *response = scratch;
848     scratch = NULL;
849
850 cleanup:
851     krb5_free_data(kdc_context, fast_edata);
852     krb5_free_data(kdc_context, e_data_asn1);
853     free(scratch);
854     free(e_data);
855     if (cookie != NULL)
856         free(cookie->contents);
857     free(cookie);
858     return retval;
859 }