1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * kdc/main.c 10 * 11 * Copyright 1990,2001 by the Massachusetts Institute of Technology. 12 * 13 * Export of this software from the United States of America may 14 * require a specific license from the United States Government. 15 * It is the responsibility of any person or organization contemplating 16 * export to obtain such a license before exporting. 17 * 18 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 19 * distribute this software and its documentation for any purpose and 20 * without fee is hereby granted, provided that the above copyright 21 * notice appear in all copies and that both that copyright notice and 22 * this permission notice appear in supporting documentation, and that 23 * the name of M.I.T. not be used in advertising or publicity pertaining 24 * to distribution of the software without specific, written prior 25 * permission. Furthermore if you modify this software you must label 26 * your software as modified software and not distribute it in such a 27 * fashion that it might be confused with the original M.I.T. software. 28 * M.I.T. makes no representations about the suitability of 29 * this software for any purpose. It is provided "as is" without express 30 * or implied warranty. 31 * 32 * 33 * Main procedure body for the KDC server process. 34 */ 35 36 #include <stdio.h> 37 #include <syslog.h> 38 #include <signal.h> 39 #include <errno.h> 40 #include <netdb.h> 41 42 #include "k5-int.h" 43 #include "com_err.h" 44 #include "adm.h" 45 #include "adm_proto.h" 46 #include "kdc_util.h" 47 #include "extern.h" 48 #include "kdc5_err.h" 49 #include <libintl.h> 50 #include <locale.h> 51 52 #ifdef HAVE_NETINET_IN_H 53 #include <netinet/in.h> 54 #endif 55 56 kdc_realm_t *find_realm_data PROTOTYPE((char *, krb5_ui_4)); 57 58 void usage PROTOTYPE((char *)); 59 60 krb5_sigtype request_exit PROTOTYPE((int)); 61 krb5_sigtype request_hup PROTOTYPE((int)); 62 63 void setup_signal_handlers PROTOTYPE((void)); 64 65 krb5_error_code setup_sam PROTOTYPE((void)); 66 67 void initialize_realms PROTOTYPE((krb5_context, int, char **)); 68 69 void finish_realms PROTOTYPE((char *)); 70 71 static int nofork = 0; 72 static int rkey_init_done = 0; 73 74 /* Solaris Kerberos: global here that other functions access */ 75 int max_tcp_data_connections; 76 77 #ifdef POSIX_SIGNALS 78 static struct sigaction s_action; 79 #endif /* POSIX_SIGNALS */ 80 81 #define KRB5_KDC_MAX_REALMS 32 82 83 /* 84 * Find the realm entry for a given realm. 85 */ 86 kdc_realm_t * 87 find_realm_data(rname, rsize) 88 char *rname; 89 krb5_ui_4 rsize; 90 { 91 int i; 92 for (i=0; i<kdc_numrealms; i++) { 93 if ((rsize == strlen(kdc_realmlist[i]->realm_name)) && 94 !strncmp(rname, kdc_realmlist[i]->realm_name, rsize)) 95 return(kdc_realmlist[i]); 96 } 97 return((kdc_realm_t *) NULL); 98 } 99 100 krb5_error_code 101 setup_server_realm(sprinc) 102 krb5_principal sprinc; 103 { 104 krb5_error_code kret; 105 kdc_realm_t *newrealm; 106 107 kret = 0; 108 if (kdc_numrealms > 1) { 109 if (!(newrealm = find_realm_data(sprinc->realm.data, 110 (krb5_ui_4) sprinc->realm.length))) 111 kret = ENOENT; 112 else 113 kdc_active_realm = newrealm; 114 } 115 else 116 kdc_active_realm = kdc_realmlist[0]; 117 return(kret); 118 } 119 120 static void 121 finish_realm(rdp) 122 kdc_realm_t *rdp; 123 { 124 if (rdp->realm_dbname) 125 free(rdp->realm_dbname); 126 if (rdp->realm_mpname) 127 free(rdp->realm_mpname); 128 if (rdp->realm_stash) 129 free(rdp->realm_stash); 130 if (rdp->realm_ports) 131 free(rdp->realm_ports); 132 if (rdp->realm_tcp_ports) 133 free(rdp->realm_tcp_ports); 134 if (rdp->realm_kstypes) 135 free(rdp->realm_kstypes); 136 if (rdp->realm_keytab) 137 krb5_kt_close(rdp->realm_context, rdp->realm_keytab); 138 if (rdp->realm_context) { 139 if (rdp->realm_mprinc) 140 krb5_free_principal(rdp->realm_context, rdp->realm_mprinc); 141 if (rdp->realm_mkey.length && rdp->realm_mkey.contents) { 142 memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length); 143 free(rdp->realm_mkey.contents); 144 } 145 if (rdp->realm_tgskey.length && rdp->realm_tgskey.contents) { 146 memset(rdp->realm_tgskey.contents, 0, rdp->realm_tgskey.length); 147 free(rdp->realm_tgskey.contents); 148 } 149 krb5_db_fini(rdp->realm_context); 150 if (rdp->realm_tgsprinc) 151 krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc); 152 krb5_free_context(rdp->realm_context); 153 } 154 free(rdp); 155 } 156 157 /* 158 * Initialize a realm control structure from the alternate profile or from 159 * the specified defaults. 160 * 161 * After we're complete here, the essence of the realm is embodied in the 162 * realm data and we should be all set to begin operation for that realm. 163 */ 164 static krb5_error_code 165 init_realm(progname, rdp, realm, def_dbname, def_mpname, 166 def_enctype, def_udp_ports, def_tcp_ports, def_manual) 167 char *progname; 168 kdc_realm_t *rdp; 169 char *realm; 170 char *def_dbname; 171 char *def_mpname; 172 krb5_enctype def_enctype; 173 char *def_udp_ports; 174 char *def_tcp_ports; 175 krb5_boolean def_manual; 176 { 177 krb5_error_code kret; 178 krb5_boolean manual; 179 krb5_db_entry db_entry; 180 int num2get; 181 krb5_boolean more; 182 krb5_boolean db_inited; 183 krb5_realm_params *rparams; 184 krb5_key_data *kdata; 185 krb5_key_salt_tuple *kslist; 186 krb5_int32 nkslist; 187 int i; 188 krb5_deltat now, krb5_kdb_max_time; 189 190 db_inited = 0; 191 memset((char *) rdp, 0, sizeof(kdc_realm_t)); 192 if (!realm) { 193 kret = EINVAL; 194 goto whoops; 195 } 196 197 rdp->realm_name = realm; 198 kret = krb5_init_context(&rdp->realm_context); 199 if (kret) { 200 com_err(progname, kret, gettext("while getting context for realm %s"), 201 realm); 202 goto whoops; 203 } 204 205 kret = krb5_read_realm_params(rdp->realm_context, rdp->realm_name, 206 (char *) NULL, (char *) NULL, &rparams); 207 if (kret) { 208 com_err(progname, kret, gettext("while reading realm parameters")); 209 goto whoops; 210 } 211 212 /* Handle profile file name */ 213 if (rparams && rparams->realm_profile) 214 rdp->realm_profile = strdup(rparams->realm_profile); 215 216 /* Handle database name */ 217 if (rparams && rparams->realm_dbname) 218 rdp->realm_dbname = strdup(rparams->realm_dbname); 219 else 220 rdp->realm_dbname = (def_dbname) ? strdup(def_dbname) : 221 strdup(DEFAULT_KDB_FILE); 222 223 /* Handle master key name */ 224 if (rparams && rparams->realm_mkey_name) 225 rdp->realm_mpname = strdup(rparams->realm_mkey_name); 226 else 227 rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) : 228 strdup(KRB5_KDB_M_NAME); 229 230 /* Handle KDC ports */ 231 if (rparams && rparams->realm_kdc_ports) 232 rdp->realm_ports = strdup(rparams->realm_kdc_ports); 233 else 234 rdp->realm_ports = strdup(def_udp_ports); 235 if (rparams && rparams->realm_kdc_tcp_ports) 236 rdp->realm_tcp_ports = strdup(rparams->realm_kdc_tcp_ports); 237 else 238 rdp->realm_tcp_ports = strdup(def_tcp_ports); 239 240 /* Handle stash file */ 241 if (rparams && rparams->realm_stash_file) { 242 rdp->realm_stash = strdup(rparams->realm_stash_file); 243 manual = FALSE; 244 } else 245 manual = def_manual; 246 247 /* Handle master key type */ 248 if (rparams && rparams->realm_enctype_valid) 249 rdp->realm_mkey.enctype = (krb5_enctype) rparams->realm_enctype; 250 else 251 rdp->realm_mkey.enctype = manual ? def_enctype : ENCTYPE_UNKNOWN; 252 if ((kret = krb5_timeofday(rdp->realm_context, &now))) { 253 com_err(progname, kret, gettext("while getting timeofday")); 254 goto whoops; 255 } 256 257 /* Handle ticket maximum life */ 258 if (rparams && rparams->realm_max_life_valid) 259 rdp->realm_maxlife = rparams->realm_max_life; 260 else 261 rdp->realm_maxlife = KRB5_KDB_EXPIRATION - now - 3600; 262 263 /* Handle ticket renewable maximum life */ 264 if (rparams && rparams->realm_max_rlife_valid) 265 rdp->realm_maxrlife = rparams->realm_max_rlife; 266 else 267 rdp->realm_maxrlife = KRB5_KDB_EXPIRATION - now - 3600; 268 269 /* Handle key/salt list */ 270 if (rparams && rparams->realm_num_keysalts) { 271 rdp->realm_kstypes = rparams->realm_keysalts; 272 rdp->realm_nkstypes = rparams->realm_num_keysalts; 273 rparams->realm_keysalts = NULL; 274 rparams->realm_num_keysalts = 0; 275 kslist = (krb5_key_salt_tuple *) rdp->realm_kstypes; 276 nkslist = rdp->realm_nkstypes; 277 } else { 278 /* 279 * XXX Initialize default key/salt list. 280 */ 281 if ((kslist = (krb5_key_salt_tuple *) 282 malloc(sizeof(krb5_key_salt_tuple)))) { 283 kslist->ks_enctype = ENCTYPE_DES_CBC_CRC; 284 kslist->ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 285 rdp->realm_kstypes = kslist; 286 rdp->realm_nkstypes = 1; 287 nkslist = 1; 288 } 289 else { 290 com_err(progname, ENOMEM, 291 gettext("while setting up key/salt list for realm %s"), 292 realm); 293 exit(1); 294 } 295 } 296 297 if (rparams) 298 krb5_free_realm_params(rdp->realm_context, rparams); 299 300 /* 301 * We've got our parameters, now go and setup our realm context. 302 */ 303 304 /* Set the default realm of this context */ 305 if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) { 306 com_err(progname, kret, gettext("while setting default realm to %s"), 307 realm); 308 goto whoops; 309 } 310 311 /* Assemble and parse the master key name */ 312 if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname, 313 rdp->realm_name, (char **) NULL, 314 &rdp->realm_mprinc))) { 315 com_err(progname, kret, 316 gettext("while setting up master key name %s for realm %s"), 317 rdp->realm_mpname, realm); 318 goto whoops; 319 } 320 321 /* 322 * Get the master key. 323 */ 324 if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc, 325 rdp->realm_mkey.enctype, manual, 326 FALSE, rdp->realm_stash, 327 0, &rdp->realm_mkey))) { 328 com_err(progname, kret, 329 gettext("while fetching master key %s for realm %s"), 330 rdp->realm_mpname, realm); 331 goto whoops; 332 } 333 334 /* Set and open the database. */ 335 if (rdp->realm_dbname && 336 (kret = krb5_db_set_name(rdp->realm_context, rdp->realm_dbname))) { 337 com_err(progname, kret, 338 gettext("while setting database name to %s for realm %s"), 339 rdp->realm_dbname, realm); 340 goto whoops; 341 } 342 if ((kret = krb5_db_init(rdp->realm_context))) { 343 com_err(progname, kret, 344 gettext("while initializing database "), 345 gettext("for realm %s"), realm); 346 goto whoops; 347 } else 348 db_inited = 1; 349 350 /* Verify the master key */ 351 if ((kret = krb5_db_verify_master_key(rdp->realm_context, 352 rdp->realm_mprinc, 353 &rdp->realm_mkey))) { 354 com_err(progname, kret, 355 gettext("while verifying master key for realm %s"), 356 realm); 357 goto whoops; 358 } 359 360 /* Fetch the master key and get its version number */ 361 num2get = 1; 362 kret = krb5_db_get_principal(rdp->realm_context, rdp->realm_mprinc, 363 &db_entry, &num2get, &more); 364 if (!kret) { 365 if (num2get != 1) 366 kret = KRB5_KDB_NOMASTERKEY; 367 else { 368 if (more) { 369 krb5_db_free_principal(rdp->realm_context, 370 &db_entry, 371 num2get); 372 kret = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE; 373 } 374 } 375 } 376 if (kret) { 377 com_err(progname, kret, 378 gettext("while fetching master entry for realm %s"), 379 realm); 380 goto whoops; 381 } 382 383 /* 384 * Get the most recent master key. Search the key list in 385 * the order specified by the key/salt list. 386 */ 387 kdata = (krb5_key_data *) NULL; 388 for (i=0; i<nkslist; i++) { 389 if (!(kret = krb5_dbe_find_enctype(rdp->realm_context, 390 &db_entry, 391 kslist[i].ks_enctype, 392 -1, 393 -1, 394 &kdata))) 395 break; 396 } 397 if (!kdata) { 398 com_err(progname, kret, 399 gettext("while finding master key for realm %s"), 400 realm); 401 goto whoops; 402 } 403 rdp->realm_mkvno = kdata->key_data_kvno; 404 krb5_db_free_principal(rdp->realm_context, &db_entry, num2get); 405 406 if ((kret = krb5_db_set_mkey(rdp->realm_context, &rdp->realm_mkey))) { 407 com_err(progname, kret, 408 gettext("while processing master key for realm %s"), 409 realm); 410 goto whoops; 411 } 412 413 /* Set up the keytab */ 414 if ((kret = krb5_ktkdb_resolve(rdp->realm_context, 415 NULL, 416 &rdp->realm_keytab))) { 417 com_err(progname, kret, 418 gettext("while resolving kdb keytab for realm %s"), 419 realm); 420 goto whoops; 421 } 422 423 /* Preformat the TGS name */ 424 if ((kret = krb5_build_principal(rdp->realm_context, &rdp->realm_tgsprinc, 425 strlen(realm), realm, KRB5_TGS_NAME, 426 realm, (char *) NULL))) { 427 com_err(progname, kret, 428 gettext("while building TGS name for realm %s"), 429 realm); 430 goto whoops; 431 } 432 433 /* Get the TGS database entry */ 434 num2get = 1; 435 if (!(kret = krb5_db_get_principal(rdp->realm_context, 436 rdp->realm_tgsprinc, 437 &db_entry, 438 &num2get, 439 &more))) { 440 if (num2get != 1) 441 kret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 442 else { 443 if (more) { 444 krb5_db_free_principal(rdp->realm_context, 445 &db_entry, 446 num2get); 447 kret = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE; 448 } 449 } 450 } 451 if (kret) { 452 com_err(progname, kret, 453 gettext("while fetching TGS entry for realm %s"), 454 realm); 455 goto whoops; 456 } 457 /* 458 * Get the most recent TGS key. Search the key list in 459 * the order specified by the key/salt list. 460 */ 461 kdata = (krb5_key_data *) NULL; 462 for (i=0; i<nkslist; i++) { 463 if (!(kret = krb5_dbe_find_enctype(rdp->realm_context, 464 &db_entry, 465 kslist[i].ks_enctype, 466 -1, 467 -1, 468 &kdata))) 469 break; 470 } 471 if (!kdata) { 472 com_err(progname, kret, 473 gettext("while finding TGS key for realm %s"), 474 realm); 475 goto whoops; 476 } 477 if (!(kret = krb5_dbekd_decrypt_key_data(rdp->realm_context, 478 &rdp->realm_mkey, 479 kdata, 480 &rdp->realm_tgskey, NULL))){ 481 rdp->realm_tgskvno = kdata->key_data_kvno; 482 } 483 krb5_db_free_principal(rdp->realm_context, 484 &db_entry, 485 num2get); 486 if (kret) { 487 com_err(progname, kret, 488 gettext("while decrypting TGS key for realm %s"), 489 realm); 490 goto whoops; 491 } 492 493 if (!rkey_init_done) { 494 krb5_timestamp now; 495 krb5_data seed; 496 #ifdef KRB5_KRB4_COMPAT 497 krb5_keyblock temp_key; 498 #endif 499 /* 500 * If all that worked, then initialize the random key 501 * generators. 502 */ 503 504 if ((kret = krb5_timeofday(rdp->realm_context, &now))) 505 goto whoops; 506 seed.length = sizeof(now); 507 seed.data = (char *) &now; 508 if ((kret = krb5_c_random_seed(rdp->realm_context, &seed))) 509 goto whoops; 510 511 seed.length = rdp->realm_mkey.length; 512 seed.data = (char *)rdp->realm_mkey.contents; 513 514 if ((kret = krb5_c_random_seed(rdp->realm_context, &seed))) 515 goto whoops; 516 517 #ifdef KRB5_KRB4_COMPAT 518 if ((kret = krb5_c_make_random_key(rdp->realm_context, 519 ENCTYPE_DES_CBC_CRC, &temp_key))) { 520 com_err(progname, kret, 521 "while initializing V4 random key generator"); 522 goto whoops; 523 } 524 525 (void) des_init_random_number_generator(temp_key.contents); 526 krb5_free_keyblock_contents(rdp->realm_context, &temp_key); 527 #endif 528 rkey_init_done = 1; 529 } 530 whoops: 531 /* 532 * If we choked, then clean up any dirt we may have dropped on the floor. 533 */ 534 if (kret) { 535 finish_realm(rdp); 536 } 537 return(kret); 538 } 539 540 krb5_sigtype 541 request_exit(signo) 542 int signo; 543 { 544 signal_requests_exit = 1; 545 546 #ifdef POSIX_SIGTYPE 547 return; 548 #else 549 return(0); 550 #endif 551 } 552 553 krb5_sigtype 554 request_hup(signo) 555 int signo; 556 { 557 signal_requests_hup = 1; 558 559 #ifdef POSIX_SIGTYPE 560 return; 561 #else 562 return(0); 563 #endif 564 } 565 566 void 567 setup_signal_handlers() 568 { 569 #ifdef POSIX_SIGNALS 570 (void) sigemptyset(&s_action.sa_mask); 571 s_action.sa_flags = 0; 572 s_action.sa_handler = request_exit; 573 (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL); 574 (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL); 575 s_action.sa_handler = request_hup; 576 (void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL); 577 #else /* POSIX_SIGNALS */ 578 signal(SIGINT, request_exit); 579 signal(SIGTERM, request_exit); 580 signal(SIGHUP, request_hup); 581 #endif /* POSIX_SIGNALS */ 582 583 return; 584 } 585 586 krb5_error_code 587 setup_sam() 588 { 589 return krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_MD5, &psr_key); 590 } 591 592 void 593 usage(name) 594 char *name; 595 { 596 fprintf(stderr, gettext("usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-n]\n"), name); 597 return; 598 } 599 600 void 601 initialize_realms(kcontext, argc, argv) 602 krb5_context kcontext; 603 int argc; 604 char **argv; 605 { 606 int c; 607 char *db_name = (char *) NULL; 608 char *mkey_name = (char *) NULL; 609 char *rcname = KDCRCACHE; 610 char *lrealm; 611 krb5_error_code retval; 612 krb5_enctype menctype = ENCTYPE_UNKNOWN; 613 kdc_realm_t *rdatap; 614 krb5_boolean manual = FALSE; 615 char *default_udp_ports = 0; 616 char *default_tcp_ports = 0; 617 krb5_pointer aprof; 618 const char *hierarchy[3]; 619 #ifdef KRB5_KRB4_COMPAT 620 char *v4mode = 0; 621 #endif 622 extern char *optarg; 623 #ifdef ATHENA_DES3_KLUDGE 624 extern struct krb5_keytypes krb5_enctypes_list[]; 625 extern int krb5_enctypes_length; 626 #endif 627 628 if (!krb5_aprof_init(DEFAULT_KDC_PROFILE, KDC_PROFILE_ENV, &aprof)) { 629 hierarchy[0] = "kdcdefaults"; 630 hierarchy[1] = "kdc_ports"; 631 hierarchy[2] = (char *) NULL; 632 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_udp_ports)) 633 default_udp_ports = 0; 634 hierarchy[1] = "kdc_tcp_ports"; 635 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_tcp_ports)) 636 default_tcp_ports = 0; 637 hierarchy[1] = "kdc_max_tcp_connections"; 638 if (krb5_aprof_get_int32(aprof, hierarchy, TRUE, 639 &max_tcp_data_connections)) { 640 max_tcp_data_connections = DEFAULT_KDC_TCP_CONNECTIONS; 641 } else if (max_tcp_data_connections < MIN_KDC_TCP_CONNECTIONS) { 642 max_tcp_data_connections = DEFAULT_KDC_TCP_CONNECTIONS; 643 } 644 #ifdef KRB5_KRB4_COMPAT 645 hierarchy[1] = "v4_mode"; 646 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &v4mode)) 647 v4mode = 0; 648 #endif 649 /* aprof_init can return 0 with aprof == NULL */ 650 if (aprof) 651 krb5_aprof_finish(aprof); 652 } 653 if (default_udp_ports == 0) 654 default_udp_ports = strdup(DEFAULT_KDC_UDP_PORTLIST); 655 if (default_tcp_ports == 0) 656 default_tcp_ports = strdup(DEFAULT_KDC_TCP_PORTLIST); 657 /* 658 * Loop through the option list. Each time we encounter a realm name, 659 * use the previously scanned options to fill in for defaults. 660 */ 661 while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:s:n")) != -1) { /* SUNW */ 662 switch(c) { 663 case 'r': /* realm name for db */ 664 if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) { 665 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) { 666 if ((retval = init_realm(argv[0], rdatap, optarg, db_name, 667 mkey_name, menctype, 668 default_udp_ports, 669 default_tcp_ports, manual))) { 670 fprintf(stderr,gettext("%s: cannot initialize realm %s\n"), 671 argv[0], optarg); 672 exit(1); 673 } 674 kdc_realmlist[kdc_numrealms] = rdatap; 675 kdc_numrealms++; 676 } 677 } 678 break; 679 case 'd': /* pathname for db */ 680 db_name = optarg; 681 break; 682 case 'm': /* manual type-in of master key */ 683 manual = TRUE; 684 if (menctype == ENCTYPE_UNKNOWN) 685 menctype = ENCTYPE_DES_CBC_CRC; 686 break; 687 case 'M': /* master key name in DB */ 688 mkey_name = optarg; 689 break; 690 case 'n': 691 nofork++; /* don't detach from terminal */ 692 break; 693 case 'k': /* enctype for master key */ 694 if (krb5_string_to_enctype(optarg, &menctype)) 695 com_err(argv[0], 0, 696 gettext("invalid enctype %s"), optarg); 697 break; 698 case 'R': 699 rcname = optarg; 700 break; 701 case 'p': 702 if (default_udp_ports) 703 free(default_udp_ports); 704 default_udp_ports = strdup(optarg); 705 706 if (default_tcp_ports) 707 free(default_tcp_ports); 708 default_tcp_ports = strdup(optarg); 709 710 break; 711 case '4': 712 #ifdef KRB5_KRB4_COMPAT 713 if (v4mode) 714 free(v4mode); 715 v4mode = strdup(optarg); 716 #endif 717 break; 718 case '3': 719 #ifdef ATHENA_DES3_KLUDGE 720 if (krb5_enctypes_list[krb5_enctypes_length-1].etype 721 != ENCTYPE_LOCAL_DES3_HMAC_SHA1) { 722 fprintf(stderr, 723 "internal inconsistency in enctypes_list" 724 " while disabling\n" 725 "des3-marc-hmac-sha1 enctype\n"); 726 exit(1); 727 } 728 krb5_enctypes_length--; 729 break; 730 #endif 731 case '?': 732 default: 733 usage(argv[0]); 734 exit(1); 735 } 736 } 737 738 #ifdef KRB5_KRB4_COMPAT 739 /* 740 * Setup the v4 mode 741 */ 742 process_v4_mode(argv[0], v4mode); 743 #endif 744 745 /* 746 * Check to see if we processed any realms. 747 */ 748 if (kdc_numrealms == 0) { 749 /* no realm specified, use default realm */ 750 if ((retval = krb5_get_default_realm(kcontext, &lrealm))) { 751 com_err(argv[0], retval, 752 gettext("while attempting to retrieve default realm")); 753 exit(1); 754 } 755 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) { 756 if ((retval = init_realm(argv[0], rdatap, lrealm, db_name, 757 mkey_name, menctype, default_udp_ports, 758 default_tcp_ports, manual))) { 759 fprintf(stderr, 760 gettext("%s: cannot initialize realm %s\n"), 761 argv[0], lrealm); 762 exit(1); 763 } 764 kdc_realmlist[0] = rdatap; 765 kdc_numrealms++; 766 } 767 } 768 769 #ifdef USE_RCACHE 770 /* 771 * Now handle the replay cache. 772 */ 773 if ((retval = kdc_initialize_rcache(kcontext, rcname))) { 774 com_err(argv[0], retval, gettext("while initializing KDC replay cache")); 775 exit(1); 776 } 777 #endif 778 779 /* Ensure that this is set for our first request. */ 780 kdc_active_realm = kdc_realmlist[0]; 781 if (default_udp_ports) 782 free(default_udp_ports); 783 if (default_tcp_ports) 784 free(default_tcp_ports); 785 786 return; 787 } 788 789 void 790 finish_realms(prog) 791 char *prog; 792 { 793 int i; 794 795 for (i = 0; i < kdc_numrealms; i++) { 796 finish_realm(kdc_realmlist[i]); 797 kdc_realmlist[i] = 0; 798 } 799 } 800 801 /* 802 outline: 803 804 process args & setup 805 806 initialize database access (fetch master key, open DB) 807 808 initialize network 809 810 loop: 811 listen for packet 812 813 determine packet type, dispatch to handling routine 814 (AS or TGS (or V4?)) 815 816 reflect response 817 818 exit on signal 819 820 clean up secrets, close db 821 822 shut down network 823 824 exit 825 */ 826 827 int main(argc, argv) 828 int argc; 829 char *argv[]; 830 { 831 krb5_error_code retval; 832 krb5_context kcontext; 833 int *port_list; 834 int errout = 0; 835 836 (void) setlocale(LC_ALL, ""); 837 838 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 839 #define TEXT_DOMAIN "KRB5KDC_TEST" /* Use this only if it weren't */ 840 #endif 841 842 (void) textdomain(TEXT_DOMAIN); 843 844 if (strrchr(argv[0], '/')) 845 argv[0] = strrchr(argv[0], '/')+1; 846 847 if (!(kdc_realmlist = (kdc_realm_t **) malloc(sizeof(kdc_realm_t *) * 848 KRB5_KDC_MAX_REALMS))) { 849 fprintf(stderr, gettext("%s: cannot get memory for realm list\n"), argv[0]); 850 exit(1); 851 } 852 memset((char *) kdc_realmlist, 0, 853 (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS)); 854 port_list = NULL; 855 856 /* 857 * A note about Kerberos contexts: This context, "kcontext", is used 858 * for the KDC operations, i.e. setup, network connection and error 859 * reporting. The per-realm operations use the "realm_context" 860 * associated with each realm. 861 */ 862 retval = krb5_init_context(&kcontext); 863 if (retval) { 864 com_err(argv[0], retval, gettext("while initializing krb5")); 865 exit(1); 866 } 867 krb5_klog_init(kcontext, "kdc", argv[0], 1); 868 /* initialize_kdc5_error_table(); SUNWresync121 XXX */ 869 870 /* 871 * Scan through the argument list 872 */ 873 initialize_realms(kcontext, argc, argv); 874 875 setup_signal_handlers(); 876 877 if (retval = setup_sam()) { 878 com_err(argv[0], retval, gettext("while initializing SAM")); 879 finish_realms(argv[0]); 880 return 1; 881 } 882 883 if ((retval = setup_network(argv[0]))) { 884 com_err(argv[0], retval, gettext("while initializing network")); 885 finish_realms(argv[0]); 886 return 1; 887 } 888 if (!nofork && daemon(0, 0)) { 889 com_err(argv[0], errno, gettext("while detaching from tty")); 890 finish_realms(argv[0]); 891 return 1; 892 } 893 if (retval = krb5_klog_syslog(LOG_INFO, "commencing operation")) { 894 com_err(argv[0], retval, gettext("while logging message")); 895 errout++; 896 }; 897 898 if ((retval = listen_and_process(argv[0]))) { 899 com_err(argv[0], retval, gettext("while processing network requests")); 900 errout++; 901 } 902 if ((retval = closedown_network(argv[0]))) { 903 com_err(argv[0], retval, gettext("while shutting down network")); 904 errout++; 905 } 906 krb5_klog_syslog(LOG_INFO, "shutting down"); 907 krb5_klog_close(kdc_context); 908 finish_realms(argv[0]); 909 krb5_free_context(kcontext); 910 return errout; 911 } 912