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 *, krb5_error_code, krb5_pa_data **, 80 krb5_boolean, krb5_principal, krb5_data **, const char *); 81 82 /* Determine the key-expiration value according to RFC 4120 section 5.4.2. */ 83 static krb5_timestamp 84 get_key_exp(krb5_db_entry *entry) 85 { 86 if (entry->expiration == 0) 87 return entry->pw_expiration; 88 if (entry->pw_expiration == 0) 89 return entry->expiration; 90 return ts_min(entry->expiration, entry->pw_expiration); 91 } 92 93 /* 94 * Find the key in client for the most preferred enctype in req_enctypes. Fill 95 * in *kb_out with the decrypted keyblock (which the caller must free) and set 96 * *kd_out to an alias to that key data entry. Set *kd_out to NULL and leave 97 * *kb_out zeroed if no key is found for any of the requested enctypes. 98 * kb_out->enctype may differ from the enctype of *kd_out for DES enctypes; in 99 * this case, kb_out->enctype is the requested enctype used to match the key 100 * data entry. 101 */ 102 static krb5_error_code 103 select_client_key(krb5_context context, krb5_db_entry *client, 104 krb5_enctype *req_enctypes, int n_req_enctypes, 105 krb5_keyblock *kb_out, krb5_key_data **kd_out) 106 { 107 krb5_error_code ret; 108 krb5_key_data *kd; 109 krb5_enctype etype; 110 int i; 111 112 memset(kb_out, 0, sizeof(*kb_out)); 113 *kd_out = NULL; 114 115 for (i = 0; i < n_req_enctypes; i++) { 116 etype = req_enctypes[i]; 117 if (!krb5_c_valid_enctype(etype)) 118 continue; 119 if (krb5_dbe_find_enctype(context, client, etype, -1, 0, &kd) == 0) { 120 /* Decrypt the client key data and set its enctype to the request 121 * enctype (which may differ from the key data enctype for DES). */ 122 ret = krb5_dbe_decrypt_key_data(context, NULL, kd, kb_out, NULL); 123 if (ret) 124 return ret; 125 kb_out->enctype = etype; 126 *kd_out = kd; 127 return 0; 128 } 129 } 130 return 0; 131 } 132 133 static krb5_error_code 134 lookup_client(krb5_context context, krb5_kdc_req *req, unsigned int flags, 135 krb5_db_entry **entry_out) 136 { 137 krb5_pa_data *pa; 138 krb5_data cert; 139 140 *entry_out = NULL; 141 pa = krb5int_find_pa_data(context, req->padata, KRB5_PADATA_S4U_X509_USER); 142 if (pa != NULL && pa->length != 0 && 143 req->client->type == KRB5_NT_X500_PRINCIPAL) { 144 cert = make_data(pa->contents, pa->length); 145 flags |= KRB5_KDB_FLAG_REFERRAL_OK; 146 return krb5_db_get_s4u_x509_principal(context, &cert, req->client, 147 flags, entry_out); 148 } else { 149 return krb5_db_get_principal(context, req->client, flags, entry_out); 150 } 151 } 152 153 struct as_req_state { 154 loop_respond_fn respond; 155 void *arg; 156 157 krb5_principal_data client_princ; 158 krb5_enc_tkt_part enc_tkt_reply; 159 krb5_enc_kdc_rep_part reply_encpart; 160 krb5_ticket ticket_reply; 161 krb5_keyblock local_tgt_key; 162 krb5_keyblock server_keyblock; 163 krb5_keyblock client_keyblock; 164 krb5_db_entry *client; 165 krb5_db_entry *server; 166 krb5_db_entry *local_tgt; 167 krb5_db_entry *local_tgt_storage; 168 krb5_key_data *client_key; 169 krb5_kdc_req *request; 170 struct krb5_kdcpreauth_rock_st rock; 171 const char *status; 172 krb5_pa_data **e_data; 173 krb5_boolean typed_e_data; 174 krb5_kdc_rep reply; 175 krb5_timestamp kdc_time; 176 krb5_keyblock session_key; 177 unsigned int c_flags; 178 krb5_data *req_pkt; 179 krb5_data *inner_body; 180 struct kdc_request_state *rstate; 181 char *sname, *cname; 182 void *pa_context; 183 const struct sockaddr *local_addr; 184 const struct sockaddr *remote_addr; 185 krb5_data **auth_indicators; 186 187 krb5_error_code preauth_err; 188 189 kdc_realm_t *active_realm; 190 krb5_audit_state *au_state; 191 }; 192 193 static void 194 finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) 195 { 196 kdc_realm_t *realm = state->active_realm; 197 krb5_context context = realm->realm_context; 198 krb5_keyblock *as_encrypting_key = NULL; 199 krb5_data *response = NULL; 200 const char *emsg = 0; 201 int did_log = 0; 202 loop_respond_fn oldrespond; 203 void *oldarg; 204 krb5_audit_state *au_state = state->au_state; 205 krb5_keyblock *replaced_reply_key = NULL; 206 207 assert(state); 208 oldrespond = state->respond; 209 oldarg = state->arg; 210 211 if (errcode) 212 goto egress; 213 214 au_state->stage = ENCR_REP; 215 216 state->ticket_reply.enc_part2 = &state->enc_tkt_reply; 217 218 errcode = check_kdcpolicy_as(context, state->request, state->client, 219 state->server, state->auth_indicators, 220 state->kdc_time, &state->enc_tkt_reply.times, 221 &state->status); 222 if (errcode) 223 goto egress; 224 225 errcode = get_first_current_key(context, state->server, 226 &state->server_keyblock); 227 if (errcode) { 228 state->status = "FINDING_SERVER_KEY"; 229 goto egress; 230 } 231 232 /* Start assembling the response */ 233 state->reply.msg_type = KRB5_AS_REP; 234 state->reply.client = state->enc_tkt_reply.client; /* post canonization */ 235 state->reply.ticket = &state->ticket_reply; 236 state->reply_encpart.session = &state->session_key; 237 if ((errcode = fetch_last_req_info(state->client, 238 &state->reply_encpart.last_req))) 239 goto egress; 240 state->reply_encpart.nonce = state->request->nonce; 241 state->reply_encpart.key_exp = get_key_exp(state->client); 242 state->reply_encpart.flags = state->enc_tkt_reply.flags; 243 state->reply_encpart.server = state->ticket_reply.server; 244 state->reply_encpart.times = state->enc_tkt_reply.times; 245 state->reply_encpart.caddrs = state->enc_tkt_reply.caddrs; 246 state->reply_encpart.enc_padata = NULL; 247 248 /* Fetch the padata info to be returned (do this before 249 * authdata to handle possible replacement of reply key 250 */ 251 errcode = return_padata(context, &state->rock, state->req_pkt, 252 state->request, &state->reply, 253 &state->client_keyblock, &state->pa_context); 254 if (errcode) { 255 state->status = "KDC_RETURN_PADATA"; 256 goto egress; 257 } 258 259 /* If we didn't find a client long-term key and no preauth mechanism 260 * replaced the reply key, error out now. */ 261 if (state->client_keyblock.enctype == ENCTYPE_NULL) { 262 state->status = "CANT_FIND_CLIENT_KEY"; 263 errcode = KRB5KDC_ERR_ETYPE_NOSUPP; 264 goto egress; 265 } 266 267 if (state->rock.replaced_reply_key) 268 replaced_reply_key = &state->client_keyblock; 269 270 errcode = handle_authdata(realm, state->c_flags, state->client, 271 state->server, NULL, state->local_tgt, 272 &state->local_tgt_key, &state->client_keyblock, 273 &state->server_keyblock, NULL, 274 replaced_reply_key, state->req_pkt, 275 state->request, NULL, NULL, NULL, 276 &state->auth_indicators, &state->enc_tkt_reply); 277 if (errcode) { 278 krb5_klog_syslog(LOG_INFO, _("AS_REQ : handle_authdata (%d)"), 279 errcode); 280 state->status = "HANDLE_AUTHDATA"; 281 goto egress; 282 } 283 284 errcode = check_indicators(context, state->server, state->auth_indicators); 285 if (errcode) { 286 state->status = "HIGHER_AUTHENTICATION_REQUIRED"; 287 goto egress; 288 } 289 290 errcode = krb5_encrypt_tkt_part(context, &state->server_keyblock, 291 &state->ticket_reply); 292 if (errcode) 293 goto egress; 294 295 errcode = kau_make_tkt_id(context, &state->ticket_reply, 296 &au_state->tkt_out_id); 297 if (errcode) 298 goto egress; 299 300 state->ticket_reply.enc_part.kvno = current_kvno(state->server); 301 errcode = kdc_fast_response_handle_padata(state->rstate, 302 state->request, 303 &state->reply, 304 state->client_keyblock.enctype); 305 if (errcode) 306 goto egress; 307 308 /* now encode/encrypt the response */ 309 310 state->reply.enc_part.enctype = state->client_keyblock.enctype; 311 312 errcode = kdc_fast_handle_reply_key(state->rstate, &state->client_keyblock, 313 &as_encrypting_key); 314 if (errcode) 315 goto egress; 316 errcode = return_enc_padata(context, state->req_pkt, state->request, 317 as_encrypting_key, state->server, 318 &state->reply_encpart, FALSE); 319 if (errcode) { 320 state->status = "KDC_RETURN_ENC_PADATA"; 321 goto egress; 322 } 323 324 if (kdc_fast_hide_client(state->rstate)) 325 state->reply.client = (krb5_principal)krb5_anonymous_principal(); 326 errcode = krb5_encode_kdc_rep(context, KRB5_AS_REP, &state->reply_encpart, 327 0, as_encrypting_key, &state->reply, 328 &response); 329 if (state->client_key != NULL) 330 state->reply.enc_part.kvno = state->client_key->key_data_kvno; 331 if (errcode) 332 goto egress; 333 334 /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we 335 can use them in raw form if needed. But, we don't... */ 336 memset(state->reply.enc_part.ciphertext.data, 0, 337 state->reply.enc_part.ciphertext.length); 338 free(state->reply.enc_part.ciphertext.data); 339 340 log_as_req(context, state->local_addr, state->remote_addr, 341 state->request, &state->reply, state->client, state->cname, 342 state->server, state->sname, state->kdc_time, 0, 0, 0); 343 did_log = 1; 344 345 egress: 346 if (errcode != 0 && state->status == NULL) 347 state->status = "UNKNOWN_REASON"; 348 349 au_state->status = state->status; 350 au_state->reply = &state->reply; 351 kau_as_req(context, (errcode || state->preauth_err) ? FALSE : TRUE, 352 au_state); 353 kau_free_kdc_req(au_state); 354 355 free_padata_context(context, state->pa_context); 356 if (as_encrypting_key) 357 krb5_free_keyblock(context, as_encrypting_key); 358 if (errcode) 359 emsg = krb5_get_error_message(context, errcode); 360 361 if (state->status) { 362 log_as_req(context, state->local_addr, state->remote_addr, 363 state->request, &state->reply, state->client, 364 state->cname, state->server, state->sname, state->kdc_time, 365 state->status, errcode, emsg); 366 did_log = 1; 367 } 368 if (errcode) { 369 if (state->status == 0) { 370 state->status = emsg; 371 } 372 if (errcode != KRB5KDC_ERR_DISCARD) { 373 errcode = prepare_error_as(state->rstate, state->request, 374 state->local_tgt, &state->local_tgt_key, 375 errcode, state->e_data, 376 state->typed_e_data, 377 ((state->client != NULL) ? 378 state->client->princ : NULL), 379 &response, state->status); 380 state->status = 0; 381 } 382 } 383 384 if (emsg) 385 krb5_free_error_message(context, emsg); 386 if (state->enc_tkt_reply.authorization_data != NULL) 387 krb5_free_authdata(context, state->enc_tkt_reply.authorization_data); 388 if (state->local_tgt_key.contents != NULL) 389 krb5_free_keyblock_contents(context, &state->local_tgt_key); 390 if (state->server_keyblock.contents != NULL) 391 krb5_free_keyblock_contents(context, &state->server_keyblock); 392 if (state->client_keyblock.contents != NULL) 393 krb5_free_keyblock_contents(context, &state->client_keyblock); 394 if (state->reply.padata != NULL) 395 krb5_free_pa_data(context, state->reply.padata); 396 if (state->reply_encpart.enc_padata) 397 krb5_free_pa_data(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(context, state->client); 404 krb5_db_free_principal(context, state->server); 405 krb5_db_free_principal(context, state->local_tgt_storage); 406 if (state->session_key.contents != NULL) 407 krb5_free_keyblock_contents(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(context, state->e_data); 415 krb5_free_data(context, state->inner_body); 416 kdc_free_rstate(state->rstate); 417 krb5_free_kdc_req(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 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 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 470 process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, 471 const struct sockaddr *local_addr, 472 const struct sockaddr *remote_addr, kdc_realm_t *realm, 473 verto_ctx *vctx, loop_respond_fn respond, void *arg) 474 { 475 krb5_context context = realm->realm_context; 476 krb5_error_code errcode; 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 = realm; 494 495 errcode = kdc_make_rstate(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(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(context, TRUE, au_state); 521 522 errcode = krb5_timeofday(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(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 errcode = krb5_unparse_name(context, state->request->client, 557 &state->cname); 558 if (errcode) 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 errcode = krb5_unparse_name(context, state->request->server, 568 &state->sname); 569 if (errcode) 570 goto errout; 571 limit_string(state->sname); 572 573 setflag(state->c_flags, KRB5_KDB_FLAG_CLIENT); 574 if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) || 575 state->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL) 576 setflag(state->c_flags, KRB5_KDB_FLAG_REFERRAL_OK); 577 errcode = lookup_client(context, state->request, state->c_flags, 578 &state->client); 579 if (errcode == KRB5_KDB_CANTLOCK_DB) 580 errcode = KRB5KDC_ERR_SVC_UNAVAILABLE; 581 if (errcode == KRB5_KDB_NOENTRY) { 582 state->status = "CLIENT_NOT_FOUND"; 583 if (vague_errors) 584 errcode = KRB5KRB_ERR_GENERIC; 585 else 586 errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; 587 goto errout; 588 } else if (errcode) { 589 state->status = "LOOKING_UP_CLIENT"; 590 goto errout; 591 } 592 state->rock.client = state->client; 593 594 au_state->stage = SRVC_PRINC; 595 596 errcode = krb5_db_get_principal(context, state->request->server, 0, 597 &state->server); 598 if (errcode == KRB5_KDB_CANTLOCK_DB) 599 errcode = KRB5KDC_ERR_SVC_UNAVAILABLE; 600 if (errcode == KRB5_KDB_NOENTRY) { 601 state->status = "SERVER_NOT_FOUND"; 602 errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 603 goto errout; 604 } else if (errcode) { 605 state->status = "LOOKING_UP_SERVER"; 606 goto errout; 607 } 608 609 /* If the KDB module returned a different realm for the client and server, 610 * we need to issue a client realm referral. */ 611 if (!data_eq(state->server->princ->realm, state->client->princ->realm)) { 612 state->status = "REFERRAL"; 613 au_state->cl_realm = &state->client->princ->realm; 614 errcode = KRB5KDC_ERR_WRONG_REALM; 615 goto errout; 616 } 617 618 errcode = get_local_tgt(context, &state->request->server->realm, 619 state->server, &state->local_tgt, 620 &state->local_tgt_storage, &state->local_tgt_key); 621 if (errcode) { 622 state->status = "GET_LOCAL_TGT"; 623 goto errout; 624 } 625 state->rock.local_tgt = state->local_tgt; 626 state->rock.local_tgt_key = &state->local_tgt_key; 627 628 au_state->stage = VALIDATE_POL; 629 630 errcode = validate_as_request(realm, state->request, state->client, 631 state->server, state->kdc_time, 632 &state->status, &state->e_data); 633 if (errcode) 634 goto errout; 635 636 au_state->stage = ISSUE_TKT; 637 638 /* 639 * Select the keytype for the ticket session key. 640 */ 641 useenctype = select_session_keytype(context, state->server, 642 state->request->nktypes, 643 state->request->ktype); 644 if (useenctype == 0) { 645 /* unsupported ktype */ 646 state->status = "BAD_ENCRYPTION_TYPE"; 647 errcode = KRB5KDC_ERR_ETYPE_NOSUPP; 648 goto errout; 649 } 650 651 errcode = krb5_c_make_random_key(context, useenctype, &state->session_key); 652 if (errcode) 653 goto errout; 654 655 /* 656 * Canonicalization is only effective if we are issuing a TGT 657 * (the intention is to allow support for Windows "short" realm 658 * aliases, nothing more). 659 */ 660 if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) && 661 krb5_is_tgs_principal(state->request->server) && 662 krb5_is_tgs_principal(state->server->princ)) { 663 state->ticket_reply.server = state->server->princ; 664 } else { 665 state->ticket_reply.server = state->request->server; 666 } 667 668 /* Copy options that request the corresponding ticket flags. */ 669 state->enc_tkt_reply.flags = get_ticket_flags(state->request->kdc_options, 670 state->client, state->server, 671 NULL); 672 state->enc_tkt_reply.times.authtime = state->kdc_time; 673 674 /* 675 * It should be noted that local policy may affect the 676 * processing of any of these flags. For example, some 677 * realms may refuse to issue renewable tickets 678 */ 679 680 state->enc_tkt_reply.session = &state->session_key; 681 if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) { 682 state->client_princ = *(state->client->princ); 683 } else { 684 state->client_princ = *(state->request->client); 685 /* The realm is always canonicalized */ 686 state->client_princ.realm = state->client->princ->realm; 687 } 688 state->enc_tkt_reply.client = &state->client_princ; 689 state->enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS; 690 state->enc_tkt_reply.transited.tr_contents = empty_string; 691 692 if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED)) 693 state->enc_tkt_reply.times.starttime = state->request->from; 694 else 695 state->enc_tkt_reply.times.starttime = state->kdc_time; 696 697 kdc_get_ticket_endtime(realm, state->enc_tkt_reply.times.starttime, 698 kdc_infinity, state->request->till, state->client, 699 state->server, &state->enc_tkt_reply.times.endtime); 700 701 kdc_get_ticket_renewtime(realm, state->request, NULL, state->client, 702 state->server, &state->enc_tkt_reply.flags, 703 &state->enc_tkt_reply.times); 704 705 /* 706 * starttime is optional, and treated as authtime if not present. 707 * so we can nuke it if it matches 708 */ 709 if (state->enc_tkt_reply.times.starttime == 710 state->enc_tkt_reply.times.authtime) 711 state->enc_tkt_reply.times.starttime = 0; 712 713 state->enc_tkt_reply.caddrs = state->request->addresses; 714 state->enc_tkt_reply.authorization_data = 0; 715 716 /* If anonymous requests are being used, adjust the realm of the client 717 * principal. */ 718 if (isflagset(state->request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) { 719 if (!krb5_principal_compare_any_realm(context, state->request->client, 720 krb5_anonymous_principal())) { 721 errcode = KRB5KDC_ERR_BADOPTION; 722 /* Anonymous requested but anonymous principal not used.*/ 723 state->status = "VALIDATE_ANONYMOUS_PRINCIPAL"; 724 goto errout; 725 } 726 krb5_free_principal(context, state->request->client); 727 state->request->client = NULL; 728 errcode = krb5_copy_principal(context, krb5_anonymous_principal(), 729 &state->request->client); 730 if (errcode) 731 goto errout; 732 state->enc_tkt_reply.client = state->request->client; 733 setflag(state->client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH); 734 } 735 736 errcode = select_client_key(context, state->client, state->request->ktype, 737 state->request->nktypes, 738 &state->client_keyblock, &state->client_key); 739 if (errcode) { 740 state->status = "DECRYPT_CLIENT_KEY"; 741 goto errout; 742 } 743 if (state->client_key != NULL) 744 state->rock.client_key = state->client_key; 745 state->rock.client_keyblock = &state->client_keyblock; 746 747 errcode = kdc_fast_read_cookie(context, state->rstate, state->request, 748 state->local_tgt, &state->local_tgt_key); 749 if (errcode) { 750 state->status = "READ_COOKIE"; 751 goto errout; 752 } 753 754 /* 755 * Check the preauthentication if it is there. 756 */ 757 if (state->request->padata) { 758 check_padata(context, &state->rock, state->req_pkt, state->request, 759 &state->enc_tkt_reply, &state->pa_context, &state->e_data, 760 &state->typed_e_data, finish_preauth, state); 761 } else 762 finish_preauth(state, 0); 763 return; 764 765 errout: 766 finish_process_as_req(state, errcode); 767 } 768 769 static krb5_error_code 770 prepare_error_as(struct kdc_request_state *rstate, krb5_kdc_req *request, 771 krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key, 772 krb5_error_code code, krb5_pa_data **e_data_in, 773 krb5_boolean typed_e_data, krb5_principal canon_client, 774 krb5_data **response, const char *status) 775 { 776 krb5_context context = rstate->realm_data->realm_context; 777 krb5_error errpkt; 778 krb5_error_code retval; 779 krb5_data *scratch = NULL, *e_data_asn1 = NULL, *fast_edata = NULL; 780 krb5_pa_data **e_data = NULL, *cookie = NULL; 781 size_t count; 782 783 errpkt.magic = KV5M_ERROR; 784 785 if (e_data_in != NULL) { 786 /* Add a PA-FX-COOKIE to e_data_in. e_data is a shallow copy 787 * containing aliases. */ 788 for (count = 0; e_data_in[count] != NULL; count++); 789 e_data = calloc(count + 2, sizeof(*e_data)); 790 if (e_data == NULL) 791 return ENOMEM; 792 memcpy(e_data, e_data_in, count * sizeof(*e_data)); 793 retval = kdc_fast_make_cookie(context, rstate, local_tgt, 794 local_tgt_key, request->client, &cookie); 795 e_data[count] = cookie; 796 } 797 798 errpkt.ctime = 0; 799 errpkt.cusec = 0; 800 801 retval = krb5_us_timeofday(context, &errpkt.stime, &errpkt.susec); 802 if (retval) 803 goto cleanup; 804 errpkt.error = errcode_to_protocol(code); 805 errpkt.server = request->server; 806 errpkt.client = (code == KRB5KDC_ERR_WRONG_REALM) ? canon_client : 807 request->client; 808 errpkt.text = string2data((char *)status); 809 810 if (e_data != NULL) { 811 if (typed_e_data) 812 retval = encode_krb5_typed_data(e_data, &e_data_asn1); 813 else 814 retval = encode_krb5_padata_sequence(e_data, &e_data_asn1); 815 if (retval) 816 goto cleanup; 817 errpkt.e_data = *e_data_asn1; 818 } else 819 errpkt.e_data = empty_data(); 820 821 retval = kdc_fast_handle_error(context, rstate, request, e_data, &errpkt, 822 &fast_edata); 823 if (retval) 824 goto cleanup; 825 if (fast_edata != NULL) 826 errpkt.e_data = *fast_edata; 827 828 scratch = k5alloc(sizeof(*scratch), &retval); 829 if (scratch == NULL) 830 goto cleanup; 831 if (kdc_fast_hide_client(rstate) && errpkt.client != NULL) 832 errpkt.client = (krb5_principal)krb5_anonymous_principal(); 833 retval = krb5_mk_error(context, &errpkt, scratch); 834 if (retval) 835 goto cleanup; 836 837 *response = scratch; 838 scratch = NULL; 839 840 cleanup: 841 krb5_free_data(context, fast_edata); 842 krb5_free_data(context, e_data_asn1); 843 free(scratch); 844 free(e_data); 845 if (cookie != NULL) 846 free(cookie->contents); 847 free(cookie); 848 return retval; 849 } 850