1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* kdc/kdc_util.c - Utility functions for the KDC implementation */ 3 /* 4 * Copyright 1990,1991,2007,2008,2009 by the Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 /* 27 * Copyright (c) 2006-2008, Novell, Inc. 28 * All rights reserved. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions are met: 32 * 33 * * Redistributions of source code must retain the above copyright notice, 34 * this list of conditions and the following disclaimer. 35 * * Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * * The copyright holder's name is not used to endorse or promote products 39 * derived from this software without specific prior written permission. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 51 * POSSIBILITY OF SUCH DAMAGE. 52 */ 53 54 #include "k5-int.h" 55 #include "kdc_util.h" 56 #include "extern.h" 57 #include <stdio.h> 58 #include <ctype.h> 59 #include <syslog.h> 60 #include <kadm5/admin.h> 61 #include "adm_proto.h" 62 #include "net-server.h" 63 #include <limits.h> 64 65 #ifdef KRBCONF_VAGUE_ERRORS 66 const int vague_errors = 1; 67 #else 68 const int vague_errors = 0; 69 #endif 70 71 static krb5_error_code kdc_rd_ap_req(kdc_realm_t *realm, krb5_ap_req *apreq, 72 krb5_auth_context auth_context, 73 krb5_db_entry **server, 74 krb5_keyblock **tgskey); 75 static krb5_error_code find_server_key(krb5_context, 76 krb5_db_entry *, krb5_enctype, 77 krb5_kvno, krb5_keyblock **, 78 krb5_kvno *); 79 80 /* 81 * Returns TRUE if the kerberos principal is the name of a Kerberos ticket 82 * service. 83 */ 84 krb5_boolean 85 krb5_is_tgs_principal(krb5_const_principal principal) 86 { 87 if (krb5_princ_size(kdc_context, principal) != 2) 88 return FALSE; 89 if (data_eq_string(*krb5_princ_component(kdc_context, principal, 0), 90 KRB5_TGS_NAME)) 91 return TRUE; 92 else 93 return FALSE; 94 } 95 96 /* Returns TRUE if principal is the name of a cross-realm TGS. */ 97 krb5_boolean 98 is_cross_tgs_principal(krb5_const_principal principal) 99 { 100 return krb5_is_tgs_principal(principal) && 101 !data_eq(principal->data[1], principal->realm); 102 } 103 104 /* Return true if princ is the name of a local TGS for any realm. */ 105 krb5_boolean 106 is_local_tgs_principal(krb5_const_principal principal) 107 { 108 return krb5_is_tgs_principal(principal) && 109 data_eq(principal->data[1], principal->realm); 110 } 111 112 /* 113 * given authentication data (provides seed for checksum), verify checksum 114 * for source data. 115 */ 116 static krb5_error_code 117 comp_cksum(krb5_context kcontext, krb5_data *source, krb5_ticket *ticket, 118 krb5_checksum *his_cksum) 119 { 120 krb5_error_code retval; 121 krb5_boolean valid; 122 123 if (!krb5_c_valid_cksumtype(his_cksum->checksum_type)) 124 return KRB5KDC_ERR_SUMTYPE_NOSUPP; 125 126 /* must be collision proof */ 127 if (!krb5_c_is_coll_proof_cksum(his_cksum->checksum_type)) 128 return KRB5KRB_AP_ERR_INAPP_CKSUM; 129 130 /* verify checksum */ 131 if ((retval = krb5_c_verify_checksum(kcontext, ticket->enc_part2->session, 132 KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, 133 source, his_cksum, &valid))) 134 return(retval); 135 136 if (!valid) 137 return(KRB5KRB_AP_ERR_BAD_INTEGRITY); 138 139 return(0); 140 } 141 142 /* If a header ticket is decrypted, *ticket_out is filled in even on error. */ 143 krb5_error_code 144 kdc_process_tgs_req(kdc_realm_t *realm, krb5_kdc_req *request, 145 const krb5_fulladdr *from, krb5_data *pkt, 146 krb5_ticket **ticket_out, krb5_db_entry **krbtgt_ptr, 147 krb5_keyblock **tgskey, krb5_keyblock **subkey, 148 krb5_pa_data **pa_tgs_req) 149 { 150 krb5_context context = realm->realm_context; 151 krb5_pa_data * tmppa; 152 krb5_ap_req * apreq; 153 krb5_error_code retval; 154 krb5_authdata **authdata = NULL; 155 krb5_data scratch1; 156 krb5_data * scratch = NULL; 157 krb5_auth_context auth_context = NULL; 158 krb5_authenticator * authenticator = NULL; 159 krb5_checksum * his_cksum = NULL; 160 krb5_db_entry * krbtgt = NULL; 161 krb5_ticket * ticket; 162 163 *ticket_out = NULL; 164 *krbtgt_ptr = NULL; 165 *tgskey = NULL; 166 167 tmppa = krb5int_find_pa_data(context, request->padata, KRB5_PADATA_AP_REQ); 168 if (!tmppa) 169 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 170 171 scratch1.length = tmppa->length; 172 scratch1.data = (char *)tmppa->contents; 173 if ((retval = decode_krb5_ap_req(&scratch1, &apreq))) 174 return retval; 175 ticket = apreq->ticket; 176 177 if (isflagset(apreq->ap_options, AP_OPTS_USE_SESSION_KEY) || 178 isflagset(apreq->ap_options, AP_OPTS_MUTUAL_REQUIRED)) { 179 krb5_klog_syslog(LOG_INFO, _("TGS_REQ: SESSION KEY or MUTUAL")); 180 retval = KRB5KDC_ERR_POLICY; 181 goto cleanup; 182 } 183 184 retval = krb5_auth_con_init(context, &auth_context); 185 if (retval) 186 goto cleanup; 187 188 /* Don't use a replay cache. */ 189 retval = krb5_auth_con_setflags(context, auth_context, 0); 190 if (retval) 191 goto cleanup; 192 193 retval = krb5_auth_con_setaddrs(context, auth_context, NULL, 194 from->address); 195 if (retval) 196 goto cleanup_auth_context; 197 198 retval = kdc_rd_ap_req(realm, apreq, auth_context, &krbtgt, tgskey); 199 if (retval) 200 goto cleanup_auth_context; 201 202 retval = krb5_auth_con_getrecvsubkey(context, auth_context, subkey); 203 if (retval) 204 goto cleanup_auth_context; 205 206 retval = krb5_auth_con_getauthenticator(context, auth_context, 207 &authenticator); 208 if (retval) 209 goto cleanup_auth_context; 210 211 retval = krb5_find_authdata(context, ticket->enc_part2->authorization_data, 212 authenticator->authorization_data, 213 KRB5_AUTHDATA_FX_ARMOR, &authdata); 214 if (retval != 0) 215 goto cleanup_authenticator; 216 if (authdata&& authdata[0]) { 217 k5_setmsg(context, KRB5KDC_ERR_POLICY, 218 "ticket valid only as FAST armor"); 219 retval = KRB5KDC_ERR_POLICY; 220 krb5_free_authdata(context, authdata); 221 goto cleanup_authenticator; 222 } 223 krb5_free_authdata(context, authdata); 224 225 226 /* Check for a checksum */ 227 if (!(his_cksum = authenticator->checksum)) { 228 retval = KRB5KRB_AP_ERR_INAPP_CKSUM; 229 goto cleanup_authenticator; 230 } 231 232 /* 233 * Check application checksum vs. tgs request 234 * 235 * We try checksumming the req-body two different ways: first we 236 * try reaching into the raw asn.1 stream (if available), and 237 * checksum that directly; if that fails, then we try encoding 238 * using our local asn.1 library. 239 */ 240 if (pkt && (fetch_asn1_field((unsigned char *) pkt->data, 241 1, 4, &scratch1) >= 0)) { 242 if (comp_cksum(context, &scratch1, ticket, his_cksum)) { 243 if (!(retval = encode_krb5_kdc_req_body(request, &scratch))) 244 retval = comp_cksum(context, scratch, ticket, his_cksum); 245 krb5_free_data(context, scratch); 246 if (retval) 247 goto cleanup_authenticator; 248 } 249 } 250 251 *pa_tgs_req = tmppa; 252 *krbtgt_ptr = krbtgt; 253 krbtgt = NULL; 254 255 cleanup_authenticator: 256 krb5_free_authenticator(context, authenticator); 257 258 cleanup_auth_context: 259 krb5_auth_con_free(context, auth_context); 260 261 cleanup: 262 if (retval != 0) { 263 krb5_free_keyblock(context, *tgskey); 264 *tgskey = NULL; 265 } 266 if (apreq->ticket->enc_part2 != NULL) { 267 /* Steal the decrypted ticket pointer, even on error. */ 268 *ticket_out = apreq->ticket; 269 apreq->ticket = NULL; 270 } 271 krb5_free_ap_req(context, apreq); 272 krb5_db_free_principal(context, krbtgt); 273 return retval; 274 } 275 276 /* 277 * This is a KDC wrapper around krb5_rd_req_decoded_anyflag(). 278 * 279 * We can't depend on KDB-as-keytab for handling the AP-REQ here for 280 * optimization reasons: we want to minimize the number of KDB lookups. We'll 281 * need the KDB entry for the TGS principal, and the TGS key used to decrypt 282 * the TGT, elsewhere in the TGS code. 283 * 284 * This function also implements key rollover support for kvno 0 cross-realm 285 * TGTs issued by AD. 286 */ 287 static 288 krb5_error_code 289 kdc_rd_ap_req(kdc_realm_t *realm, krb5_ap_req *apreq, 290 krb5_auth_context auth_context, krb5_db_entry **server, 291 krb5_keyblock **tgskey) 292 { 293 krb5_context context = realm->realm_context; 294 krb5_error_code retval; 295 krb5_enctype search_enctype = apreq->ticket->enc_part.enctype; 296 krb5_boolean match_enctype = 1; 297 krb5_kvno kvno; 298 size_t tries = 3; 299 300 /* 301 * When we issue tickets we use the first key in the principals' highest 302 * kvno keyset. For non-cross-realm krbtgt principals we want to only 303 * allow the use of the first key of the principal's keyset that matches 304 * the given kvno. 305 */ 306 if (krb5_is_tgs_principal(apreq->ticket->server) && 307 !is_cross_tgs_principal(apreq->ticket->server)) { 308 search_enctype = -1; 309 match_enctype = 0; 310 } 311 312 retval = kdc_get_server_key(context, apreq->ticket, 0, match_enctype, 313 server, NULL, NULL); 314 if (retval) 315 return retval; 316 317 *tgskey = NULL; 318 kvno = apreq->ticket->enc_part.kvno; 319 do { 320 krb5_free_keyblock(context, *tgskey); 321 retval = find_server_key(context, *server, search_enctype, kvno, 322 tgskey, &kvno); 323 if (retval) 324 continue; 325 326 /* Make the TGS key available to krb5_rd_req_decoded_anyflag() */ 327 retval = krb5_auth_con_setuseruserkey(context, auth_context, *tgskey); 328 if (retval) 329 return retval; 330 331 retval = krb5_rd_req_decoded_anyflag(context, &auth_context, apreq, 332 apreq->ticket->server, 333 realm->realm_keytab, NULL, NULL); 334 335 /* If the ticket was decrypted, don't try any more keys. */ 336 if (apreq->ticket->enc_part2 != NULL) 337 break; 338 339 } while (retval && apreq->ticket->enc_part.kvno == 0 && kvno-- > 1 && 340 --tries > 0); 341 342 return retval; 343 } 344 345 /* 346 * The KDC should take the keytab associated with the realm and pass 347 * that to the krb5_rd_req_decoded_anyflag(), but we still need to use 348 * the service (TGS, here) key elsewhere. This approach is faster than 349 * the KDB keytab approach too. 350 * 351 * This is also used by do_tgs_req() for u2u auth. 352 */ 353 krb5_error_code 354 kdc_get_server_key(krb5_context context, 355 krb5_ticket *ticket, unsigned int flags, 356 krb5_boolean match_enctype, krb5_db_entry **server_ptr, 357 krb5_keyblock **key, krb5_kvno *kvno) 358 { 359 krb5_error_code retval; 360 krb5_db_entry * server = NULL; 361 krb5_enctype search_enctype = -1; 362 krb5_kvno search_kvno = -1; 363 364 if (match_enctype) 365 search_enctype = ticket->enc_part.enctype; 366 if (ticket->enc_part.kvno) 367 search_kvno = ticket->enc_part.kvno; 368 369 *server_ptr = NULL; 370 371 retval = krb5_db_get_principal(context, ticket->server, flags, 372 &server); 373 if (retval == KRB5_KDB_NOENTRY) { 374 char *sname; 375 if (!krb5_unparse_name(context, ticket->server, &sname)) { 376 limit_string(sname); 377 krb5_klog_syslog(LOG_ERR, 378 _("TGS_REQ: UNKNOWN SERVER: server='%s'"), sname); 379 free(sname); 380 } 381 return KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 382 } else if (retval) 383 return retval; 384 if (server->attributes & KRB5_KDB_DISALLOW_SVR || 385 server->attributes & KRB5_KDB_DISALLOW_ALL_TIX) { 386 retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 387 goto errout; 388 } 389 390 if (key) { 391 retval = find_server_key(context, server, search_enctype, search_kvno, 392 key, kvno); 393 if (retval) 394 goto errout; 395 } 396 *server_ptr = server; 397 server = NULL; 398 return 0; 399 400 errout: 401 krb5_db_free_principal(context, server); 402 return retval; 403 } 404 405 /* 406 * A utility function to get the right key from a KDB entry. Used in handling 407 * of kvno 0 TGTs, for example. 408 */ 409 static 410 krb5_error_code 411 find_server_key(krb5_context context, 412 krb5_db_entry *server, krb5_enctype enctype, krb5_kvno kvno, 413 krb5_keyblock **key_out, krb5_kvno *kvno_out) 414 { 415 krb5_error_code retval; 416 krb5_key_data * server_key; 417 krb5_keyblock * key; 418 419 *key_out = NULL; 420 retval = krb5_dbe_find_enctype(context, server, enctype, -1, 421 kvno ? (krb5_int32)kvno : -1, &server_key); 422 if (retval) 423 return retval; 424 if (!server_key) 425 return KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 426 if ((key = (krb5_keyblock *)malloc(sizeof *key)) == NULL) 427 return ENOMEM; 428 retval = krb5_dbe_decrypt_key_data(context, NULL, server_key, 429 key, NULL); 430 if (retval) 431 goto errout; 432 if (enctype != -1) { 433 krb5_boolean similar; 434 retval = krb5_c_enctype_compare(context, enctype, key->enctype, 435 &similar); 436 if (retval) 437 goto errout; 438 if (!similar) { 439 retval = KRB5_KDB_NO_PERMITTED_KEY; 440 goto errout; 441 } 442 key->enctype = enctype; 443 } 444 *key_out = key; 445 key = NULL; 446 if (kvno_out) 447 *kvno_out = server_key->key_data_kvno; 448 errout: 449 krb5_free_keyblock(context, key); 450 return retval; 451 } 452 453 /* Find the first key data entry (of a valid enctype) of the highest kvno in 454 * entry, and decrypt it into *key_out. */ 455 krb5_error_code 456 get_first_current_key(krb5_context context, krb5_db_entry *entry, 457 krb5_keyblock *key_out) 458 { 459 krb5_error_code ret; 460 krb5_key_data *kd; 461 462 memset(key_out, 0, sizeof(*key_out)); 463 ret = krb5_dbe_find_enctype(context, entry, -1, -1, 0, &kd); 464 if (ret) 465 return ret; 466 return krb5_dbe_decrypt_key_data(context, NULL, kd, key_out, NULL); 467 } 468 469 /* 470 * If candidate is the local TGT for realm, set *alias_out to candidate and 471 * *storage_out to NULL. Otherwise, load the local TGT into *storage_out and 472 * set *alias_out to *storage_out. In either case, set *key_out to the 473 * decrypted first key of the local TGT. 474 * 475 * In the future we might generalize this to a small per-request principal 476 * cache. For now, it saves a load operation in the common case where the AS 477 * server or TGS header ticket server is the local TGT. 478 */ 479 krb5_error_code 480 get_local_tgt(krb5_context context, const krb5_data *realm, 481 krb5_db_entry *candidate, krb5_db_entry **alias_out, 482 krb5_db_entry **storage_out, krb5_keyblock *key_out) 483 { 484 krb5_error_code ret; 485 krb5_principal princ; 486 krb5_db_entry *storage = NULL, *tgt; 487 488 *alias_out = NULL; 489 *storage_out = NULL; 490 memset(key_out, 0, sizeof(*key_out)); 491 492 ret = krb5_build_principal_ext(context, &princ, realm->length, realm->data, 493 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, 494 realm->length, realm->data, 0); 495 if (ret) 496 goto cleanup; 497 498 if (!krb5_principal_compare(context, candidate->princ, princ)) { 499 ret = krb5_db_get_principal(context, princ, 0, &storage); 500 if (ret) 501 goto cleanup; 502 tgt = storage; 503 } else { 504 tgt = candidate; 505 } 506 507 ret = get_first_current_key(context, tgt, key_out); 508 if (ret) 509 goto cleanup; 510 511 *alias_out = tgt; 512 *storage_out = storage; 513 storage = NULL; 514 515 cleanup: 516 krb5_db_free_principal(context, storage); 517 krb5_free_principal(context, princ); 518 return ret; 519 } 520 521 /* If server has a pac_privsvr_enctype attribute and it differs from tgt_key's 522 * enctype, derive a key of the specified enctype. Otherwise copy tgt_key. */ 523 krb5_error_code 524 pac_privsvr_key(krb5_context context, krb5_db_entry *server, 525 const krb5_keyblock *tgt_key, krb5_keyblock **key_out) 526 { 527 krb5_error_code ret; 528 char *attrval = NULL; 529 krb5_enctype privsvr_enctype; 530 krb5_data prf_input = string2data("pac_privsvr"); 531 532 ret = krb5_dbe_get_string(context, server, KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE, 533 &attrval); 534 if (ret) 535 return ret; 536 if (attrval == NULL) 537 return krb5_copy_keyblock(context, tgt_key, key_out); 538 539 ret = krb5_string_to_enctype(attrval, &privsvr_enctype); 540 if (ret) { 541 k5_setmsg(context, ret, _("Invalid pac_privsvr_enctype value %s"), 542 attrval); 543 goto cleanup; 544 } 545 546 if (tgt_key->enctype == privsvr_enctype) { 547 ret = krb5_copy_keyblock(context, tgt_key, key_out); 548 } else { 549 ret = krb5_c_derive_prfplus(context, tgt_key, &prf_input, 550 privsvr_enctype, key_out); 551 } 552 553 cleanup: 554 krb5_dbe_free_string(context, attrval); 555 return ret; 556 } 557 558 /* Try verifying a ticket's PAC using a privsvr key either equal to or derived 559 * from tgt_key, respecting the server's pac_privsvr_enctype value if set. */ 560 static krb5_error_code 561 try_verify_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt, 562 krb5_db_entry *server, krb5_keyblock *server_key, 563 const krb5_keyblock *tgt_key, krb5_pac *pac_out) 564 { 565 krb5_error_code ret; 566 krb5_keyblock *privsvr_key; 567 568 ret = pac_privsvr_key(context, server, tgt_key, &privsvr_key); 569 if (ret) 570 return ret; 571 ret = krb5_kdc_verify_ticket(context, enc_tkt, server->princ, server_key, 572 privsvr_key, pac_out); 573 krb5_free_keyblock(context, privsvr_key); 574 return ret; 575 } 576 577 /* 578 * If a PAC is present in enc_tkt, verify it and place it in *pac_out. sprinc 579 * is the canonical name of the server principal entry used to decrypt enc_tkt. 580 * server_key is the ticket decryption key. tgt is the local krbtgt entry for 581 * the ticket server realm, and tgt_key is its first key. 582 */ 583 krb5_error_code 584 get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt, 585 krb5_db_entry *server, krb5_keyblock *server_key, 586 krb5_db_entry *tgt, krb5_keyblock *tgt_key, krb5_pac *pac_out) 587 { 588 krb5_error_code ret; 589 krb5_key_data *kd; 590 krb5_keyblock old_key; 591 krb5_kvno kvno; 592 int tries; 593 594 *pac_out = NULL; 595 596 /* For local or cross-realm TGTs we only check the server signature. */ 597 if (krb5_is_tgs_principal(server->princ)) { 598 return krb5_kdc_verify_ticket(context, enc_tkt, server->princ, 599 server_key, NULL, pac_out); 600 } 601 602 ret = try_verify_pac(context, enc_tkt, server, server_key, tgt_key, 603 pac_out); 604 if (ret != KRB5KRB_AP_ERR_MODIFIED && ret != KRB5_BAD_ENCTYPE) 605 return ret; 606 607 /* There is no kvno in PAC signatures, so try two previous versions. */ 608 kvno = tgt->key_data[0].key_data_kvno - 1; 609 for (tries = 2; tries > 0 && kvno > 0; tries--, kvno--) { 610 ret = krb5_dbe_find_enctype(context, tgt, -1, -1, kvno, &kd); 611 if (ret) 612 return KRB5KRB_AP_ERR_MODIFIED; 613 ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &old_key, NULL); 614 if (ret) 615 return ret; 616 ret = try_verify_pac(context, enc_tkt, server, server_key, &old_key, 617 pac_out); 618 krb5_free_keyblock_contents(context, &old_key); 619 if (!ret) 620 return 0; 621 } 622 623 return KRB5KRB_AP_ERR_MODIFIED; 624 } 625 626 /* 627 * Fetch the client info from pac and parse it into a principal name, expecting 628 * a realm in the string. Set *authtime_out to the client info authtime if it 629 * is not null. 630 */ 631 krb5_error_code 632 get_pac_princ_with_realm(krb5_context context, krb5_pac pac, 633 krb5_principal *princ_out, 634 krb5_timestamp *authtime_out) 635 { 636 krb5_error_code ret; 637 int n_atsigns, flags = KRB5_PRINCIPAL_PARSE_REQUIRE_REALM; 638 char *client_str = NULL; 639 const char *p; 640 641 *princ_out = NULL; 642 643 ret = krb5_pac_get_client_info(context, pac, authtime_out, &client_str); 644 if (ret) 645 return ret; 646 647 n_atsigns = 0; 648 for (p = client_str; *p != '\0'; p++) { 649 if (*p == '@') 650 n_atsigns++; 651 } 652 653 if (n_atsigns == 2) { 654 flags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE; 655 } else if (n_atsigns != 1) { 656 ret = KRB5_PARSE_MALFORMED; 657 goto cleanup; 658 } 659 660 ret = krb5_parse_name_flags(context, client_str, flags, princ_out); 661 if (ret) 662 return ret; 663 664 (*princ_out)->type = KRB5_NT_MS_PRINCIPAL; 665 666 cleanup: 667 free(client_str); 668 return 0; 669 } 670 671 /* This probably wants to be updated if you support last_req stuff */ 672 673 static krb5_last_req_entry nolrentry = { KV5M_LAST_REQ_ENTRY, KRB5_LRQ_NONE, 0 }; 674 static krb5_last_req_entry *nolrarray[] = { &nolrentry, 0 }; 675 676 krb5_error_code 677 fetch_last_req_info(krb5_db_entry *dbentry, krb5_last_req_entry ***lrentry) 678 { 679 *lrentry = nolrarray; 680 return 0; 681 } 682 683 684 /* Convert an API error code to a protocol error code. */ 685 int 686 errcode_to_protocol(krb5_error_code code) 687 { 688 int protcode; 689 690 protcode = code - ERROR_TABLE_BASE_krb5; 691 return (protcode >= 0 && protcode <= 128) ? protcode : KRB_ERR_GENERIC; 692 } 693 694 /* Return -1 if the AS or TGS request is disallowed due to KDC policy on 695 * anonymous tickets. */ 696 int 697 check_anon(kdc_realm_t *realm, krb5_principal client, krb5_principal server) 698 { 699 /* If restrict_anon is set, reject requests from anonymous clients to 700 * server principals other than local TGTs. */ 701 if (realm->realm_restrict_anon && 702 krb5_principal_compare_any_realm(realm->realm_context, client, 703 krb5_anonymous_principal()) && 704 !is_local_tgs_principal(server)) 705 return -1; 706 return 0; 707 } 708 709 krb5_error_code 710 validate_as_request(kdc_realm_t *realm, krb5_kdc_req *request, 711 krb5_db_entry *client, krb5_db_entry *server, 712 krb5_timestamp kdc_time, const char **status, 713 krb5_pa_data ***e_data) 714 { 715 krb5_context context = realm->realm_context; 716 krb5_error_code ret; 717 718 /* 719 * If an option is set that is only allowed in TGS requests, complain. 720 */ 721 if (request->kdc_options & AS_INVALID_OPTIONS) { 722 *status = "INVALID AS OPTIONS"; 723 return KRB5KDC_ERR_BADOPTION; 724 } 725 726 /* The client must not be expired */ 727 if (client->expiration && ts_after(kdc_time, client->expiration)) { 728 *status = "CLIENT EXPIRED"; 729 if (vague_errors) 730 return KRB5KRB_ERR_GENERIC; 731 else 732 return KRB5KDC_ERR_NAME_EXP; 733 } 734 735 /* The client's password must not be expired, unless the server is 736 a KRB5_KDC_PWCHANGE_SERVICE. */ 737 if (client->pw_expiration && ts_after(kdc_time, client->pw_expiration) && 738 !isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE)) { 739 *status = "CLIENT KEY EXPIRED"; 740 if (vague_errors) 741 return KRB5KRB_ERR_GENERIC; 742 else 743 return KRB5KDC_ERR_KEY_EXP; 744 } 745 746 /* The server must not be expired */ 747 if (server->expiration && ts_after(kdc_time, server->expiration)) { 748 *status = "SERVICE EXPIRED"; 749 return KRB5KDC_ERR_SERVICE_EXP; 750 } 751 752 /* 753 * If the client requires password changing, then only allow the 754 * pwchange service. 755 */ 756 if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PWCHANGE) && 757 !isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE)) { 758 *status = "REQUIRED PWCHANGE"; 759 return KRB5KDC_ERR_KEY_EXP; 760 } 761 762 /* Client and server must allow postdating tickets */ 763 if ((isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE) || 764 isflagset(request->kdc_options, KDC_OPT_POSTDATED)) && 765 (isflagset(client->attributes, KRB5_KDB_DISALLOW_POSTDATED) || 766 isflagset(server->attributes, KRB5_KDB_DISALLOW_POSTDATED))) { 767 *status = "POSTDATE NOT ALLOWED"; 768 return KRB5KDC_ERR_CANNOT_POSTDATE; 769 } 770 771 /* Check to see if client is locked out */ 772 if (isflagset(client->attributes, KRB5_KDB_DISALLOW_ALL_TIX)) { 773 *status = "CLIENT LOCKED OUT"; 774 return KRB5KDC_ERR_CLIENT_REVOKED; 775 } 776 777 /* Check to see if server is locked out */ 778 if (isflagset(server->attributes, KRB5_KDB_DISALLOW_ALL_TIX)) { 779 *status = "SERVICE LOCKED OUT"; 780 return KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 781 } 782 783 /* Check to see if server is allowed to be a service */ 784 if (isflagset(server->attributes, KRB5_KDB_DISALLOW_SVR)) { 785 *status = "SERVICE NOT ALLOWED"; 786 return KRB5KDC_ERR_MUST_USE_USER2USER; 787 } 788 789 if (check_anon(realm, client->princ, request->server) != 0) { 790 *status = "ANONYMOUS NOT ALLOWED"; 791 return KRB5KDC_ERR_POLICY; 792 } 793 794 /* Perform KDB module policy checks. */ 795 ret = krb5_db_check_policy_as(context, request, client, server, kdc_time, 796 status, e_data); 797 return (ret == KRB5_PLUGIN_OP_NOTSUPP) ? 0 : ret; 798 } 799 800 /* 801 * Compute ticket flags based on the request, the client and server DB entry 802 * (which may prohibit forwardable or proxiable tickets), and the header 803 * ticket. client may be NULL for a TGS request (although it may be set, such 804 * as for an S4U2Self request). header_enc may be NULL for an AS request. 805 */ 806 krb5_flags 807 get_ticket_flags(krb5_flags reqflags, krb5_db_entry *client, 808 krb5_db_entry *server, krb5_enc_tkt_part *header_enc) 809 { 810 krb5_flags flags; 811 812 /* Validation and renewal TGS requests preserve the header ticket flags. */ 813 if ((reqflags & (KDC_OPT_VALIDATE | KDC_OPT_RENEW)) && header_enc != NULL) 814 return header_enc->flags & ~TKT_FLG_INVALID; 815 816 /* Indicate support for encrypted padata (RFC 6806), and set flags based on 817 * request options and the header ticket. */ 818 flags = OPTS2FLAGS(reqflags) | TKT_FLG_ENC_PA_REP; 819 if (reqflags & KDC_OPT_POSTDATED) 820 flags |= TKT_FLG_INVALID; 821 if (header_enc != NULL) 822 flags |= COPY_TKT_FLAGS(header_enc->flags); 823 if (header_enc == NULL) 824 flags |= TKT_FLG_INITIAL; 825 826 /* For TGS requests, indicate if the service is marked ok-as-delegate. */ 827 if (header_enc != NULL && (server->attributes & KRB5_KDB_OK_AS_DELEGATE)) 828 flags |= TKT_FLG_OK_AS_DELEGATE; 829 830 /* Unset PROXIABLE if it is disallowed. */ 831 if (client != NULL && (client->attributes & KRB5_KDB_DISALLOW_PROXIABLE)) 832 flags &= ~TKT_FLG_PROXIABLE; 833 if (server->attributes & KRB5_KDB_DISALLOW_PROXIABLE) 834 flags &= ~TKT_FLG_PROXIABLE; 835 if (header_enc != NULL && !(header_enc->flags & TKT_FLG_PROXIABLE)) 836 flags &= ~TKT_FLG_PROXIABLE; 837 838 /* Unset FORWARDABLE if it is disallowed. */ 839 if (client != NULL && (client->attributes & KRB5_KDB_DISALLOW_FORWARDABLE)) 840 flags &= ~TKT_FLG_FORWARDABLE; 841 if (server->attributes & KRB5_KDB_DISALLOW_FORWARDABLE) 842 flags &= ~TKT_FLG_FORWARDABLE; 843 if (header_enc != NULL && !(header_enc->flags & TKT_FLG_FORWARDABLE)) 844 flags &= ~TKT_FLG_FORWARDABLE; 845 846 /* We don't currently handle issuing anonymous tickets based on 847 * non-anonymous ones. */ 848 if (header_enc != NULL && !(header_enc->flags & TKT_FLG_ANONYMOUS)) 849 flags &= ~TKT_FLG_ANONYMOUS; 850 851 return flags; 852 } 853 854 /* Return KRB5KDC_ERR_POLICY if indicators does not contain the required auth 855 * indicators for server, ENOMEM on allocation error, 0 otherwise. */ 856 krb5_error_code 857 check_indicators(krb5_context context, krb5_db_entry *server, 858 krb5_data *const *indicators) 859 { 860 krb5_error_code ret; 861 char *str = NULL, *copy = NULL, *save, *ind; 862 863 ret = krb5_dbe_get_string(context, server, KRB5_KDB_SK_REQUIRE_AUTH, &str); 864 if (ret || str == NULL) 865 goto cleanup; 866 copy = strdup(str); 867 if (copy == NULL) { 868 ret = ENOMEM; 869 goto cleanup; 870 } 871 872 /* Look for any of the space-separated strings in indicators. */ 873 ind = strtok_r(copy, " ", &save); 874 while (ind != NULL) { 875 if (authind_contains(indicators, ind)) 876 goto cleanup; 877 ind = strtok_r(NULL, " ", &save); 878 } 879 880 ret = KRB5KDC_ERR_POLICY; 881 k5_setmsg(context, ret, 882 _("Required auth indicators not present in ticket: %s"), str); 883 884 cleanup: 885 krb5_dbe_free_string(context, str); 886 free(copy); 887 return ret; 888 } 889 890 #define ASN1_ID_CLASS (0xc0) 891 #define ASN1_ID_TYPE (0x20) 892 #define ASN1_ID_TAG (0x1f) 893 #define ASN1_CLASS_UNIV (0) 894 #define ASN1_CLASS_APP (1) 895 #define ASN1_CLASS_CTX (2) 896 #define ASN1_CLASS_PRIV (3) 897 #define asn1_id_constructed(x) (x & ASN1_ID_TYPE) 898 #define asn1_id_primitive(x) (!asn1_id_constructed(x)) 899 #define asn1_id_class(x) ((x & ASN1_ID_CLASS) >> 6) 900 #define asn1_id_tag(x) (x & ASN1_ID_TAG) 901 902 /* 903 * asn1length - return encoded length of value. 904 * 905 * passed a pointer into the asn.1 stream, which is updated 906 * to point right after the length bits. 907 * 908 * returns -1 on failure. 909 */ 910 static int 911 asn1length(unsigned char **astream) 912 { 913 int length; /* resulting length */ 914 int sublen; /* sublengths */ 915 int blen; /* bytes of length */ 916 unsigned char *p; /* substring searching */ 917 918 if (**astream & 0x80) { 919 blen = **astream & 0x7f; 920 if (blen > 3) { 921 return(-1); 922 } 923 for (++*astream, length = 0; blen; ++*astream, blen--) { 924 length = (length << 8) | **astream; 925 } 926 if (length == 0) { 927 /* indefinite length, figure out by hand */ 928 p = *astream; 929 p++; 930 while (1) { 931 /* compute value length. */ 932 if ((sublen = asn1length(&p)) < 0) { 933 return(-1); 934 } 935 p += sublen; 936 /* check for termination */ 937 if ((!*p++) && (!*p)) { 938 p++; 939 break; 940 } 941 } 942 length = p - *astream; 943 } 944 } else { 945 length = **astream; 946 ++*astream; 947 } 948 return(length); 949 } 950 951 /* 952 * fetch_asn1_field - return raw asn.1 stream of subfield. 953 * 954 * this routine is passed a context-dependent tag number and "level" and returns 955 * the size and length of the corresponding level subfield. 956 * 957 * levels and are numbered starting from 1. 958 * 959 * returns 0 on success, -1 otherwise. 960 */ 961 int 962 fetch_asn1_field(unsigned char *astream, unsigned int level, 963 unsigned int field, krb5_data *data) 964 { 965 unsigned char *estream; /* end of stream */ 966 int classes; /* # classes seen so far this level */ 967 unsigned int levels = 0; /* levels seen so far */ 968 int lastlevel = 1000; /* last level seen */ 969 int length; /* various lengths */ 970 int tag; /* tag number */ 971 unsigned char savelen; /* saved length of our field */ 972 973 classes = -1; 974 /* we assume that the first identifier/length will tell us 975 how long the entire stream is. */ 976 astream++; 977 estream = astream; 978 if ((length = asn1length(&astream)) < 0) { 979 return(-1); 980 } 981 estream += length; 982 /* search down the stream, checking identifiers. we process identifiers 983 until we hit the "level" we want, and then process that level for our 984 subfield, always making sure we don't go off the end of the stream. */ 985 while (astream < estream) { 986 if (!asn1_id_constructed(*astream)) { 987 return(-1); 988 } 989 if (asn1_id_class(*astream) == ASN1_CLASS_CTX) { 990 if ((tag = (int)asn1_id_tag(*astream)) <= lastlevel) { 991 levels++; 992 classes = -1; 993 } 994 lastlevel = tag; 995 if (levels == level) { 996 /* in our context-dependent class, is this the one we're looking for ? */ 997 if (tag == (int)field) { 998 /* return length and data */ 999 astream++; 1000 savelen = *astream; 1001 if ((length = asn1length(&astream)) < 0) { 1002 return(-1); 1003 } 1004 data->length = length; 1005 /* if the field length is indefinite, we will have to subtract two 1006 (terminating octets) from the length returned since we don't want 1007 to pass any info from the "wrapper" back. asn1length will always return 1008 the *total* length of the field, not just what's contained in it */ 1009 if ((savelen & 0xff) == 0x80) { 1010 data->length -=2 ; 1011 } 1012 data->data = (char *)astream; 1013 return(0); 1014 } else if (tag <= classes) { 1015 /* we've seen this class before, something must be wrong */ 1016 return(-1); 1017 } else { 1018 classes = tag; 1019 } 1020 } 1021 } 1022 /* if we're not on our level yet, process this value. otherwise skip over it */ 1023 astream++; 1024 if ((length = asn1length(&astream)) < 0) { 1025 return(-1); 1026 } 1027 if (levels == level) { 1028 astream += length; 1029 } 1030 } 1031 return(-1); 1032 } 1033 1034 /* Return true if we believe server can support enctype as a session key. */ 1035 static krb5_boolean 1036 dbentry_supports_enctype(krb5_context context, krb5_db_entry *server, 1037 krb5_enctype enctype) 1038 { 1039 krb5_error_code retval; 1040 krb5_key_data *datap; 1041 char *etypes_str = NULL; 1042 krb5_enctype default_enctypes[1] = { 0 }; 1043 krb5_enctype *etypes = NULL; 1044 krb5_boolean in_list; 1045 1046 /* Look up the supported session key enctypes list in the KDB. */ 1047 retval = krb5_dbe_get_string(context, server, KRB5_KDB_SK_SESSION_ENCTYPES, 1048 &etypes_str); 1049 if (retval == 0 && etypes_str != NULL && *etypes_str != '\0') { 1050 /* Pass a fake profile key for tracing of unrecognized tokens. */ 1051 retval = krb5int_parse_enctype_list(context, "KDB-session_etypes", 1052 etypes_str, default_enctypes, 1053 &etypes); 1054 if (retval == 0 && etypes != NULL && etypes[0]) { 1055 in_list = k5_etypes_contains(etypes, enctype); 1056 free(etypes_str); 1057 free(etypes); 1058 return in_list; 1059 } 1060 /* Fall through on error or empty list */ 1061 } 1062 free(etypes_str); 1063 free(etypes); 1064 1065 /* Assume every server without a session_enctypes attribute supports 1066 * aes256-cts-hmac-sha1-96. */ 1067 if (enctype == ENCTYPE_AES256_CTS_HMAC_SHA1_96) 1068 return TRUE; 1069 /* Assume the server supports any enctype it has a long-term key for. */ 1070 return !krb5_dbe_find_enctype(context, server, enctype, -1, 0, &datap); 1071 } 1072 1073 /* 1074 * This function returns the keytype which should be selected for the 1075 * session key. It is based on the ordered list which the user 1076 * requested, and what the KDC and the application server can support. 1077 */ 1078 krb5_enctype 1079 select_session_keytype(krb5_context context, krb5_db_entry *server, 1080 int nktypes, krb5_enctype *ktype) 1081 { 1082 int i; 1083 1084 for (i = 0; i < nktypes; i++) { 1085 if (!krb5_c_valid_enctype(ktype[i])) 1086 continue; 1087 1088 if (!krb5_is_permitted_enctype(context, ktype[i])) 1089 continue; 1090 1091 /* 1092 * Prevent these deprecated enctypes from being used as session keys 1093 * unless they are explicitly allowed. In the future they will be more 1094 * comprehensively disabled and eventually removed. 1095 */ 1096 if (ktype[i] == ENCTYPE_DES3_CBC_SHA1 && !context->allow_des3) 1097 continue; 1098 if (ktype[i] == ENCTYPE_ARCFOUR_HMAC && !context->allow_rc4) 1099 continue; 1100 1101 if (dbentry_supports_enctype(context, server, ktype[i])) 1102 return ktype[i]; 1103 } 1104 1105 return 0; 1106 } 1107 1108 /* 1109 * Limit strings to a "reasonable" length to prevent crowding out of 1110 * other useful information in the log entry 1111 */ 1112 #define NAME_LENGTH_LIMIT 128 1113 1114 void limit_string(char *name) 1115 { 1116 int i; 1117 1118 if (!name) 1119 return; 1120 1121 if (strlen(name) < NAME_LENGTH_LIMIT) 1122 return; 1123 1124 i = NAME_LENGTH_LIMIT-4; 1125 name[i++] = '.'; 1126 name[i++] = '.'; 1127 name[i++] = '.'; 1128 name[i] = '\0'; 1129 return; 1130 } 1131 1132 /* Wrapper of krb5_enctype_to_name() to include the PKINIT types. */ 1133 static krb5_error_code 1134 enctype_name(krb5_enctype ktype, char *buf, size_t buflen) 1135 { 1136 const char *name, *prefix = ""; 1137 size_t len; 1138 1139 if (buflen == 0) 1140 return EINVAL; 1141 *buf = '\0'; /* ensure these are always valid C-strings */ 1142 1143 if (!krb5_c_valid_enctype(ktype)) 1144 prefix = "UNSUPPORTED:"; 1145 else if (krb5int_c_deprecated_enctype(ktype)) 1146 prefix = "DEPRECATED:"; 1147 len = strlcpy(buf, prefix, buflen); 1148 if (len >= buflen) 1149 return ENOMEM; 1150 buflen -= len; 1151 buf += len; 1152 1153 /* rfc4556 recommends that clients wishing to indicate support for these 1154 * pkinit algorithms include them in the etype field of the AS-REQ. */ 1155 if (ktype == ENCTYPE_DSA_SHA1_CMS) 1156 name = "id-dsa-with-sha1-CmsOID"; 1157 else if (ktype == ENCTYPE_MD5_RSA_CMS) 1158 name = "md5WithRSAEncryption-CmsOID"; 1159 else if (ktype == ENCTYPE_SHA1_RSA_CMS) 1160 name = "sha-1WithRSAEncryption-CmsOID"; 1161 else if (ktype == ENCTYPE_RC2_CBC_ENV) 1162 name = "rc2-cbc-EnvOID"; 1163 else if (ktype == ENCTYPE_RSA_ENV) 1164 name = "rsaEncryption-EnvOID"; 1165 else if (ktype == ENCTYPE_RSA_ES_OAEP_ENV) 1166 name = "id-RSAES-OAEP-EnvOID"; 1167 else if (ktype == ENCTYPE_DES3_CBC_ENV) 1168 name = "des-ede3-cbc-EnvOID"; 1169 else 1170 return krb5_enctype_to_name(ktype, FALSE, buf, buflen); 1171 1172 if (strlcpy(buf, name, buflen) >= buflen) 1173 return ENOMEM; 1174 return 0; 1175 } 1176 1177 char * 1178 ktypes2str(krb5_enctype *ktype, int nktypes) 1179 { 1180 struct k5buf buf; 1181 int i; 1182 char name[64]; 1183 1184 if (nktypes < 0) 1185 return NULL; 1186 1187 k5_buf_init_dynamic(&buf); 1188 k5_buf_add_fmt(&buf, "%d etypes {", nktypes); 1189 for (i = 0; i < nktypes; i++) { 1190 enctype_name(ktype[i], name, sizeof(name)); 1191 k5_buf_add_fmt(&buf, "%s%s(%ld)", i ? ", " : "", name, (long)ktype[i]); 1192 } 1193 k5_buf_add(&buf, "}"); 1194 return k5_buf_cstring(&buf); 1195 } 1196 1197 char * 1198 rep_etypes2str(krb5_kdc_rep *rep) 1199 { 1200 struct k5buf buf; 1201 char name[64]; 1202 krb5_enctype etype; 1203 1204 k5_buf_init_dynamic(&buf); 1205 k5_buf_add(&buf, "etypes {rep="); 1206 enctype_name(rep->enc_part.enctype, name, sizeof(name)); 1207 k5_buf_add_fmt(&buf, "%s(%ld)", name, (long)rep->enc_part.enctype); 1208 1209 if (rep->ticket != NULL) { 1210 etype = rep->ticket->enc_part.enctype; 1211 enctype_name(etype, name, sizeof(name)); 1212 k5_buf_add_fmt(&buf, ", tkt=%s(%ld)", name, (long)etype); 1213 } 1214 1215 if (rep->ticket != NULL && rep->ticket->enc_part2 != NULL && 1216 rep->ticket->enc_part2->session != NULL) { 1217 etype = rep->ticket->enc_part2->session->enctype; 1218 enctype_name(etype, name, sizeof(name)); 1219 k5_buf_add_fmt(&buf, ", ses=%s(%ld)", name, (long)etype); 1220 } 1221 1222 k5_buf_add(&buf, "}"); 1223 return k5_buf_cstring(&buf); 1224 } 1225 1226 static krb5_error_code 1227 verify_for_user_checksum(krb5_context context, 1228 krb5_keyblock *key, 1229 krb5_pa_for_user *req) 1230 { 1231 krb5_error_code code; 1232 int i; 1233 krb5_int32 name_type; 1234 char *p; 1235 krb5_data data; 1236 krb5_boolean valid = FALSE; 1237 1238 if (!krb5_c_is_keyed_cksum(req->cksum.checksum_type)) { 1239 return KRB5KRB_AP_ERR_INAPP_CKSUM; 1240 } 1241 1242 /* 1243 * Checksum is over name type and string components of 1244 * client principal name and auth_package. 1245 */ 1246 data.length = 4; 1247 for (i = 0; i < krb5_princ_size(context, req->user); i++) { 1248 data.length += krb5_princ_component(context, req->user, i)->length; 1249 } 1250 data.length += krb5_princ_realm(context, req->user)->length; 1251 data.length += req->auth_package.length; 1252 1253 p = data.data = malloc(data.length); 1254 if (data.data == NULL) { 1255 return ENOMEM; 1256 } 1257 1258 name_type = krb5_princ_type(context, req->user); 1259 p[0] = (name_type >> 0 ) & 0xFF; 1260 p[1] = (name_type >> 8 ) & 0xFF; 1261 p[2] = (name_type >> 16) & 0xFF; 1262 p[3] = (name_type >> 24) & 0xFF; 1263 p += 4; 1264 1265 for (i = 0; i < krb5_princ_size(context, req->user); i++) { 1266 if (krb5_princ_component(context, req->user, i)->length > 0) { 1267 memcpy(p, krb5_princ_component(context, req->user, i)->data, 1268 krb5_princ_component(context, req->user, i)->length); 1269 } 1270 p += krb5_princ_component(context, req->user, i)->length; 1271 } 1272 1273 if (krb5_princ_realm(context, req->user)->length > 0) { 1274 memcpy(p, krb5_princ_realm(context, req->user)->data, 1275 krb5_princ_realm(context, req->user)->length); 1276 } 1277 p += krb5_princ_realm(context, req->user)->length; 1278 1279 if (req->auth_package.length > 0) 1280 memcpy(p, req->auth_package.data, req->auth_package.length); 1281 p += req->auth_package.length; 1282 1283 code = krb5_c_verify_checksum(context, 1284 key, 1285 KRB5_KEYUSAGE_APP_DATA_CKSUM, 1286 &data, 1287 &req->cksum, 1288 &valid); 1289 1290 if (code == 0 && valid == FALSE) 1291 code = KRB5KRB_AP_ERR_MODIFIED; 1292 1293 free(data.data); 1294 1295 return code; 1296 } 1297 1298 /* 1299 * Legacy protocol transition (Windows 2003 and above) 1300 */ 1301 static krb5_error_code 1302 kdc_process_for_user(krb5_context context, krb5_pa_data *pa_data, 1303 krb5_keyblock *tgs_session, 1304 krb5_pa_s4u_x509_user **s4u_x509_user, 1305 const char **status) 1306 { 1307 krb5_error_code code; 1308 krb5_pa_for_user *for_user; 1309 krb5_data req_data; 1310 1311 req_data.length = pa_data->length; 1312 req_data.data = (char *)pa_data->contents; 1313 1314 code = decode_krb5_pa_for_user(&req_data, &for_user); 1315 if (code) { 1316 *status = "DECODE_PA_FOR_USER"; 1317 return code; 1318 } 1319 1320 code = verify_for_user_checksum(context, tgs_session, for_user); 1321 if (code) { 1322 *status = "INVALID_S4U2SELF_CHECKSUM"; 1323 krb5_free_pa_for_user(context, for_user); 1324 return code; 1325 } 1326 1327 *s4u_x509_user = calloc(1, sizeof(krb5_pa_s4u_x509_user)); 1328 if (*s4u_x509_user == NULL) { 1329 krb5_free_pa_for_user(context, for_user); 1330 return ENOMEM; 1331 } 1332 1333 (*s4u_x509_user)->user_id.user = for_user->user; 1334 for_user->user = NULL; 1335 krb5_free_pa_for_user(context, for_user); 1336 1337 return 0; 1338 } 1339 1340 static krb5_error_code 1341 verify_s4u_x509_user_checksum(krb5_context context, 1342 krb5_keyblock *key, 1343 krb5_data *req_data, 1344 krb5_int32 kdc_req_nonce, 1345 krb5_pa_s4u_x509_user *req) 1346 { 1347 krb5_error_code code; 1348 krb5_data scratch; 1349 krb5_boolean valid = FALSE; 1350 1351 if (enctype_requires_etype_info_2(key->enctype) && 1352 !krb5_c_is_keyed_cksum(req->cksum.checksum_type)) 1353 return KRB5KRB_AP_ERR_INAPP_CKSUM; 1354 1355 if (req->user_id.nonce != kdc_req_nonce) 1356 return KRB5KRB_AP_ERR_MODIFIED; 1357 1358 /* 1359 * Verify checksum over the encoded userid. If that fails, 1360 * re-encode, and verify that. This is similar to the 1361 * behaviour in kdc_process_tgs_req(). 1362 */ 1363 if (fetch_asn1_field((unsigned char *)req_data->data, 1, 0, &scratch) < 0) 1364 return ASN1_PARSE_ERROR; 1365 1366 code = krb5_c_verify_checksum(context, 1367 key, 1368 KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST, 1369 &scratch, 1370 &req->cksum, 1371 &valid); 1372 if (code != 0) 1373 return code; 1374 1375 if (valid == FALSE) { 1376 krb5_data *data; 1377 1378 code = encode_krb5_s4u_userid(&req->user_id, &data); 1379 if (code != 0) 1380 return code; 1381 1382 code = krb5_c_verify_checksum(context, 1383 key, 1384 KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST, 1385 data, 1386 &req->cksum, 1387 &valid); 1388 1389 krb5_free_data(context, data); 1390 1391 if (code != 0) 1392 return code; 1393 } 1394 1395 return valid ? 0 : KRB5KRB_AP_ERR_MODIFIED; 1396 } 1397 1398 /* 1399 * New protocol transition request (Windows 2008 and above) 1400 */ 1401 static krb5_error_code 1402 kdc_process_s4u_x509_user(krb5_context context, 1403 krb5_kdc_req *request, 1404 krb5_pa_data *pa_data, 1405 krb5_keyblock *tgs_subkey, 1406 krb5_keyblock *tgs_session, 1407 krb5_pa_s4u_x509_user **s4u_x509_user, 1408 const char **status) 1409 { 1410 krb5_error_code code; 1411 krb5_data req_data; 1412 1413 req_data.length = pa_data->length; 1414 req_data.data = (char *)pa_data->contents; 1415 1416 code = decode_krb5_pa_s4u_x509_user(&req_data, s4u_x509_user); 1417 if (code) { 1418 *status = "DECODE_PA_S4U_X509_USER"; 1419 return code; 1420 } 1421 1422 code = verify_s4u_x509_user_checksum(context, 1423 tgs_subkey ? tgs_subkey : 1424 tgs_session, 1425 &req_data, 1426 request->nonce, *s4u_x509_user); 1427 1428 if (code) { 1429 *status = "INVALID_S4U2SELF_CHECKSUM"; 1430 krb5_free_pa_s4u_x509_user(context, *s4u_x509_user); 1431 *s4u_x509_user = NULL; 1432 return code; 1433 } 1434 1435 if (krb5_princ_size(context, (*s4u_x509_user)->user_id.user) == 0 && 1436 (*s4u_x509_user)->user_id.subject_cert.length == 0) { 1437 *status = "INVALID_S4U2SELF_REQUEST"; 1438 krb5_free_pa_s4u_x509_user(context, *s4u_x509_user); 1439 *s4u_x509_user = NULL; 1440 return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; 1441 } 1442 1443 return 0; 1444 } 1445 1446 krb5_error_code 1447 kdc_make_s4u2self_rep(krb5_context context, 1448 krb5_keyblock *tgs_subkey, 1449 krb5_keyblock *tgs_session, 1450 krb5_pa_s4u_x509_user *req_s4u_user, 1451 krb5_kdc_rep *reply, 1452 krb5_enc_kdc_rep_part *reply_encpart) 1453 { 1454 krb5_error_code code; 1455 krb5_data *der_user_id = NULL, *der_s4u_x509_user = NULL; 1456 krb5_pa_s4u_x509_user rep_s4u_user; 1457 krb5_pa_data *pa = NULL; 1458 krb5_enctype enctype; 1459 krb5_keyusage usage; 1460 1461 memset(&rep_s4u_user, 0, sizeof(rep_s4u_user)); 1462 1463 rep_s4u_user.user_id.nonce = req_s4u_user->user_id.nonce; 1464 rep_s4u_user.user_id.user = req_s4u_user->user_id.user; 1465 rep_s4u_user.user_id.options = 1466 req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE; 1467 1468 code = encode_krb5_s4u_userid(&rep_s4u_user.user_id, &der_user_id); 1469 if (code != 0) 1470 goto cleanup; 1471 1472 if (req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE) 1473 usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY; 1474 else 1475 usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST; 1476 1477 code = krb5_c_make_checksum(context, req_s4u_user->cksum.checksum_type, 1478 tgs_subkey != NULL ? tgs_subkey : tgs_session, 1479 usage, der_user_id, &rep_s4u_user.cksum); 1480 if (code != 0) 1481 goto cleanup; 1482 1483 code = encode_krb5_pa_s4u_x509_user(&rep_s4u_user, &der_s4u_x509_user); 1484 if (code != 0) 1485 goto cleanup; 1486 1487 code = k5_add_pa_data_from_data(&reply->padata, KRB5_PADATA_S4U_X509_USER, 1488 der_s4u_x509_user); 1489 if (code != 0) 1490 goto cleanup; 1491 1492 if (tgs_subkey != NULL) 1493 enctype = tgs_subkey->enctype; 1494 else 1495 enctype = tgs_session->enctype; 1496 1497 /* 1498 * Owing to a bug in Windows, unkeyed checksums were used for older 1499 * enctypes, including rc4-hmac. A forthcoming workaround for this 1500 * includes the checksum bytes in the encrypted padata. 1501 */ 1502 if (enctype_requires_etype_info_2(enctype) == FALSE) { 1503 code = k5_alloc_pa_data(KRB5_PADATA_S4U_X509_USER, 1504 req_s4u_user->cksum.length + 1505 rep_s4u_user.cksum.length, &pa); 1506 if (code != 0) 1507 goto cleanup; 1508 memcpy(pa->contents, 1509 req_s4u_user->cksum.contents, req_s4u_user->cksum.length); 1510 memcpy(&pa->contents[req_s4u_user->cksum.length], 1511 rep_s4u_user.cksum.contents, rep_s4u_user.cksum.length); 1512 1513 code = k5_add_pa_data_element(&reply_encpart->enc_padata, &pa); 1514 if (code != 0) 1515 goto cleanup; 1516 } 1517 1518 cleanup: 1519 if (rep_s4u_user.cksum.contents != NULL) 1520 krb5_free_checksum_contents(context, &rep_s4u_user.cksum); 1521 krb5_free_data(context, der_user_id); 1522 krb5_free_data(context, der_s4u_x509_user); 1523 k5_free_pa_data_element(pa); 1524 return code; 1525 } 1526 1527 /* Return true if princ canonicalizes to the same principal as entry's. */ 1528 krb5_boolean 1529 is_client_db_alias(krb5_context context, const krb5_db_entry *entry, 1530 krb5_const_principal princ) 1531 { 1532 krb5_error_code ret; 1533 krb5_db_entry *self; 1534 krb5_boolean is_self = FALSE; 1535 1536 ret = krb5_db_get_principal(context, princ, KRB5_KDB_FLAG_CLIENT, &self); 1537 if (!ret) { 1538 is_self = krb5_principal_compare(context, entry->princ, self->princ); 1539 krb5_db_free_principal(context, self); 1540 } 1541 1542 return is_self; 1543 } 1544 1545 /* 1546 * If S4U2Self padata is present in request, verify the checksum and set 1547 * *s4u_x509_user to the S4U2Self request. If the requested client realm is 1548 * local, look up the client and set *princ_ptr to its DB entry. 1549 */ 1550 krb5_error_code 1551 kdc_process_s4u2self_req(krb5_context context, krb5_kdc_req *request, 1552 const krb5_db_entry *server, 1553 krb5_keyblock *tgs_subkey, krb5_keyblock *tgs_session, 1554 krb5_pa_s4u_x509_user **s4u_x509_user, 1555 krb5_db_entry **princ_ptr, const char **status) 1556 { 1557 krb5_error_code code; 1558 krb5_pa_data *pa_data; 1559 krb5_db_entry *princ; 1560 krb5_s4u_userid *id; 1561 1562 *princ_ptr = NULL; 1563 1564 pa_data = krb5int_find_pa_data(context, request->padata, 1565 KRB5_PADATA_S4U_X509_USER); 1566 if (pa_data != NULL) { 1567 code = kdc_process_s4u_x509_user(context, request, pa_data, tgs_subkey, 1568 tgs_session, s4u_x509_user, status); 1569 if (code != 0) 1570 return code; 1571 } else { 1572 pa_data = krb5int_find_pa_data(context, request->padata, 1573 KRB5_PADATA_FOR_USER); 1574 if (pa_data != NULL) { 1575 code = kdc_process_for_user(context, pa_data, tgs_session, 1576 s4u_x509_user, status); 1577 if (code != 0) 1578 return code; 1579 } else 1580 return 0; 1581 } 1582 id = &(*s4u_x509_user)->user_id; 1583 1584 if (data_eq(server->princ->realm, id->user->realm)) { 1585 if (id->subject_cert.length != 0) { 1586 code = krb5_db_get_s4u_x509_principal(context, 1587 &id->subject_cert, id->user, 1588 KRB5_KDB_FLAG_CLIENT, 1589 &princ); 1590 if (code == 0 && id->user->length == 0) { 1591 krb5_free_principal(context, id->user); 1592 code = krb5_copy_principal(context, princ->princ, &id->user); 1593 } 1594 } else { 1595 code = krb5_db_get_principal(context, id->user, 1596 KRB5_KDB_FLAG_CLIENT, &princ); 1597 } 1598 if (code == KRB5_KDB_NOENTRY) { 1599 *status = "UNKNOWN_S4U2SELF_PRINCIPAL"; 1600 return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; 1601 } else if (code) { 1602 *status = "LOOKING_UP_S4U2SELF_PRINCIPAL"; 1603 return code; /* caller can free for_user */ 1604 } 1605 1606 /* Ignore password expiration and needchange attributes (as Windows 1607 * does), since S4U2Self is not password authentication. */ 1608 princ->pw_expiration = 0; 1609 clear(princ->attributes, KRB5_KDB_REQUIRES_PWCHANGE); 1610 1611 *princ_ptr = princ; 1612 } 1613 1614 return 0; 1615 } 1616 1617 /* Clear the forwardable flag in tkt if server cannot obtain forwardable 1618 * S4U2Self tickets according to [MS-SFU] 3.2.5.1.2. */ 1619 krb5_error_code 1620 s4u2self_forwardable(krb5_context context, krb5_db_entry *server, 1621 krb5_flags *tktflags) 1622 { 1623 krb5_error_code ret; 1624 1625 /* Allow the forwardable flag if server has ok-to-auth-as-delegate set. */ 1626 if (server->attributes & KRB5_KDB_OK_TO_AUTH_AS_DELEGATE) 1627 return 0; 1628 1629 /* Deny the forwardable flag if server has any authorized delegation 1630 * targets for traditional S4U2Proxy. */ 1631 ret = krb5_db_check_allowed_to_delegate(context, NULL, server, NULL); 1632 if (!ret) 1633 *tktflags &= ~TKT_FLG_FORWARDABLE; 1634 1635 if (ret == KRB5KDC_ERR_BADOPTION || ret == KRB5_PLUGIN_OP_NOTSUPP) 1636 return 0; 1637 return ret; 1638 } 1639 1640 krb5_error_code 1641 kdc_check_transited_list(krb5_context context, const krb5_data *trans, 1642 const krb5_data *realm1, const krb5_data *realm2) 1643 { 1644 krb5_error_code code; 1645 1646 /* Check against the KDB module. Treat this answer as authoritative if the 1647 * method is supported and doesn't explicitly pass control. */ 1648 code = krb5_db_check_transited_realms(context, trans, realm1, realm2); 1649 if (code != KRB5_PLUGIN_OP_NOTSUPP && code != KRB5_PLUGIN_NO_HANDLE) 1650 return code; 1651 1652 /* Check using krb5.conf [capaths] or hierarchical relationships. */ 1653 return krb5_check_transited_list(context, trans, realm1, realm2); 1654 } 1655 1656 krb5_boolean 1657 enctype_requires_etype_info_2(krb5_enctype enctype) 1658 { 1659 switch(enctype) { 1660 case ENCTYPE_DES3_CBC_SHA1: 1661 case ENCTYPE_DES3_CBC_RAW: 1662 case ENCTYPE_ARCFOUR_HMAC: 1663 case ENCTYPE_ARCFOUR_HMAC_EXP : 1664 return 0; 1665 default: 1666 return krb5_c_valid_enctype(enctype); 1667 } 1668 } 1669 1670 void 1671 kdc_get_ticket_endtime(kdc_realm_t *realm, krb5_timestamp starttime, 1672 krb5_timestamp endtime, krb5_timestamp till, 1673 krb5_db_entry *client, krb5_db_entry *server, 1674 krb5_timestamp *out_endtime) 1675 { 1676 krb5_timestamp until; 1677 krb5_deltat life; 1678 1679 if (till == 0) 1680 till = kdc_infinity; 1681 1682 until = ts_min(till, endtime); 1683 1684 /* Determine the requested lifetime, capped at the maximum valid time 1685 * interval. */ 1686 life = ts_delta(until, starttime); 1687 if (ts_after(until, starttime) && life < 0) 1688 life = INT32_MAX; 1689 1690 if (client != NULL && client->max_life != 0) 1691 life = min(life, client->max_life); 1692 if (server->max_life != 0) 1693 life = min(life, server->max_life); 1694 if (realm->realm_maxlife != 0) 1695 life = min(life, realm->realm_maxlife); 1696 1697 *out_endtime = ts_incr(starttime, life); 1698 } 1699 1700 /* 1701 * Set times->renew_till to the requested renewable lifetime as modified by 1702 * policy. Set the TKT_FLG_RENEWABLE bit in *tktflags if we set a nonzero 1703 * renew_till. *times must be filled in except for renew_till. client and tgt 1704 * may be NULL. 1705 */ 1706 void 1707 kdc_get_ticket_renewtime(kdc_realm_t *realm, krb5_kdc_req *request, 1708 krb5_enc_tkt_part *tgt, krb5_db_entry *client, 1709 krb5_db_entry *server, krb5_flags *tktflags, 1710 krb5_ticket_times *times) 1711 { 1712 krb5_timestamp rtime, max_rlife; 1713 1714 *tktflags &= ~TKT_FLG_RENEWABLE; 1715 times->renew_till = 0; 1716 1717 /* Don't issue renewable tickets if the client or server don't allow it, 1718 * or if this is a TGS request and the TGT isn't renewable. */ 1719 if (server->attributes & KRB5_KDB_DISALLOW_RENEWABLE) 1720 return; 1721 if (client != NULL && (client->attributes & KRB5_KDB_DISALLOW_RENEWABLE)) 1722 return; 1723 if (tgt != NULL && !(tgt->flags & TKT_FLG_RENEWABLE)) 1724 return; 1725 1726 /* Determine the requested renewable time. */ 1727 if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) 1728 rtime = request->rtime ? request->rtime : kdc_infinity; 1729 else if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) && 1730 ts_after(request->till, times->endtime)) 1731 rtime = request->till; 1732 else 1733 return; 1734 1735 /* Truncate it to the allowable renewable time. */ 1736 if (tgt != NULL) 1737 rtime = ts_min(rtime, tgt->times.renew_till); 1738 max_rlife = min(server->max_renewable_life, realm->realm_maxrlife); 1739 if (client != NULL) 1740 max_rlife = min(max_rlife, client->max_renewable_life); 1741 rtime = ts_min(rtime, ts_incr(times->starttime, max_rlife)); 1742 1743 /* If the client only specified renewable-ok, don't issue a renewable 1744 * ticket unless the truncated renew time exceeds the ticket end time. */ 1745 if (!isflagset(request->kdc_options, KDC_OPT_RENEWABLE) && 1746 !ts_after(rtime, times->endtime)) 1747 return; 1748 1749 *tktflags |= TKT_FLG_RENEWABLE; 1750 times->renew_till = rtime; 1751 } 1752 1753 /** 1754 * Handle protected negotiation of FAST using enc_padata 1755 * - If ENCPADATA_REQ_ENC_PA_REP is present, then: 1756 * - Return ENCPADATA_REQ_ENC_PA_REP with checksum of AS-REQ from client 1757 * - Include PADATA_FX_FAST in the enc_padata to indicate FAST 1758 * @pre @c out_enc_padata has space for at least two more padata 1759 * @param index in/out index into @c out_enc_padata for next item 1760 */ 1761 krb5_error_code 1762 kdc_handle_protected_negotiation(krb5_context context, 1763 krb5_data *req_pkt, krb5_kdc_req *request, 1764 const krb5_keyblock *reply_key, 1765 krb5_pa_data ***out_enc_padata) 1766 { 1767 krb5_error_code retval = 0; 1768 krb5_checksum checksum; 1769 krb5_data *der_cksum = NULL; 1770 krb5_pa_data *pa_in; 1771 1772 memset(&checksum, 0, sizeof(checksum)); 1773 1774 pa_in = krb5int_find_pa_data(context, request->padata, 1775 KRB5_ENCPADATA_REQ_ENC_PA_REP); 1776 if (pa_in == NULL) 1777 return 0; 1778 1779 /* Compute and encode a checksum over the AS-REQ. */ 1780 retval = krb5_c_make_checksum(context, 0, reply_key, KRB5_KEYUSAGE_AS_REQ, 1781 req_pkt, &checksum); 1782 if (retval != 0) 1783 goto cleanup; 1784 retval = encode_krb5_checksum(&checksum, &der_cksum); 1785 if (retval != 0) 1786 goto cleanup; 1787 1788 retval = k5_add_pa_data_from_data(out_enc_padata, 1789 KRB5_ENCPADATA_REQ_ENC_PA_REP, 1790 der_cksum); 1791 if (retval) 1792 goto cleanup; 1793 1794 /* Add a zero-length PA-FX-FAST element to the list. */ 1795 retval = k5_add_empty_pa_data(out_enc_padata, KRB5_PADATA_FX_FAST); 1796 1797 cleanup: 1798 krb5_free_checksum_contents(context, &checksum); 1799 krb5_free_data(context, der_cksum); 1800 return retval; 1801 } 1802 1803 krb5_error_code 1804 kdc_get_pa_pac_options(krb5_context context, krb5_pa_data **in_padata, 1805 krb5_pa_pac_options **pac_options_out) 1806 { 1807 krb5_pa_data *pa; 1808 krb5_data der_pac_options; 1809 1810 *pac_options_out = NULL; 1811 1812 pa = krb5int_find_pa_data(context, in_padata, KRB5_PADATA_PAC_OPTIONS); 1813 if (pa == NULL) 1814 return 0; 1815 1816 der_pac_options = make_data(pa->contents, pa->length); 1817 return decode_krb5_pa_pac_options(&der_pac_options, pac_options_out); 1818 } 1819 1820 krb5_error_code 1821 kdc_add_pa_pac_options(krb5_context context, krb5_kdc_req *request, 1822 krb5_pa_data ***out_enc_padata) 1823 { 1824 krb5_error_code ret; 1825 krb5_pa_pac_options *pac_options = NULL; 1826 krb5_data *der_pac_options; 1827 1828 ret = kdc_get_pa_pac_options(context, request->padata, &pac_options); 1829 if (ret || pac_options == NULL) 1830 return ret; 1831 1832 /* Only return supported PAC options (currently only resource-based 1833 * constrained delegation support). */ 1834 pac_options->options &= KRB5_PA_PAC_OPTIONS_RBCD; 1835 if (pac_options->options == 0) { 1836 free(pac_options); 1837 return 0; 1838 } 1839 1840 ret = encode_krb5_pa_pac_options(pac_options, &der_pac_options); 1841 free(pac_options); 1842 if (ret) 1843 return ret; 1844 1845 ret = k5_add_pa_data_from_data(out_enc_padata, KRB5_PADATA_PAC_OPTIONS, 1846 der_pac_options); 1847 krb5_free_data(context, der_pac_options); 1848 return ret; 1849 } 1850 1851 krb5_error_code 1852 kdc_get_pa_pac_rbcd(krb5_context context, krb5_pa_data **in_padata, 1853 krb5_boolean *supported) 1854 { 1855 krb5_error_code retval; 1856 krb5_pa_pac_options *pac_options = NULL; 1857 1858 *supported = FALSE; 1859 1860 retval = kdc_get_pa_pac_options(context, in_padata, &pac_options); 1861 if (retval || !pac_options) 1862 return retval; 1863 1864 if (pac_options->options & KRB5_PA_PAC_OPTIONS_RBCD) 1865 *supported = TRUE; 1866 1867 free(pac_options); 1868 return 0; 1869 } 1870 1871 /* 1872 * Although the KDC doesn't call this function directly, 1873 * process_tcp_connection_read() in net-server.c does call it. 1874 */ 1875 krb5_error_code 1876 make_toolong_error (void *handle, krb5_data **out) 1877 { 1878 krb5_error errpkt; 1879 krb5_error_code retval; 1880 krb5_data *scratch; 1881 struct server_handle *h = handle; 1882 1883 retval = krb5_us_timeofday(h->kdc_err_context, 1884 &errpkt.stime, &errpkt.susec); 1885 if (retval) 1886 return retval; 1887 errpkt.error = KRB_ERR_FIELD_TOOLONG; 1888 errpkt.server = h->kdc_realmlist[0]->realm_tgsprinc; 1889 errpkt.client = NULL; 1890 errpkt.cusec = 0; 1891 errpkt.ctime = 0; 1892 errpkt.text.length = 0; 1893 errpkt.text.data = 0; 1894 errpkt.e_data.length = 0; 1895 errpkt.e_data.data = 0; 1896 scratch = malloc(sizeof(*scratch)); 1897 if (scratch == NULL) 1898 return ENOMEM; 1899 retval = krb5_mk_error(h->kdc_err_context, &errpkt, scratch); 1900 if (retval) { 1901 free(scratch); 1902 return retval; 1903 } 1904 1905 *out = scratch; 1906 return 0; 1907 } 1908 1909 void reset_for_hangup(void *ctx) 1910 { 1911 int k; 1912 struct server_handle *h = ctx; 1913 1914 for (k = 0; k < h->kdc_numrealms; k++) 1915 krb5_db_refresh_config(h->kdc_realmlist[k]->realm_context); 1916 } 1917