1 /* 2 * kdc/kdc_util.c 3 * 4 * Copyright 1990,1991 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 * Utility functions for the KDC implementation. 28 */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include "k5-int.h" 34 #include "kdc_util.h" 35 #include "extern.h" 36 #include <stdio.h> 37 #include <syslog.h> 38 #include "adm.h" 39 #include "adm_proto.h" 40 41 #ifdef USE_RCACHE 42 static char *kdc_current_rcname = (char *) NULL; 43 krb5_deltat rc_lifetime; /* See kdc_initialize_rcache() */ 44 #endif 45 46 #ifdef USE_RCACHE 47 /* 48 * initialize the replay cache. 49 */ 50 krb5_error_code 51 kdc_initialize_rcache(kcontext, rcache_name) 52 krb5_context kcontext; 53 char *rcache_name; 54 { 55 krb5_error_code retval; 56 char *rcname; 57 char *sname; 58 59 rcname = (rcache_name) ? rcache_name : kdc_current_rcname; 60 61 /* rc_lifetime used elsewhere to verify we're not */ 62 /* replaying really old data */ 63 rc_lifetime = kcontext->clockskew; 64 65 if (!rcname) 66 rcname = KDCRCACHE; 67 if (!(retval = krb5_rc_resolve_full(kcontext, &kdc_rcache, rcname))) { 68 /* Recover or initialize the replay cache */ 69 if (!(retval = krb5_rc_recover(kcontext, kdc_rcache)) || 70 !(retval = krb5_rc_initialize(kcontext, 71 kdc_rcache, 72 kcontext->clockskew)) 73 ) { 74 /* Expunge the replay cache */ 75 if (!(retval = krb5_rc_expunge(kcontext, kdc_rcache))) { 76 sname = kdc_current_rcname; 77 kdc_current_rcname = strdup(rcname); 78 if (sname) 79 free(sname); 80 } 81 } 82 if (retval) 83 krb5_rc_close(kcontext, kdc_rcache); 84 } 85 return(retval); 86 } 87 #endif 88 89 /* 90 * concatenate first two authdata arrays, returning an allocated replacement. 91 * The replacement should be freed with krb5_free_authdata(). 92 */ 93 krb5_error_code 94 concat_authorization_data(first, second, output) 95 krb5_authdata **first; 96 krb5_authdata **second; 97 krb5_authdata ***output; 98 { 99 register int i, j; 100 register krb5_authdata **ptr, **retdata; 101 102 /* count up the entries */ 103 i = 0; 104 if (first) 105 for (ptr = first; *ptr; ptr++) 106 i++; 107 if (second) 108 for (ptr = second; *ptr; ptr++) 109 i++; 110 111 retdata = (krb5_authdata **)malloc((i+1)*sizeof(*retdata)); 112 if (!retdata) 113 return ENOMEM; 114 retdata[i] = 0; /* null-terminated array */ 115 for (i = 0, j = 0, ptr = first; j < 2 ; ptr = second, j++) 116 while (ptr && *ptr) { 117 /* now walk & copy */ 118 retdata[i] = (krb5_authdata *)malloc(sizeof(*retdata[i])); 119 if (!retdata[i]) { 120 krb5_free_authdata(kdc_context, retdata); 121 return ENOMEM; 122 } 123 *retdata[i] = **ptr; 124 if (!(retdata[i]->contents = 125 (krb5_octet *)malloc(retdata[i]->length))) { 126 free((char *)retdata[i]); 127 retdata[i] = 0; 128 krb5_free_authdata(kdc_context, retdata); 129 return ENOMEM; 130 } 131 memcpy((char *) retdata[i]->contents, 132 (char *)(*ptr)->contents, 133 retdata[i]->length); 134 135 ptr++; 136 i++; 137 } 138 *output = retdata; 139 return 0; 140 } 141 142 krb5_boolean 143 realm_compare(princ1, princ2) 144 krb5_principal princ1; 145 krb5_principal princ2; 146 { 147 krb5_data *realm1 = krb5_princ_realm(kdc_context, princ1); 148 krb5_data *realm2 = krb5_princ_realm(kdc_context, princ2); 149 150 return((realm1->length == realm2->length) && 151 !memcmp(realm1->data, realm2->data, realm1->length)); 152 } 153 154 /* 155 * Returns TRUE if the kerberos principal is the name of a Kerberos ticket 156 * service. 157 */ 158 krb5_boolean krb5_is_tgs_principal(principal) 159 krb5_principal principal; 160 { 161 162 if (krb5_princ_size(kdc_context, principal) > 0 && 163 (krb5_princ_component(kdc_context, principal, 0)->length == 164 KRB5_TGS_NAME_SIZE) && 165 (!memcmp(krb5_princ_component(kdc_context, principal, 0)->data, 166 KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE))) 167 return TRUE; 168 return FALSE; 169 } 170 171 /* 172 * given authentication data (provides seed for checksum), verify checksum 173 * for source data. 174 */ 175 static krb5_error_code 176 comp_cksum(kcontext, source, ticket, his_cksum) 177 krb5_context kcontext; 178 krb5_data * source; 179 krb5_ticket * ticket; 180 krb5_checksum * his_cksum; 181 { 182 krb5_error_code retval; 183 krb5_boolean valid; 184 185 if (!krb5_c_valid_cksumtype(his_cksum->checksum_type)) 186 return KRB5KDC_ERR_SUMTYPE_NOSUPP; 187 188 /* must be collision proof */ 189 if (!krb5_c_is_coll_proof_cksum(his_cksum->checksum_type)) 190 return KRB5KRB_AP_ERR_INAPP_CKSUM; 191 192 /* verify checksum */ 193 if ((retval = krb5_c_verify_checksum(kcontext, ticket->enc_part2->session, 194 KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, 195 source, his_cksum, &valid))) 196 return(retval); 197 198 if (!valid) 199 return(KRB5KRB_AP_ERR_BAD_INTEGRITY); 200 201 return(0); 202 } 203 204 krb5_error_code 205 kdc_process_tgs_req(request, from, pkt, ticket, subkey) 206 krb5_kdc_req * request; 207 const krb5_fulladdr * from; 208 krb5_data * pkt; 209 krb5_ticket ** ticket; 210 krb5_keyblock ** subkey; 211 { 212 krb5_pa_data ** tmppa; 213 krb5_ap_req * apreq; 214 krb5_error_code retval; 215 krb5_data scratch1; 216 krb5_data * scratch = NULL; 217 krb5_boolean foreign_server = FALSE; 218 krb5_auth_context auth_context = NULL; 219 krb5_authenticator * authenticator = NULL; 220 krb5_checksum * his_cksum = NULL; 221 krb5_keyblock * key = NULL; 222 krb5_kvno kvno = 0; 223 224 if (!request->padata) 225 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 226 for (tmppa = request->padata; *tmppa; tmppa++) { 227 if ((*tmppa)->pa_type == KRB5_PADATA_AP_REQ) 228 break; 229 } 230 if (!*tmppa) /* cannot find any AP_REQ */ 231 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 232 233 scratch1.length = (*tmppa)->length; 234 scratch1.data = (char *)(*tmppa)->contents; 235 if ((retval = decode_krb5_ap_req(&scratch1, &apreq))) 236 return retval; 237 238 if (isflagset(apreq->ap_options, AP_OPTS_USE_SESSION_KEY) || 239 isflagset(apreq->ap_options, AP_OPTS_MUTUAL_REQUIRED)) { 240 krb5_klog_syslog(LOG_INFO, "TGS_REQ: SESSION KEY or MUTUAL"); 241 retval = KRB5KDC_ERR_POLICY; 242 goto cleanup; 243 } 244 245 /* If the "server" principal in the ticket is not something 246 in the local realm, then we must refuse to service the request 247 if the client claims to be from the local realm. 248 249 If we don't do this, then some other realm's nasty KDC can 250 claim to be authenticating a client from our realm, and we'll 251 give out tickets concurring with it! 252 253 we set a flag here for checking below. 254 */ 255 if ((krb5_princ_realm(kdc_context, apreq->ticket->server)->length != 256 krb5_princ_realm(kdc_context, tgs_server)->length) || 257 memcmp(krb5_princ_realm(kdc_context, apreq->ticket->server)->data, 258 krb5_princ_realm(kdc_context, tgs_server)->data, 259 krb5_princ_realm(kdc_context, tgs_server)->length)) 260 foreign_server = TRUE; 261 262 if ((retval = krb5_auth_con_init(kdc_context, &auth_context))) 263 goto cleanup; 264 265 if ((retval = krb5_auth_con_setaddrs(kdc_context, auth_context, NULL, 266 from->address)) ) 267 goto cleanup_auth_context; 268 #ifdef USE_RCACHE 269 if ((retval = krb5_auth_con_setrcache(kdc_context, auth_context, 270 kdc_rcache))) 271 goto cleanup_auth_context; 272 #endif 273 274 /* 275 if ((retval = kdc_get_server_key(apreq->ticket, &key, &kvno))) 276 goto cleanup_auth_context; 277 */ 278 279 /* 280 * XXX This is currently wrong but to fix it will require making a 281 * new keytab for groveling over the kdb. 282 */ 283 /* 284 retval = krb5_auth_con_setuseruserkey(kdc_context, auth_context, key); 285 krb5_free_keyblock(kdc_context, key); 286 if (retval) 287 goto cleanup_auth_context; 288 */ 289 290 if ((retval = krb5_rd_req_decoded_anyflag(kdc_context, &auth_context, apreq, 291 apreq->ticket->server, 292 kdc_active_realm->realm_keytab, 293 NULL, ticket))) { 294 #ifdef USE_RCACHE 295 /* 296 * I'm not so sure that this is right, but it's better than nothing 297 * at all. 298 * 299 * If we choke in the rd_req because of the replay cache, then attempt 300 * to reinitialize the replay cache because somebody could have deleted 301 * it from underneath us (e.g. a cron job) 302 */ 303 if ((retval == KRB5_RC_IO_IO) || 304 (retval == KRB5_RC_IO_UNKNOWN)) { 305 (void) krb5_rc_close(kdc_context, kdc_rcache); 306 kdc_rcache = (krb5_rcache) NULL; 307 if (!(retval = kdc_initialize_rcache(kdc_context, (char *) NULL))) { 308 if ((retval = krb5_auth_con_setrcache(kdc_context, auth_context, 309 kdc_rcache)) || 310 (retval = krb5_rd_req_decoded_anyflag(kdc_context, &auth_context, 311 apreq, apreq->ticket->server, 312 kdc_active_realm->realm_keytab, 313 NULL, ticket)) 314 ) 315 goto cleanup_auth_context; 316 } 317 } else 318 goto cleanup_auth_context; 319 #else 320 goto cleanup_auth_context; 321 #endif 322 } 323 324 /* "invalid flag" tickets can must be used to validate */ 325 if (isflagset((*ticket)->enc_part2->flags, TKT_FLG_INVALID) 326 && !isflagset(request->kdc_options, KDC_OPT_VALIDATE)) { 327 retval = KRB5KRB_AP_ERR_TKT_INVALID; 328 goto cleanup_auth_context; 329 } 330 331 if ((retval = krb5_auth_con_getremotesubkey(kdc_context, 332 auth_context, subkey))) 333 goto cleanup_auth_context; 334 335 if ((retval = krb5_auth_con_getauthenticator(kdc_context, auth_context, 336 &authenticator))) 337 goto cleanup_auth_context; 338 339 /* Check for a checksum */ 340 if (!(his_cksum = authenticator->checksum)) { 341 retval = KRB5KRB_AP_ERR_INAPP_CKSUM; 342 goto cleanup_authenticator; 343 } 344 345 /* make sure the client is of proper lineage (see above) */ 346 if (foreign_server) { 347 krb5_data *tkt_realm = krb5_princ_realm(kdc_context, 348 (*ticket)->enc_part2->client); 349 krb5_data *tgs_realm = krb5_princ_realm(kdc_context, tgs_server); 350 if (tkt_realm->length == tgs_realm->length && 351 !memcmp(tkt_realm->data, tgs_realm->data, tgs_realm->length)) { 352 /* someone in a foreign realm claiming to be local */ 353 krb5_klog_syslog(LOG_INFO, "PROCESS_TGS: failed lineage check"); 354 retval = KRB5KDC_ERR_POLICY; 355 goto cleanup_authenticator; 356 } 357 } 358 359 /* 360 * Check application checksum vs. tgs request 361 * 362 * We try checksumming the req-body two different ways: first we 363 * try reaching into the raw asn.1 stream (if available), and 364 * checksum that directly; if that fails, then we try encoding 365 * using our local asn.1 library. 366 */ 367 if (pkt && (fetch_asn1_field((unsigned char *) pkt->data, 368 1, 4, &scratch1) >= 0)) { 369 if (comp_cksum(kdc_context, &scratch1, *ticket, his_cksum)) { 370 if (!(retval = encode_krb5_kdc_req_body(request, &scratch))) 371 retval = comp_cksum(kdc_context, scratch, *ticket, his_cksum); 372 krb5_free_data(kdc_context, scratch); 373 } 374 } 375 376 cleanup_authenticator: 377 krb5_free_authenticator(kdc_context, authenticator); 378 379 cleanup_auth_context: 380 /* We do not want the free of the auth_context to close the rcache */ 381 #ifdef USE_RCACHE 382 (void) krb5_auth_con_setrcache(kdc_context, auth_context, 0); 383 #endif 384 krb5_auth_con_free(kdc_context, auth_context); 385 386 cleanup: 387 krb5_free_ap_req(kdc_context, apreq); 388 return retval; 389 } 390 391 /* XXX This function should no longer be necessary. 392 * The KDC should take the keytab associated with the realm and pass that to 393 * the krb5_rd_req_decode(). --proven 394 * 395 * It's actually still used by do_tgs_req() for u2u auth, and not too 396 * much else. -- tlyu 397 */ 398 krb5_error_code 399 kdc_get_server_key(ticket, key, kvno) 400 krb5_ticket * ticket; 401 krb5_keyblock ** key; 402 krb5_kvno * kvno; /* XXX nothing uses this */ 403 { 404 krb5_error_code retval; 405 krb5_db_entry server; 406 krb5_boolean more; 407 int nprincs; 408 krb5_key_data * server_key; 409 int i; 410 411 nprincs = 1; 412 413 if ((retval = krb5_db_get_principal(kdc_context, ticket->server, 414 &server, &nprincs, 415 &more))) { 416 return(retval); 417 } 418 if (more) { 419 krb5_db_free_principal(kdc_context, &server, nprincs); 420 return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE); 421 } else if (nprincs != 1) { 422 char *sname; 423 424 krb5_db_free_principal(kdc_context, &server, nprincs); 425 if (!krb5_unparse_name(kdc_context, ticket->server, &sname)) { 426 krb5_klog_syslog(LOG_ERR,"TGS_REQ: UNKNOWN SERVER: server='%s'", 427 sname); 428 free(sname); 429 } 430 return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN); 431 } 432 retval = krb5_dbe_find_enctype(kdc_context, &server, 433 ticket->enc_part.enctype, -1, 434 ticket->enc_part.kvno, &server_key); 435 if (retval) 436 goto errout; 437 if (!server_key) { 438 retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 439 goto errout; 440 } 441 *kvno = server_key->key_data_kvno; 442 if ((*key = (krb5_keyblock *)malloc(sizeof **key))) { 443 retval = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock, 444 server_key, 445 *key, NULL); 446 } else 447 retval = ENOMEM; 448 errout: 449 krb5_db_free_principal(kdc_context, &server, nprincs); 450 return retval; 451 } 452 453 /* This probably wants to be updated if you support last_req stuff */ 454 455 static krb5_last_req_entry nolrentry = { KV5M_LAST_REQ_ENTRY, KRB5_LRQ_NONE, 0 }; 456 static krb5_last_req_entry *nolrarray[] = { &nolrentry, 0 }; 457 458 krb5_error_code 459 fetch_last_req_info(dbentry, lrentry) 460 krb5_db_entry *dbentry; 461 krb5_last_req_entry ***lrentry; 462 { 463 *lrentry = nolrarray; 464 return 0; 465 } 466 467 468 /* XXX! This is a temporary place-holder */ 469 470 krb5_error_code 471 check_hot_list(ticket) 472 krb5_ticket *ticket; 473 { 474 return 0; 475 } 476 477 478 #define MAX_REALM_LN 500 479 480 481 /* 482 * subrealm - determine if r2 is a subrealm of r1 483 * 484 * SUBREALM takes two realms, r1 and r2, and 485 * determines if r2 is a subrealm of r1. 486 * r2 is a subrealm of r1 if (r1 is a prefix 487 * of r2 AND r1 and r2 begin with a /) or if 488 * (r1 is a suffix of r2 and neither r1 nor r2 489 * begin with a /). 490 * 491 * RETURNS: If r2 is a subrealm, and r1 is a prefix, the number 492 * of characters in the suffix of r2 is returned as a 493 * negative number. 494 * 495 * If r2 is a subrealm, and r1 is a suffix, the number 496 * of characters in the prefix of r2 is returned as a 497 * positive number. 498 * 499 * If r2 is not a subrealm, SUBREALM returns 0. 500 */ 501 static int 502 subrealm(r1,r2) 503 char *r1; 504 char *r2; 505 { 506 int l1,l2; 507 l1 = strlen(r1); 508 l2 = strlen(r2); 509 if(l2 <= l1) return(0); 510 if((*r1 == '/') && (*r2 == '/') && (strncmp(r1,r2,l1) == 0)) return(l1-l2); 511 if((*r1 != '/') && (*r2 != '/') && (strncmp(r1,r2+l2-l1,l1) == 0)) 512 return(l2-l1); 513 return(0); 514 } 515 516 /* 517 * add_to_transited Adds the name of the realm which issued the 518 * ticket granting ticket on which the new ticket to 519 * be issued is based (note that this is the same as 520 * the realm of the server listed in the ticket 521 * granting ticket. 522 * 523 * ASSUMPTIONS: This procedure assumes that the transited field from 524 * the existing ticket granting ticket already appears 525 * in compressed form. It will add the new realm while 526 * maintaining that form. As long as each successive 527 * realm is added using this (or a similar) routine, the 528 * transited field will be in compressed form. The 529 * basis step is an empty transited field which is, by 530 * its nature, in its most compressed form. 531 * 532 * ARGUMENTS: krb5_data *tgt_trans Transited field from TGT 533 * krb5_data *new_trans The transited field for the new ticket 534 * krb5_principal tgs Name of ticket granting server 535 * This includes the realm of the KDC 536 * that issued the ticket granting 537 * ticket. This is the realm that is 538 * to be added to the transited field. 539 * krb5_principal client Name of the client 540 * krb5_principal server The name of the requested server. 541 * This may be the an intermediate 542 * ticket granting server. 543 * 544 * The last two argument are needed since they are 545 * implicitly part of the transited field of the new ticket 546 * even though they are not explicitly listed. 547 * 548 * RETURNS: krb5_error_code - Success, or out of memory 549 * 550 * MODIFIES: new_trans: ->length will contain the length of the new 551 * transited field. 552 * 553 * If ->data was not null when this procedure 554 * is called, the memory referenced by ->data 555 * will be deallocated. 556 * 557 * Memory will be allocated for the new transited field 558 * ->data will be updated to point to the newly 559 * allocated memory. 560 * 561 * BUGS: The space allocated for the new transited field is the 562 * maximum that might be needed given the old transited field, 563 * and the realm to be added. This length is calculated 564 * assuming that no compression of the new realm is possible. 565 * This has no adverse consequences other than the allocation 566 * of more space than required. 567 * 568 * This procedure will not yet use the null subfield notation, 569 * and it will get confused if it sees it. 570 * 571 * This procedure does not check for quoted commas in realm 572 * names. 573 */ 574 575 krb5_error_code 576 add_to_transited(tgt_trans, new_trans, tgs, client, server) 577 krb5_data * tgt_trans; 578 krb5_data * new_trans; 579 krb5_principal tgs; 580 krb5_principal client; 581 krb5_principal server; 582 { 583 krb5_error_code retval; 584 char *realm; 585 char *trans; 586 char *otrans, *otrans_ptr; 587 588 /* The following are for stepping through the transited field */ 589 590 char prev[MAX_REALM_LN]; 591 char next[MAX_REALM_LN]; 592 char current[MAX_REALM_LN]; 593 char exp[MAX_REALM_LN]; /* Expanded current realm name */ 594 595 int i; 596 int clst, nlst; /* count of last character in current and next */ 597 int pl, pl1; /* prefix length */ 598 int added; /* TRUE = new realm has been added */ 599 600 if (!(realm = (char *) malloc(krb5_princ_realm(kdc_context, tgs)->length+1))) { 601 return(ENOMEM); 602 } 603 memcpy(realm, krb5_princ_realm(kdc_context, tgs)->data, 604 krb5_princ_realm(kdc_context, tgs)->length); 605 realm[krb5_princ_realm(kdc_context, tgs)->length] = '\0'; 606 607 if (!(otrans = (char *) malloc(tgt_trans->length+1))) { 608 free(realm); 609 return(ENOMEM); 610 } 611 memcpy(otrans, tgt_trans->data, tgt_trans->length); 612 otrans[tgt_trans->length] = '\0'; 613 /* Keep track of start so we can free */ 614 otrans_ptr = otrans; 615 616 /* +1 for null, 617 +1 for extra comma which may be added between 618 +1 for potential space when leading slash in realm */ 619 if (!(trans = (char *) malloc(strlen(realm) + strlen(otrans) + 3))) { 620 retval = ENOMEM; 621 goto fail; 622 } 623 624 if (new_trans->data) free(new_trans->data); 625 new_trans->data = trans; 626 new_trans->length = 0; 627 628 trans[0] = '\0'; 629 630 /* For the purpose of appending, the realm preceding the first */ 631 /* realm in the transited field is considered the null realm */ 632 633 prev[0] = '\0'; 634 635 /* read field into current */ 636 for (i = 0; *otrans != '\0';) { 637 if (*otrans == '\\') 638 if (*(++otrans) == '\0') 639 break; 640 else 641 continue; 642 if (*otrans == ',') { 643 otrans++; 644 break; 645 } 646 current[i++] = *otrans++; 647 if (i >= MAX_REALM_LN) { 648 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 649 goto fail; 650 } 651 } 652 current[i] = '\0'; 653 654 added = (krb5_princ_realm(kdc_context, client)->length == strlen(realm) && 655 !strncmp(krb5_princ_realm(kdc_context, client)->data, realm, strlen(realm))) || 656 (krb5_princ_realm(kdc_context, server)->length == strlen(realm) && 657 !strncmp(krb5_princ_realm(kdc_context, server)->data, realm, strlen(realm))); 658 659 while (current[0]) { 660 661 /* figure out expanded form of current name */ 662 663 clst = strlen(current) - 1; 664 if (current[0] == ' ') { 665 strncpy(exp, current+1, sizeof(exp) - 1); 666 exp[sizeof(exp) - 1] = '\0'; 667 } 668 else if ((current[0] == '/') && (prev[0] == '/')) { 669 strncpy(exp, prev, sizeof(exp) - 1); 670 exp[sizeof(exp) - 1] = '\0'; 671 if (strlen(exp) + strlen(current) + 1 >= MAX_REALM_LN) { 672 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 673 goto fail; 674 } 675 strncat(exp, current, sizeof(exp) - 1 - strlen(exp)); 676 } 677 else if (current[clst] == '.') { 678 strncpy(exp, current, sizeof(exp) - 1); 679 exp[sizeof(exp) - 1] = '\0'; 680 if (strlen(exp) + strlen(prev) + 1 >= MAX_REALM_LN) { 681 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 682 goto fail; 683 } 684 strncat(exp, prev, sizeof(exp) - 1 - strlen(exp)); 685 } 686 else { 687 strncpy(exp, current, sizeof(exp) - 1); 688 exp[sizeof(exp) - 1] = '\0'; 689 } 690 691 /* read field into next */ 692 for (i = 0; *otrans != '\0';) { 693 if (*otrans == '\\') 694 if (*(++otrans) == '\0') 695 break; 696 else 697 continue; 698 if (*otrans == ',') { 699 otrans++; 700 break; 701 } 702 next[i++] = *otrans++; 703 if (i >= MAX_REALM_LN) { 704 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 705 goto fail; 706 } 707 } 708 next[i] = '\0'; 709 nlst = i - 1; 710 711 if (!strcmp(exp, realm)) added = TRUE; 712 713 /* If we still have to insert the new realm */ 714 715 if (!added) { 716 717 /* Is the next field compressed? If not, and if the new */ 718 /* realm is a subrealm of the current realm, compress */ 719 /* the new realm, and insert immediately following the */ 720 /* current one. Note that we can not do this if the next*/ 721 /* field is already compressed since it would mess up */ 722 /* what has already been done. In most cases, this is */ 723 /* not a problem because the realm to be added will be a */ 724 /* subrealm of the next field too, and we will catch */ 725 /* it in a future iteration. */ 726 727 if ((next[nlst] != '.') && (next[0] != '/') && 728 (pl = subrealm(exp, realm))) { 729 added = TRUE; 730 current[sizeof(current) - 1] = '\0'; 731 if (strlen(current) + (pl>0?pl:-pl) + 2 >= MAX_REALM_LN) { 732 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 733 goto fail; 734 } 735 strncat(current, ",", sizeof(current) - 1 - strlen(current)); 736 if (pl > 0) { 737 strncat(current, realm, pl); 738 } 739 else { 740 strncat(current, realm+strlen(realm)+pl, -pl); 741 } 742 } 743 744 /* Whether or not the next field is compressed, if the */ 745 /* realm to be added is a superrealm of the current realm,*/ 746 /* then the current realm can be compressed. First the */ 747 /* realm to be added must be compressed relative to the */ 748 /* previous realm (if possible), and then the current */ 749 /* realm compressed relative to the new realm. Note that */ 750 /* if the realm to be added is also a superrealm of the */ 751 /* previous realm, it would have been added earlier, and */ 752 /* we would not reach this step this time around. */ 753 754 else if ((pl = subrealm(realm, exp))) { 755 added = TRUE; 756 current[0] = '\0'; 757 if ((pl1 = subrealm(prev,realm))) { 758 if (strlen(current) + (pl1>0?pl1:-pl1) + 1 >= MAX_REALM_LN) { 759 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 760 goto fail; 761 } 762 if (pl1 > 0) { 763 strncat(current, realm, pl1); 764 } 765 else { 766 strncat(current, realm+strlen(realm)+pl1, -pl1); 767 } 768 } 769 else { /* If not a subrealm */ 770 if ((realm[0] == '/') && prev[0]) { 771 if (strlen(current) + 2 >= MAX_REALM_LN) { 772 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 773 goto fail; 774 } 775 strncat(current, " ", sizeof(current) - 1 - strlen(current)); 776 current[sizeof(current) - 1] = '\0'; 777 } 778 if (strlen(current) + strlen(realm) + 1 >= MAX_REALM_LN) { 779 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 780 goto fail; 781 } 782 strncat(current, realm, sizeof(current) - 1 - strlen(current)); 783 current[sizeof(current) - 1] = '\0'; 784 } 785 if (strlen(current) + (pl>0?pl:-pl) + 2 >= MAX_REALM_LN) { 786 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 787 goto fail; 788 } 789 strncat(current,",", sizeof(current) - 1 - strlen(current)); 790 current[sizeof(current) - 1] = '\0'; 791 if (pl > 0) { 792 strncat(current, exp, pl); 793 } 794 else { 795 strncat(current, exp+strlen(exp)+pl, -pl); 796 } 797 } 798 } 799 800 if (new_trans->length != 0) { 801 if (strlen(trans) + 2 >= MAX_REALM_LN) { 802 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 803 goto fail; 804 } 805 strcat(trans, ","); 806 } 807 if (strlen(trans) + strlen(current) + 1 >= MAX_REALM_LN) { 808 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 809 goto fail; 810 } 811 strcat(trans, current); 812 new_trans->length = strlen(trans); 813 814 strncpy(prev, exp, sizeof(prev) - 1); 815 prev[sizeof(prev) - 1] = '\0'; 816 strncpy(current, next, sizeof(current) - 1); 817 current[sizeof(current) - 1] = '\0'; 818 } 819 820 if (!added) { 821 if (new_trans->length != 0) { 822 if (strlen(trans) + 2 >= MAX_REALM_LN) { 823 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 824 goto fail; 825 } 826 strcat(trans, ","); 827 } 828 if((realm[0] == '/') && trans[0]) { 829 if (strlen(trans) + 2 >= MAX_REALM_LN) { 830 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 831 goto fail; 832 } 833 strcat(trans, " "); 834 } 835 if (strlen(trans) + strlen(realm) + 1 >= MAX_REALM_LN) { 836 retval = KRB5KRB_AP_ERR_ILL_CR_TKT; 837 goto fail; 838 } 839 strcat(trans, realm); 840 new_trans->length = strlen(trans); 841 } 842 843 retval = 0; 844 fail: 845 free(realm); 846 free(otrans_ptr); 847 return (retval); 848 } 849 850 /* 851 * Routines that validate a AS request; checks a lot of things. :-) 852 * 853 * Returns a Kerberos protocol error number, which is _not_ the same 854 * as a com_err error number! 855 */ 856 #define AS_INVALID_OPTIONS (KDC_OPT_FORWARDED | KDC_OPT_PROXY |\ 857 KDC_OPT_VALIDATE | KDC_OPT_RENEW | KDC_OPT_ENC_TKT_IN_SKEY) 858 859 int 860 validate_as_request(request, client, server, kdc_time, status) 861 register krb5_kdc_req *request; 862 krb5_db_entry client; 863 krb5_db_entry server; 864 krb5_timestamp kdc_time; 865 const char **status; 866 { 867 int errcode; 868 869 /* 870 * If an illegal option is set, complain. 871 */ 872 if (request->kdc_options & AS_INVALID_OPTIONS) { 873 *status = "INVALID AS OPTIONS"; 874 return KDC_ERR_BADOPTION; 875 } 876 877 /* The client's password must not be expired, unless the server is 878 a KRB5_KDC_PWCHANGE_SERVICE. */ 879 if (client.pw_expiration && client.pw_expiration < kdc_time && 880 !isflagset(server.attributes, KRB5_KDB_PWCHANGE_SERVICE)) { 881 *status = "CLIENT KEY EXPIRED"; 882 #ifdef KRBCONF_VAGUE_ERRORS 883 return(KRB_ERR_GENERIC); 884 #else 885 return(KDC_ERR_KEY_EXP); 886 #endif 887 } 888 889 /* The client must not be expired */ 890 if (client.expiration && client.expiration < kdc_time) { 891 *status = "CLIENT EXPIRED"; 892 #ifdef KRBCONF_VAGUE_ERRORS 893 return(KRB_ERR_GENERIC); 894 #else 895 return(KDC_ERR_NAME_EXP); 896 #endif 897 } 898 899 /* The server must not be expired */ 900 if (server.expiration && server.expiration < kdc_time) { 901 *status = "SERVICE EXPIRED"; 902 return(KDC_ERR_SERVICE_EXP); 903 } 904 905 /* 906 * If the client requires password changing, then only allow the 907 * pwchange service. 908 */ 909 if (isflagset(client.attributes, KRB5_KDB_REQUIRES_PWCHANGE) && 910 !isflagset(server.attributes, KRB5_KDB_PWCHANGE_SERVICE)) { 911 *status = "REQUIRED PWCHANGE"; 912 return(KDC_ERR_KEY_EXP); 913 } 914 915 /* Client and server must allow postdating tickets */ 916 if ((isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE) || 917 isflagset(request->kdc_options, KDC_OPT_POSTDATED)) && 918 (isflagset(client.attributes, KRB5_KDB_DISALLOW_POSTDATED) || 919 isflagset(server.attributes, KRB5_KDB_DISALLOW_POSTDATED))) { 920 *status = "POSTDATE NOT ALLOWED"; 921 return(KDC_ERR_CANNOT_POSTDATE); 922 } 923 924 /* Client and server must allow forwardable tickets */ 925 if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE) && 926 (isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE) || 927 isflagset(server.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))) { 928 *status = "FORWARDABLE NOT ALLOWED"; 929 return(KDC_ERR_POLICY); 930 } 931 932 /* Client and server must allow renewable tickets */ 933 if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE) && 934 (isflagset(client.attributes, KRB5_KDB_DISALLOW_RENEWABLE) || 935 isflagset(server.attributes, KRB5_KDB_DISALLOW_RENEWABLE))) { 936 *status = "RENEWABLE NOT ALLOWED"; 937 return(KDC_ERR_POLICY); 938 } 939 940 /* Client and server must allow proxiable tickets */ 941 if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE) && 942 (isflagset(client.attributes, KRB5_KDB_DISALLOW_PROXIABLE) || 943 isflagset(server.attributes, KRB5_KDB_DISALLOW_PROXIABLE))) { 944 *status = "PROXIABLE NOT ALLOWED"; 945 return(KDC_ERR_POLICY); 946 } 947 948 /* Check to see if client is locked out */ 949 if (isflagset(client.attributes, KRB5_KDB_DISALLOW_ALL_TIX)) { 950 *status = "CLIENT LOCKED OUT"; 951 return(KDC_ERR_C_PRINCIPAL_UNKNOWN); 952 } 953 954 /* Check to see if server is locked out */ 955 if (isflagset(server.attributes, KRB5_KDB_DISALLOW_ALL_TIX)) { 956 *status = "SERVICE LOCKED OUT"; 957 return(KDC_ERR_S_PRINCIPAL_UNKNOWN); 958 } 959 960 /* Check to see if server is allowed to be a service */ 961 if (isflagset(server.attributes, KRB5_KDB_DISALLOW_SVR)) { 962 *status = "SERVICE NOT ALLOWED"; 963 return(KDC_ERR_S_PRINCIPAL_UNKNOWN); 964 } 965 966 /* 967 * Check against local policy 968 */ 969 errcode = against_local_policy_as(request, server, client, 970 kdc_time, status); 971 if (errcode) 972 return errcode; 973 974 return 0; 975 } 976 977 #define ASN1_ID_CLASS (0xc0) 978 #define ASN1_ID_TYPE (0x20) 979 #define ASN1_ID_TAG (0x1f) 980 #define ASN1_CLASS_UNIV (0) 981 #define ASN1_CLASS_APP (1) 982 #define ASN1_CLASS_CTX (2) 983 #define ASN1_CLASS_PRIV (3) 984 #define asn1_id_constructed(x) (x & ASN1_ID_TYPE) 985 #define asn1_id_primitive(x) (!asn1_id_constructed(x)) 986 #define asn1_id_class(x) ((x & ASN1_ID_CLASS) >> 6) 987 #define asn1_id_tag(x) (x & ASN1_ID_TAG) 988 989 /* 990 * asn1length - return encoded length of value. 991 * 992 * passed a pointer into the asn.1 stream, which is updated 993 * to point right after the length bits. 994 * 995 * returns -1 on failure. 996 */ 997 static int 998 asn1length(astream) 999 unsigned char **astream; 1000 { 1001 int length; /* resulting length */ 1002 int sublen; /* sublengths */ 1003 int blen; /* bytes of length */ 1004 unsigned char *p; /* substring searching */ 1005 1006 if (**astream & 0x80) { 1007 blen = **astream & 0x7f; 1008 if (blen > 3) { 1009 return(-1); 1010 } 1011 for (++*astream, length = 0; blen; ++*astream, blen--) { 1012 length = (length << 8) | **astream; 1013 } 1014 if (length == 0) { 1015 /* indefinite length, figure out by hand */ 1016 p = *astream; 1017 p++; 1018 while (1) { 1019 /* compute value length. */ 1020 if ((sublen = asn1length(&p)) < 0) { 1021 return(-1); 1022 } 1023 p += sublen; 1024 /* check for termination */ 1025 if ((!*p++) && (!*p)) { 1026 p++; 1027 break; 1028 } 1029 } 1030 length = p - *astream; 1031 } 1032 } else { 1033 length = **astream; 1034 ++*astream; 1035 } 1036 return(length); 1037 } 1038 1039 /* 1040 * fetch_asn1_field - return raw asn.1 stream of subfield. 1041 * 1042 * this routine is passed a context-dependent tag number and "level" and returns 1043 * the size and length of the corresponding level subfield. 1044 * 1045 * levels and are numbered starting from 1. 1046 * 1047 * returns 0 on success, -1 otherwise. 1048 */ 1049 int 1050 fetch_asn1_field(astream, level, field, data) 1051 unsigned char *astream; 1052 unsigned int level; 1053 unsigned int field; 1054 krb5_data *data; 1055 { 1056 unsigned char *estream; /* end of stream */ 1057 int classes; /* # classes seen so far this level */ 1058 unsigned int levels = 0; /* levels seen so far */ 1059 int lastlevel = 1000; /* last level seen */ 1060 int length; /* various lengths */ 1061 int tag; /* tag number */ 1062 unsigned char savelen; /* saved length of our field */ 1063 1064 classes = -1; 1065 /* we assume that the first identifier/length will tell us 1066 how long the entire stream is. */ 1067 astream++; 1068 estream = astream; 1069 if ((length = asn1length(&astream)) < 0) { 1070 return(-1); 1071 } 1072 estream += length; 1073 /* search down the stream, checking identifiers. we process identifiers 1074 until we hit the "level" we want, and then process that level for our 1075 subfield, always making sure we don't go off the end of the stream. */ 1076 while (astream < estream) { 1077 if (!asn1_id_constructed(*astream)) { 1078 return(-1); 1079 } 1080 if (asn1_id_class(*astream) == ASN1_CLASS_CTX) { 1081 if ((tag = (int)asn1_id_tag(*astream)) <= lastlevel) { 1082 levels++; 1083 classes = -1; 1084 } 1085 lastlevel = tag; 1086 if (levels == level) { 1087 /* in our context-dependent class, is this the one we're looking for ? */ 1088 if (tag == field) { 1089 /* return length and data */ 1090 astream++; 1091 savelen = *astream; 1092 if ((data->length = asn1length(&astream)) < 0) { 1093 return(-1); 1094 } 1095 /* if the field length is indefinite, we will have to subtract two 1096 (terminating octets) from the length returned since we don't want 1097 to pass any info from the "wrapper" back. asn1length will always return 1098 the *total* length of the field, not just what's contained in it */ 1099 if ((savelen & 0xff) == 0x80) { 1100 data->length -=2 ; 1101 } 1102 data->data = (char *)astream; 1103 return(0); 1104 } else if (tag <= classes) { 1105 /* we've seen this class before, something must be wrong */ 1106 return(-1); 1107 } else { 1108 classes = tag; 1109 } 1110 } 1111 } 1112 /* if we're not on our level yet, process this value. otherwise skip over it */ 1113 astream++; 1114 if ((length = asn1length(&astream)) < 0) { 1115 return(-1); 1116 } 1117 if (levels == level) { 1118 astream += length; 1119 } 1120 } 1121 return(-1); 1122 } 1123 1124 /* 1125 * Routines that validate a TGS request; checks a lot of things. :-) 1126 * 1127 * Returns a Kerberos protocol error number, which is _not_ the same 1128 * as a com_err error number! 1129 */ 1130 #define TGS_OPTIONS_HANDLED (KDC_OPT_FORWARDABLE | KDC_OPT_FORWARDED | \ 1131 KDC_OPT_PROXIABLE | KDC_OPT_PROXY | \ 1132 KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED | \ 1133 KDC_OPT_RENEWABLE | KDC_OPT_RENEWABLE_OK | \ 1134 KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_RENEW | \ 1135 KDC_OPT_VALIDATE) 1136 1137 #define NO_TGT_OPTION (KDC_OPT_FORWARDED | KDC_OPT_PROXY | KDC_OPT_RENEW | \ 1138 KDC_OPT_VALIDATE) 1139 1140 int 1141 validate_tgs_request(request, server, ticket, kdc_time, status) 1142 register krb5_kdc_req *request; 1143 krb5_db_entry server; 1144 krb5_ticket *ticket; 1145 krb5_timestamp kdc_time; 1146 const char **status; 1147 { 1148 int errcode; 1149 int st_idx = 0; 1150 krb5_flags badflags; 1151 1152 /* 1153 * If an illegal option is set, ignore it. 1154 */ 1155 badflags = request->kdc_options & ~(TGS_OPTIONS_HANDLED); 1156 request->kdc_options &= ~badflags; 1157 1158 /* Check to see if server has expired */ 1159 if (server.expiration && server.expiration < kdc_time) { 1160 *status = "SERVICE EXPIRED"; 1161 return(KDC_ERR_SERVICE_EXP); 1162 } 1163 1164 /* 1165 * Verify that the server principal in authdat->ticket is correct 1166 * (either the ticket granting service or the service that was 1167 * originally requested) 1168 */ 1169 if (request->kdc_options & NO_TGT_OPTION) { 1170 if (!krb5_principal_compare(kdc_context, ticket->server, request->server)) { 1171 *status = "SERVER DIDN'T MATCH TICKET FOR RENEW/FORWARD/ETC"; 1172 return(KDC_ERR_SERVER_NOMATCH); 1173 } 1174 } else { 1175 /* 1176 * OK, we need to validate the krbtgt service in the ticket. 1177 * 1178 * The krbtgt service is of the form: 1179 * krbtgt/realm-A@realm-B 1180 * 1181 * Realm A is the "server realm"; the realm of the 1182 * server of the requested ticket must match this realm. 1183 * Of course, it should be a realm serviced by this KDC. 1184 * 1185 * Realm B is the "client realm"; this is what should be 1186 * added to the transited field. (which is done elsewhere) 1187 */ 1188 1189 /* Make sure there are two components... */ 1190 if (krb5_princ_size(kdc_context, ticket->server) != 2) { 1191 *status = "BAD TGS SERVER LENGTH"; 1192 return KRB_AP_ERR_NOT_US; 1193 } 1194 /* ...that the first component is krbtgt... */ 1195 if (!krb5_is_tgs_principal(ticket->server)) { 1196 *status = "BAD TGS SERVER NAME"; 1197 return KRB_AP_ERR_NOT_US; 1198 } 1199 /* ...and that the second component matches the server realm... */ 1200 if ((krb5_princ_component(kdc_context, ticket->server, 1)->length != 1201 krb5_princ_realm(kdc_context, request->server)->length) || 1202 memcmp(krb5_princ_component(kdc_context, ticket->server, 1)->data, 1203 krb5_princ_realm(kdc_context, request->server)->data, 1204 krb5_princ_realm(kdc_context, request->server)->length)) { 1205 *status = "BAD TGS SERVER INSTANCE"; 1206 return KRB_AP_ERR_NOT_US; 1207 } 1208 /* XXX add check that second component must match locally 1209 * supported realm? 1210 */ 1211 1212 /* Server must allow TGS based issuances */ 1213 if (isflagset(server.attributes, KRB5_KDB_DISALLOW_TGT_BASED)) { 1214 *status = "TGT BASED NOT ALLOWED"; 1215 return(KDC_ERR_POLICY); 1216 } 1217 } 1218 1219 /* TGS must be forwardable to get forwarded or forwardable ticket */ 1220 if ((isflagset(request->kdc_options, KDC_OPT_FORWARDED) || 1221 isflagset(request->kdc_options, KDC_OPT_FORWARDABLE)) && 1222 !isflagset(ticket->enc_part2->flags, TKT_FLG_FORWARDABLE)) { 1223 *status = "TGT NOT FORWARDABLE"; 1224 1225 return KDC_ERR_BADOPTION; 1226 } 1227 1228 /* TGS must be proxiable to get proxiable ticket */ 1229 if ((isflagset(request->kdc_options, KDC_OPT_PROXY) || 1230 isflagset(request->kdc_options, KDC_OPT_PROXIABLE)) && 1231 !isflagset(ticket->enc_part2->flags, TKT_FLG_PROXIABLE)) { 1232 *status = "TGT NOT PROXIABLE"; 1233 return KDC_ERR_BADOPTION; 1234 } 1235 1236 /* TGS must allow postdating to get postdated ticket */ 1237 if ((isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE) || 1238 isflagset(request->kdc_options, KDC_OPT_POSTDATED)) && 1239 !isflagset(ticket->enc_part2->flags, TKT_FLG_MAY_POSTDATE)) { 1240 *status = "TGT NOT POSTDATABLE"; 1241 return KDC_ERR_BADOPTION; 1242 } 1243 1244 /* can only validate invalid tix */ 1245 if (isflagset(request->kdc_options, KDC_OPT_VALIDATE) && 1246 !isflagset(ticket->enc_part2->flags, TKT_FLG_INVALID)) { 1247 *status = "VALIDATE VALID TICKET"; 1248 return KDC_ERR_BADOPTION; 1249 } 1250 1251 /* can only renew renewable tix */ 1252 if ((isflagset(request->kdc_options, KDC_OPT_RENEW) || 1253 isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) && 1254 !isflagset(ticket->enc_part2->flags, TKT_FLG_RENEWABLE)) { 1255 *status = "TICKET NOT RENEWABLE"; 1256 return KDC_ERR_BADOPTION; 1257 } 1258 1259 /* can not proxy ticket granting tickets */ 1260 if (isflagset(request->kdc_options, KDC_OPT_PROXY) && 1261 (!request->server->data || 1262 request->server->data[0].length != KRB5_TGS_NAME_SIZE || 1263 memcmp(request->server->data[0].data, KRB5_TGS_NAME, 1264 KRB5_TGS_NAME_SIZE))) { 1265 *status = "CAN'T PROXY TGT"; 1266 return KDC_ERR_BADOPTION; 1267 } 1268 1269 /* Server must allow forwardable tickets */ 1270 if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE) && 1271 isflagset(server.attributes, KRB5_KDB_DISALLOW_FORWARDABLE)) { 1272 *status = "NON-FORWARDABLE TICKET"; 1273 return(KDC_ERR_POLICY); 1274 } 1275 1276 /* Server must allow renewable tickets */ 1277 if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE) && 1278 isflagset(server.attributes, KRB5_KDB_DISALLOW_RENEWABLE)) { 1279 *status = "NON-RENEWABLE TICKET"; 1280 return(KDC_ERR_POLICY); 1281 } 1282 1283 /* Server must allow proxiable tickets */ 1284 if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE) && 1285 isflagset(server.attributes, KRB5_KDB_DISALLOW_PROXIABLE)) { 1286 *status = "NON-PROXIABLE TICKET"; 1287 return(KDC_ERR_POLICY); 1288 } 1289 1290 /* Server must allow postdated tickets */ 1291 if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE) && 1292 isflagset(server.attributes, KRB5_KDB_DISALLOW_POSTDATED)) { 1293 *status = "NON-POSTDATABLE TICKET"; 1294 return(KDC_ERR_CANNOT_POSTDATE); 1295 } 1296 1297 /* Server must allow DUP SKEY requests */ 1298 if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY) && 1299 isflagset(server.attributes, KRB5_KDB_DISALLOW_DUP_SKEY)) { 1300 *status = "DUP_SKEY DISALLOWED"; 1301 return(KDC_ERR_POLICY); 1302 } 1303 1304 /* Server must not be locked out */ 1305 if (isflagset(server.attributes, KRB5_KDB_DISALLOW_ALL_TIX)) { 1306 *status = "SERVER LOCKED OUT"; 1307 return(KDC_ERR_S_PRINCIPAL_UNKNOWN); 1308 } 1309 1310 /* Server must be allowed to be a service */ 1311 if (isflagset(server.attributes, KRB5_KDB_DISALLOW_SVR)) { 1312 *status = "SERVER NOT ALLOWED"; 1313 return(KDC_ERR_S_PRINCIPAL_UNKNOWN); 1314 } 1315 1316 /* Check the hot list */ 1317 if (check_hot_list(ticket)) { 1318 *status = "HOT_LIST"; 1319 return(KRB_AP_ERR_REPEAT); 1320 } 1321 1322 /* Check the start time vs. the KDC time */ 1323 if (isflagset(request->kdc_options, KDC_OPT_VALIDATE)) { 1324 if (ticket->enc_part2->times.starttime > kdc_time) { 1325 *status = "NOT_YET_VALID"; 1326 return(KRB_AP_ERR_TKT_NYV); 1327 } 1328 } 1329 1330 /* 1331 * Check the renew_till time. The endtime was already 1332 * been checked in the initial authentication check. 1333 */ 1334 if (isflagset(request->kdc_options, KDC_OPT_RENEW) && 1335 (ticket->enc_part2->times.renew_till < kdc_time)) { 1336 *status = "TKT_EXPIRED"; 1337 return(KRB_AP_ERR_TKT_EXPIRED); 1338 } 1339 1340 /* 1341 * Checks for ENC_TKT_IN_SKEY: 1342 * 1343 * (1) Make sure the second ticket exists 1344 * (2) Make sure it is a ticket granting ticket 1345 */ 1346 if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) { 1347 if (!request->second_ticket || 1348 !request->second_ticket[st_idx]) { 1349 *status = "NO_2ND_TKT"; 1350 return(KDC_ERR_BADOPTION); 1351 } 1352 if (!krb5_principal_compare(kdc_context, request->second_ticket[st_idx]->server, 1353 tgs_server)) { 1354 *status = "2ND_TKT_NOT_TGS"; 1355 return(KDC_ERR_POLICY); 1356 } 1357 st_idx++; 1358 } 1359 1360 /* Check for hardware preauthentication */ 1361 if (isflagset(server.attributes, KRB5_KDB_REQUIRES_HW_AUTH) && 1362 !isflagset(ticket->enc_part2->flags,TKT_FLG_HW_AUTH)) { 1363 *status = "NO HW PREAUTH"; 1364 return KRB_ERR_GENERIC; 1365 } 1366 1367 /* Check for any kind of preauthentication */ 1368 if (isflagset(server.attributes, KRB5_KDB_REQUIRES_PRE_AUTH) && 1369 !isflagset(ticket->enc_part2->flags, TKT_FLG_PRE_AUTH)) { 1370 *status = "NO PREAUTH"; 1371 return KRB_ERR_GENERIC; 1372 } 1373 1374 /* 1375 * Check local policy 1376 */ 1377 errcode = against_local_policy_tgs(request, server, ticket, status); 1378 if (errcode) 1379 return errcode; 1380 1381 1382 return 0; 1383 } 1384 1385 /* 1386 * This function returns 1 if the dbentry has a key for a specified 1387 * keytype, and 0 if not. 1388 */ 1389 int 1390 dbentry_has_key_for_enctype(context, client, enctype) 1391 krb5_context context; 1392 krb5_db_entry * client; 1393 krb5_enctype enctype; 1394 { 1395 krb5_error_code retval; 1396 krb5_key_data *datap; 1397 1398 retval = krb5_dbe_find_enctype(context, client, enctype, 1399 -1, 0, &datap); 1400 if (retval) 1401 return 0; 1402 else 1403 return 1; 1404 } 1405 1406 /* 1407 * This function returns 1 if the entity referenced by this 1408 * structure can support the a particular encryption system, and 0 if 1409 * not. 1410 * 1411 * XXX eventually this information should be looked up in the 1412 * database. Since it isn't, we use some hueristics and attribute 1413 * options bits for now. 1414 */ 1415 int 1416 dbentry_supports_enctype(context, client, enctype) 1417 krb5_context context; 1418 krb5_db_entry * client; 1419 krb5_enctype enctype; 1420 { 1421 /* 1422 * If it's DES_CBC_MD5, there's a bit in the attribute mask which 1423 * checks to see if we support it. 1424 * 1425 * In theory everything's supposed to support DES_CBC_MD5, but 1426 * that's not the reality.... 1427 */ 1428 1429 /* 1430 * We are assuming that all entries can support MD5; this information 1431 * need not be kept in the database. 1432 */ 1433 1434 1435 if (enctype == ENCTYPE_DES_CBC_MD5) 1436 return 1; 1437 1438 /* 1439 * XXX we assume everything can understand DES_CBC_CRC 1440 */ 1441 if (enctype == ENCTYPE_DES_CBC_CRC) 1442 return 1; 1443 1444 /* 1445 * If we have a key for the encryption system, we assume it's 1446 * supported. 1447 */ 1448 return dbentry_has_key_for_enctype(context, client, enctype); 1449 } 1450 1451 /* 1452 * This function returns the keytype which should be selected for the 1453 * session key. It is based on the ordered list which the user 1454 * requested, and what the KDC and the application server can support. 1455 */ 1456 krb5_enctype 1457 select_session_keytype(context, server, nktypes, ktype) 1458 krb5_context context; 1459 krb5_db_entry * server; 1460 int nktypes; 1461 krb5_enctype *ktype; 1462 { 1463 int i; 1464 krb5_enctype dfl = 0; 1465 1466 for (i = 0; i < nktypes; i++) { 1467 if (!krb5_c_valid_enctype(ktype[i])) 1468 continue; 1469 1470 if (dbentry_supports_enctype(context, server, ktype[i])) 1471 return ktype[i]; 1472 } 1473 return 0; 1474 } 1475 1476 /* 1477 * This function returns salt information for a particular client_key 1478 */ 1479 krb5_error_code 1480 get_salt_from_key(context, client, client_key, salt) 1481 krb5_context context; 1482 krb5_principal client; 1483 krb5_key_data * client_key; 1484 krb5_data * salt; 1485 { 1486 krb5_error_code retval; 1487 krb5_data * realm; 1488 1489 salt->data = 0; 1490 salt->length = -1; 1491 1492 if (client_key->key_data_ver == 1) 1493 return 0; 1494 1495 switch (client_key->key_data_type[1]) { 1496 case KRB5_KDB_SALTTYPE_NORMAL: 1497 break; 1498 case KRB5_KDB_SALTTYPE_V4: 1499 /* send an empty (V4) salt */ 1500 salt->data = 0; 1501 salt->length = 0; 1502 break; 1503 case KRB5_KDB_SALTTYPE_NOREALM: 1504 if ((retval = krb5_principal2salt_norealm(context, client, salt))) 1505 return retval; 1506 break; 1507 case KRB5_KDB_SALTTYPE_AFS3: 1508 /* send the same salt as with onlyrealm - but with no type info, 1509 we just hope they figure it out on the other end. */ 1510 /* fall through to onlyrealm: */ 1511 case KRB5_KDB_SALTTYPE_ONLYREALM: 1512 realm = krb5_princ_realm(context, client); 1513 salt->length = realm->length; 1514 if ((salt->data = malloc(realm->length)) == NULL) 1515 return ENOMEM; 1516 memcpy(salt->data, realm->data, realm->length); 1517 break; 1518 case KRB5_KDB_SALTTYPE_SPECIAL: 1519 salt->length = client_key->key_data_length[1]; 1520 if ((salt->data = malloc(salt->length)) == NULL) 1521 return ENOMEM; 1522 memcpy(salt->data, client_key->key_data_contents[1], salt->length); 1523 break; 1524 } 1525 return 0; 1526 } 1527 1528 /* 1529 * Limit strings to a "reasonable" length to prevent crowding out of 1530 * other useful information in the log entry 1531 */ 1532 #define NAME_LENGTH_LIMIT 128 1533 1534 void limit_string(char *name) 1535 { 1536 int i; 1537 1538 if (!name) 1539 return; 1540 1541 if (strlen(name) < NAME_LENGTH_LIMIT) 1542 return; 1543 1544 i = NAME_LENGTH_LIMIT-4; 1545 name[i++] = '.'; 1546 name[i++] = '.'; 1547 name[i++] = '.'; 1548 name[i] = '\0'; 1549 return; 1550 } 1551