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