1/* 2 * Copyright (c) 1997 - 2006 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 36#include <krb5-v4compat.h> 37 38RCSID("$Id: kerberos4.c 21577 2007-07-16 08:14:06Z lha $"); 39 40#ifndef swap32 41static uint32_t 42swap32(uint32_t x) 43{ 44 return ((x << 24) & 0xff000000) | 45 ((x << 8) & 0xff0000) | 46 ((x >> 8) & 0xff00) | 47 ((x >> 24) & 0xff); 48} 49#endif /* swap32 */ 50 51int 52_kdc_maybe_version4(unsigned char *buf, int len) 53{ 54 return len > 0 && *buf == 4; 55} 56 57static void 58make_err_reply(krb5_context context, krb5_data *reply, 59 int code, const char *msg) 60{ 61 _krb5_krb_cr_err_reply(context, "", "", "", 62 kdc_time, code, msg, reply); 63} 64 65struct valid_princ_ctx { 66 krb5_kdc_configuration *config; 67 unsigned flags; 68}; 69 70static krb5_boolean 71valid_princ(krb5_context context, 72 void *funcctx, 73 krb5_principal princ) 74{ 75 struct valid_princ_ctx *ctx = funcctx; 76 krb5_error_code ret; 77 char *s; 78 hdb_entry_ex *ent; 79 80 ret = krb5_unparse_name(context, princ, &s); 81 if (ret) 82 return FALSE; 83 ret = _kdc_db_fetch(context, ctx->config, princ, ctx->flags, NULL, &ent); 84 if (ret) { 85 kdc_log(context, ctx->config, 7, "Lookup %s failed: %s", s, 86 krb5_get_err_text (context, ret)); 87 free(s); 88 return FALSE; 89 } 90 kdc_log(context, ctx->config, 7, "Lookup %s succeeded", s); 91 free(s); 92 _kdc_free_ent(context, ent); 93 return TRUE; 94} 95 96krb5_error_code 97_kdc_db_fetch4(krb5_context context, 98 krb5_kdc_configuration *config, 99 const char *name, const char *instance, const char *realm, 100 unsigned flags, 101 hdb_entry_ex **ent) 102{ 103 krb5_principal p; 104 krb5_error_code ret; 105 struct valid_princ_ctx ctx; 106 107 ctx.config = config; 108 ctx.flags = flags; 109 110 ret = krb5_425_conv_principal_ext2(context, name, instance, realm, 111 valid_princ, &ctx, 0, &p); 112 if(ret) 113 return ret; 114 ret = _kdc_db_fetch(context, config, p, flags, NULL, ent); 115 krb5_free_principal(context, p); 116 return ret; 117} 118 119#define RCHECK(X, L) if(X){make_err_reply(context, reply, KFAILURE, "Packet too short"); goto L;} 120 121/* 122 * Process the v4 request in `buf, len' (received from `addr' 123 * (with string `from'). 124 * Return an error code and a reply in `reply'. 125 */ 126 127krb5_error_code 128_kdc_do_version4(krb5_context context, 129 krb5_kdc_configuration *config, 130 unsigned char *buf, 131 size_t len, 132 krb5_data *reply, 133 const char *from, 134 struct sockaddr_in *addr) 135{ 136 krb5_storage *sp; 137 krb5_error_code ret; 138 hdb_entry_ex *client = NULL, *server = NULL; 139 Key *ckey, *skey; 140 int8_t pvno; 141 int8_t msg_type; 142 int lsb; 143 char *name = NULL, *inst = NULL, *realm = NULL; 144 char *sname = NULL, *sinst = NULL; 145 int32_t req_time; 146 time_t max_life; 147 uint8_t life; 148 char client_name[256]; 149 char server_name[256]; 150 151 if(!config->enable_v4) { 152 kdc_log(context, config, 0, 153 "Rejected version 4 request from %s", from); 154 make_err_reply(context, reply, KRB4ET_KDC_GEN_ERR, 155 "Function not enabled"); 156 return 0; 157 } 158 159 sp = krb5_storage_from_mem(buf, len); 160 RCHECK(krb5_ret_int8(sp, &pvno), out); 161 if(pvno != 4){ 162 kdc_log(context, config, 0, 163 "Protocol version mismatch (krb4) (%d)", pvno); 164 make_err_reply(context, reply, KRB4ET_KDC_PKT_VER, "protocol mismatch"); 165 goto out; 166 } 167 RCHECK(krb5_ret_int8(sp, &msg_type), out); 168 lsb = msg_type & 1; 169 msg_type &= ~1; 170 switch(msg_type){ 171 case AUTH_MSG_KDC_REQUEST: { 172 krb5_data ticket, cipher; 173 krb5_keyblock session; 174 175 krb5_data_zero(&ticket); 176 krb5_data_zero(&cipher); 177 178 RCHECK(krb5_ret_stringz(sp, &name), out1); 179 RCHECK(krb5_ret_stringz(sp, &inst), out1); 180 RCHECK(krb5_ret_stringz(sp, &realm), out1); 181 RCHECK(krb5_ret_int32(sp, &req_time), out1); 182 if(lsb) 183 req_time = swap32(req_time); 184 RCHECK(krb5_ret_uint8(sp, &life), out1); 185 RCHECK(krb5_ret_stringz(sp, &sname), out1); 186 RCHECK(krb5_ret_stringz(sp, &sinst), out1); 187 snprintf (client_name, sizeof(client_name), 188 "%s.%s@%s", name, inst, realm); 189 snprintf (server_name, sizeof(server_name), 190 "%s.%s@%s", sname, sinst, config->v4_realm); 191 192 kdc_log(context, config, 0, "AS-REQ (krb4) %s from %s for %s", 193 client_name, from, server_name); 194 195 ret = _kdc_db_fetch4(context, config, name, inst, realm, 196 HDB_F_GET_CLIENT, &client); 197 if(ret) { 198 kdc_log(context, config, 0, "Client not found in database: %s: %s", 199 client_name, krb5_get_err_text(context, ret)); 200 make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, 201 "principal unknown"); 202 goto out1; 203 } 204 ret = _kdc_db_fetch4(context, config, sname, sinst, config->v4_realm, 205 HDB_F_GET_SERVER, &server); 206 if(ret){ 207 kdc_log(context, config, 0, "Server not found in database: %s: %s", 208 server_name, krb5_get_err_text(context, ret)); 209 make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, 210 "principal unknown"); 211 goto out1; 212 } 213 214 ret = _kdc_check_flags (context, config, 215 client, client_name, 216 server, server_name, 217 TRUE); 218 if (ret) { 219 /* good error code? */ 220 make_err_reply(context, reply, KRB4ET_KDC_NAME_EXP, 221 "operation not allowed"); 222 goto out1; 223 } 224 225 if (config->enable_v4_per_principal && 226 client->entry.flags.allow_kerberos4 == 0) 227 { 228 kdc_log(context, config, 0, 229 "Per principal Kerberos 4 flag not turned on for %s", 230 client_name); 231 make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, 232 "allow kerberos4 flag required"); 233 goto out1; 234 } 235 236 /* 237 * There's no way to do pre-authentication in v4 and thus no 238 * good error code to return if preauthentication is required. 239 */ 240 241 if (config->require_preauth 242 || client->entry.flags.require_preauth 243 || server->entry.flags.require_preauth) { 244 kdc_log(context, config, 0, 245 "Pre-authentication required for v4-request: " 246 "%s for %s", 247 client_name, server_name); 248 make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, 249 "preauth required"); 250 goto out1; 251 } 252 253 ret = _kdc_get_des_key(context, client, FALSE, FALSE, &ckey); 254 if(ret){ 255 kdc_log(context, config, 0, "no suitable DES key for client"); 256 make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, 257 "no suitable DES key for client"); 258 goto out1; 259 } 260 261#if 0 262 /* this is not necessary with the new code in libkrb */ 263 /* find a properly salted key */ 264 while(ckey->salt == NULL || ckey->salt->salt.length != 0) 265 ret = hdb_next_keytype2key(context, &client->entry, KEYTYPE_DES, &ckey); 266 if(ret){ 267 kdc_log(context, config, 0, "No version-4 salted key in database -- %s.%s@%s", 268 name, inst, realm); 269 make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, 270 "No version-4 salted key in database"); 271 goto out1; 272 } 273#endif 274 275 ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey); 276 if(ret){ 277 kdc_log(context, config, 0, "no suitable DES key for server"); 278 make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, 279 "no suitable DES key for server"); 280 goto out1; 281 } 282 283 max_life = _krb5_krb_life_to_time(0, life); 284 if(client->entry.max_life) 285 max_life = min(max_life, *client->entry.max_life); 286 if(server->entry.max_life) 287 max_life = min(max_life, *server->entry.max_life); 288 289 life = krb_time_to_life(kdc_time, kdc_time + max_life); 290 291 ret = krb5_generate_random_keyblock(context, 292 ETYPE_DES_PCBC_NONE, 293 &session); 294 if (ret) { 295 make_err_reply(context, reply, KFAILURE, 296 "Not enough random i KDC"); 297 goto out1; 298 } 299 300 ret = _krb5_krb_create_ticket(context, 301 0, 302 name, 303 inst, 304 config->v4_realm, 305 addr->sin_addr.s_addr, 306 &session, 307 life, 308 kdc_time, 309 sname, 310 sinst, 311 &skey->key, 312 &ticket); 313 if (ret) { 314 krb5_free_keyblock_contents(context, &session); 315 make_err_reply(context, reply, KFAILURE, 316 "failed to create v4 ticket"); 317 goto out1; 318 } 319 320 ret = _krb5_krb_create_ciph(context, 321 &session, 322 sname, 323 sinst, 324 config->v4_realm, 325 life, 326 server->entry.kvno % 255, 327 &ticket, 328 kdc_time, 329 &ckey->key, 330 &cipher); 331 krb5_free_keyblock_contents(context, &session); 332 krb5_data_free(&ticket); 333 if (ret) { 334 make_err_reply(context, reply, KFAILURE, 335 "Failed to create v4 cipher"); 336 goto out1; 337 } 338 339 ret = _krb5_krb_create_auth_reply(context, 340 name, 341 inst, 342 realm, 343 req_time, 344 0, 345 client->entry.pw_end ? *client->entry.pw_end : 0, 346 client->entry.kvno % 256, 347 &cipher, 348 reply); 349 krb5_data_free(&cipher); 350 351 out1: 352 break; 353 } 354 case AUTH_MSG_APPL_REQUEST: { 355 struct _krb5_krb_auth_data ad; 356 int8_t kvno; 357 int8_t ticket_len; 358 int8_t req_len; 359 krb5_data auth; 360 int32_t address; 361 size_t pos; 362 krb5_principal tgt_princ = NULL; 363 hdb_entry_ex *tgt = NULL; 364 Key *tkey; 365 time_t max_end, actual_end, issue_time; 366 367 memset(&ad, 0, sizeof(ad)); 368 krb5_data_zero(&auth); 369 370 RCHECK(krb5_ret_int8(sp, &kvno), out2); 371 RCHECK(krb5_ret_stringz(sp, &realm), out2); 372 373 ret = krb5_425_conv_principal(context, "krbtgt", realm, 374 config->v4_realm, 375 &tgt_princ); 376 if(ret){ 377 kdc_log(context, config, 0, 378 "Converting krbtgt principal (krb4): %s", 379 krb5_get_err_text(context, ret)); 380 make_err_reply(context, reply, KFAILURE, 381 "Failed to convert v4 principal (krbtgt)"); 382 goto out2; 383 } 384 385 ret = _kdc_db_fetch(context, config, tgt_princ, 386 HDB_F_GET_KRBTGT, NULL, &tgt); 387 if(ret){ 388 char *s; 389 s = kdc_log_msg(context, config, 0, "Ticket-granting ticket not " 390 "found in database (krb4): krbtgt.%s@%s: %s", 391 realm, config->v4_realm, 392 krb5_get_err_text(context, ret)); 393 make_err_reply(context, reply, KFAILURE, s); 394 free(s); 395 goto out2; 396 } 397 398 if(tgt->entry.kvno % 256 != kvno){ 399 kdc_log(context, config, 0, 400 "tgs-req (krb4) with old kvno %d (current %d) for " 401 "krbtgt.%s@%s", kvno, tgt->entry.kvno % 256, 402 realm, config->v4_realm); 403 make_err_reply(context, reply, KRB4ET_KDC_AUTH_EXP, 404 "old krbtgt kvno used"); 405 goto out2; 406 } 407 408 ret = _kdc_get_des_key(context, tgt, TRUE, FALSE, &tkey); 409 if(ret){ 410 kdc_log(context, config, 0, 411 "no suitable DES key for krbtgt (krb4)"); 412 make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, 413 "no suitable DES key for krbtgt"); 414 goto out2; 415 } 416 417 RCHECK(krb5_ret_int8(sp, &ticket_len), out2); 418 RCHECK(krb5_ret_int8(sp, &req_len), out2); 419 420 pos = krb5_storage_seek(sp, ticket_len + req_len, SEEK_CUR); 421 422 auth.data = buf; 423 auth.length = pos; 424 425 if (config->check_ticket_addresses) 426 address = addr->sin_addr.s_addr; 427 else 428 address = 0; 429 430 ret = _krb5_krb_rd_req(context, &auth, "krbtgt", realm, 431 config->v4_realm, 432 address, &tkey->key, &ad); 433 if(ret){ 434 kdc_log(context, config, 0, "krb_rd_req: %d", ret); 435 make_err_reply(context, reply, ret, "failed to parse request"); 436 goto out2; 437 } 438 439 RCHECK(krb5_ret_int32(sp, &req_time), out2); 440 if(lsb) 441 req_time = swap32(req_time); 442 RCHECK(krb5_ret_uint8(sp, &life), out2); 443 RCHECK(krb5_ret_stringz(sp, &sname), out2); 444 RCHECK(krb5_ret_stringz(sp, &sinst), out2); 445 snprintf (server_name, sizeof(server_name), 446 "%s.%s@%s", 447 sname, sinst, config->v4_realm); 448 snprintf (client_name, sizeof(client_name), 449 "%s.%s@%s", 450 ad.pname, ad.pinst, ad.prealm); 451 452 kdc_log(context, config, 0, "TGS-REQ (krb4) %s from %s for %s", 453 client_name, from, server_name); 454 455 if(strcmp(ad.prealm, realm)){ 456 kdc_log(context, config, 0, 457 "Can't hop realms (krb4) %s -> %s", realm, ad.prealm); 458 make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, 459 "Can't hop realms"); 460 goto out2; 461 } 462 463 if (!config->enable_v4_cross_realm && strcmp(realm, config->v4_realm) != 0) { 464 kdc_log(context, config, 0, 465 "krb4 Cross-realm %s -> %s disabled", 466 realm, config->v4_realm); 467 make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, 468 "Can't hop realms"); 469 goto out2; 470 } 471 472 if(strcmp(sname, "changepw") == 0){ 473 kdc_log(context, config, 0, 474 "Bad request for changepw ticket (krb4)"); 475 make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, 476 "Can't authorize password change based on TGT"); 477 goto out2; 478 } 479 480 ret = _kdc_db_fetch4(context, config, ad.pname, ad.pinst, ad.prealm, 481 HDB_F_GET_CLIENT, &client); 482 if(ret && ret != HDB_ERR_NOENTRY) { 483 char *s; 484 s = kdc_log_msg(context, config, 0, 485 "Client not found in database: (krb4) %s: %s", 486 client_name, krb5_get_err_text(context, ret)); 487 make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, s); 488 free(s); 489 goto out2; 490 } 491 if (client == NULL && strcmp(ad.prealm, config->v4_realm) == 0) { 492 char *s; 493 s = kdc_log_msg(context, config, 0, 494 "Local client not found in database: (krb4) " 495 "%s", client_name); 496 make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, s); 497 free(s); 498 goto out2; 499 } 500 501 ret = _kdc_db_fetch4(context, config, sname, sinst, config->v4_realm, 502 HDB_F_GET_SERVER, &server); 503 if(ret){ 504 char *s; 505 s = kdc_log_msg(context, config, 0, 506 "Server not found in database (krb4): %s: %s", 507 server_name, krb5_get_err_text(context, ret)); 508 make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, s); 509 free(s); 510 goto out2; 511 } 512 513 ret = _kdc_check_flags (context, config, 514 client, client_name, 515 server, server_name, 516 FALSE); 517 if (ret) { 518 make_err_reply(context, reply, KRB4ET_KDC_NAME_EXP, 519 "operation not allowed"); 520 goto out2; 521 } 522 523 ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey); 524 if(ret){ 525 kdc_log(context, config, 0, 526 "no suitable DES key for server (krb4)"); 527 make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, 528 "no suitable DES key for server"); 529 goto out2; 530 } 531 532 max_end = _krb5_krb_life_to_time(ad.time_sec, ad.life); 533 max_end = min(max_end, _krb5_krb_life_to_time(kdc_time, life)); 534 if(server->entry.max_life) 535 max_end = min(max_end, kdc_time + *server->entry.max_life); 536 if(client && client->entry.max_life) 537 max_end = min(max_end, kdc_time + *client->entry.max_life); 538 life = min(life, krb_time_to_life(kdc_time, max_end)); 539 540 issue_time = kdc_time; 541 actual_end = _krb5_krb_life_to_time(issue_time, life); 542 while (actual_end > max_end && life > 1) { 543 /* move them into the next earlier lifetime bracket */ 544 life--; 545 actual_end = _krb5_krb_life_to_time(issue_time, life); 546 } 547 if (actual_end > max_end) { 548 /* if life <= 1 and it's still too long, backdate the ticket */ 549 issue_time -= actual_end - max_end; 550 } 551 552 { 553 krb5_data ticket, cipher; 554 krb5_keyblock session; 555 556 krb5_data_zero(&ticket); 557 krb5_data_zero(&cipher); 558 559 ret = krb5_generate_random_keyblock(context, 560 ETYPE_DES_PCBC_NONE, 561 &session); 562 if (ret) { 563 make_err_reply(context, reply, KFAILURE, 564 "Not enough random i KDC"); 565 goto out2; 566 } 567 568 ret = _krb5_krb_create_ticket(context, 569 0, 570 ad.pname, 571 ad.pinst, 572 ad.prealm, 573 addr->sin_addr.s_addr, 574 &session, 575 life, 576 issue_time, 577 sname, 578 sinst, 579 &skey->key, 580 &ticket); 581 if (ret) { 582 krb5_free_keyblock_contents(context, &session); 583 make_err_reply(context, reply, KFAILURE, 584 "failed to create v4 ticket"); 585 goto out2; 586 } 587 588 ret = _krb5_krb_create_ciph(context, 589 &session, 590 sname, 591 sinst, 592 config->v4_realm, 593 life, 594 server->entry.kvno % 255, 595 &ticket, 596 issue_time, 597 &ad.session, 598 &cipher); 599 krb5_free_keyblock_contents(context, &session); 600 if (ret) { 601 make_err_reply(context, reply, KFAILURE, 602 "failed to create v4 cipher"); 603 goto out2; 604 } 605 606 ret = _krb5_krb_create_auth_reply(context, 607 ad.pname, 608 ad.pinst, 609 ad.prealm, 610 req_time, 611 0, 612 0, 613 0, 614 &cipher, 615 reply); 616 krb5_data_free(&cipher); 617 } 618 out2: 619 _krb5_krb_free_auth_data(context, &ad); 620 if(tgt_princ) 621 krb5_free_principal(context, tgt_princ); 622 if(tgt) 623 _kdc_free_ent(context, tgt); 624 break; 625 } 626 case AUTH_MSG_ERR_REPLY: 627 break; 628 default: 629 kdc_log(context, config, 0, "Unknown message type (krb4): %d from %s", 630 msg_type, from); 631 632 make_err_reply(context, reply, KFAILURE, "Unknown message type"); 633 } 634 out: 635 if(name) 636 free(name); 637 if(inst) 638 free(inst); 639 if(realm) 640 free(realm); 641 if(sname) 642 free(sname); 643 if(sinst) 644 free(sinst); 645 if(client) 646 _kdc_free_ent(context, client); 647 if(server) 648 _kdc_free_ent(context, server); 649 krb5_storage_free(sp); 650 return 0; 651} 652 653krb5_error_code 654_kdc_encode_v4_ticket(krb5_context context, 655 krb5_kdc_configuration *config, 656 void *buf, size_t len, const EncTicketPart *et, 657 const PrincipalName *service, size_t *size) 658{ 659 krb5_storage *sp; 660 krb5_error_code ret; 661 char name[40], inst[40], realm[40]; 662 char sname[40], sinst[40]; 663 664 { 665 krb5_principal princ; 666 _krb5_principalname2krb5_principal(context, 667 &princ, 668 *service, 669 et->crealm); 670 ret = krb5_524_conv_principal(context, 671 princ, 672 sname, 673 sinst, 674 realm); 675 krb5_free_principal(context, princ); 676 if(ret) 677 return ret; 678 679 _krb5_principalname2krb5_principal(context, 680 &princ, 681 et->cname, 682 et->crealm); 683 684 ret = krb5_524_conv_principal(context, 685 princ, 686 name, 687 inst, 688 realm); 689 krb5_free_principal(context, princ); 690 } 691 if(ret) 692 return ret; 693 694 sp = krb5_storage_emem(); 695 696 krb5_store_int8(sp, 0); /* flags */ 697 krb5_store_stringz(sp, name); 698 krb5_store_stringz(sp, inst); 699 krb5_store_stringz(sp, realm); 700 { 701 unsigned char tmp[4] = { 0, 0, 0, 0 }; 702 int i; 703 if(et->caddr){ 704 for(i = 0; i < et->caddr->len; i++) 705 if(et->caddr->val[i].addr_type == AF_INET && 706 et->caddr->val[i].address.length == 4){ 707 memcpy(tmp, et->caddr->val[i].address.data, 4); 708 break; 709 } 710 } 711 krb5_storage_write(sp, tmp, sizeof(tmp)); 712 } 713 714 if((et->key.keytype != ETYPE_DES_CBC_MD5 && 715 et->key.keytype != ETYPE_DES_CBC_MD4 && 716 et->key.keytype != ETYPE_DES_CBC_CRC) || 717 et->key.keyvalue.length != 8) 718 return -1; 719 krb5_storage_write(sp, et->key.keyvalue.data, 8); 720 721 { 722 time_t start = et->starttime ? *et->starttime : et->authtime; 723 krb5_store_int8(sp, krb_time_to_life(start, et->endtime)); 724 krb5_store_int32(sp, start); 725 } 726 727 krb5_store_stringz(sp, sname); 728 krb5_store_stringz(sp, sinst); 729 730 { 731 krb5_data data; 732 krb5_storage_to_data(sp, &data); 733 krb5_storage_free(sp); 734 *size = (data.length + 7) & ~7; /* pad to 8 bytes */ 735 if(*size > len) 736 return -1; 737 memset((unsigned char*)buf - *size + 1, 0, *size); 738 memcpy((unsigned char*)buf - *size + 1, data.data, data.length); 739 krb5_data_free(&data); 740 } 741 return 0; 742} 743 744krb5_error_code 745_kdc_get_des_key(krb5_context context, 746 hdb_entry_ex *principal, krb5_boolean is_server, 747 krb5_boolean prefer_afs_key, Key **ret_key) 748{ 749 Key *v5_key = NULL, *v4_key = NULL, *afs_key = NULL, *server_key = NULL; 750 int i; 751 krb5_enctype etypes[] = { ETYPE_DES_CBC_MD5, 752 ETYPE_DES_CBC_MD4, 753 ETYPE_DES_CBC_CRC }; 754 755 for(i = 0; 756 i < sizeof(etypes)/sizeof(etypes[0]) 757 && (v5_key == NULL || v4_key == NULL || 758 afs_key == NULL || server_key == NULL); 759 ++i) { 760 Key *key = NULL; 761 while(hdb_next_enctype2key(context, &principal->entry, etypes[i], &key) == 0) { 762 if(key->salt == NULL) { 763 if(v5_key == NULL) 764 v5_key = key; 765 } else if(key->salt->type == hdb_pw_salt && 766 key->salt->salt.length == 0) { 767 if(v4_key == NULL) 768 v4_key = key; 769 } else if(key->salt->type == hdb_afs3_salt) { 770 if(afs_key == NULL) 771 afs_key = key; 772 } else if(server_key == NULL) 773 server_key = key; 774 } 775 } 776 777 if(prefer_afs_key) { 778 if(afs_key) 779 *ret_key = afs_key; 780 else if(v4_key) 781 *ret_key = v4_key; 782 else if(v5_key) 783 *ret_key = v5_key; 784 else if(is_server && server_key) 785 *ret_key = server_key; 786 else 787 return KRB4ET_KDC_NULL_KEY; 788 } else { 789 if(v4_key) 790 *ret_key = v4_key; 791 else if(afs_key) 792 *ret_key = afs_key; 793 else if(v5_key) 794 *ret_key = v5_key; 795 else if(is_server && server_key) 796 *ret_key = server_key; 797 else 798 return KRB4ET_KDC_NULL_KEY; 799 } 800 801 if((*ret_key)->key.keyvalue.length == 0) 802 return KRB4ET_KDC_NULL_KEY; 803 return 0; 804} 805 806