Imported Upstream version 1.15.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                  int, krb5_pa_data **, krb5_boolean, krb5_principal,
80                  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 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 struct as_req_state {
134     loop_respond_fn respond;
135     void *arg;
136
137     krb5_principal_data client_princ;
138     krb5_enc_tkt_part enc_tkt_reply;
139     krb5_enc_kdc_rep_part reply_encpart;
140     krb5_ticket ticket_reply;
141     krb5_keyblock server_keyblock;
142     krb5_keyblock client_keyblock;
143     krb5_db_entry *client;
144     krb5_db_entry *server;
145     krb5_db_entry *local_tgt;
146     krb5_db_entry *local_tgt_storage;
147     krb5_key_data *client_key;
148     krb5_kdc_req *request;
149     struct krb5_kdcpreauth_rock_st rock;
150     const char *status;
151     krb5_pa_data **e_data;
152     krb5_boolean typed_e_data;
153     krb5_kdc_rep reply;
154     krb5_timestamp kdc_time;
155     krb5_timestamp authtime;
156     krb5_keyblock session_key;
157     unsigned int c_flags;
158     krb5_data *req_pkt;
159     krb5_data *inner_body;
160     struct kdc_request_state *rstate;
161     char *sname, *cname;
162     void *pa_context;
163     const krb5_fulladdr *from;
164     krb5_data **auth_indicators;
165
166     krb5_error_code preauth_err;
167
168     kdc_realm_t *active_realm;
169     krb5_audit_state *au_state;
170 };
171
172 static void
173 finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
174 {
175     krb5_key_data *server_key;
176     krb5_keyblock *as_encrypting_key = NULL;
177     krb5_data *response = NULL;
178     const char *emsg = 0;
179     int did_log = 0;
180     loop_respond_fn oldrespond;
181     void *oldarg;
182     kdc_realm_t *kdc_active_realm = state->active_realm;
183     krb5_audit_state *au_state = state->au_state;
184
185     assert(state);
186     oldrespond = state->respond;
187     oldarg = state->arg;
188
189     if (errcode)
190         goto egress;
191
192     au_state->stage = ENCR_REP;
193
194     if ((errcode = validate_forwardable(state->request, *state->client,
195                                         *state->server, state->kdc_time,
196                                         &state->status))) {
197         errcode += ERROR_TABLE_BASE_krb5;
198         goto egress;
199     }
200
201     errcode = check_indicators(kdc_context, state->server,
202                                state->auth_indicators);
203     if (errcode) {
204         state->status = "HIGHER_AUTHENTICATION_REQUIRED";
205         goto egress;
206     }
207
208     state->ticket_reply.enc_part2 = &state->enc_tkt_reply;
209
210     /*
211      * Find the server key
212      */
213     if ((errcode = krb5_dbe_find_enctype(kdc_context, state->server,
214                                          -1, /* ignore keytype   */
215                                          -1, /* Ignore salttype  */
216                                          0,  /* Get highest kvno */
217                                          &server_key))) {
218         state->status = "FINDING_SERVER_KEY";
219         goto egress;
220     }
221
222     /*
223      * Convert server->key into a real key
224      * (it may be encrypted in the database)
225      *
226      *  server_keyblock is later used to generate auth data signatures
227      */
228     if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
229                                              server_key,
230                                              &state->server_keyblock,
231                                              NULL))) {
232         state->status = "DECRYPT_SERVER_KEY";
233         goto egress;
234     }
235
236     /* Start assembling the response */
237     state->reply.msg_type = KRB5_AS_REP;
238     state->reply.client = state->enc_tkt_reply.client; /* post canonization */
239     state->reply.ticket = &state->ticket_reply;
240     state->reply_encpart.session = &state->session_key;
241     if ((errcode = fetch_last_req_info(state->client,
242                                        &state->reply_encpart.last_req))) {
243         state->status = "FETCH_LAST_REQ";
244         goto egress;
245     }
246     state->reply_encpart.nonce = state->request->nonce;
247     state->reply_encpart.key_exp = get_key_exp(state->client);
248     state->reply_encpart.flags = state->enc_tkt_reply.flags;
249     state->reply_encpart.server = state->ticket_reply.server;
250
251     /* copy the time fields EXCEPT for authtime; it's location
252      *  is used for ktime
253      */
254     state->reply_encpart.times = state->enc_tkt_reply.times;
255     state->reply_encpart.times.authtime = state->authtime = state->kdc_time;
256
257     state->reply_encpart.caddrs = state->enc_tkt_reply.caddrs;
258     state->reply_encpart.enc_padata = NULL;
259
260     /* Fetch the padata info to be returned (do this before
261      *  authdata to handle possible replacement of reply key
262      */
263     errcode = return_padata(kdc_context, &state->rock, state->req_pkt,
264                             state->request, &state->reply,
265                             &state->client_keyblock, &state->pa_context);
266     if (errcode) {
267         state->status = "KDC_RETURN_PADATA";
268         goto egress;
269     }
270
271     /* If we didn't find a client long-term key and no preauth mechanism
272      * replaced the reply key, error out now. */
273     if (state->client_keyblock.enctype == ENCTYPE_NULL) {
274         state->status = "CANT_FIND_CLIENT_KEY";
275         errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
276         goto egress;
277     }
278
279     errcode = handle_authdata(kdc_context,
280                               state->c_flags,
281                               state->client,
282                               state->server,
283                               NULL,
284                               state->local_tgt,
285                               &state->client_keyblock,
286                               &state->server_keyblock,
287                               NULL,
288                               state->req_pkt,
289                               state->request,
290                               NULL, /* for_user_princ */
291                               NULL, /* enc_tkt_request */
292                               state->auth_indicators,
293                               &state->enc_tkt_reply);
294     if (errcode) {
295         krb5_klog_syslog(LOG_INFO, _("AS_REQ : handle_authdata (%d)"),
296                          errcode);
297         state->status = "HANDLE_AUTHDATA";
298         goto egress;
299     }
300
301     errcode = krb5_encrypt_tkt_part(kdc_context, &state->server_keyblock,
302                                     &state->ticket_reply);
303     if (errcode) {
304         state->status = "ENCRYPT_TICKET";
305         goto egress;
306     }
307
308     errcode = kau_make_tkt_id(kdc_context, &state->ticket_reply,
309                               &au_state->tkt_out_id);
310     if (errcode) {
311         state->status = "GENERATE_TICKET_ID";
312         goto egress;
313     }
314
315     state->ticket_reply.enc_part.kvno = server_key->key_data_kvno;
316     errcode = kdc_fast_response_handle_padata(state->rstate,
317                                               state->request,
318                                               &state->reply,
319                                               state->client_keyblock.enctype);
320     if (errcode) {
321         state->status = "MAKE_FAST_RESPONSE";
322         goto egress;
323     }
324
325     /* now encode/encrypt the response */
326
327     state->reply.enc_part.enctype = state->client_keyblock.enctype;
328
329     errcode = kdc_fast_handle_reply_key(state->rstate, &state->client_keyblock,
330                                         &as_encrypting_key);
331     if (errcode) {
332         state->status = "MAKE_FAST_REPLY_KEY";
333         goto egress;
334     }
335     errcode = return_enc_padata(kdc_context, state->req_pkt, state->request,
336                                 as_encrypting_key, state->server,
337                                 &state->reply_encpart, FALSE);
338     if (errcode) {
339         state->status = "KDC_RETURN_ENC_PADATA";
340         goto egress;
341     }
342
343     if (kdc_fast_hide_client(state->rstate))
344         state->reply.client = (krb5_principal)krb5_anonymous_principal();
345     errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP,
346                                   &state->reply_encpart, 0,
347                                   as_encrypting_key,
348                                   &state->reply, &response);
349     if (state->client_key != NULL)
350         state->reply.enc_part.kvno = state->client_key->key_data_kvno;
351     if (errcode) {
352         state->status = "ENCODE_KDC_REP";
353         goto egress;
354     }
355
356     /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
357        can use them in raw form if needed.  But, we don't... */
358     memset(state->reply.enc_part.ciphertext.data, 0,
359            state->reply.enc_part.ciphertext.length);
360     free(state->reply.enc_part.ciphertext.data);
361
362     log_as_req(kdc_context, state->from, state->request, &state->reply,
363                state->client, state->cname, state->server,
364                state->sname, state->authtime, 0, 0, 0);
365     did_log = 1;
366
367 egress:
368     if (errcode != 0)
369         assert (state->status != 0);
370
371     au_state->status = state->status;
372     au_state->reply = &state->reply;
373     kau_as_req(kdc_context,
374               (errcode || state->preauth_err) ? FALSE : TRUE, au_state);
375     kau_free_kdc_req(au_state);
376
377     free_padata_context(kdc_context, state->pa_context);
378     if (as_encrypting_key)
379         krb5_free_keyblock(kdc_context, as_encrypting_key);
380     if (errcode)
381         emsg = krb5_get_error_message(kdc_context, errcode);
382
383     if (state->status) {
384         log_as_req(kdc_context,
385                    state->from, state->request, &state->reply, state->client,
386                    state->cname, state->server, state->sname, state->authtime,
387                    state->status, errcode, emsg);
388         did_log = 1;
389     }
390     if (errcode) {
391         if (state->status == 0) {
392             state->status = emsg;
393         }
394         if (errcode != KRB5KDC_ERR_DISCARD) {
395             errcode -= ERROR_TABLE_BASE_krb5;
396             if (errcode < 0 || errcode > KRB_ERR_MAX)
397                 errcode = KRB_ERR_GENERIC;
398
399             errcode = prepare_error_as(state->rstate, state->request,
400                                        state->local_tgt, errcode,
401                                        state->e_data, state->typed_e_data,
402                                        ((state->client != NULL) ?
403                                         state->client->princ : NULL),
404                                        &response, state->status);
405             state->status = 0;
406         }
407     }
408
409     if (emsg)
410         krb5_free_error_message(kdc_context, emsg);
411     if (state->enc_tkt_reply.authorization_data != NULL)
412         krb5_free_authdata(kdc_context,
413                            state->enc_tkt_reply.authorization_data);
414     if (state->server_keyblock.contents != NULL)
415         krb5_free_keyblock_contents(kdc_context, &state->server_keyblock);
416     if (state->client_keyblock.contents != NULL)
417         krb5_free_keyblock_contents(kdc_context, &state->client_keyblock);
418     if (state->reply.padata != NULL)
419         krb5_free_pa_data(kdc_context, state->reply.padata);
420     if (state->reply_encpart.enc_padata)
421         krb5_free_pa_data(kdc_context, state->reply_encpart.enc_padata);
422
423     if (state->cname != NULL)
424         free(state->cname);
425     if (state->sname != NULL)
426         free(state->sname);
427     krb5_db_free_principal(kdc_context, state->client);
428     krb5_db_free_principal(kdc_context, state->server);
429     krb5_db_free_principal(kdc_context, state->local_tgt_storage);
430     if (state->session_key.contents != NULL)
431         krb5_free_keyblock_contents(kdc_context, &state->session_key);
432     if (state->ticket_reply.enc_part.ciphertext.data != NULL) {
433         memset(state->ticket_reply.enc_part.ciphertext.data , 0,
434                state->ticket_reply.enc_part.ciphertext.length);
435         free(state->ticket_reply.enc_part.ciphertext.data);
436     }
437
438     krb5_free_pa_data(kdc_context, state->e_data);
439     krb5_free_data(kdc_context, state->inner_body);
440     kdc_free_rstate(state->rstate);
441     krb5_free_kdc_req(kdc_context, state->request);
442     k5_free_data_ptr_list(state->auth_indicators);
443     assert(did_log != 0);
444
445     free(state);
446     (*oldrespond)(oldarg, errcode, response);
447 }
448
449 static void
450 finish_missing_required_preauth(void *arg)
451 {
452     struct as_req_state *state = (struct as_req_state *)arg;
453
454     finish_process_as_req(state, state->preauth_err);
455 }
456
457 static void
458 finish_preauth(void *arg, krb5_error_code code)
459 {
460     struct as_req_state *state = arg;
461     krb5_error_code real_code = code;
462
463     if (code) {
464         if (vague_errors)
465             code = KRB5KRB_ERR_GENERIC;
466         state->status = "PREAUTH_FAILED";
467         if (real_code == KRB5KDC_ERR_PREAUTH_FAILED) {
468             state->preauth_err = code;
469             get_preauth_hint_list(state->request, &state->rock, &state->e_data,
470                                   finish_missing_required_preauth, state);
471             return;
472         }
473     } else {
474         /*
475          * Final check before handing out ticket: If the client requires
476          * preauthentication, verify that the proper kind of
477          * preauthentication was carried out.
478          */
479         state->status = missing_required_preauth(state->client, state->server,
480                                                  &state->enc_tkt_reply);
481         if (state->status) {
482             state->preauth_err = KRB5KDC_ERR_PREAUTH_REQUIRED;
483             get_preauth_hint_list(state->request, &state->rock, &state->e_data,
484                                   finish_missing_required_preauth, state);
485             return;
486         }
487     }
488
489     finish_process_as_req(state, code);
490 }
491
492 /*ARGSUSED*/
493 void
494 process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
495                const krb5_fulladdr *from, kdc_realm_t *kdc_active_realm,
496                verto_ctx *vctx, loop_respond_fn respond, void *arg)
497 {
498     krb5_error_code errcode;
499     unsigned int s_flags = 0;
500     krb5_data encoded_req_body;
501     krb5_enctype useenctype;
502     struct as_req_state *state;
503     krb5_audit_state *au_state = NULL;
504
505     state = k5alloc(sizeof(*state), &errcode);
506     if (state == NULL) {
507         (*respond)(arg, errcode, NULL);
508         return;
509     }
510     state->respond = respond;
511     state->arg = arg;
512     state->request = request;
513     state->req_pkt = req_pkt;
514     state->from = from;
515     state->active_realm = kdc_active_realm;
516
517     errcode = kdc_make_rstate(kdc_active_realm, &state->rstate);
518     if (errcode != 0) {
519         (*respond)(arg, errcode, NULL);
520         free(state);
521         return;
522     }
523
524     /* Initialize audit state. */
525     errcode = kau_init_kdc_req(kdc_context, state->request, from, &au_state);
526     if (errcode) {
527         (*respond)(arg, errcode, NULL);
528         kdc_free_rstate(state->rstate);
529         free(state);
530         return;
531     }
532     state->au_state = au_state;
533
534     if (state->request->msg_type != KRB5_AS_REQ) {
535         state->status = "VALIDATE_MESSAGE_TYPE";
536         errcode = KRB5_BADMSGTYPE;
537         goto errout;
538     }
539
540     /* Seed the audit trail with the request ID and basic information. */
541     kau_as_req(kdc_context, TRUE, au_state);
542
543     if (fetch_asn1_field((unsigned char *) req_pkt->data,
544                          1, 4, &encoded_req_body) != 0) {
545         errcode = ASN1_BAD_ID;
546         state->status = "FETCH_REQ_BODY";
547         goto errout;
548     }
549     errcode = kdc_find_fast(&state->request, &encoded_req_body, NULL, NULL,
550                             state->rstate, &state->inner_body);
551     if (errcode) {
552         state->status = "FIND_FAST";
553         goto errout;
554     }
555     if (state->inner_body == NULL) {
556         /* Not a FAST request; copy the encoded request body. */
557         errcode = krb5_copy_data(kdc_context, &encoded_req_body,
558                                  &state->inner_body);
559         if (errcode) {
560             state->status = "COPY_REQ_BODY";
561             goto errout;
562         }
563     }
564     au_state->request = state->request;
565     state->rock.request = state->request;
566     state->rock.inner_body = state->inner_body;
567     state->rock.rstate = state->rstate;
568     state->rock.vctx = vctx;
569     state->rock.auth_indicators = &state->auth_indicators;
570     if (!state->request->client) {
571         state->status = "NULL_CLIENT";
572         errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
573         goto errout;
574     }
575     if ((errcode = krb5_unparse_name(kdc_context,
576                                      state->request->client,
577                                      &state->cname))) {
578         state->status = "UNPARSE_CLIENT";
579         goto errout;
580     }
581     limit_string(state->cname);
582
583     if (!state->request->server) {
584         state->status = "NULL_SERVER";
585         errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
586         goto errout;
587     }
588     if ((errcode = krb5_unparse_name(kdc_context,
589                                      state->request->server,
590                                      &state->sname))) {
591         state->status = "UNPARSE_SERVER";
592         goto errout;
593     }
594     limit_string(state->sname);
595
596     /*
597      * We set KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY as a hint
598      * to the backend to return naming information in lieu
599      * of cross realm TGS entries.
600      */
601     setflag(state->c_flags, KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY);
602     /*
603      * Note that according to the referrals draft we should
604      * always canonicalize enterprise principal names.
605      */
606     if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) ||
607         state->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
608         setflag(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE);
609         setflag(state->c_flags, KRB5_KDB_FLAG_ALIAS_OK);
610     }
611     if (include_pac_p(kdc_context, state->request)) {
612         setflag(state->c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
613     }
614     errcode = krb5_db_get_principal(kdc_context, state->request->client,
615                                     state->c_flags, &state->client);
616     if (errcode == KRB5_KDB_CANTLOCK_DB)
617         errcode = KRB5KDC_ERR_SVC_UNAVAILABLE;
618     if (errcode == KRB5_KDB_NOENTRY) {
619         state->status = "CLIENT_NOT_FOUND";
620         if (vague_errors)
621             errcode = KRB5KRB_ERR_GENERIC;
622         else
623             errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
624         goto errout;
625     } else if (errcode) {
626         state->status = "LOOKING_UP_CLIENT";
627         goto errout;
628     }
629     state->rock.client = state->client;
630
631     /*
632      * If the backend returned a principal that is not in the local
633      * realm, then we need to refer the client to that realm.
634      */
635     if (!is_local_principal(kdc_active_realm, state->client->princ)) {
636         /* Entry is a referral to another realm */
637         state->status = "REFERRAL";
638         au_state->cl_realm = &state->client->princ->realm;
639         errcode = KRB5KDC_ERR_WRONG_REALM;
640         goto errout;
641     }
642
643     au_state->stage = SRVC_PRINC;
644
645     s_flags = 0;
646     setflag(s_flags, KRB5_KDB_FLAG_ALIAS_OK);
647     if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) {
648         setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
649     }
650     errcode = krb5_db_get_principal(kdc_context, state->request->server,
651                                     s_flags, &state->server);
652     if (errcode == KRB5_KDB_CANTLOCK_DB)
653         errcode = KRB5KDC_ERR_SVC_UNAVAILABLE;
654     if (errcode == KRB5_KDB_NOENTRY) {
655         state->status = "SERVER_NOT_FOUND";
656         errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
657         goto errout;
658     } else if (errcode) {
659         state->status = "LOOKING_UP_SERVER";
660         goto errout;
661     }
662
663     errcode = get_local_tgt(kdc_context, &state->request->server->realm,
664                             state->server, &state->local_tgt,
665                             &state->local_tgt_storage);
666     if (errcode) {
667         state->status = "GET_LOCAL_TGT";
668         goto errout;
669     }
670
671     au_state->stage = VALIDATE_POL;
672
673     if ((errcode = krb5_timeofday(kdc_context, &state->kdc_time))) {
674         state->status = "TIMEOFDAY";
675         goto errout;
676     }
677     state->authtime = state->kdc_time; /* for audit_as_request() */
678
679     if ((errcode = validate_as_request(kdc_active_realm,
680                                        state->request, *state->client,
681                                        *state->server, state->kdc_time,
682                                        &state->status, &state->e_data))) {
683         if (!state->status)
684             state->status = "UNKNOWN_REASON";
685         errcode += ERROR_TABLE_BASE_krb5;
686         goto errout;
687     }
688
689     au_state->stage = ISSUE_TKT;
690
691     /*
692      * Select the keytype for the ticket session key.
693      */
694     if ((useenctype = select_session_keytype(kdc_active_realm, state->server,
695                                              state->request->nktypes,
696                                              state->request->ktype)) == 0) {
697         /* unsupported ktype */
698         state->status = "BAD_ENCRYPTION_TYPE";
699         errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
700         goto errout;
701     }
702
703     if ((errcode = krb5_c_make_random_key(kdc_context, useenctype,
704                                           &state->session_key))) {
705         state->status = "MAKE_RANDOM_KEY";
706         goto errout;
707     }
708
709     /*
710      * Canonicalization is only effective if we are issuing a TGT
711      * (the intention is to allow support for Windows "short" realm
712      * aliases, nothing more).
713      */
714     if (isflagset(s_flags, KRB5_KDB_FLAG_CANONICALIZE) &&
715         krb5_is_tgs_principal(state->request->server) &&
716         krb5_is_tgs_principal(state->server->princ)) {
717         state->ticket_reply.server = state->server->princ;
718     } else {
719         state->ticket_reply.server = state->request->server;
720     }
721
722     /* Copy options that request the corresponding ticket flags. */
723     state->enc_tkt_reply.flags = OPTS2FLAGS(state->request->kdc_options);
724     state->enc_tkt_reply.times.authtime = state->authtime;
725
726     setflag(state->enc_tkt_reply.flags, TKT_FLG_INITIAL);
727     setflag(state->enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP);
728
729     /*
730      * It should be noted that local policy may affect the
731      * processing of any of these flags.  For example, some
732      * realms may refuse to issue renewable tickets
733      */
734
735     state->enc_tkt_reply.session = &state->session_key;
736     if (isflagset(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
737         state->client_princ = *(state->client->princ);
738     } else {
739         state->client_princ = *(state->request->client);
740         /* The realm is always canonicalized */
741         state->client_princ.realm = state->client->princ->realm;
742     }
743     state->enc_tkt_reply.client = &state->client_princ;
744     state->enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
745     state->enc_tkt_reply.transited.tr_contents = empty_string;
746
747     if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED)) {
748         setflag(state->enc_tkt_reply.flags, TKT_FLG_INVALID);
749         state->enc_tkt_reply.times.starttime = state->request->from;
750     } else
751         state->enc_tkt_reply.times.starttime = state->kdc_time;
752
753     kdc_get_ticket_endtime(kdc_active_realm,
754                            state->enc_tkt_reply.times.starttime,
755                            kdc_infinity, state->request->till, state->client,
756                            state->server, &state->enc_tkt_reply.times.endtime);
757
758     kdc_get_ticket_renewtime(kdc_active_realm, state->request, NULL,
759                              state->client, state->server,
760                              &state->enc_tkt_reply);
761
762     /*
763      * starttime is optional, and treated as authtime if not present.
764      * so we can nuke it if it matches
765      */
766     if (state->enc_tkt_reply.times.starttime ==
767         state->enc_tkt_reply.times.authtime)
768         state->enc_tkt_reply.times.starttime = 0;
769
770     state->enc_tkt_reply.caddrs = state->request->addresses;
771     state->enc_tkt_reply.authorization_data = 0;
772
773     /* If anonymous requests are being used, adjust the realm of the client
774      * principal. */
775     if (isflagset(state->request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) {
776         if (!krb5_principal_compare_any_realm(kdc_context,
777                                               state->request->client,
778                                               krb5_anonymous_principal())) {
779             errcode = KRB5KDC_ERR_BADOPTION;
780             /* Anonymous requested but anonymous principal not used.*/
781             state->status = "VALIDATE_ANONYMOUS_PRINCIPAL";
782             goto errout;
783         }
784         krb5_free_principal(kdc_context, state->request->client);
785         state->request->client = NULL;
786         errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
787                                       &state->request->client);
788         if (errcode) {
789             state->status = "COPY_ANONYMOUS_PRINCIPAL";
790             goto errout;
791         }
792         state->enc_tkt_reply.client = state->request->client;
793         setflag(state->client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH);
794     }
795
796     errcode = select_client_key(kdc_context, state->client,
797                                 state->request->ktype, state->request->nktypes,
798                                 &state->client_keyblock, &state->client_key);
799     if (errcode) {
800         state->status = "DECRYPT_CLIENT_KEY";
801         goto errout;
802     }
803     if (state->client_key != NULL) {
804         state->rock.client_key = state->client_key;
805         state->rock.client_keyblock = &state->client_keyblock;
806     }
807
808     errcode = kdc_fast_read_cookie(kdc_context, state->rstate, state->request,
809                                    state->local_tgt);
810     if (errcode) {
811         state->status = "READ_COOKIE";
812         goto errout;
813     }
814
815     /*
816      * Check the preauthentication if it is there.
817      */
818     if (state->request->padata) {
819         check_padata(kdc_context, &state->rock, state->req_pkt,
820                      state->request, &state->enc_tkt_reply, &state->pa_context,
821                      &state->e_data, &state->typed_e_data, finish_preauth,
822                      state);
823     } else
824         finish_preauth(state, 0);
825     return;
826
827 errout:
828     finish_process_as_req(state, errcode);
829 }
830
831 static krb5_error_code
832 prepare_error_as(struct kdc_request_state *rstate, krb5_kdc_req *request,
833                  krb5_db_entry *local_tgt, int error, krb5_pa_data **e_data_in,
834                  krb5_boolean typed_e_data, krb5_principal canon_client,
835                  krb5_data **response, const char *status)
836 {
837     krb5_error errpkt;
838     krb5_error_code retval;
839     krb5_data *scratch = NULL, *e_data_asn1 = NULL, *fast_edata = NULL;
840     krb5_pa_data **e_data = NULL, *cookie = NULL;
841     kdc_realm_t *kdc_active_realm = rstate->realm_data;
842     size_t count;
843
844     if (e_data_in != NULL) {
845         /* Add a PA-FX-COOKIE to e_data_in.  e_data is a shallow copy
846          * containing aliases. */
847         for (count = 0; e_data_in[count] != NULL; count++);
848         e_data = calloc(count + 2, sizeof(*e_data));
849         if (e_data == NULL)
850             return ENOMEM;
851         memcpy(e_data, e_data_in, count * sizeof(*e_data));
852         retval = kdc_fast_make_cookie(kdc_context, rstate, local_tgt,
853                                       request->client, &cookie);
854         e_data[count] = cookie;
855     }
856
857     errpkt.ctime = request->nonce;
858     errpkt.cusec = 0;
859
860     retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec);
861     if (retval)
862         goto cleanup;
863     errpkt.error = error;
864     errpkt.server = request->server;
865     errpkt.client = (error == KDC_ERR_WRONG_REALM) ? canon_client :
866         request->client;
867     errpkt.text = string2data((char *)status);
868
869     if (e_data != NULL) {
870         if (typed_e_data)
871             retval = encode_krb5_typed_data(e_data, &e_data_asn1);
872         else
873             retval = encode_krb5_padata_sequence(e_data, &e_data_asn1);
874         if (retval)
875             goto cleanup;
876         errpkt.e_data = *e_data_asn1;
877     } else
878         errpkt.e_data = empty_data();
879
880     retval = kdc_fast_handle_error(kdc_context, rstate, request, e_data,
881                                    &errpkt, &fast_edata);
882     if (retval)
883         goto cleanup;
884     if (fast_edata != NULL)
885         errpkt.e_data = *fast_edata;
886
887     scratch = k5alloc(sizeof(*scratch), &retval);
888     if (scratch == NULL)
889         goto cleanup;
890     if (kdc_fast_hide_client(rstate) && errpkt.client != NULL)
891         errpkt.client = (krb5_principal)krb5_anonymous_principal();
892     retval = krb5_mk_error(kdc_context, &errpkt, scratch);
893     if (retval)
894         goto cleanup;
895
896     *response = scratch;
897     scratch = NULL;
898
899 cleanup:
900     krb5_free_data(kdc_context, fast_edata);
901     krb5_free_data(kdc_context, e_data_asn1);
902     free(scratch);
903     free(e_data);
904     if (cookie != NULL)
905         free(cookie->contents);
906     free(cookie);
907     return retval;
908 }