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