1 /* 2 * Copyright 2006 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 #ifdef KRB5_KRB4_COMPAT 57 #include <des.h> 58 #endif 59 60 #if defined(NEED_DAEMON_PROTO) 61 extern int daemon(int, int); 62 #endif 63 64 void usage (char *); 65 66 krb5_sigtype request_exit (int); 67 krb5_sigtype request_hup (int); 68 69 void setup_signal_handlers (void); 70 71 krb5_error_code setup_sam (void); 72 73 void initialize_realms (krb5_context, int, char **); 74 75 void finish_realms (char *); 76 77 static int nofork = 0; 78 static int rkey_init_done = 0; 79 80 /* Solaris Kerberos: global here that other functions access */ 81 int max_tcp_data_connections; 82 83 #ifdef POSIX_SIGNALS 84 static struct sigaction s_action; 85 #endif /* POSIX_SIGNALS */ 86 87 #define KRB5_KDC_MAX_REALMS 32 88 89 /* 90 * Find the realm entry for a given realm. 91 */ 92 kdc_realm_t * 93 find_realm_data(char *rname, krb5_ui_4 rsize) 94 { 95 int i; 96 for (i=0; i<kdc_numrealms; i++) { 97 if ((rsize == strlen(kdc_realmlist[i]->realm_name)) && 98 !strncmp(rname, kdc_realmlist[i]->realm_name, rsize)) 99 return(kdc_realmlist[i]); 100 } 101 return((kdc_realm_t *) NULL); 102 } 103 104 krb5_error_code 105 setup_server_realm(krb5_principal sprinc) 106 { 107 krb5_error_code kret; 108 kdc_realm_t *newrealm; 109 110 kret = 0; 111 if (kdc_numrealms > 1) { 112 if (!(newrealm = find_realm_data(sprinc->realm.data, 113 (krb5_ui_4) sprinc->realm.length))) 114 kret = ENOENT; 115 else 116 kdc_active_realm = newrealm; 117 } 118 else 119 kdc_active_realm = kdc_realmlist[0]; 120 return(kret); 121 } 122 123 static void 124 finish_realm(kdc_realm_t *rdp) 125 { 126 if (rdp->realm_dbname) 127 free(rdp->realm_dbname); 128 if (rdp->realm_mpname) 129 free(rdp->realm_mpname); 130 if (rdp->realm_stash) 131 free(rdp->realm_stash); 132 if (rdp->realm_ports) 133 free(rdp->realm_ports); 134 if (rdp->realm_tcp_ports) 135 free(rdp->realm_tcp_ports); 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 krb5_db_fini(rdp->realm_context); 146 if (rdp->realm_tgsprinc) 147 krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc); 148 krb5_free_context(rdp->realm_context); 149 } 150 memset((char *) rdp, 0, sizeof(*rdp)); 151 free(rdp); 152 } 153 154 /* 155 * Initialize a realm control structure from the alternate profile or from 156 * the specified defaults. 157 * 158 * After we're complete here, the essence of the realm is embodied in the 159 * realm data and we should be all set to begin operation for that realm. 160 */ 161 static krb5_error_code 162 init_realm(char *progname, kdc_realm_t *rdp, char *realm, char *def_dbname, 163 char *def_mpname, krb5_enctype def_enctype, char *def_udp_ports, 164 char *def_tcp_ports, krb5_boolean def_manual) 165 { 166 krb5_error_code kret; 167 krb5_boolean manual; 168 krb5_realm_params *rparams; 169 170 memset((char *) rdp, 0, sizeof(kdc_realm_t)); 171 if (!realm) { 172 kret = EINVAL; 173 goto whoops; 174 } 175 176 rdp->realm_name = realm; 177 kret = krb5_init_context(&rdp->realm_context); 178 if (kret) { 179 com_err(progname, kret, gettext("while getting context for realm %s"), 180 realm); 181 goto whoops; 182 } 183 184 kret = krb5_read_realm_params(rdp->realm_context, rdp->realm_name, 185 (char *) NULL, (char *) NULL, &rparams); 186 if (kret) { 187 com_err(progname, kret, gettext("while reading realm parameters")); 188 goto whoops; 189 } 190 191 /* Handle profile file name */ 192 if (rparams && rparams->realm_profile) 193 rdp->realm_profile = strdup(rparams->realm_profile); 194 195 /* Handle database name */ 196 if (rparams && rparams->realm_dbname) 197 rdp->realm_dbname = strdup(rparams->realm_dbname); 198 else 199 rdp->realm_dbname = (def_dbname) ? strdup(def_dbname) : 200 strdup(DEFAULT_KDB_FILE); 201 202 /* Handle master key name */ 203 if (rparams && rparams->realm_mkey_name) 204 rdp->realm_mpname = strdup(rparams->realm_mkey_name); 205 else 206 rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) : 207 strdup(KRB5_KDB_M_NAME); 208 209 /* Handle KDC ports */ 210 if (rparams && rparams->realm_kdc_ports) 211 rdp->realm_ports = strdup(rparams->realm_kdc_ports); 212 else 213 rdp->realm_ports = strdup(def_udp_ports); 214 if (rparams && rparams->realm_kdc_tcp_ports) 215 rdp->realm_tcp_ports = strdup(rparams->realm_kdc_tcp_ports); 216 else 217 rdp->realm_tcp_ports = strdup(def_tcp_ports); 218 219 /* Handle stash file */ 220 if (rparams && rparams->realm_stash_file) { 221 rdp->realm_stash = strdup(rparams->realm_stash_file); 222 manual = FALSE; 223 } else 224 manual = def_manual; 225 226 /* Handle master key type */ 227 if (rparams && rparams->realm_enctype_valid) 228 rdp->realm_mkey.enctype = (krb5_enctype) rparams->realm_enctype; 229 else 230 rdp->realm_mkey.enctype = manual ? def_enctype : ENCTYPE_UNKNOWN; 231 232 /* Handle reject-bad-transit flag */ 233 if (rparams && rparams->realm_reject_bad_transit_valid) 234 rdp->realm_reject_bad_transit = rparams->realm_reject_bad_transit; 235 else 236 rdp->realm_reject_bad_transit = 1; 237 238 /* Handle ticket maximum life */ 239 rdp->realm_maxlife = (rparams && rparams->realm_max_life_valid) ? 240 rparams->realm_max_life : KRB5_KDB_MAX_LIFE; 241 242 /* Handle ticket renewable maximum life */ 243 rdp->realm_maxrlife = (rparams && rparams->realm_max_rlife_valid) ? 244 rparams->realm_max_rlife : KRB5_KDB_MAX_RLIFE; 245 246 if (rparams) 247 krb5_free_realm_params(rdp->realm_context, rparams); 248 249 /* 250 * We've got our parameters, now go and setup our realm context. 251 */ 252 253 /* Set the default realm of this context */ 254 if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) { 255 com_err(progname, kret, gettext("while setting default realm to %s"), 256 realm); 257 goto whoops; 258 } 259 260 /* Assemble and parse the master key name */ 261 if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname, 262 rdp->realm_name, (char **) NULL, 263 &rdp->realm_mprinc))) { 264 com_err(progname, kret, 265 gettext("while setting up master key name %s for realm %s"), 266 rdp->realm_mpname, realm); 267 goto whoops; 268 } 269 270 /* 271 * Get the master key. 272 */ 273 if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc, 274 rdp->realm_mkey.enctype, manual, 275 FALSE, rdp->realm_stash, 276 0, &rdp->realm_mkey))) { 277 com_err(progname, kret, 278 gettext("while fetching master key %s for realm %s"), 279 rdp->realm_mpname, realm); 280 goto whoops; 281 } 282 283 /* Set and open the database. */ 284 if (rdp->realm_dbname && 285 (kret = krb5_db_set_name(rdp->realm_context, rdp->realm_dbname))) { 286 com_err(progname, kret, 287 gettext("while setting database name to %s for realm %s"), 288 rdp->realm_dbname, realm); 289 goto whoops; 290 } 291 if ((kret = krb5_db_init(rdp->realm_context))) { 292 com_err(progname, kret, 293 gettext("while initializing database "), 294 gettext("for realm %s"), realm); 295 goto whoops; 296 } 297 298 /* Verify the master key */ 299 if ((kret = krb5_db_verify_master_key(rdp->realm_context, 300 rdp->realm_mprinc, 301 &rdp->realm_mkey))) { 302 com_err(progname, kret, 303 gettext("while verifying master key for realm %s"), 304 realm); 305 goto whoops; 306 } 307 308 if ((kret = krb5_db_set_mkey(rdp->realm_context, &rdp->realm_mkey))) { 309 com_err(progname, kret, 310 gettext("while processing master key for realm %s"), 311 realm); 312 goto whoops; 313 } 314 315 /* Set up the keytab */ 316 if ((kret = krb5_ktkdb_resolve(rdp->realm_context, NULL, 317 &rdp->realm_keytab))) { 318 com_err(progname, kret, 319 gettext("while resolving kdb keytab for realm %s"), 320 realm); 321 goto whoops; 322 } 323 324 /* Preformat the TGS name */ 325 if ((kret = krb5_build_principal(rdp->realm_context, &rdp->realm_tgsprinc, 326 strlen(realm), realm, KRB5_TGS_NAME, 327 realm, (char *) NULL))) { 328 com_err(progname, kret, 329 gettext("while building TGS name for realm %s"), 330 realm); 331 goto whoops; 332 } 333 334 if (!rkey_init_done) { 335 krb5_data seed; 336 #ifdef KRB5_KRB4_COMPAT 337 krb5_keyblock temp_key; 338 #endif 339 /* 340 * If all that worked, then initialize the random key 341 * generators. 342 */ 343 344 seed.length = rdp->realm_mkey.length; 345 seed.data = (char *)rdp->realm_mkey.contents; 346 /* SUNW14resync - XXX */ 347 #if 0 348 if ((kret = krb5_c_random_add_entropy(rdp->realm_context, 349 KRB5_C_RANDSOURCE_TRUSTEDPARTY, &seed))) 350 goto whoops; 351 #endif 352 353 #ifdef KRB5_KRB4_COMPAT 354 if ((kret = krb5_c_make_random_key(rdp->realm_context, 355 ENCTYPE_DES_CBC_CRC, &temp_key))) { 356 com_err(progname, kret, 357 "while initializing V4 random key generator"); 358 goto whoops; 359 } 360 361 (void) des_init_random_number_generator(temp_key.contents); 362 krb5_free_keyblock_contents(rdp->realm_context, &temp_key); 363 #endif 364 rkey_init_done = 1; 365 } 366 whoops: 367 /* 368 * If we choked, then clean up any dirt we may have dropped on the floor. 369 */ 370 if (kret) { 371 372 finish_realm(rdp); 373 } 374 return(kret); 375 } 376 377 krb5_sigtype 378 request_exit(int signo) 379 { 380 signal_requests_exit = 1; 381 382 #ifdef POSIX_SIGTYPE 383 return; 384 #else 385 return(0); 386 #endif 387 } 388 389 krb5_sigtype 390 request_hup(int signo) 391 { 392 signal_requests_hup = 1; 393 394 #ifdef POSIX_SIGTYPE 395 return; 396 #else 397 return(0); 398 #endif 399 } 400 401 void 402 setup_signal_handlers(void) 403 { 404 #ifdef POSIX_SIGNALS 405 (void) sigemptyset(&s_action.sa_mask); 406 s_action.sa_flags = 0; 407 s_action.sa_handler = request_exit; 408 (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL); 409 (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL); 410 s_action.sa_handler = request_hup; 411 (void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL); 412 #else /* POSIX_SIGNALS */ 413 signal(SIGINT, request_exit); 414 signal(SIGTERM, request_exit); 415 signal(SIGHUP, request_hup); 416 #endif /* POSIX_SIGNALS */ 417 418 return; 419 } 420 421 krb5_error_code 422 setup_sam(void) 423 { 424 return krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_MD5, &psr_key); 425 } 426 427 void 428 usage(char *name) 429 { 430 fprintf(stderr, gettext("usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-n]\n"), name); 431 return; 432 } 433 434 void 435 initialize_realms(krb5_context kcontext, int argc, char **argv) 436 { 437 int c; 438 char *db_name = (char *) NULL; 439 char *mkey_name = (char *) NULL; 440 char *rcname = KDCRCACHE; 441 char *lrealm; 442 krb5_error_code retval; 443 krb5_enctype menctype = ENCTYPE_UNKNOWN; 444 kdc_realm_t *rdatap; 445 krb5_boolean manual = FALSE; 446 char *default_udp_ports = 0; 447 char *default_tcp_ports = 0; 448 krb5_pointer aprof; 449 const char *hierarchy[3]; 450 #ifdef KRB5_KRB4_COMPAT 451 char *v4mode = 0; 452 #endif 453 extern char *optarg; 454 455 if (!krb5_aprof_init(DEFAULT_KDC_PROFILE, KDC_PROFILE_ENV, &aprof)) { 456 hierarchy[0] = "kdcdefaults"; 457 hierarchy[1] = "kdc_ports"; 458 hierarchy[2] = (char *) NULL; 459 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_udp_ports)) 460 default_udp_ports = 0; 461 hierarchy[1] = "kdc_tcp_ports"; 462 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_tcp_ports)) 463 default_tcp_ports = 0; 464 hierarchy[1] = "kdc_max_tcp_connections"; 465 if (krb5_aprof_get_int32(aprof, hierarchy, TRUE, 466 &max_tcp_data_connections)) { 467 max_tcp_data_connections = DEFAULT_KDC_TCP_CONNECTIONS; 468 } else if (max_tcp_data_connections < MIN_KDC_TCP_CONNECTIONS) { 469 max_tcp_data_connections = DEFAULT_KDC_TCP_CONNECTIONS; 470 } 471 #ifdef KRB5_KRB4_COMPAT 472 hierarchy[1] = "v4_mode"; 473 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &v4mode)) 474 v4mode = 0; 475 #endif 476 /* aprof_init can return 0 with aprof == NULL */ 477 if (aprof) 478 krb5_aprof_finish(aprof); 479 } 480 if (default_udp_ports == 0) 481 default_udp_ports = strdup(DEFAULT_KDC_UDP_PORTLIST); 482 if (default_tcp_ports == 0) 483 default_tcp_ports = strdup(DEFAULT_KDC_TCP_PORTLIST); 484 /* 485 * Loop through the option list. Each time we encounter a realm name, 486 * use the previously scanned options to fill in for defaults. 487 */ 488 while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:s:n")) != -1) { /* SUNW */ 489 switch(c) { 490 case 'r': /* realm name for db */ 491 if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) { 492 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) { 493 if ((retval = init_realm(argv[0], rdatap, optarg, db_name, 494 mkey_name, menctype, 495 default_udp_ports, 496 default_tcp_ports, manual))) { 497 fprintf(stderr,gettext("%s: cannot initialize realm %s\n"), 498 argv[0], optarg); 499 exit(1); 500 } 501 kdc_realmlist[kdc_numrealms] = rdatap; 502 kdc_numrealms++; 503 } 504 } 505 break; 506 case 'd': /* pathname for db */ 507 db_name = optarg; 508 break; 509 case 'm': /* manual type-in of master key */ 510 manual = TRUE; 511 if (menctype == ENCTYPE_UNKNOWN) 512 menctype = ENCTYPE_DES_CBC_CRC; 513 break; 514 case 'M': /* master key name in DB */ 515 mkey_name = optarg; 516 break; 517 case 'n': 518 nofork++; /* don't detach from terminal */ 519 break; 520 case 'k': /* enctype for master key */ 521 if (krb5_string_to_enctype(optarg, &menctype)) 522 com_err(argv[0], 0, 523 gettext("invalid enctype %s"), optarg); 524 break; 525 case 'R': 526 rcname = optarg; 527 break; 528 case 'p': 529 if (default_udp_ports) 530 free(default_udp_ports); 531 default_udp_ports = strdup(optarg); 532 533 if (default_tcp_ports) 534 free(default_tcp_ports); 535 default_tcp_ports = strdup(optarg); 536 537 break; 538 case '4': 539 #ifdef KRB5_KRB4_COMPAT 540 if (v4mode) 541 free(v4mode); 542 v4mode = strdup(optarg); 543 #endif 544 break; 545 case 'X': 546 #ifdef KRB5_KRB4_COMPAT 547 enable_v4_crossrealm(argv[0]); 548 #endif 549 break; 550 case '?': 551 default: 552 usage(argv[0]); 553 exit(1); 554 } 555 } 556 557 #ifdef KRB5_KRB4_COMPAT 558 /* 559 * Setup the v4 mode 560 */ 561 process_v4_mode(argv[0], v4mode); 562 #endif 563 564 /* 565 * Check to see if we processed any realms. 566 */ 567 if (kdc_numrealms == 0) { 568 /* no realm specified, use default realm */ 569 if ((retval = krb5_get_default_realm(kcontext, &lrealm))) { 570 com_err(argv[0], retval, 571 gettext("while attempting to retrieve default realm")); 572 fprintf (stderr, "%s: %s, %s", argv[0], error_message (retval), 573 gettext("attempting to retrieve default realm\n")); 574 exit(1); 575 } 576 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) { 577 if ((retval = init_realm(argv[0], rdatap, lrealm, db_name, 578 mkey_name, menctype, default_udp_ports, 579 default_tcp_ports, manual))) { 580 fprintf(stderr, 581 gettext("%s: cannot initialize realm %s\n"), 582 argv[0], lrealm); 583 exit(1); 584 } 585 kdc_realmlist[0] = rdatap; 586 kdc_numrealms++; 587 } 588 } 589 590 #ifdef USE_RCACHE 591 /* 592 * Now handle the replay cache. 593 */ 594 if ((retval = kdc_initialize_rcache(kcontext, rcname))) { 595 com_err(argv[0], retval, gettext("while initializing KDC replay cache '%s'"), 596 rcname); 597 exit(1); 598 } 599 #endif 600 601 /* Ensure that this is set for our first request. */ 602 kdc_active_realm = kdc_realmlist[0]; 603 if (default_udp_ports) 604 free(default_udp_ports); 605 if (default_tcp_ports) 606 free(default_tcp_ports); 607 608 return; 609 } 610 611 void 612 finish_realms(char *prog) 613 { 614 int i; 615 616 for (i = 0; i < kdc_numrealms; i++) { 617 finish_realm(kdc_realmlist[i]); 618 kdc_realmlist[i] = 0; 619 } 620 } 621 622 /* 623 outline: 624 625 process args & setup 626 627 initialize database access (fetch master key, open DB) 628 629 initialize network 630 631 loop: 632 listen for packet 633 634 determine packet type, dispatch to handling routine 635 (AS or TGS (or V4?)) 636 637 reflect response 638 639 exit on signal 640 641 clean up secrets, close db 642 643 shut down network 644 645 exit 646 */ 647 648 int main(int argc, char **argv) 649 { 650 krb5_error_code retval; 651 krb5_context kcontext; 652 int errout = 0; 653 654 (void) setlocale(LC_ALL, ""); 655 656 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 657 #define TEXT_DOMAIN "KRB5KDC_TEST" /* Use this only if it weren't */ 658 #endif 659 660 (void) textdomain(TEXT_DOMAIN); 661 662 if (strrchr(argv[0], '/')) 663 argv[0] = strrchr(argv[0], '/')+1; 664 665 if (!(kdc_realmlist = (kdc_realm_t **) malloc(sizeof(kdc_realm_t *) * 666 KRB5_KDC_MAX_REALMS))) { 667 fprintf(stderr, gettext("%s: cannot get memory for realm list\n"), argv[0]); 668 exit(1); 669 } 670 memset((char *) kdc_realmlist, 0, 671 (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS)); 672 673 /* 674 * A note about Kerberos contexts: This context, "kcontext", is used 675 * for the KDC operations, i.e. setup, network connection and error 676 * reporting. The per-realm operations use the "realm_context" 677 * associated with each realm. 678 */ 679 retval = krb5_init_context(&kcontext); 680 if (retval) { 681 com_err(argv[0], retval, gettext("while initializing krb5")); 682 exit(1); 683 } 684 krb5_klog_init(kcontext, "kdc", argv[0], 1); 685 /* initialize_kdc5_error_table(); SUNWresync121 XXX */ 686 687 /* 688 * Scan through the argument list 689 */ 690 initialize_realms(kcontext, argc, argv); 691 692 setup_signal_handlers(); 693 694 retval = setup_sam(); 695 if (retval) { 696 com_err(argv[0], retval, gettext("while initializing SAM")); 697 finish_realms(argv[0]); 698 return 1; 699 } 700 701 if ((retval = setup_network(argv[0]))) { 702 com_err(argv[0], retval, gettext("while initializing network")); 703 finish_realms(argv[0]); 704 return 1; 705 } 706 if (!nofork && daemon(0, 0)) { 707 com_err(argv[0], errno, gettext("while detaching from tty")); 708 finish_realms(argv[0]); 709 return 1; 710 } 711 if (retval = krb5_klog_syslog(LOG_INFO, "commencing operation")) { 712 com_err(argv[0], retval, gettext("while logging message")); 713 errout++; 714 }; 715 716 if ((retval = listen_and_process(argv[0]))) { 717 com_err(argv[0], retval, gettext("while processing network requests")); 718 errout++; 719 } 720 if ((retval = closedown_network(argv[0]))) { 721 com_err(argv[0], retval, gettext("while shutting down network")); 722 errout++; 723 } 724 krb5_klog_syslog(LOG_INFO, "shutting down"); 725 krb5_klog_close(kdc_context); 726 finish_realms(argv[0]); 727 if (kdc_realmlist) 728 free(kdc_realmlist); 729 #ifdef USE_RCACHE 730 (void) krb5_rc_close(kcontext, kdc_rcache); 731 #endif 732 #ifndef NOCACHE 733 kdc_free_lookaside(kcontext); 734 #endif 735 krb5_free_context(kcontext); 736 return errout; 737 } 738 739 740 741 742