1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* kdc/main.c - Main procedure body for the KDC server process */ 3 /* 4 * Copyright 1990,2001,2008,2009,2016 by the Massachusetts Institute of 5 * Technology. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 #include "k5-int.h" 28 #include "com_err.h" 29 #include <kadm5/admin.h> 30 #include "adm_proto.h" 31 #include "kdc_util.h" 32 #include "kdc_audit.h" 33 #include "extern.h" 34 #include "policy.h" 35 #include "kdc5_err.h" 36 #include "kdb_kt.h" 37 #include "net-server.h" 38 #ifdef HAVE_NETINET_IN_H 39 #include <netinet/in.h> 40 #endif 41 42 #include <locale.h> 43 #include <syslog.h> 44 #include <signal.h> 45 #include <netdb.h> 46 #include <unistd.h> 47 #include <ctype.h> 48 #include <sys/wait.h> 49 50 #if defined(NEED_DAEMON_PROTO) 51 extern int daemon(int, int); 52 #endif 53 54 static void usage (char *); 55 56 static void initialize_realms(krb5_context kcontext, int argc, char **argv, 57 int *tcp_listen_backlog_out); 58 59 static void finish_realms (void); 60 61 static int nofork = 0; 62 static int workers = 0; 63 static int time_offset = 0; 64 static const char *pid_file = NULL; 65 static volatile int signal_received = 0; 66 static volatile int sighup_received = 0; 67 68 #define KRB5_KDC_MAX_REALMS 32 69 70 static const char *kdc_progname; 71 72 /* 73 * Static server_handle for this file. Other code will get access to 74 * it through the application handle that net-server.c uses. 75 */ 76 static struct server_handle shandle; 77 78 /* 79 * We use krb5_klog_init to set up a com_err callback to log error 80 * messages. The callback also pulls the error message out of the 81 * context we pass to krb5_klog_init; however, we use realm-specific 82 * contexts for most of our krb5 library calls, so the error message 83 * isn't present in the global context. This wrapper ensures that the 84 * error message state from the call context is copied into the 85 * context known by krb5_klog. call_context can be NULL if the error 86 * code did not come from a krb5 library function. 87 */ 88 void 89 kdc_err(krb5_context call_context, errcode_t code, const char *fmt, ...) 90 { 91 va_list ap; 92 93 if (call_context) 94 krb5_copy_error_message(shandle.kdc_err_context, call_context); 95 va_start(ap, fmt); 96 com_err_va(kdc_progname, code, fmt, ap); 97 va_end(ap); 98 } 99 100 /* 101 * Find the realm entry for a given realm. 102 */ 103 kdc_realm_t * 104 find_realm_data(struct server_handle *handle, char *rname, krb5_ui_4 rsize) 105 { 106 int i; 107 kdc_realm_t **kdc_realmlist = handle->kdc_realmlist; 108 int kdc_numrealms = handle->kdc_numrealms; 109 110 for (i=0; i<kdc_numrealms; i++) { 111 if ((rsize == strlen(kdc_realmlist[i]->realm_name)) && 112 !strncmp(rname, kdc_realmlist[i]->realm_name, rsize)) 113 return(kdc_realmlist[i]); 114 } 115 return((kdc_realm_t *) NULL); 116 } 117 118 kdc_realm_t * 119 setup_server_realm(struct server_handle *handle, krb5_principal sprinc) 120 { 121 kdc_realm_t *newrealm; 122 kdc_realm_t **kdc_realmlist = handle->kdc_realmlist; 123 int kdc_numrealms = handle->kdc_numrealms; 124 125 if (sprinc == NULL) 126 return NULL; 127 128 if (kdc_numrealms > 1) { 129 newrealm = find_realm_data(handle, sprinc->realm.data, 130 sprinc->realm.length); 131 } else { 132 newrealm = kdc_realmlist[0]; 133 } 134 if (newrealm != NULL) { 135 krb5_klog_set_context(newrealm->realm_context); 136 shandle.kdc_err_context = newrealm->realm_context; 137 } 138 return newrealm; 139 } 140 141 static void 142 finish_realm(kdc_realm_t *rdp) 143 { 144 if (rdp->realm_name) 145 free(rdp->realm_name); 146 if (rdp->realm_mpname) 147 free(rdp->realm_mpname); 148 if (rdp->realm_stash) 149 free(rdp->realm_stash); 150 if (rdp->realm_listen) 151 free(rdp->realm_listen); 152 if (rdp->realm_tcp_listen) 153 free(rdp->realm_tcp_listen); 154 if (rdp->realm_keytab) 155 krb5_kt_close(rdp->realm_context, rdp->realm_keytab); 156 if (rdp->realm_hostbased) 157 free(rdp->realm_hostbased); 158 if (rdp->realm_no_referral) 159 free(rdp->realm_no_referral); 160 if (rdp->realm_context) { 161 if (rdp->realm_mprinc) 162 krb5_free_principal(rdp->realm_context, rdp->realm_mprinc); 163 zapfree(rdp->realm_mkey.contents, rdp->realm_mkey.length); 164 krb5_db_fini(rdp->realm_context); 165 if (rdp->realm_tgsprinc) 166 krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc); 167 krb5_free_context(rdp->realm_context); 168 } 169 zapfree(rdp, sizeof(*rdp)); 170 } 171 172 /* Set *val_out to an allocated string containing val1 and/or val2, separated 173 * by a space if both are set, or NULL if neither is set. */ 174 static krb5_error_code 175 combine(const char *val1, const char *val2, char **val_out) 176 { 177 if (val1 == NULL && val2 == NULL) { 178 *val_out = NULL; 179 } else if (val1 != NULL && val2 != NULL) { 180 if (asprintf(val_out, "%s %s", val1, val2) < 0) { 181 *val_out = NULL; 182 return ENOMEM; 183 } 184 } else { 185 *val_out = strdup((val1 != NULL) ? val1 : val2); 186 if (*val_out == NULL) 187 return ENOMEM; 188 } 189 return 0; 190 } 191 192 /* 193 * Initialize a realm control structure from the alternate profile or from 194 * the specified defaults. 195 * 196 * After we're complete here, the essence of the realm is embodied in the 197 * realm data and we should be all set to begin operation for that realm. 198 */ 199 static krb5_error_code 200 init_realm(kdc_realm_t * rdp, krb5_pointer aprof, char *realm, 201 char *def_mpname, krb5_enctype def_enctype, char *def_udp_listen, 202 char *def_tcp_listen, krb5_boolean def_manual, 203 krb5_boolean def_restrict_anon, char **db_args, char *no_referral, 204 char *hostbased) 205 { 206 krb5_error_code kret; 207 krb5_boolean manual; 208 int kdb_open_flags; 209 char *svalue = NULL; 210 const char *hierarchy[4]; 211 krb5_kvno mkvno = IGNORE_VNO; 212 char ename[32]; 213 214 memset(rdp, 0, sizeof(kdc_realm_t)); 215 if (!realm) { 216 kret = EINVAL; 217 goto whoops; 218 } 219 220 if (def_enctype != ENCTYPE_UNKNOWN && 221 krb5int_c_deprecated_enctype(def_enctype)) { 222 if (krb5_enctype_to_name(def_enctype, FALSE, ename, sizeof(ename))) 223 ename[0] = '\0'; 224 fprintf(stderr, 225 _("Requested master password enctype %s in %s is " 226 "DEPRECATED!\n"), 227 ename, realm); 228 } 229 230 hierarchy[0] = KRB5_CONF_REALMS; 231 hierarchy[1] = realm; 232 hierarchy[3] = NULL; 233 234 rdp->realm_name = strdup(realm); 235 if (rdp->realm_name == NULL) { 236 kret = ENOMEM; 237 goto whoops; 238 } 239 kret = krb5int_init_context_kdc(&rdp->realm_context); 240 if (kret) { 241 kdc_err(NULL, kret, _("while getting context for realm %s"), realm); 242 goto whoops; 243 } 244 if (time_offset != 0) 245 (void)krb5_set_time_offsets(rdp->realm_context, time_offset, 0); 246 247 /* Handle master key name */ 248 hierarchy[2] = KRB5_CONF_MASTER_KEY_NAME; 249 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &rdp->realm_mpname)) { 250 rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) : 251 strdup(KRB5_KDB_M_NAME); 252 } 253 if (!rdp->realm_mpname) { 254 kret = ENOMEM; 255 goto whoops; 256 } 257 258 /* Handle KDC addresses/ports */ 259 hierarchy[2] = KRB5_CONF_KDC_LISTEN; 260 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &rdp->realm_listen)) { 261 /* Try the old kdc_ports configuration option. */ 262 hierarchy[2] = KRB5_CONF_KDC_PORTS; 263 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &rdp->realm_listen)) 264 rdp->realm_listen = strdup(def_udp_listen); 265 } 266 if (!rdp->realm_listen) { 267 kret = ENOMEM; 268 goto whoops; 269 } 270 hierarchy[2] = KRB5_CONF_KDC_TCP_LISTEN; 271 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, 272 &rdp->realm_tcp_listen)) { 273 /* Try the old kdc_tcp_ports configuration option. */ 274 hierarchy[2] = KRB5_CONF_KDC_TCP_PORTS; 275 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, 276 &rdp->realm_tcp_listen)) 277 rdp->realm_tcp_listen = strdup(def_tcp_listen); 278 } 279 if (!rdp->realm_tcp_listen) { 280 kret = ENOMEM; 281 goto whoops; 282 } 283 /* Handle stash file */ 284 hierarchy[2] = KRB5_CONF_KEY_STASH_FILE; 285 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &rdp->realm_stash)) 286 manual = def_manual; 287 else 288 manual = FALSE; 289 290 hierarchy[2] = KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT; 291 if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE, 292 &rdp->realm_restrict_anon)) 293 rdp->realm_restrict_anon = def_restrict_anon; 294 295 /* Handle master key type */ 296 hierarchy[2] = KRB5_CONF_MASTER_KEY_TYPE; 297 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &svalue) || 298 krb5_string_to_enctype(svalue, &rdp->realm_mkey.enctype)) 299 rdp->realm_mkey.enctype = manual ? def_enctype : ENCTYPE_UNKNOWN; 300 free(svalue); 301 svalue = NULL; 302 303 /* Handle reject-bad-transit flag */ 304 hierarchy[2] = KRB5_CONF_REJECT_BAD_TRANSIT; 305 if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE, 306 &rdp->realm_reject_bad_transit)) 307 rdp->realm_reject_bad_transit = TRUE; 308 309 /* Handle ticket maximum life */ 310 hierarchy[2] = KRB5_CONF_MAX_LIFE; 311 if (krb5_aprof_get_deltat(aprof, hierarchy, TRUE, &rdp->realm_maxlife)) 312 rdp->realm_maxlife = KRB5_KDB_MAX_LIFE; 313 314 /* Handle ticket renewable maximum life */ 315 hierarchy[2] = KRB5_CONF_MAX_RENEWABLE_LIFE; 316 if (krb5_aprof_get_deltat(aprof, hierarchy, TRUE, &rdp->realm_maxrlife)) 317 rdp->realm_maxrlife = KRB5_KDB_MAX_RLIFE; 318 319 /* Handle KDC referrals */ 320 hierarchy[2] = KRB5_CONF_NO_HOST_REFERRAL; 321 (void)krb5_aprof_get_string_all(aprof, hierarchy, &svalue); 322 kret = combine(no_referral, svalue, &rdp->realm_no_referral); 323 if (kret) 324 goto whoops; 325 free(svalue); 326 svalue = NULL; 327 328 hierarchy[2] = KRB5_CONF_HOST_BASED_SERVICES; 329 (void)krb5_aprof_get_string_all(aprof, hierarchy, &svalue); 330 kret = combine(hostbased, svalue, &rdp->realm_hostbased); 331 if (kret) 332 goto whoops; 333 free(svalue); 334 svalue = NULL; 335 336 hierarchy[2] = KRB5_CONF_DISABLE_PAC; 337 if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE, 338 &rdp->realm_disable_pac)) 339 rdp->realm_disable_pac = FALSE; 340 341 /* 342 * We've got our parameters, now go and setup our realm context. 343 */ 344 345 /* Set the default realm of this context */ 346 if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) { 347 kdc_err(rdp->realm_context, kret, 348 _("while setting default realm to %s"), realm); 349 goto whoops; 350 } 351 352 /* first open the database before doing anything */ 353 kdb_open_flags = KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_KDC; 354 if ((kret = krb5_db_open(rdp->realm_context, db_args, kdb_open_flags))) { 355 kdc_err(rdp->realm_context, kret, 356 _("while initializing database for realm %s"), realm); 357 goto whoops; 358 } 359 360 /* Assemble and parse the master key name */ 361 if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname, 362 rdp->realm_name, (char **) NULL, 363 &rdp->realm_mprinc))) { 364 kdc_err(rdp->realm_context, kret, 365 _("while setting up master key name %s for realm %s"), 366 rdp->realm_mpname, realm); 367 goto whoops; 368 } 369 370 /* 371 * Get the master key (note, may not be the most current mkey). 372 */ 373 if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc, 374 rdp->realm_mkey.enctype, manual, 375 FALSE, rdp->realm_stash, 376 &mkvno, NULL, &rdp->realm_mkey))) { 377 kdc_err(rdp->realm_context, kret, 378 _("while fetching master key %s for realm %s"), 379 rdp->realm_mpname, realm); 380 goto whoops; 381 } 382 383 if (krb5int_c_deprecated_enctype(rdp->realm_mkey.enctype)) { 384 if (krb5_enctype_to_name(rdp->realm_mkey.enctype, FALSE, ename, 385 sizeof(ename))) 386 ename[0] = '\0'; 387 fprintf(stderr, _("Stash file %s uses DEPRECATED enctype %s!\n"), 388 rdp->realm_stash, ename); 389 } 390 391 if ((kret = krb5_db_fetch_mkey_list(rdp->realm_context, rdp->realm_mprinc, 392 &rdp->realm_mkey))) { 393 kdc_err(rdp->realm_context, kret, 394 _("while fetching master keys list for realm %s"), realm); 395 goto whoops; 396 } 397 398 399 /* Set up the keytab */ 400 if ((kret = krb5_ktkdb_resolve(rdp->realm_context, NULL, 401 &rdp->realm_keytab))) { 402 kdc_err(rdp->realm_context, kret, 403 _("while resolving kdb keytab for realm %s"), realm); 404 goto whoops; 405 } 406 407 /* Preformat the TGS name */ 408 if ((kret = krb5_build_principal(rdp->realm_context, &rdp->realm_tgsprinc, 409 strlen(realm), realm, KRB5_TGS_NAME, 410 realm, (char *) NULL))) { 411 kdc_err(rdp->realm_context, kret, 412 _("while building TGS name for realm %s"), realm); 413 goto whoops; 414 } 415 416 whoops: 417 /* 418 * If we choked, then clean up any dirt we may have dropped on the floor. 419 */ 420 if (kret) { 421 422 finish_realm(rdp); 423 } 424 return(kret); 425 } 426 427 static void 428 on_monitor_signal(int signo) 429 { 430 signal_received = signo; 431 } 432 433 static void 434 on_monitor_sighup(int signo) 435 { 436 sighup_received = 1; 437 } 438 439 /* 440 * Kill the worker subprocesses given by pids[0..bound-1], skipping any which 441 * are set to -1, and wait for them to exit (so that we know the ports are no 442 * longer in use). 443 */ 444 static void 445 terminate_workers(pid_t *pids, int bound) 446 { 447 int i, status, num_active = 0; 448 pid_t pid; 449 450 /* Kill the active worker pids. */ 451 for (i = 0; i < bound; i++) { 452 if (pids[i] == -1) 453 continue; 454 kill(pids[i], SIGTERM); 455 num_active++; 456 } 457 458 /* Wait for them to exit. */ 459 while (num_active > 0) { 460 pid = wait(&status); 461 if (pid >= 0) 462 num_active--; 463 } 464 } 465 466 /* 467 * Create num worker processes and return successfully in each child. The 468 * parent process will act as a supervisor and will only return from this 469 * function in error cases. 470 */ 471 static krb5_error_code 472 create_workers(verto_ctx *ctx, int num) 473 { 474 krb5_error_code retval; 475 int i, status; 476 pid_t pid, *pids; 477 #ifdef POSIX_SIGNALS 478 struct sigaction s_action; 479 #endif /* POSIX_SIGNALS */ 480 481 /* 482 * Setup our signal handlers which will forward to the children. 483 * These handlers will be overridden in the child processes. 484 */ 485 #ifdef POSIX_SIGNALS 486 (void) sigemptyset(&s_action.sa_mask); 487 s_action.sa_flags = 0; 488 s_action.sa_handler = on_monitor_signal; 489 (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL); 490 (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL); 491 (void) sigaction(SIGQUIT, &s_action, (struct sigaction *) NULL); 492 s_action.sa_handler = on_monitor_sighup; 493 (void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL); 494 #else /* POSIX_SIGNALS */ 495 signal(SIGINT, on_monitor_signal); 496 signal(SIGTERM, on_monitor_signal); 497 signal(SIGQUIT, on_monitor_signal); 498 signal(SIGHUP, on_monitor_sighup); 499 #endif /* POSIX_SIGNALS */ 500 501 /* Create child worker processes; return in each child. */ 502 krb5_klog_syslog(LOG_INFO, _("creating %d worker processes"), num); 503 pids = calloc(num, sizeof(pid_t)); 504 if (pids == NULL) 505 return ENOMEM; 506 for (i = 0; i < num; i++) { 507 pid = fork(); 508 if (pid == 0) { 509 free(pids); 510 if (!verto_reinitialize(ctx)) { 511 krb5_klog_syslog(LOG_ERR, 512 _("Unable to reinitialize main loop")); 513 return ENOMEM; 514 } 515 retval = loop_setup_signals(ctx, &shandle, reset_for_hangup); 516 if (retval) { 517 krb5_klog_syslog(LOG_ERR, _("Unable to initialize signal " 518 "handlers in pid %d"), pid); 519 return retval; 520 } 521 522 /* Avoid race condition */ 523 if (signal_received) 524 exit(0); 525 526 /* Return control to main() in the new worker process. */ 527 return 0; 528 } 529 if (pid == -1) { 530 /* Couldn't fork enough times. */ 531 status = errno; 532 terminate_workers(pids, i); 533 free(pids); 534 return status; 535 } 536 pids[i] = pid; 537 } 538 539 /* We're going to use our own main loop here. */ 540 loop_free(ctx); 541 542 /* Supervise the worker processes. */ 543 while (!signal_received) { 544 /* Wait until a worker process exits or we get a signal. */ 545 pid = wait(&status); 546 if (pid >= 0) { 547 krb5_klog_syslog(LOG_ERR, _("worker %ld exited with status %d"), 548 (long) pid, status); 549 550 /* Remove the pid from the table. */ 551 for (i = 0; i < num; i++) { 552 if (pids[i] == pid) 553 pids[i] = -1; 554 } 555 556 /* When one worker process exits, terminate them all, so that KDC 557 * crashes behave similarly with or without worker processes. */ 558 break; 559 } 560 561 /* Propagate HUP signal to worker processes if we received one. */ 562 if (sighup_received) { 563 sighup_received = 0; 564 for (i = 0; i < num; i++) { 565 if (pids[i] != -1) 566 kill(pids[i], SIGHUP); 567 } 568 } 569 } 570 if (signal_received) 571 krb5_klog_syslog(LOG_INFO, _("signal %d received in supervisor"), 572 signal_received); 573 574 terminate_workers(pids, num); 575 free(pids); 576 exit(0); 577 } 578 579 static void 580 usage(char *name) 581 { 582 fprintf(stderr, 583 _("usage: %s [-x db_args]* [-d dbpathname] [-r dbrealmname]\n" 584 "\t\t[-T time_offset] [-m] [-k masterenctype]\n" 585 "\t\t[-M masterkeyname] [-p port] [-P pid_file]\n" 586 "\t\t[-n] [-w numworkers] [/]\n\n" 587 "where,\n" 588 "\t[-x db_args]* - Any number of database specific arguments.\n" 589 "\t\t\tLook at each database module documentation for " 590 "\t\t\tsupported arguments\n"), 591 name); 592 exit(1); 593 } 594 595 596 static void 597 initialize_realms(krb5_context kcontext, int argc, char **argv, 598 int *tcp_listen_backlog_out) 599 { 600 int c; 601 char *db_name = (char *) NULL; 602 char *lrealm = (char *) NULL; 603 char *mkey_name = (char *) NULL; 604 krb5_error_code retval; 605 krb5_enctype menctype = ENCTYPE_UNKNOWN; 606 kdc_realm_t *rdatap = NULL; 607 krb5_boolean manual = FALSE; 608 krb5_boolean def_restrict_anon; 609 char *def_udp_listen = NULL; 610 char *def_tcp_listen = NULL; 611 krb5_pointer aprof = kcontext->profile; 612 const char *hierarchy[3]; 613 char *no_referral = NULL; 614 char *hostbased = NULL; 615 int db_args_size = 0; 616 char **db_args = NULL; 617 618 extern char *optarg; 619 620 hierarchy[0] = KRB5_CONF_KDCDEFAULTS; 621 hierarchy[1] = KRB5_CONF_KDC_LISTEN; 622 hierarchy[2] = NULL; 623 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &def_udp_listen)) { 624 hierarchy[1] = KRB5_CONF_KDC_PORTS; 625 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &def_udp_listen)) 626 def_udp_listen = NULL; 627 } 628 hierarchy[1] = KRB5_CONF_KDC_TCP_LISTEN; 629 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &def_tcp_listen)) { 630 hierarchy[1] = KRB5_CONF_KDC_TCP_PORTS; 631 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &def_tcp_listen)) 632 def_tcp_listen = NULL; 633 } 634 hierarchy[1] = KRB5_CONF_KDC_MAX_DGRAM_REPLY_SIZE; 635 if (krb5_aprof_get_int32(aprof, hierarchy, TRUE, &max_dgram_reply_size)) 636 max_dgram_reply_size = MAX_DGRAM_SIZE; 637 if (tcp_listen_backlog_out != NULL) { 638 hierarchy[1] = KRB5_CONF_KDC_TCP_LISTEN_BACKLOG; 639 if (krb5_aprof_get_int32(aprof, hierarchy, TRUE, 640 tcp_listen_backlog_out)) 641 *tcp_listen_backlog_out = DEFAULT_TCP_LISTEN_BACKLOG; 642 } 643 hierarchy[1] = KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT; 644 if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE, &def_restrict_anon)) 645 def_restrict_anon = FALSE; 646 hierarchy[1] = KRB5_CONF_NO_HOST_REFERRAL; 647 if (krb5_aprof_get_string_all(aprof, hierarchy, &no_referral)) 648 no_referral = 0; 649 hierarchy[1] = KRB5_CONF_HOST_BASED_SERVICES; 650 if (krb5_aprof_get_string_all(aprof, hierarchy, &hostbased)) 651 hostbased = 0; 652 653 if (def_udp_listen == NULL) { 654 def_udp_listen = strdup(DEFAULT_KDC_UDP_PORTLIST); 655 if (def_udp_listen == NULL) { 656 fprintf(stderr, _(" KDC cannot initialize. Not enough memory\n")); 657 exit(1); 658 } 659 } 660 if (def_tcp_listen == NULL) { 661 def_tcp_listen = strdup(DEFAULT_KDC_TCP_PORTLIST); 662 if (def_tcp_listen == NULL) { 663 fprintf(stderr, _(" KDC cannot initialize. Not enough memory\n")); 664 exit(1); 665 } 666 } 667 668 /* 669 * Loop through the option list. Each time we encounter a realm name, use 670 * the previously scanned options to fill in for defaults. We do this 671 * twice if worker processes are used, so we must initialize optind. 672 */ 673 optind = 1; 674 while ((c = getopt(argc, argv, "x:r:d:mM:k:R:P:p:nw:4:T:X3")) != -1) { 675 switch(c) { 676 case 'x': 677 db_args_size++; 678 { 679 char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */ 680 if( temp == NULL ) 681 { 682 fprintf(stderr, _("%s: KDC cannot initialize. Not enough " 683 "memory\n"), argv[0]); 684 exit(1); 685 } 686 687 db_args = temp; 688 } 689 db_args[db_args_size-1] = optarg; 690 db_args[db_args_size] = NULL; 691 break; 692 693 case 'r': /* realm name for db */ 694 if (!find_realm_data(&shandle, optarg, (krb5_ui_4) strlen(optarg))) { 695 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) { 696 retval = init_realm(rdatap, aprof, optarg, mkey_name, 697 menctype, def_udp_listen, 698 def_tcp_listen, manual, 699 def_restrict_anon, db_args, 700 no_referral, hostbased); 701 if (retval) { 702 fprintf(stderr, _("%s: cannot initialize realm %s - " 703 "see log file for details\n"), 704 argv[0], optarg); 705 exit(1); 706 } 707 shandle.kdc_realmlist[shandle.kdc_numrealms] = rdatap; 708 shandle.kdc_numrealms++; 709 free(db_args), db_args=NULL, db_args_size = 0; 710 } 711 else 712 { 713 fprintf(stderr, _("%s: cannot initialize realm %s. Not " 714 "enough memory\n"), argv[0], optarg); 715 exit(1); 716 } 717 } 718 break; 719 case 'd': /* pathname for db */ 720 /* now db_name is not a separate argument. 721 * It has to be passed as part of the db_args 722 */ 723 if( db_name == NULL ) { 724 if (asprintf(&db_name, "dbname=%s", optarg) < 0) { 725 fprintf(stderr, _("%s: KDC cannot initialize. Not enough " 726 "memory\n"), argv[0]); 727 exit(1); 728 } 729 } 730 731 db_args_size++; 732 { 733 char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */ 734 if( temp == NULL ) 735 { 736 fprintf(stderr, _("%s: KDC cannot initialize. Not enough " 737 "memory\n"), argv[0]); 738 exit(1); 739 } 740 741 db_args = temp; 742 } 743 db_args[db_args_size-1] = db_name; 744 db_args[db_args_size] = NULL; 745 break; 746 case 'm': /* manual type-in of master key */ 747 manual = TRUE; 748 if (menctype == ENCTYPE_UNKNOWN) 749 menctype = DEFAULT_KDC_ENCTYPE; 750 break; 751 case 'M': /* master key name in DB */ 752 mkey_name = optarg; 753 break; 754 case 'n': 755 nofork++; /* don't detach from terminal */ 756 break; 757 case 'w': /* create multiple worker processes */ 758 workers = atoi(optarg); 759 if (workers <= 0) 760 usage(argv[0]); 761 break; 762 case 'k': /* enctype for master key */ 763 if (krb5_string_to_enctype(optarg, &menctype)) 764 com_err(argv[0], 0, _("invalid enctype %s"), optarg); 765 break; 766 case 'R': 767 /* Replay cache name; defunct since we don't use a replay cache. */ 768 break; 769 case 'P': 770 pid_file = optarg; 771 break; 772 case 'p': 773 free(def_udp_listen); 774 free(def_tcp_listen); 775 def_udp_listen = strdup(optarg); 776 def_tcp_listen = strdup(optarg); 777 if (def_udp_listen == NULL || def_tcp_listen == NULL) { 778 fprintf(stderr, _(" KDC cannot initialize. Not enough " 779 "memory\n")); 780 exit(1); 781 } 782 break; 783 case 'T': 784 time_offset = atoi(optarg); 785 break; 786 case '4': 787 break; 788 case 'X': 789 break; 790 case '?': 791 default: 792 usage(argv[0]); 793 } 794 } 795 796 /* 797 * Check to see if we processed any realms. 798 */ 799 if (shandle.kdc_numrealms == 0) { 800 /* no realm specified, use default realm */ 801 if ((retval = krb5_get_default_realm(kcontext, &lrealm))) { 802 com_err(argv[0], retval, 803 _("while attempting to retrieve default realm")); 804 fprintf (stderr, 805 _("%s: %s, attempting to retrieve default realm\n"), 806 argv[0], krb5_get_error_message(kcontext, retval)); 807 exit(1); 808 } 809 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) { 810 retval = init_realm(rdatap, aprof, lrealm, mkey_name, menctype, 811 def_udp_listen, def_tcp_listen, manual, 812 def_restrict_anon, db_args, no_referral, 813 hostbased); 814 if (retval) { 815 fprintf(stderr, _("%s: cannot initialize realm %s - see log " 816 "file for details\n"), argv[0], lrealm); 817 exit(1); 818 } 819 shandle.kdc_realmlist[0] = rdatap; 820 shandle.kdc_numrealms++; 821 } 822 krb5_free_default_realm(kcontext, lrealm); 823 } 824 825 if (def_udp_listen) 826 free(def_udp_listen); 827 if (def_tcp_listen) 828 free(def_tcp_listen); 829 if (db_args) 830 free(db_args); 831 if (db_name) 832 free(db_name); 833 if (hostbased) 834 free(hostbased); 835 if (no_referral) 836 free(no_referral); 837 838 return; 839 } 840 841 static krb5_error_code 842 write_pid_file(const char *path) 843 { 844 FILE *file; 845 unsigned long pid; 846 847 file = fopen(path, "w"); 848 if (file == NULL) 849 return errno; 850 pid = (unsigned long) getpid(); 851 if (fprintf(file, "%ld\n", pid) < 0 || fclose(file) == EOF) 852 return errno; 853 return 0; 854 } 855 856 static void 857 finish_realms() 858 { 859 int i; 860 861 for (i = 0; i < shandle.kdc_numrealms; i++) { 862 finish_realm(shandle.kdc_realmlist[i]); 863 shandle.kdc_realmlist[i] = 0; 864 } 865 shandle.kdc_numrealms = 0; 866 } 867 868 /* 869 outline: 870 871 process args & setup 872 873 initialize database access (fetch master key, open DB) 874 875 initialize network 876 877 loop: 878 listen for packet 879 880 determine packet type, dispatch to handling routine 881 (AS or TGS (or V4?)) 882 883 reflect response 884 885 exit on signal 886 887 clean up secrets, close db 888 889 shut down network 890 891 exit 892 */ 893 894 int main(int argc, char **argv) 895 { 896 krb5_error_code retval; 897 krb5_context kcontext; 898 kdc_realm_t *realm; 899 verto_ctx *ctx; 900 int tcp_listen_backlog; 901 int errout = 0; 902 int i; 903 904 setlocale(LC_ALL, ""); 905 if (strrchr(argv[0], '/')) 906 argv[0] = strrchr(argv[0], '/')+1; 907 908 shandle.kdc_realmlist = malloc(sizeof(kdc_realm_t *) * 909 KRB5_KDC_MAX_REALMS); 910 if (shandle.kdc_realmlist == NULL) { 911 fprintf(stderr, _("%s: cannot get memory for realm list\n"), argv[0]); 912 exit(1); 913 } 914 memset(shandle.kdc_realmlist, 0, 915 (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS)); 916 917 /* 918 * A note about Kerberos contexts: This context, "kcontext", is used 919 * for the KDC operations, i.e. setup, network connection and error 920 * reporting. The per-realm operations use the "realm_context" 921 * associated with each realm. 922 */ 923 retval = krb5int_init_context_kdc(&kcontext); 924 if (retval) { 925 com_err(argv[0], retval, _("while initializing krb5")); 926 exit(1); 927 } 928 krb5_klog_init(kcontext, "kdc", argv[0], 1); 929 shandle.kdc_err_context = kcontext; 930 kdc_progname = argv[0]; 931 /* N.B.: After this point, com_err sends output to the KDC log 932 file, and not to stderr. We use the kdc_err wrapper around 933 com_err to ensure that the error state exists in the context 934 known to the krb5_klog callback. */ 935 936 initialize_kdc5_error_table(); 937 938 /* 939 * Scan through the argument list 940 */ 941 initialize_realms(kcontext, argc, argv, &tcp_listen_backlog); 942 943 #ifndef NOCACHE 944 retval = kdc_init_lookaside(kcontext); 945 if (retval) { 946 kdc_err(kcontext, retval, _("while initializing lookaside cache")); 947 finish_realms(); 948 return 1; 949 } 950 #endif 951 952 ctx = loop_init(VERTO_EV_TYPE_NONE); 953 if (!ctx) { 954 kdc_err(kcontext, ENOMEM, _("while creating main loop")); 955 finish_realms(); 956 return 1; 957 } 958 959 load_preauth_plugins(&shandle, kcontext, ctx); 960 load_authdata_plugins(kcontext); 961 retval = load_kdcpolicy_plugins(kcontext); 962 if (retval) { 963 kdc_err(kcontext, retval, _("while loading KDC policy plugin")); 964 finish_realms(); 965 return 1; 966 } 967 968 /* Add each realm's listener addresses to the loop. */ 969 for (i = 0; i < shandle.kdc_numrealms; i++) { 970 realm = shandle.kdc_realmlist[i]; 971 if (*realm->realm_listen != '\0') { 972 retval = loop_add_udp_address(KRB5_DEFAULT_PORT, 973 realm->realm_listen); 974 if (retval) 975 goto net_init_error; 976 } 977 if (*realm->realm_tcp_listen != '\0') { 978 retval = loop_add_tcp_address(KRB5_DEFAULT_PORT, 979 realm->realm_tcp_listen); 980 if (retval) 981 goto net_init_error; 982 } 983 } 984 985 if (workers == 0) { 986 retval = loop_setup_signals(ctx, &shandle, reset_for_hangup); 987 if (retval) { 988 kdc_err(kcontext, retval, _("while initializing signal handlers")); 989 finish_realms(); 990 return 1; 991 } 992 } 993 if ((retval = loop_setup_network(ctx, &shandle, kdc_progname, 994 tcp_listen_backlog))) { 995 net_init_error: 996 kdc_err(kcontext, retval, _("while initializing network")); 997 finish_realms(); 998 return 1; 999 } 1000 1001 /* Clean up realms for now and reinitialize them after daemonizing, since 1002 * some KDB modules are not fork-safe. */ 1003 finish_realms(); 1004 1005 if (!nofork && daemon(0, 0)) { 1006 kdc_err(kcontext, errno, _("while detaching from tty")); 1007 return 1; 1008 } 1009 if (pid_file != NULL) { 1010 retval = write_pid_file(pid_file); 1011 if (retval) { 1012 kdc_err(kcontext, retval, _("while creating PID file")); 1013 finish_realms(); 1014 return 1; 1015 } 1016 } 1017 if (workers > 0) { 1018 retval = create_workers(ctx, workers); 1019 if (retval) { 1020 kdc_err(kcontext, errno, _("creating worker processes")); 1021 return 1; 1022 } 1023 } 1024 1025 initialize_realms(kcontext, argc, argv, NULL); 1026 1027 /* Initialize audit system and audit KDC startup. */ 1028 retval = load_audit_modules(kcontext); 1029 if (retval) { 1030 kdc_err(kcontext, retval, _("while loading audit plugin module(s)")); 1031 finish_realms(); 1032 return 1; 1033 } 1034 krb5_klog_syslog(LOG_INFO, _("commencing operation")); 1035 if (nofork) 1036 fprintf(stderr, _("%s: starting...\n"), kdc_progname); 1037 kau_kdc_start(kcontext, TRUE); 1038 1039 verto_run(ctx); 1040 kau_kdc_stop(kcontext, TRUE); 1041 krb5_klog_syslog(LOG_INFO, _("shutting down")); 1042 unload_preauth_plugins(kcontext); 1043 unload_authdata_plugins(kcontext); 1044 unload_kdcpolicy_plugins(kcontext); 1045 unload_audit_modules(kcontext); 1046 krb5_klog_close(kcontext); 1047 finish_realms(); 1048 if (shandle.kdc_realmlist) 1049 free(shandle.kdc_realmlist); 1050 #ifndef NOCACHE 1051 kdc_free_lookaside(kcontext); 1052 #endif 1053 loop_free(ctx); 1054 krb5_free_context(kcontext); 1055 return errout; 1056 } 1057