1/* 2 * Copyright (c) 1997 - 2005 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "kdc_locl.h" 35 36RCSID("$Id: kaserver.c 21654 2007-07-21 17:30:18Z lha $"); 37 38#include <krb5-v4compat.h> 39#include <rx.h> 40 41#define KA_AUTHENTICATION_SERVICE 731 42#define KA_TICKET_GRANTING_SERVICE 732 43#define KA_MAINTENANCE_SERVICE 733 44 45#define AUTHENTICATE_OLD 1 46#define CHANGEPASSWORD 2 47#define GETTICKET_OLD 3 48#define SETPASSWORD 4 49#define SETFIELDS 5 50#define CREATEUSER 6 51#define DELETEUSER 7 52#define GETENTRY 8 53#define LISTENTRY 9 54#define GETSTATS 10 55#define DEBUG 11 56#define GETPASSWORD 12 57#define GETRANDOMKEY 13 58#define AUTHENTICATE 21 59#define AUTHENTICATE_V2 22 60#define GETTICKET 23 61 62/* XXX - Where do we get these? */ 63 64#define RXGEN_OPCODE (-455) 65 66#define KADATABASEINCONSISTENT (180480L) 67#define KAEXIST (180481L) 68#define KAIO (180482L) 69#define KACREATEFAIL (180483L) 70#define KANOENT (180484L) 71#define KAEMPTY (180485L) 72#define KABADNAME (180486L) 73#define KABADINDEX (180487L) 74#define KANOAUTH (180488L) 75#define KAANSWERTOOLONG (180489L) 76#define KABADREQUEST (180490L) 77#define KAOLDINTERFACE (180491L) 78#define KABADARGUMENT (180492L) 79#define KABADCMD (180493L) 80#define KANOKEYS (180494L) 81#define KAREADPW (180495L) 82#define KABADKEY (180496L) 83#define KAUBIKINIT (180497L) 84#define KAUBIKCALL (180498L) 85#define KABADPROTOCOL (180499L) 86#define KANOCELLS (180500L) 87#define KANOCELL (180501L) 88#define KATOOMANYUBIKS (180502L) 89#define KATOOMANYKEYS (180503L) 90#define KABADTICKET (180504L) 91#define KAUNKNOWNKEY (180505L) 92#define KAKEYCACHEINVALID (180506L) 93#define KABADSERVER (180507L) 94#define KABADUSER (180508L) 95#define KABADCPW (180509L) 96#define KABADCREATE (180510L) 97#define KANOTICKET (180511L) 98#define KAASSOCUSER (180512L) 99#define KANOTSPECIAL (180513L) 100#define KACLOCKSKEW (180514L) 101#define KANORECURSE (180515L) 102#define KARXFAIL (180516L) 103#define KANULLPASSWORD (180517L) 104#define KAINTERNALERROR (180518L) 105#define KAPWEXPIRED (180519L) 106#define KAREUSED (180520L) 107#define KATOOSOON (180521L) 108#define KALOCKED (180522L) 109 110 111static krb5_error_code 112decode_rx_header (krb5_storage *sp, 113 struct rx_header *h) 114{ 115 krb5_error_code ret; 116 117 ret = krb5_ret_uint32(sp, &h->epoch); 118 if (ret) return ret; 119 ret = krb5_ret_uint32(sp, &h->connid); 120 if (ret) return ret; 121 ret = krb5_ret_uint32(sp, &h->callid); 122 if (ret) return ret; 123 ret = krb5_ret_uint32(sp, &h->seqno); 124 if (ret) return ret; 125 ret = krb5_ret_uint32(sp, &h->serialno); 126 if (ret) return ret; 127 ret = krb5_ret_uint8(sp, &h->type); 128 if (ret) return ret; 129 ret = krb5_ret_uint8(sp, &h->flags); 130 if (ret) return ret; 131 ret = krb5_ret_uint8(sp, &h->status); 132 if (ret) return ret; 133 ret = krb5_ret_uint8(sp, &h->secindex); 134 if (ret) return ret; 135 ret = krb5_ret_uint16(sp, &h->reserved); 136 if (ret) return ret; 137 ret = krb5_ret_uint16(sp, &h->serviceid); 138 if (ret) return ret; 139 140 return 0; 141} 142 143static krb5_error_code 144encode_rx_header (struct rx_header *h, 145 krb5_storage *sp) 146{ 147 krb5_error_code ret; 148 149 ret = krb5_store_uint32(sp, h->epoch); 150 if (ret) return ret; 151 ret = krb5_store_uint32(sp, h->connid); 152 if (ret) return ret; 153 ret = krb5_store_uint32(sp, h->callid); 154 if (ret) return ret; 155 ret = krb5_store_uint32(sp, h->seqno); 156 if (ret) return ret; 157 ret = krb5_store_uint32(sp, h->serialno); 158 if (ret) return ret; 159 ret = krb5_store_uint8(sp, h->type); 160 if (ret) return ret; 161 ret = krb5_store_uint8(sp, h->flags); 162 if (ret) return ret; 163 ret = krb5_store_uint8(sp, h->status); 164 if (ret) return ret; 165 ret = krb5_store_uint8(sp, h->secindex); 166 if (ret) return ret; 167 ret = krb5_store_uint16(sp, h->reserved); 168 if (ret) return ret; 169 ret = krb5_store_uint16(sp, h->serviceid); 170 if (ret) return ret; 171 172 return 0; 173} 174 175static void 176init_reply_header (struct rx_header *hdr, 177 struct rx_header *reply_hdr, 178 u_char type, 179 u_char flags) 180{ 181 reply_hdr->epoch = hdr->epoch; 182 reply_hdr->connid = hdr->connid; 183 reply_hdr->callid = hdr->callid; 184 reply_hdr->seqno = 1; 185 reply_hdr->serialno = 1; 186 reply_hdr->type = type; 187 reply_hdr->flags = flags; 188 reply_hdr->status = 0; 189 reply_hdr->secindex = 0; 190 reply_hdr->reserved = 0; 191 reply_hdr->serviceid = hdr->serviceid; 192} 193 194/* 195 * Create an error `reply� using for the packet `hdr' with the error 196 * `error� code. 197 */ 198static void 199make_error_reply (struct rx_header *hdr, 200 uint32_t error, 201 krb5_data *reply) 202 203{ 204 struct rx_header reply_hdr; 205 krb5_error_code ret; 206 krb5_storage *sp; 207 208 init_reply_header (hdr, &reply_hdr, HT_ABORT, HF_LAST); 209 sp = krb5_storage_emem(); 210 if (sp == NULL) 211 return; 212 ret = encode_rx_header (&reply_hdr, sp); 213 if (ret) 214 return; 215 krb5_store_int32(sp, error); 216 krb5_storage_to_data (sp, reply); 217 krb5_storage_free (sp); 218} 219 220static krb5_error_code 221krb5_ret_xdr_data(krb5_storage *sp, 222 krb5_data *data) 223{ 224 int ret; 225 int size; 226 ret = krb5_ret_int32(sp, &size); 227 if(ret) 228 return ret; 229 if(size < 0) 230 return ERANGE; 231 data->length = size; 232 if (size) { 233 u_char foo[4]; 234 size_t pad = (4 - size % 4) % 4; 235 236 data->data = malloc(size); 237 if (data->data == NULL) 238 return ENOMEM; 239 ret = krb5_storage_read(sp, data->data, size); 240 if(ret != size) 241 return (ret < 0)? errno : KRB5_CC_END; 242 if (pad) { 243 ret = krb5_storage_read(sp, foo, pad); 244 if (ret != pad) 245 return (ret < 0)? errno : KRB5_CC_END; 246 } 247 } else 248 data->data = NULL; 249 return 0; 250} 251 252static krb5_error_code 253krb5_store_xdr_data(krb5_storage *sp, 254 krb5_data data) 255{ 256 u_char zero[4] = {0, 0, 0, 0}; 257 int ret; 258 size_t pad; 259 260 ret = krb5_store_int32(sp, data.length); 261 if(ret < 0) 262 return ret; 263 ret = krb5_storage_write(sp, data.data, data.length); 264 if(ret != data.length){ 265 if(ret < 0) 266 return errno; 267 return KRB5_CC_END; 268 } 269 pad = (4 - data.length % 4) % 4; 270 if (pad) { 271 ret = krb5_storage_write(sp, zero, pad); 272 if (ret != pad) { 273 if (ret < 0) 274 return errno; 275 return KRB5_CC_END; 276 } 277 } 278 return 0; 279} 280 281 282static krb5_error_code 283create_reply_ticket (krb5_context context, 284 struct rx_header *hdr, 285 Key *skey, 286 char *name, char *instance, char *realm, 287 struct sockaddr_in *addr, 288 int life, 289 int kvno, 290 int32_t max_seq_len, 291 const char *sname, const char *sinstance, 292 uint32_t challenge, 293 const char *label, 294 krb5_keyblock *key, 295 krb5_data *reply) 296{ 297 krb5_error_code ret; 298 krb5_data ticket; 299 krb5_keyblock session; 300 krb5_storage *sp; 301 krb5_data enc_data; 302 struct rx_header reply_hdr; 303 char zero[8]; 304 size_t pad; 305 unsigned fyrtiosjuelva; 306 307 /* create the ticket */ 308 309 krb5_generate_random_keyblock(context, ETYPE_DES_PCBC_NONE, &session); 310 311 _krb5_krb_create_ticket(context, 312 0, 313 name, 314 instance, 315 realm, 316 addr->sin_addr.s_addr, 317 &session, 318 life, 319 kdc_time, 320 sname, 321 sinstance, 322 &skey->key, 323 &ticket); 324 325 /* create the encrypted part of the reply */ 326 sp = krb5_storage_emem (); 327 krb5_generate_random_block(&fyrtiosjuelva, sizeof(fyrtiosjuelva)); 328 fyrtiosjuelva &= 0xffffffff; 329 krb5_store_int32 (sp, fyrtiosjuelva); 330 krb5_store_int32 (sp, challenge); 331 krb5_storage_write (sp, session.keyvalue.data, 8); 332 krb5_free_keyblock_contents(context, &session); 333 krb5_store_int32 (sp, kdc_time); 334 krb5_store_int32 (sp, kdc_time + _krb5_krb_life_to_time (0, life)); 335 krb5_store_int32 (sp, kvno); 336 krb5_store_int32 (sp, ticket.length); 337 krb5_store_stringz (sp, name); 338 krb5_store_stringz (sp, instance); 339#if 1 /* XXX - Why shouldn't the realm go here? */ 340 krb5_store_stringz (sp, ""); 341#else 342 krb5_store_stringz (sp, realm); 343#endif 344 krb5_store_stringz (sp, sname); 345 krb5_store_stringz (sp, sinstance); 346 krb5_storage_write (sp, ticket.data, ticket.length); 347 krb5_storage_write (sp, label, strlen(label)); 348 349 /* pad to DES block */ 350 memset (zero, 0, sizeof(zero)); 351 pad = (8 - krb5_storage_seek (sp, 0, SEEK_CUR) % 8) % 8; 352 krb5_storage_write (sp, zero, pad); 353 354 krb5_storage_to_data (sp, &enc_data); 355 krb5_storage_free (sp); 356 357 if (enc_data.length > max_seq_len) { 358 krb5_data_free (&enc_data); 359 make_error_reply (hdr, KAANSWERTOOLONG, reply); 360 return 0; 361 } 362 363 /* encrypt it */ 364 { 365 DES_key_schedule schedule; 366 DES_cblock deskey; 367 368 memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); 369 DES_set_key (&deskey, &schedule); 370 DES_pcbc_encrypt (enc_data.data, 371 enc_data.data, 372 enc_data.length, 373 &schedule, 374 &deskey, 375 DES_ENCRYPT); 376 memset (&schedule, 0, sizeof(schedule)); 377 memset (&deskey, 0, sizeof(deskey)); 378 } 379 380 /* create the reply packet */ 381 init_reply_header (hdr, &reply_hdr, HT_DATA, HF_LAST); 382 sp = krb5_storage_emem (); 383 ret = encode_rx_header (&reply_hdr, sp); 384 krb5_store_int32 (sp, max_seq_len); 385 krb5_store_xdr_data (sp, enc_data); 386 krb5_data_free (&enc_data); 387 krb5_storage_to_data (sp, reply); 388 krb5_storage_free (sp); 389 return 0; 390} 391 392static krb5_error_code 393unparse_auth_args (krb5_storage *sp, 394 char **name, 395 char **instance, 396 time_t *start_time, 397 time_t *end_time, 398 krb5_data *request, 399 int32_t *max_seq_len) 400{ 401 krb5_data data; 402 int32_t tmp; 403 404 krb5_ret_xdr_data (sp, &data); 405 *name = malloc(data.length + 1); 406 if (*name == NULL) 407 return ENOMEM; 408 memcpy (*name, data.data, data.length); 409 (*name)[data.length] = '\0'; 410 krb5_data_free (&data); 411 412 krb5_ret_xdr_data (sp, &data); 413 *instance = malloc(data.length + 1); 414 if (*instance == NULL) { 415 free (*name); 416 return ENOMEM; 417 } 418 memcpy (*instance, data.data, data.length); 419 (*instance)[data.length] = '\0'; 420 krb5_data_free (&data); 421 422 krb5_ret_int32 (sp, &tmp); 423 *start_time = tmp; 424 krb5_ret_int32 (sp, &tmp); 425 *end_time = tmp; 426 krb5_ret_xdr_data (sp, request); 427 krb5_ret_int32 (sp, max_seq_len); 428 /* ignore the rest */ 429 return 0; 430} 431 432static void 433do_authenticate (krb5_context context, 434 krb5_kdc_configuration *config, 435 struct rx_header *hdr, 436 krb5_storage *sp, 437 struct sockaddr_in *addr, 438 const char *from, 439 krb5_data *reply) 440{ 441 krb5_error_code ret; 442 char *name = NULL; 443 char *instance = NULL; 444 time_t start_time; 445 time_t end_time; 446 krb5_data request; 447 int32_t max_seq_len; 448 hdb_entry_ex *client_entry = NULL; 449 hdb_entry_ex *server_entry = NULL; 450 Key *ckey = NULL; 451 Key *skey = NULL; 452 krb5_storage *reply_sp; 453 time_t max_life; 454 uint8_t life; 455 int32_t chal; 456 char client_name[256]; 457 char server_name[256]; 458 459 krb5_data_zero (&request); 460 461 ret = unparse_auth_args (sp, &name, &instance, &start_time, &end_time, 462 &request, &max_seq_len); 463 if (ret != 0 || request.length < 8) { 464 make_error_reply (hdr, KABADREQUEST, reply); 465 goto out; 466 } 467 468 snprintf (client_name, sizeof(client_name), "%s.%s@%s", 469 name, instance, config->v4_realm); 470 snprintf (server_name, sizeof(server_name), "%s.%s@%s", 471 "krbtgt", config->v4_realm, config->v4_realm); 472 473 kdc_log(context, config, 0, "AS-REQ (kaserver) %s from %s for %s", 474 client_name, from, server_name); 475 476 ret = _kdc_db_fetch4 (context, config, name, instance, 477 config->v4_realm, HDB_F_GET_CLIENT, 478 &client_entry); 479 if (ret) { 480 kdc_log(context, config, 0, "Client not found in database: %s: %s", 481 client_name, krb5_get_err_text(context, ret)); 482 make_error_reply (hdr, KANOENT, reply); 483 goto out; 484 } 485 486 ret = _kdc_db_fetch4 (context, config, "krbtgt", 487 config->v4_realm, config->v4_realm, 488 HDB_F_GET_KRBTGT, &server_entry); 489 if (ret) { 490 kdc_log(context, config, 0, "Server not found in database: %s: %s", 491 server_name, krb5_get_err_text(context, ret)); 492 make_error_reply (hdr, KANOENT, reply); 493 goto out; 494 } 495 496 ret = _kdc_check_flags (context, config, 497 client_entry, client_name, 498 server_entry, server_name, 499 TRUE); 500 if (ret) { 501 make_error_reply (hdr, KAPWEXPIRED, reply); 502 goto out; 503 } 504 505 /* find a DES key */ 506 ret = _kdc_get_des_key(context, client_entry, FALSE, TRUE, &ckey); 507 if(ret){ 508 kdc_log(context, config, 0, "no suitable DES key for client"); 509 make_error_reply (hdr, KANOKEYS, reply); 510 goto out; 511 } 512 513 /* find a DES key */ 514 ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey); 515 if(ret){ 516 kdc_log(context, config, 0, "no suitable DES key for server"); 517 make_error_reply (hdr, KANOKEYS, reply); 518 goto out; 519 } 520 521 { 522 DES_cblock key; 523 DES_key_schedule schedule; 524 525 /* try to decode the `request' */ 526 memcpy (&key, ckey->key.keyvalue.data, sizeof(key)); 527 DES_set_key (&key, &schedule); 528 DES_pcbc_encrypt (request.data, 529 request.data, 530 request.length, 531 &schedule, 532 &key, 533 DES_DECRYPT); 534 memset (&schedule, 0, sizeof(schedule)); 535 memset (&key, 0, sizeof(key)); 536 } 537 538 /* check for the magic label */ 539 if (memcmp ((char *)request.data + 4, "gTGS", 4) != 0) { 540 kdc_log(context, config, 0, "preauth failed for %s", client_name); 541 make_error_reply (hdr, KABADREQUEST, reply); 542 goto out; 543 } 544 545 reply_sp = krb5_storage_from_mem (request.data, 4); 546 krb5_ret_int32 (reply_sp, &chal); 547 krb5_storage_free (reply_sp); 548 549 if (abs(chal - kdc_time) > context->max_skew) { 550 make_error_reply (hdr, KACLOCKSKEW, reply); 551 goto out; 552 } 553 554 /* life */ 555 max_life = end_time - kdc_time; 556 /* end_time - kdc_time can sometimes be non-positive due to slight 557 time skew between client and server. Let's make sure it is postive */ 558 if(max_life < 1) 559 max_life = 1; 560 if (client_entry->entry.max_life) 561 max_life = min(max_life, *client_entry->entry.max_life); 562 if (server_entry->entry.max_life) 563 max_life = min(max_life, *server_entry->entry.max_life); 564 565 life = krb_time_to_life(kdc_time, kdc_time + max_life); 566 567 create_reply_ticket (context, 568 hdr, skey, 569 name, instance, config->v4_realm, 570 addr, life, server_entry->entry.kvno, 571 max_seq_len, 572 "krbtgt", config->v4_realm, 573 chal + 1, "tgsT", 574 &ckey->key, reply); 575 576 out: 577 if (request.length) { 578 memset (request.data, 0, request.length); 579 krb5_data_free (&request); 580 } 581 if (name) 582 free (name); 583 if (instance) 584 free (instance); 585 if (client_entry) 586 _kdc_free_ent (context, client_entry); 587 if (server_entry) 588 _kdc_free_ent (context, server_entry); 589} 590 591static krb5_error_code 592unparse_getticket_args (krb5_storage *sp, 593 int *kvno, 594 char **auth_domain, 595 krb5_data *ticket, 596 char **name, 597 char **instance, 598 krb5_data *times, 599 int32_t *max_seq_len) 600{ 601 krb5_data data; 602 int32_t tmp; 603 604 krb5_ret_int32 (sp, &tmp); 605 *kvno = tmp; 606 607 krb5_ret_xdr_data (sp, &data); 608 *auth_domain = malloc(data.length + 1); 609 if (*auth_domain == NULL) 610 return ENOMEM; 611 memcpy (*auth_domain, data.data, data.length); 612 (*auth_domain)[data.length] = '\0'; 613 krb5_data_free (&data); 614 615 krb5_ret_xdr_data (sp, ticket); 616 617 krb5_ret_xdr_data (sp, &data); 618 *name = malloc(data.length + 1); 619 if (*name == NULL) { 620 free (*auth_domain); 621 return ENOMEM; 622 } 623 memcpy (*name, data.data, data.length); 624 (*name)[data.length] = '\0'; 625 krb5_data_free (&data); 626 627 krb5_ret_xdr_data (sp, &data); 628 *instance = malloc(data.length + 1); 629 if (*instance == NULL) { 630 free (*auth_domain); 631 free (*name); 632 return ENOMEM; 633 } 634 memcpy (*instance, data.data, data.length); 635 (*instance)[data.length] = '\0'; 636 krb5_data_free (&data); 637 638 krb5_ret_xdr_data (sp, times); 639 640 krb5_ret_int32 (sp, max_seq_len); 641 /* ignore the rest */ 642 return 0; 643} 644 645static void 646do_getticket (krb5_context context, 647 krb5_kdc_configuration *config, 648 struct rx_header *hdr, 649 krb5_storage *sp, 650 struct sockaddr_in *addr, 651 const char *from, 652 krb5_data *reply) 653{ 654 krb5_error_code ret; 655 int kvno; 656 char *auth_domain = NULL; 657 krb5_data aticket; 658 char *name = NULL; 659 char *instance = NULL; 660 krb5_data times; 661 int32_t max_seq_len; 662 hdb_entry_ex *server_entry = NULL; 663 hdb_entry_ex *client_entry = NULL; 664 hdb_entry_ex *krbtgt_entry = NULL; 665 Key *kkey = NULL; 666 Key *skey = NULL; 667 DES_cblock key; 668 DES_key_schedule schedule; 669 DES_cblock session; 670 time_t max_life; 671 int8_t life; 672 time_t start_time, end_time; 673 char server_name[256]; 674 char client_name[256]; 675 struct _krb5_krb_auth_data ad; 676 677 krb5_data_zero (&aticket); 678 krb5_data_zero (×); 679 680 memset(&ad, 0, sizeof(ad)); 681 682 unparse_getticket_args (sp, &kvno, &auth_domain, &aticket, 683 &name, &instance, ×, &max_seq_len); 684 if (times.length < 8) { 685 make_error_reply (hdr, KABADREQUEST, reply); 686 goto out; 687 688 } 689 690 snprintf (server_name, sizeof(server_name), 691 "%s.%s@%s", name, instance, config->v4_realm); 692 693 ret = _kdc_db_fetch4 (context, config, name, instance, 694 config->v4_realm, HDB_F_GET_SERVER, &server_entry); 695 if (ret) { 696 kdc_log(context, config, 0, "Server not found in database: %s: %s", 697 server_name, krb5_get_err_text(context, ret)); 698 make_error_reply (hdr, KANOENT, reply); 699 goto out; 700 } 701 702 ret = _kdc_db_fetch4 (context, config, "krbtgt", 703 config->v4_realm, config->v4_realm, HDB_F_GET_KRBTGT, &krbtgt_entry); 704 if (ret) { 705 kdc_log(context, config, 0, 706 "Server not found in database: %s.%s@%s: %s", 707 "krbtgt", config->v4_realm, config->v4_realm, 708 krb5_get_err_text(context, ret)); 709 make_error_reply (hdr, KANOENT, reply); 710 goto out; 711 } 712 713 /* find a DES key */ 714 ret = _kdc_get_des_key(context, krbtgt_entry, TRUE, TRUE, &kkey); 715 if(ret){ 716 kdc_log(context, config, 0, "no suitable DES key for krbtgt"); 717 make_error_reply (hdr, KANOKEYS, reply); 718 goto out; 719 } 720 721 /* find a DES key */ 722 ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey); 723 if(ret){ 724 kdc_log(context, config, 0, "no suitable DES key for server"); 725 make_error_reply (hdr, KANOKEYS, reply); 726 goto out; 727 } 728 729 /* decrypt the incoming ticket */ 730 memcpy (&key, kkey->key.keyvalue.data, sizeof(key)); 731 732 /* unpack the ticket */ 733 { 734 char *sname = NULL; 735 char *sinstance = NULL; 736 737 ret = _krb5_krb_decomp_ticket(context, &aticket, &kkey->key, 738 config->v4_realm, &sname, 739 &sinstance, &ad); 740 if (ret) { 741 kdc_log(context, config, 0, 742 "kaserver: decomp failed for %s.%s with %d", 743 sname, sinstance, ret); 744 make_error_reply (hdr, KABADTICKET, reply); 745 goto out; 746 } 747 748 if (strcmp (sname, "krbtgt") != 0 749 || strcmp (sinstance, config->v4_realm) != 0) { 750 kdc_log(context, config, 0, "no TGT: %s.%s for %s.%s@%s", 751 sname, sinstance, 752 ad.pname, ad.pinst, ad.prealm); 753 make_error_reply (hdr, KABADTICKET, reply); 754 free(sname); 755 free(sinstance); 756 goto out; 757 } 758 free(sname); 759 free(sinstance); 760 761 if (kdc_time > _krb5_krb_life_to_time(ad.time_sec, ad.life)) { 762 kdc_log(context, config, 0, "TGT expired: %s.%s@%s", 763 ad.pname, ad.pinst, ad.prealm); 764 make_error_reply (hdr, KABADTICKET, reply); 765 goto out; 766 } 767 } 768 769 snprintf (client_name, sizeof(client_name), 770 "%s.%s@%s", ad.pname, ad.pinst, ad.prealm); 771 772 kdc_log(context, config, 0, "TGS-REQ (kaserver) %s from %s for %s", 773 client_name, from, server_name); 774 775 ret = _kdc_db_fetch4 (context, config, 776 ad.pname, ad.pinst, ad.prealm, HDB_F_GET_CLIENT, 777 &client_entry); 778 if(ret && ret != HDB_ERR_NOENTRY) { 779 kdc_log(context, config, 0, 780 "Client not found in database: (krb4) %s: %s", 781 client_name, krb5_get_err_text(context, ret)); 782 make_error_reply (hdr, KANOENT, reply); 783 goto out; 784 } 785 if (client_entry == NULL && strcmp(ad.prealm, config->v4_realm) == 0) { 786 kdc_log(context, config, 0, 787 "Local client not found in database: (krb4) " 788 "%s", client_name); 789 make_error_reply (hdr, KANOENT, reply); 790 goto out; 791 } 792 793 ret = _kdc_check_flags (context, config, 794 client_entry, client_name, 795 server_entry, server_name, 796 FALSE); 797 if (ret) { 798 make_error_reply (hdr, KAPWEXPIRED, reply); 799 goto out; 800 } 801 802 /* decrypt the times */ 803 memcpy(&session, ad.session.keyvalue.data, sizeof(session)); 804 DES_set_key (&session, &schedule); 805 DES_ecb_encrypt (times.data, 806 times.data, 807 &schedule, 808 DES_DECRYPT); 809 memset (&schedule, 0, sizeof(schedule)); 810 memset (&session, 0, sizeof(session)); 811 812 /* and extract them */ 813 { 814 krb5_storage *tsp; 815 int32_t tmp; 816 817 tsp = krb5_storage_from_mem (times.data, times.length); 818 krb5_ret_int32 (tsp, &tmp); 819 start_time = tmp; 820 krb5_ret_int32 (tsp, &tmp); 821 end_time = tmp; 822 krb5_storage_free (tsp); 823 } 824 825 /* life */ 826 max_life = end_time - kdc_time; 827 /* end_time - kdc_time can sometimes be non-positive due to slight 828 time skew between client and server. Let's make sure it is postive */ 829 if(max_life < 1) 830 max_life = 1; 831 if (krbtgt_entry->entry.max_life) 832 max_life = min(max_life, *krbtgt_entry->entry.max_life); 833 if (server_entry->entry.max_life) 834 max_life = min(max_life, *server_entry->entry.max_life); 835 /* if this is a cross realm request, the client_entry will likely 836 be NULL */ 837 if (client_entry && client_entry->entry.max_life) 838 max_life = min(max_life, *client_entry->entry.max_life); 839 840 life = _krb5_krb_time_to_life(kdc_time, kdc_time + max_life); 841 842 create_reply_ticket (context, 843 hdr, skey, 844 ad.pname, ad.pinst, ad.prealm, 845 addr, life, server_entry->entry.kvno, 846 max_seq_len, 847 name, instance, 848 0, "gtkt", 849 &ad.session, reply); 850 851 out: 852 _krb5_krb_free_auth_data(context, &ad); 853 if (aticket.length) { 854 memset (aticket.data, 0, aticket.length); 855 krb5_data_free (&aticket); 856 } 857 if (times.length) { 858 memset (times.data, 0, times.length); 859 krb5_data_free (×); 860 } 861 if (auth_domain) 862 free (auth_domain); 863 if (name) 864 free (name); 865 if (instance) 866 free (instance); 867 if (krbtgt_entry) 868 _kdc_free_ent (context, krbtgt_entry); 869 if (server_entry) 870 _kdc_free_ent (context, server_entry); 871} 872 873krb5_error_code 874_kdc_do_kaserver(krb5_context context, 875 krb5_kdc_configuration *config, 876 unsigned char *buf, 877 size_t len, 878 krb5_data *reply, 879 const char *from, 880 struct sockaddr_in *addr) 881{ 882 krb5_error_code ret = 0; 883 struct rx_header hdr; 884 uint32_t op; 885 krb5_storage *sp; 886 887 if (len < RX_HEADER_SIZE) 888 return -1; 889 sp = krb5_storage_from_mem (buf, len); 890 891 ret = decode_rx_header (sp, &hdr); 892 if (ret) 893 goto out; 894 buf += RX_HEADER_SIZE; 895 len -= RX_HEADER_SIZE; 896 897 switch (hdr.type) { 898 case HT_DATA : 899 break; 900 case HT_ACK : 901 case HT_BUSY : 902 case HT_ABORT : 903 case HT_ACKALL : 904 case HT_CHAL : 905 case HT_RESP : 906 case HT_DEBUG : 907 default: 908 /* drop */ 909 goto out; 910 } 911 912 913 if (hdr.serviceid != KA_AUTHENTICATION_SERVICE 914 && hdr.serviceid != KA_TICKET_GRANTING_SERVICE) { 915 ret = -1; 916 goto out; 917 } 918 919 ret = krb5_ret_uint32(sp, &op); 920 if (ret) 921 goto out; 922 switch (op) { 923 case AUTHENTICATE : 924 case AUTHENTICATE_V2 : 925 do_authenticate (context, config, &hdr, sp, addr, from, reply); 926 break; 927 case GETTICKET : 928 do_getticket (context, config, &hdr, sp, addr, from, reply); 929 break; 930 case AUTHENTICATE_OLD : 931 case CHANGEPASSWORD : 932 case GETTICKET_OLD : 933 case SETPASSWORD : 934 case SETFIELDS : 935 case CREATEUSER : 936 case DELETEUSER : 937 case GETENTRY : 938 case LISTENTRY : 939 case GETSTATS : 940 case DEBUG : 941 case GETPASSWORD : 942 case GETRANDOMKEY : 943 default : 944 make_error_reply (&hdr, RXGEN_OPCODE, reply); 945 break; 946 } 947 948out: 949 krb5_storage_free (sp); 950 return ret; 951} 952