1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* kdc/main.c - Main procedure body for the KDC server process */
4 * Copyright 1990,2001,2008,2009 by the Massachusetts Institute of Technology.
6 * Export of this software from the United States of America may
7 * require a specific license from the United States Government.
8 * It is the responsibility of any person or organization contemplating
9 * export to obtain such a license before exporting.
11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12 * distribute this software and its documentation for any purpose and
13 * without fee is hereby granted, provided that the above copyright
14 * notice appear in all copies and that both that copyright notice and
15 * this permission notice appear in supporting documentation, and that
16 * the name of M.I.T. not be used in advertising or publicity pertaining
17 * to distribution of the software without specific, written prior
18 * permission. Furthermore if you modify this software you must label
19 * your software as modified software and not distribute it in such a
20 * fashion that it might be confused with the original M.I.T. software.
21 * M.I.T. makes no representations about the suitability of
22 * this software for any purpose. It is provided "as is" without express
23 * or implied warranty.
26 * Copyright (c) 2006-2008, Novell, Inc.
27 * All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions are met:
32 * * Redistributions of source code must retain the above copyright notice,
33 * this list of conditions and the following disclaimer.
34 * * Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * * The copyright holder's name is not used to endorse or promote products
38 * derived from this software without specific prior written permission.
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
41 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
44 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
48 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
50 * POSSIBILITY OF SUCH DAMAGE.
65 #include "adm_proto.h"
70 #include "net-server.h"
71 #ifdef HAVE_NETINET_IN_H
72 #include <netinet/in.h>
75 #if defined(NEED_DAEMON_PROTO)
76 extern int daemon(int, int);
79 static void usage (char *);
81 static krb5_error_code setup_sam (void);
83 static void initialize_realms (krb5_context, int, char **);
85 static void finish_realms (void);
87 static int nofork = 0;
88 static int workers = 0;
89 static const char *pid_file = NULL;
90 static int rkey_init_done = 0;
91 static volatile int signal_received = 0;
92 static volatile int sighup_received = 0;
94 #define KRB5_KDC_MAX_REALMS 32
96 static krb5_context kdc_err_context;
97 static const char *kdc_progname;
100 * We use krb5_klog_init to set up a com_err callback to log error
101 * messages. The callback also pulls the error message out of the
102 * context we pass to krb5_klog_init; however, we use realm-specific
103 * contexts for most of our krb5 library calls, so the error message
104 * isn't present in the global context. This wrapper ensures that the
105 * error message state from the call context is copied into the
106 * context known by krb5_klog. call_context can be NULL if the error
107 * code did not come from a krb5 library function.
110 kdc_err(krb5_context call_context, errcode_t code, const char *fmt, ...)
115 krb5_copy_error_message(kdc_err_context, call_context);
117 com_err_va(kdc_progname, code, fmt, ap);
122 * Find the realm entry for a given realm.
125 find_realm_data(char *rname, krb5_ui_4 rsize)
128 for (i=0; i<kdc_numrealms; i++) {
129 if ((rsize == strlen(kdc_realmlist[i]->realm_name)) &&
130 !strncmp(rname, kdc_realmlist[i]->realm_name, rsize))
131 return(kdc_realmlist[i]);
133 return((kdc_realm_t *) NULL);
137 setup_server_realm(krb5_principal sprinc)
139 krb5_error_code kret;
140 kdc_realm_t *newrealm;
143 if (kdc_numrealms > 1) {
144 if (!(newrealm = find_realm_data(sprinc->realm.data,
145 (krb5_ui_4) sprinc->realm.length)))
148 kdc_active_realm = newrealm;
151 kdc_active_realm = kdc_realmlist[0];
156 finish_realm(kdc_realm_t *rdp)
159 free(rdp->realm_name);
160 if (rdp->realm_mpname)
161 free(rdp->realm_mpname);
162 if (rdp->realm_stash)
163 free(rdp->realm_stash);
164 if (rdp->realm_ports)
165 free(rdp->realm_ports);
166 if (rdp->realm_tcp_ports)
167 free(rdp->realm_tcp_ports);
168 if (rdp->realm_keytab)
169 krb5_kt_close(rdp->realm_context, rdp->realm_keytab);
170 if (rdp->realm_host_based_services)
171 free(rdp->realm_host_based_services);
172 if (rdp->realm_no_host_referral)
173 free(rdp->realm_no_host_referral);
174 if (rdp->realm_context) {
175 if (rdp->realm_mprinc)
176 krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
177 if (rdp->realm_mkey.length && rdp->realm_mkey.contents) {
178 /* XXX shouldn't memset be zap for safety? */
179 memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length);
180 free(rdp->realm_mkey.contents);
183 krb5_dbe_free_key_list(rdp->realm_context, rdp->mkey_list);
184 krb5_db_fini(rdp->realm_context);
185 if (rdp->realm_tgsprinc)
186 krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
187 krb5_free_context(rdp->realm_context);
189 memset(rdp, 0, sizeof(*rdp));
193 static krb5_error_code
194 handle_referral_params(krb5_realm_params *rparams,
195 char *no_refrls, char *host_based_srvcs,
198 krb5_error_code retval = 0;
199 if (no_refrls && krb5_match_config_pattern(no_refrls, KRB5_CONF_ASTERISK) == TRUE) {
200 rdp->realm_no_host_referral = strdup(KRB5_CONF_ASTERISK);
201 if (!rdp->realm_no_host_referral)
204 if (rparams && rparams->realm_no_host_referral) {
205 if (krb5_match_config_pattern(rparams->realm_no_host_referral,
206 KRB5_CONF_ASTERISK) == TRUE) {
207 rdp->realm_no_host_referral = strdup(KRB5_CONF_ASTERISK);
208 if (!rdp->realm_no_host_referral)
210 } else if (no_refrls && (asprintf(&(rdp->realm_no_host_referral),
211 "%s%s%s%s%s", " ", no_refrls," ",
212 rparams->realm_no_host_referral, " ") < 0))
214 else if (asprintf(&(rdp->realm_no_host_referral),"%s%s%s", " ",
215 rparams->realm_no_host_referral, " ") < 0)
217 } else if( no_refrls != NULL) {
218 if ( asprintf(&(rdp->realm_no_host_referral),
219 "%s%s%s", " ", no_refrls, " ") < 0)
222 rdp->realm_no_host_referral = NULL;
225 if (rdp->realm_no_host_referral &&
226 krb5_match_config_pattern(rdp->realm_no_host_referral,
227 KRB5_CONF_ASTERISK) == TRUE) {
228 rdp->realm_host_based_services = NULL;
232 if (host_based_srvcs &&
233 (krb5_match_config_pattern(host_based_srvcs, KRB5_CONF_ASTERISK) == TRUE)) {
234 rdp->realm_host_based_services = strdup(KRB5_CONF_ASTERISK);
235 if (!rdp->realm_host_based_services)
238 if (rparams && rparams->realm_host_based_services) {
239 if (krb5_match_config_pattern(rparams->realm_host_based_services,
240 KRB5_CONF_ASTERISK) == TRUE) {
241 rdp->realm_host_based_services = strdup(KRB5_CONF_ASTERISK);
242 if (!rdp->realm_host_based_services)
244 } else if (host_based_srvcs) {
245 if (asprintf(&(rdp->realm_host_based_services), "%s%s%s%s%s",
246 " ", host_based_srvcs," ",
247 rparams->realm_host_based_services, " ") < 0)
249 } else if (asprintf(&(rdp->realm_host_based_services),"%s%s%s", " ",
250 rparams->realm_host_based_services, " ") < 0)
252 } else if (host_based_srvcs) {
253 if (asprintf(&(rdp->realm_host_based_services),"%s%s%s", " ",
254 host_based_srvcs, " ") < 0)
257 rdp->realm_host_based_services = NULL;
264 * Initialize a realm control structure from the alternate profile or from
265 * the specified defaults.
267 * After we're complete here, the essence of the realm is embodied in the
268 * realm data and we should be all set to begin operation for that realm.
270 static krb5_error_code
271 init_realm(kdc_realm_t *rdp, char *realm, char *def_mpname,
272 krb5_enctype def_enctype, char *def_udp_ports, char *def_tcp_ports,
273 krb5_boolean def_manual, krb5_boolean def_restrict_anon,
274 char **db_args, char *no_refrls, char *host_based_srvcs)
276 krb5_error_code kret;
278 krb5_realm_params *rparams;
280 krb5_kvno mkvno = IGNORE_VNO;
282 memset(rdp, 0, sizeof(kdc_realm_t));
288 rdp->realm_name = strdup(realm);
289 if (rdp->realm_name == NULL) {
293 kret = krb5int_init_context_kdc(&rdp->realm_context);
295 kdc_err(NULL, kret, _("while getting context for realm %s"), realm);
299 kret = krb5_read_realm_params(rdp->realm_context, rdp->realm_name,
302 kdc_err(rdp->realm_context, kret, _("while reading realm parameters"));
306 /* Handle profile file name */
307 if (rparams && rparams->realm_profile) {
308 rdp->realm_profile = strdup(rparams->realm_profile);
309 if (!rdp->realm_profile) {
315 /* Handle master key name */
316 if (rparams && rparams->realm_mkey_name)
317 rdp->realm_mpname = strdup(rparams->realm_mkey_name);
319 rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) :
320 strdup(KRB5_KDB_M_NAME);
321 if (!rdp->realm_mpname) {
326 /* Handle KDC ports */
327 if (rparams && rparams->realm_kdc_ports)
328 rdp->realm_ports = strdup(rparams->realm_kdc_ports);
330 rdp->realm_ports = strdup(def_udp_ports);
331 if (!rdp->realm_ports) {
335 if (rparams && rparams->realm_kdc_tcp_ports)
336 rdp->realm_tcp_ports = strdup(rparams->realm_kdc_tcp_ports);
338 rdp->realm_tcp_ports = strdup(def_tcp_ports);
339 if (!rdp->realm_tcp_ports) {
343 /* Handle stash file */
344 if (rparams && rparams->realm_stash_file) {
345 rdp->realm_stash = strdup(rparams->realm_stash_file);
346 if (!rdp->realm_stash) {
354 if (rparams && rparams->realm_restrict_anon_valid)
355 rdp->realm_restrict_anon = rparams->realm_restrict_anon;
357 rdp->realm_restrict_anon = def_restrict_anon;
359 /* Handle master key type */
360 if (rparams && rparams->realm_enctype_valid)
361 rdp->realm_mkey.enctype = (krb5_enctype) rparams->realm_enctype;
363 rdp->realm_mkey.enctype = manual ? def_enctype : ENCTYPE_UNKNOWN;
365 /* Handle reject-bad-transit flag */
366 if (rparams && rparams->realm_reject_bad_transit_valid)
367 rdp->realm_reject_bad_transit = rparams->realm_reject_bad_transit;
369 rdp->realm_reject_bad_transit = 1;
371 /* Handle ticket maximum life */
372 rdp->realm_maxlife = (rparams && rparams->realm_max_life_valid) ?
373 rparams->realm_max_life : KRB5_KDB_MAX_LIFE;
375 /* Handle ticket renewable maximum life */
376 rdp->realm_maxrlife = (rparams && rparams->realm_max_rlife_valid) ?
377 rparams->realm_max_rlife : KRB5_KDB_MAX_RLIFE;
379 /* Handle KDC referrals */
380 kret = handle_referral_params(rparams, no_refrls, host_based_srvcs, rdp);
385 krb5_free_realm_params(rdp->realm_context, rparams);
388 * We've got our parameters, now go and setup our realm context.
391 /* Set the default realm of this context */
392 if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) {
393 kdc_err(rdp->realm_context, kret,
394 _("while setting default realm to %s"), realm);
398 /* first open the database before doing anything */
399 kdb_open_flags = KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_KDC;
400 if ((kret = krb5_db_open(rdp->realm_context, db_args, kdb_open_flags))) {
401 kdc_err(rdp->realm_context, kret,
402 _("while initializing database for realm %s"), realm);
406 /* Assemble and parse the master key name */
407 if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname,
408 rdp->realm_name, (char **) NULL,
409 &rdp->realm_mprinc))) {
410 kdc_err(rdp->realm_context, kret,
411 _("while setting up master key name %s for realm %s"),
412 rdp->realm_mpname, realm);
417 * Get the master key (note, may not be the most current mkey).
419 if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc,
420 rdp->realm_mkey.enctype, manual,
421 FALSE, rdp->realm_stash,
422 &mkvno, NULL, &rdp->realm_mkey))) {
423 kdc_err(rdp->realm_context, kret,
424 _("while fetching master key %s for realm %s"),
425 rdp->realm_mpname, realm);
429 if ((kret = krb5_db_fetch_mkey_list(rdp->realm_context, rdp->realm_mprinc,
430 &rdp->realm_mkey, mkvno, &rdp->mkey_list))) {
431 kdc_err(rdp->realm_context, kret,
432 _("while fetching master keys list for realm %s"), realm);
437 /* Set up the keytab */
438 if ((kret = krb5_ktkdb_resolve(rdp->realm_context, NULL,
439 &rdp->realm_keytab))) {
440 kdc_err(rdp->realm_context, kret,
441 _("while resolving kdb keytab for realm %s"), realm);
445 /* Preformat the TGS name */
446 if ((kret = krb5_build_principal(rdp->realm_context, &rdp->realm_tgsprinc,
447 strlen(realm), realm, KRB5_TGS_NAME,
448 realm, (char *) NULL))) {
449 kdc_err(rdp->realm_context, kret,
450 _("while building TGS name for realm %s"), realm);
454 if (!rkey_init_done) {
457 * If all that worked, then initialize the random key
461 seed.length = rdp->realm_mkey.length;
462 seed.data = (char *)rdp->realm_mkey.contents;
464 if ((kret = krb5_c_random_add_entropy(rdp->realm_context,
465 KRB5_C_RANDSOURCE_TRUSTEDPARTY, &seed)))
472 * If we choked, then clean up any dirt we may have dropped on the floor.
482 on_monitor_signal(int signo)
484 signal_received = signo;
494 on_monitor_sighup(int signo)
506 * Kill the worker subprocesses given by pids[0..bound-1], skipping any which
507 * are set to -1, and wait for them to exit (so that we know the ports are no
511 terminate_workers(pid_t *pids, int bound)
513 int i, status, num_active = 0;
516 /* Kill the active worker pids. */
517 for (i = 0; i < bound; i++) {
520 kill(pids[i], SIGTERM);
524 /* Wait for them to exit. */
525 while (num_active > 0) {
533 * Create num worker processes and return successfully in each child. The
534 * parent process will act as a supervisor and will only return from this
535 * function in error cases.
537 static krb5_error_code
538 create_workers(verto_ctx *ctx, int num)
540 krb5_error_code retval;
544 struct sigaction s_action;
545 #endif /* POSIX_SIGNALS */
548 * Setup our signal handlers which will forward to the children.
549 * These handlers will be overriden in the child processes.
552 (void) sigemptyset(&s_action.sa_mask);
553 s_action.sa_flags = 0;
554 s_action.sa_handler = on_monitor_signal;
555 (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL);
556 (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL);
557 (void) sigaction(SIGQUIT, &s_action, (struct sigaction *) NULL);
558 s_action.sa_handler = on_monitor_sighup;
559 (void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL);
560 #else /* POSIX_SIGNALS */
561 signal(SIGINT, on_monitor_signal);
562 signal(SIGTERM, on_monitor_signal);
563 signal(SIGQUIT, on_monitor_signal);
564 signal(SIGHUP, on_monitor_sighup);
565 #endif /* POSIX_SIGNALS */
567 /* Create child worker processes; return in each child. */
568 krb5_klog_syslog(LOG_INFO, _("creating %d worker processes"), num);
569 pids = calloc(num, sizeof(pid_t));
572 for (i = 0; i < num; i++) {
575 if (!verto_reinitialize(ctx)) {
576 krb5_klog_syslog(LOG_ERR,
577 _("Unable to reinitialize main loop"));
580 retval = loop_setup_signals(ctx, NULL, reset_for_hangup);
582 krb5_klog_syslog(LOG_ERR, _("Unable to initialize signal "
583 "handlers in pid %d"), pid);
587 /* Avoid race condition */
591 /* Return control to main() in the new worker process. */
596 /* Couldn't fork enough times. */
598 terminate_workers(pids, i);
605 /* We're going to use our own main loop here. */
608 /* Supervise the worker processes. */
609 while (!signal_received) {
610 /* Wait until a worker process exits or we get a signal. */
613 krb5_klog_syslog(LOG_ERR, _("worker %ld exited with status %d"),
616 /* Remove the pid from the table. */
617 for (i = 0; i < num; i++) {
622 /* When one worker process exits, terminate them all, so that KDC
623 * crashes behave similarly with or without worker processes. */
627 /* Propagate HUP signal to worker processes if we received one. */
628 if (sighup_received) {
630 for (i = 0; i < num; i++) {
632 kill(pids[i], SIGHUP);
637 krb5_klog_syslog(LOG_INFO, _("signal %d received in supervisor"),
640 terminate_workers(pids, num);
645 static krb5_error_code
648 return krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_MD5, &psr_key);
655 _("usage: %s [-x db_args]* [-d dbpathname] [-r dbrealmname]\n"
656 "\t\t[-R replaycachename] [-m] [-k masterenctype]\n"
657 "\t\t[-M masterkeyname] [-p port] [-P pid_file]\n"
658 "\t\t[-n] [-w numworkers] [/]\n\n"
660 "\t[-x db_args]* - Any number of database specific arguments.\n"
661 "\t\t\tLook at each database module documentation for "
662 "\t\t\tsupported arguments\n"),
669 initialize_realms(krb5_context kcontext, int argc, char **argv)
672 char *db_name = (char *) NULL;
673 char *lrealm = (char *) NULL;
674 char *mkey_name = (char *) NULL;
675 krb5_error_code retval;
676 krb5_enctype menctype = ENCTYPE_UNKNOWN;
677 kdc_realm_t *rdatap = NULL;
678 krb5_boolean manual = FALSE;
679 krb5_boolean def_restrict_anon;
680 char *default_udp_ports = 0;
681 char *default_tcp_ports = 0;
683 const char *hierarchy[3];
684 char *no_refrls = NULL;
685 char *host_based_srvcs = NULL;
686 int db_args_size = 0;
687 char **db_args = NULL;
691 if (!krb5_aprof_init(DEFAULT_KDC_PROFILE, KDC_PROFILE_ENV, &aprof)) {
692 hierarchy[0] = KRB5_CONF_KDCDEFAULTS;
693 hierarchy[1] = KRB5_CONF_KDC_PORTS;
694 hierarchy[2] = (char *) NULL;
695 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_udp_ports))
696 default_udp_ports = 0;
697 hierarchy[1] = KRB5_CONF_KDC_TCP_PORTS;
698 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_tcp_ports))
699 default_tcp_ports = 0;
700 hierarchy[1] = KRB5_CONF_MAX_DGRAM_REPLY_SIZE;
701 if (krb5_aprof_get_int32(aprof, hierarchy, TRUE, &max_dgram_reply_size))
702 max_dgram_reply_size = MAX_DGRAM_SIZE;
703 hierarchy[1] = KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT;
704 if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE, &def_restrict_anon))
705 def_restrict_anon = FALSE;
706 hierarchy[1] = KRB5_CONF_NO_HOST_REFERRAL;
707 if (krb5_aprof_get_string_all(aprof, hierarchy, &no_refrls))
710 krb5_match_config_pattern(no_refrls, KRB5_CONF_ASTERISK) == FALSE) {
711 hierarchy[1] = KRB5_CONF_HOST_BASED_SERVICES;
712 if (krb5_aprof_get_string_all(aprof, hierarchy, &host_based_srvcs))
713 host_based_srvcs = 0;
716 krb5_aprof_finish(aprof);
719 if (default_udp_ports == 0) {
720 default_udp_ports = strdup(DEFAULT_KDC_UDP_PORTLIST);
721 if (default_udp_ports == 0) {
722 fprintf(stderr, _(" KDC cannot initialize. Not enough memory\n"));
726 if (default_tcp_ports == 0) {
727 default_tcp_ports = strdup(DEFAULT_KDC_TCP_PORTLIST);
728 if (default_tcp_ports == 0) {
729 fprintf(stderr, _(" KDC cannot initialize. Not enough memory\n"));
735 * Loop through the option list. Each time we encounter a realm name,
736 * use the previously scanned options to fill in for defaults.
738 while ((c = getopt(argc, argv, "x:r:d:mM:k:R:e:P:p:s:nw:4:X3")) != -1) {
743 char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
746 fprintf(stderr, _("%s: KDC cannot initialize. Not enough "
747 "memory\n"), argv[0]);
753 db_args[db_args_size-1] = optarg;
754 db_args[db_args_size] = NULL;
757 case 'r': /* realm name for db */
758 if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) {
759 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
760 if ((retval = init_realm(rdatap, optarg, mkey_name,
761 menctype, default_udp_ports,
762 default_tcp_ports, manual,
763 def_restrict_anon, db_args,
764 no_refrls, host_based_srvcs))) {
765 fprintf(stderr, _("%s: cannot initialize realm %s - "
766 "see log file for details\n"),
770 kdc_realmlist[kdc_numrealms] = rdatap;
772 free(db_args), db_args=NULL, db_args_size = 0;
776 fprintf(stderr, _("%s: cannot initialize realm %s. Not "
777 "enough memory\n"), argv[0], optarg);
782 case 'd': /* pathname for db */
783 /* now db_name is not a seperate argument.
784 * It has to be passed as part of the db_args
786 if( db_name == NULL ) {
787 if (asprintf(&db_name, "dbname=%s", optarg) < 0) {
788 fprintf(stderr, _("%s: KDC cannot initialize. Not enough "
789 "memory\n"), argv[0]);
796 char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
799 fprintf(stderr, _("%s: KDC cannot initialize. Not enough "
800 "memory\n"), argv[0]);
806 db_args[db_args_size-1] = db_name;
807 db_args[db_args_size] = NULL;
809 case 'm': /* manual type-in of master key */
811 if (menctype == ENCTYPE_UNKNOWN)
812 menctype = ENCTYPE_DES_CBC_CRC;
814 case 'M': /* master key name in DB */
818 nofork++; /* don't detach from terminal */
820 case 'w': /* create multiple worker processes */
821 workers = atoi(optarg);
825 case 'k': /* enctype for master key */
826 if (krb5_string_to_enctype(optarg, &menctype))
827 com_err(argv[0], 0, _("invalid enctype %s"), optarg);
830 /* Replay cache name; defunct since we don't use a replay cache. */
836 if (default_udp_ports)
837 free(default_udp_ports);
838 default_udp_ports = strdup(optarg);
839 if (!default_udp_ports) {
840 fprintf(stderr, _(" KDC cannot initialize. Not enough "
845 if (default_tcp_ports)
846 free(default_tcp_ports);
847 default_tcp_ports = strdup(optarg);
861 * Check to see if we processed any realms.
863 if (kdc_numrealms == 0) {
864 /* no realm specified, use default realm */
865 if ((retval = krb5_get_default_realm(kcontext, &lrealm))) {
866 com_err(argv[0], retval,
867 _("while attempting to retrieve default realm"));
869 _("%s: %s, attempting to retrieve default realm\n"),
870 argv[0], krb5_get_error_message(kcontext, retval));
873 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
874 if ((retval = init_realm(rdatap, lrealm, mkey_name, menctype,
875 default_udp_ports, default_tcp_ports,
876 manual, def_restrict_anon, db_args,
877 no_refrls, host_based_srvcs))) {
878 fprintf(stderr, _("%s: cannot initialize realm %s - see log "
879 "file for details\n"), argv[0], lrealm);
882 kdc_realmlist[0] = rdatap;
885 krb5_free_default_realm(kcontext, lrealm);
888 /* Ensure that this is set for our first request. */
889 kdc_active_realm = kdc_realmlist[0];
890 if (default_udp_ports)
891 free(default_udp_ports);
892 if (default_tcp_ports)
893 free(default_tcp_ports);
898 if (host_based_srvcs)
899 free(host_based_srvcs);
906 static krb5_error_code
907 write_pid_file(const char *path)
912 file = fopen(path, "w");
915 pid = (unsigned long) getpid();
916 if (fprintf(file, "%ld\n", pid) < 0 || fclose(file) == EOF)
926 for (i = 0; i < kdc_numrealms; i++) {
927 finish_realm(kdc_realmlist[i]);
928 kdc_realmlist[i] = 0;
938 initialize database access (fetch master key, open DB)
945 determine packet type, dispatch to handling routine
952 clean up secrets, close db
959 int main(int argc, char **argv)
961 krb5_error_code retval;
962 krb5_context kcontext;
967 setlocale(LC_MESSAGES, "");
968 if (strrchr(argv[0], '/'))
969 argv[0] = strrchr(argv[0], '/')+1;
971 if (!(kdc_realmlist = (kdc_realm_t **) malloc(sizeof(kdc_realm_t *) *
972 KRB5_KDC_MAX_REALMS))) {
973 fprintf(stderr, _("%s: cannot get memory for realm list\n"), argv[0]);
976 memset(kdc_realmlist, 0,
977 (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS));
980 * A note about Kerberos contexts: This context, "kcontext", is used
981 * for the KDC operations, i.e. setup, network connection and error
982 * reporting. The per-realm operations use the "realm_context"
983 * associated with each realm.
985 retval = krb5int_init_context_kdc(&kcontext);
987 com_err(argv[0], retval, _("while initializing krb5"));
990 krb5_klog_init(kcontext, "kdc", argv[0], 1);
991 kdc_err_context = kcontext;
992 kdc_progname = argv[0];
993 /* N.B.: After this point, com_err sends output to the KDC log
994 file, and not to stderr. We use the kdc_err wrapper around
995 com_err to ensure that the error state exists in the context
996 known to the krb5_klog callback. */
998 initialize_kdc5_error_table();
1001 * Scan through the argument list
1003 initialize_realms(kcontext, argc, argv);
1005 ctx = loop_init(VERTO_EV_TYPE_NONE);
1007 kdc_err(kcontext, ENOMEM, _("while creating main loop"));
1012 load_preauth_plugins(kcontext);
1013 load_authdata_plugins(kcontext);
1015 retval = setup_sam();
1017 kdc_err(kcontext, retval, _("while initializing SAM"));
1022 /* Handle each realm's ports */
1023 for (i=0; i<kdc_numrealms; i++) {
1024 char *cp = kdc_realmlist[i]->realm_ports;
1027 if (*cp == ',' || isspace((int) *cp)) {
1031 port = strtol(cp, &cp, 10);
1034 retval = loop_add_udp_port(port);
1036 goto net_init_error;
1039 cp = kdc_realmlist[i]->realm_tcp_ports;
1041 if (*cp == ',' || isspace((int) *cp)) {
1045 port = strtol(cp, &cp, 10);
1048 retval = loop_add_tcp_port(port);
1050 goto net_init_error;
1055 * Setup network listeners. Disallow network reconfig in response to
1056 * routing socket messages if we're using worker processes, since the
1057 * children won't be able to re-open the listener sockets. Hopefully our
1058 * platform has pktinfo support and doesn't need reconfigs.
1061 retval = loop_setup_routing_socket(ctx, NULL, kdc_progname);
1063 kdc_err(kcontext, retval, _("while initializing routing socket"));
1067 retval = loop_setup_signals(ctx, NULL, reset_for_hangup);
1069 kdc_err(kcontext, retval, _("while initializing signal handlers"));
1074 if ((retval = loop_setup_network(ctx, NULL, kdc_progname))) {
1076 kdc_err(kcontext, retval, _("while initializing network"));
1080 if (!nofork && daemon(0, 0)) {
1081 kdc_err(kcontext, errno, _("while detaching from tty"));
1085 if (pid_file != NULL) {
1086 retval = write_pid_file(pid_file);
1088 kdc_err(kcontext, retval, _("while creating PID file"));
1095 retval = create_workers(ctx, workers);
1097 kdc_err(kcontext, errno, _("creating worker processes"));
1100 /* We get here only in a worker child process; re-initialize realms. */
1101 initialize_realms(kcontext, argc, argv);
1103 krb5_klog_syslog(LOG_INFO, _("commencing operation"));
1105 fprintf(stderr, _("%s: starting...\n"), kdc_progname);
1109 krb5_klog_syslog(LOG_INFO, _("shutting down"));
1110 unload_preauth_plugins(kcontext);
1111 unload_authdata_plugins(kcontext);
1112 krb5_klog_close(kdc_context);
1115 free(kdc_realmlist);
1117 kdc_free_lookaside(kcontext);
1119 krb5_free_context(kcontext);