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_sigtype request_exit (int);
82 static krb5_sigtype request_hup (int);
84 static void setup_signal_handlers (void);
86 static krb5_error_code setup_sam (void);
88 static void initialize_realms (krb5_context, int, char **);
90 static void finish_realms (void);
92 static int nofork = 0;
93 static int workers = 0;
94 static const char *pid_file = NULL;
95 static int rkey_init_done = 0;
98 static struct sigaction s_action;
99 #endif /* POSIX_SIGNALS */
101 #define KRB5_KDC_MAX_REALMS 32
103 static krb5_context kdc_err_context;
104 static const char *kdc_progname;
107 * We use krb5_klog_init to set up a com_err callback to log error
108 * messages. The callback also pulls the error message out of the
109 * context we pass to krb5_klog_init; however, we use realm-specific
110 * contexts for most of our krb5 library calls, so the error message
111 * isn't present in the global context. This wrapper ensures that the
112 * error message state from the call context is copied into the
113 * context known by krb5_klog. call_context can be NULL if the error
114 * code did not come from a krb5 library function.
117 kdc_err(krb5_context call_context, errcode_t code, const char *fmt, ...)
122 krb5_copy_error_message(kdc_err_context, call_context);
124 com_err_va(kdc_progname, code, fmt, ap);
129 * Find the realm entry for a given realm.
132 find_realm_data(char *rname, krb5_ui_4 rsize)
135 for (i=0; i<kdc_numrealms; i++) {
136 if ((rsize == strlen(kdc_realmlist[i]->realm_name)) &&
137 !strncmp(rname, kdc_realmlist[i]->realm_name, rsize))
138 return(kdc_realmlist[i]);
140 return((kdc_realm_t *) NULL);
144 setup_server_realm(krb5_principal sprinc)
146 krb5_error_code kret;
147 kdc_realm_t *newrealm;
150 if (kdc_numrealms > 1) {
151 if (!(newrealm = find_realm_data(sprinc->realm.data,
152 (krb5_ui_4) sprinc->realm.length)))
155 kdc_active_realm = newrealm;
158 kdc_active_realm = kdc_realmlist[0];
163 finish_realm(kdc_realm_t *rdp)
166 free(rdp->realm_name);
167 if (rdp->realm_mpname)
168 free(rdp->realm_mpname);
169 if (rdp->realm_stash)
170 free(rdp->realm_stash);
171 if (rdp->realm_ports)
172 free(rdp->realm_ports);
173 if (rdp->realm_tcp_ports)
174 free(rdp->realm_tcp_ports);
175 if (rdp->realm_keytab)
176 krb5_kt_close(rdp->realm_context, rdp->realm_keytab);
177 if (rdp->realm_host_based_services)
178 free(rdp->realm_host_based_services);
179 if (rdp->realm_no_host_referral)
180 free(rdp->realm_no_host_referral);
181 if (rdp->realm_context) {
182 if (rdp->realm_mprinc)
183 krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
184 if (rdp->realm_mkey.length && rdp->realm_mkey.contents) {
185 /* XXX shouldn't memset be zap for safety? */
186 memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length);
187 free(rdp->realm_mkey.contents);
190 krb5_dbe_free_key_list(rdp->realm_context, rdp->mkey_list);
191 krb5_db_fini(rdp->realm_context);
192 if (rdp->realm_tgsprinc)
193 krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
194 krb5_free_context(rdp->realm_context);
196 memset(rdp, 0, sizeof(*rdp));
200 static krb5_error_code
201 handle_referral_params(krb5_realm_params *rparams,
202 char *no_refrls, char *host_based_srvcs,
205 krb5_error_code retval = 0;
206 if (no_refrls && krb5_match_config_pattern(no_refrls, KRB5_CONF_ASTERISK) == TRUE) {
207 rdp->realm_no_host_referral = strdup(KRB5_CONF_ASTERISK);
208 if (!rdp->realm_no_host_referral)
211 if (rparams && rparams->realm_no_host_referral) {
212 if (krb5_match_config_pattern(rparams->realm_no_host_referral,
213 KRB5_CONF_ASTERISK) == TRUE) {
214 rdp->realm_no_host_referral = strdup(KRB5_CONF_ASTERISK);
215 if (!rdp->realm_no_host_referral)
217 } else if (no_refrls && (asprintf(&(rdp->realm_no_host_referral),
218 "%s%s%s%s%s", " ", no_refrls," ",
219 rparams->realm_no_host_referral, " ") < 0))
221 else if (asprintf(&(rdp->realm_no_host_referral),"%s%s%s", " ",
222 rparams->realm_no_host_referral, " ") < 0)
224 } else if( no_refrls != NULL) {
225 if ( asprintf(&(rdp->realm_no_host_referral),
226 "%s%s%s", " ", no_refrls, " ") < 0)
229 rdp->realm_no_host_referral = NULL;
232 if (rdp->realm_no_host_referral &&
233 krb5_match_config_pattern(rdp->realm_no_host_referral,
234 KRB5_CONF_ASTERISK) == TRUE) {
235 rdp->realm_host_based_services = NULL;
239 if (host_based_srvcs &&
240 (krb5_match_config_pattern(host_based_srvcs, KRB5_CONF_ASTERISK) == TRUE)) {
241 rdp->realm_host_based_services = strdup(KRB5_CONF_ASTERISK);
242 if (!rdp->realm_host_based_services)
245 if (rparams && rparams->realm_host_based_services) {
246 if (krb5_match_config_pattern(rparams->realm_host_based_services,
247 KRB5_CONF_ASTERISK) == TRUE) {
248 rdp->realm_host_based_services = strdup(KRB5_CONF_ASTERISK);
249 if (!rdp->realm_host_based_services)
251 } else if (host_based_srvcs) {
252 if (asprintf(&(rdp->realm_host_based_services), "%s%s%s%s%s",
253 " ", host_based_srvcs," ",
254 rparams->realm_host_based_services, " ") < 0)
256 } else if (asprintf(&(rdp->realm_host_based_services),"%s%s%s", " ",
257 rparams->realm_host_based_services, " ") < 0)
259 } else if (host_based_srvcs) {
260 if (asprintf(&(rdp->realm_host_based_services),"%s%s%s", " ",
261 host_based_srvcs, " ") < 0)
264 rdp->realm_host_based_services = NULL;
271 * Initialize a realm control structure from the alternate profile or from
272 * the specified defaults.
274 * After we're complete here, the essence of the realm is embodied in the
275 * realm data and we should be all set to begin operation for that realm.
277 static krb5_error_code
278 init_realm(kdc_realm_t *rdp, char *realm, char *def_mpname,
279 krb5_enctype def_enctype, char *def_udp_ports, char *def_tcp_ports,
280 krb5_boolean def_manual, krb5_boolean def_restrict_anon,
281 char **db_args, char *no_refrls, char *host_based_srvcs)
283 krb5_error_code kret;
285 krb5_realm_params *rparams;
287 krb5_kvno mkvno = IGNORE_VNO;
289 memset(rdp, 0, sizeof(kdc_realm_t));
295 rdp->realm_name = strdup(realm);
296 if (rdp->realm_name == NULL) {
300 kret = krb5int_init_context_kdc(&rdp->realm_context);
302 kdc_err(NULL, kret, _("while getting context for realm %s"), realm);
306 kret = krb5_read_realm_params(rdp->realm_context, rdp->realm_name,
309 kdc_err(rdp->realm_context, kret, _("while reading realm parameters"));
313 /* Handle profile file name */
314 if (rparams && rparams->realm_profile) {
315 rdp->realm_profile = strdup(rparams->realm_profile);
316 if (!rdp->realm_profile) {
322 /* Handle master key name */
323 if (rparams && rparams->realm_mkey_name)
324 rdp->realm_mpname = strdup(rparams->realm_mkey_name);
326 rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) :
327 strdup(KRB5_KDB_M_NAME);
328 if (!rdp->realm_mpname) {
333 /* Handle KDC ports */
334 if (rparams && rparams->realm_kdc_ports)
335 rdp->realm_ports = strdup(rparams->realm_kdc_ports);
337 rdp->realm_ports = strdup(def_udp_ports);
338 if (!rdp->realm_ports) {
342 if (rparams && rparams->realm_kdc_tcp_ports)
343 rdp->realm_tcp_ports = strdup(rparams->realm_kdc_tcp_ports);
345 rdp->realm_tcp_ports = strdup(def_tcp_ports);
346 if (!rdp->realm_tcp_ports) {
350 /* Handle stash file */
351 if (rparams && rparams->realm_stash_file) {
352 rdp->realm_stash = strdup(rparams->realm_stash_file);
353 if (!rdp->realm_stash) {
361 if (rparams && rparams->realm_restrict_anon_valid)
362 rdp->realm_restrict_anon = rparams->realm_restrict_anon;
364 rdp->realm_restrict_anon = def_restrict_anon;
366 /* Handle master key type */
367 if (rparams && rparams->realm_enctype_valid)
368 rdp->realm_mkey.enctype = (krb5_enctype) rparams->realm_enctype;
370 rdp->realm_mkey.enctype = manual ? def_enctype : ENCTYPE_UNKNOWN;
372 /* Handle reject-bad-transit flag */
373 if (rparams && rparams->realm_reject_bad_transit_valid)
374 rdp->realm_reject_bad_transit = rparams->realm_reject_bad_transit;
376 rdp->realm_reject_bad_transit = 1;
378 /* Handle ticket maximum life */
379 rdp->realm_maxlife = (rparams && rparams->realm_max_life_valid) ?
380 rparams->realm_max_life : KRB5_KDB_MAX_LIFE;
382 /* Handle ticket renewable maximum life */
383 rdp->realm_maxrlife = (rparams && rparams->realm_max_rlife_valid) ?
384 rparams->realm_max_rlife : KRB5_KDB_MAX_RLIFE;
386 /* Handle KDC referrals */
387 kret = handle_referral_params(rparams, no_refrls, host_based_srvcs, rdp);
392 krb5_free_realm_params(rdp->realm_context, rparams);
395 * We've got our parameters, now go and setup our realm context.
398 /* Set the default realm of this context */
399 if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) {
400 kdc_err(rdp->realm_context, kret,
401 _("while setting default realm to %s"), realm);
405 /* first open the database before doing anything */
406 kdb_open_flags = KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_KDC;
407 if ((kret = krb5_db_open(rdp->realm_context, db_args, kdb_open_flags))) {
408 kdc_err(rdp->realm_context, kret,
409 _("while initializing database for realm %s"), realm);
413 /* Assemble and parse the master key name */
414 if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname,
415 rdp->realm_name, (char **) NULL,
416 &rdp->realm_mprinc))) {
417 kdc_err(rdp->realm_context, kret,
418 _("while setting up master key name %s for realm %s"),
419 rdp->realm_mpname, realm);
424 * Get the master key (note, may not be the most current mkey).
426 if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc,
427 rdp->realm_mkey.enctype, manual,
428 FALSE, rdp->realm_stash,
429 &mkvno, NULL, &rdp->realm_mkey))) {
430 kdc_err(rdp->realm_context, kret,
431 _("while fetching master key %s for realm %s"),
432 rdp->realm_mpname, realm);
436 if ((kret = krb5_db_fetch_mkey_list(rdp->realm_context, rdp->realm_mprinc,
437 &rdp->realm_mkey, mkvno, &rdp->mkey_list))) {
438 kdc_err(rdp->realm_context, kret,
439 _("while fetching master keys list for realm %s"), realm);
444 /* Set up the keytab */
445 if ((kret = krb5_ktkdb_resolve(rdp->realm_context, NULL,
446 &rdp->realm_keytab))) {
447 kdc_err(rdp->realm_context, kret,
448 _("while resolving kdb keytab for realm %s"), realm);
452 /* Preformat the TGS name */
453 if ((kret = krb5_build_principal(rdp->realm_context, &rdp->realm_tgsprinc,
454 strlen(realm), realm, KRB5_TGS_NAME,
455 realm, (char *) NULL))) {
456 kdc_err(rdp->realm_context, kret,
457 _("while building TGS name for realm %s"), realm);
461 if (!rkey_init_done) {
464 * If all that worked, then initialize the random key
468 seed.length = rdp->realm_mkey.length;
469 seed.data = (char *)rdp->realm_mkey.contents;
471 if ((kret = krb5_c_random_add_entropy(rdp->realm_context,
472 KRB5_C_RANDSOURCE_TRUSTEDPARTY, &seed)))
479 * If we choked, then clean up any dirt we may have dropped on the floor.
489 request_exit(int signo)
491 signal_requests_exit = 1;
501 request_hup(int signo)
503 signal_requests_reset = 1;
513 setup_signal_handlers(void)
516 (void) sigemptyset(&s_action.sa_mask);
517 s_action.sa_flags = 0;
518 s_action.sa_handler = request_exit;
519 (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL);
520 (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL);
521 s_action.sa_handler = request_hup;
522 (void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL);
523 s_action.sa_handler = SIG_IGN;
524 (void) sigaction(SIGPIPE, &s_action, (struct sigaction *) NULL);
525 #else /* POSIX_SIGNALS */
526 signal(SIGINT, request_exit);
527 signal(SIGTERM, request_exit);
528 signal(SIGHUP, request_hup);
529 signal(SIGPIPE, SIG_IGN);
530 #endif /* POSIX_SIGNALS */
536 * Kill the worker subprocesses given by pids[0..bound-1], skipping any which
537 * are set to -1, and wait for them to exit (so that we know the ports are no
538 * longer in use). num_active must be the number of active (i.e. not -1) pids
542 terminate_workers(pid_t *pids, int bound, int num_active)
547 /* Kill the active worker pids. */
548 for (i = 0; i < bound; i++) {
550 kill(pids[i], SIGTERM);
553 /* Wait for them to exit. */
554 while (num_active > 0) {
562 * Create num worker processes and return successfully in each child. The
563 * parent process will act as a supervisor and will only return from this
564 * function in error cases.
566 static krb5_error_code
567 create_workers(int num)
569 int i, status, numleft;
572 /* Create child worker processes; return in each child. */
573 krb5_klog_syslog(LOG_INFO, _("creating %d worker processes"), num);
574 pids = calloc(num, sizeof(pid_t));
577 for (i = 0; i < num; i++) {
580 /* Return control to main() in the new worker process. */
585 /* Couldn't fork enough times. */
587 terminate_workers(pids, i, i);
594 /* Supervise the worker processes. */
596 while (!signal_requests_exit) {
597 /* Wait until a worker process exits or we get a signal. */
600 krb5_klog_syslog(LOG_ERR, _("worker %ld exited with status %d"),
603 /* Remove the pid from the table. */
604 for (i = 0; i < num; i++) {
609 /* When one worker process exits, terminate them all, so that KDC
610 * crashes behave similarly with or without worker processes. */
614 /* Propagate HUP signal to worker processes if we received one. */
615 if (signal_requests_reset) {
616 for (i = 0; i < num; i++) {
618 kill(pids[i], SIGHUP);
620 signal_requests_reset = 0;
623 if (signal_requests_exit) {
624 krb5_klog_syslog(LOG_INFO,
625 _("shutdown signal received in supervisor"));
628 terminate_workers(pids, num, numleft);
633 static krb5_error_code
636 return krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_MD5, &psr_key);
643 _("usage: %s [-x db_args]* [-d dbpathname] [-r dbrealmname]\n"
644 "\t\t[-R replaycachename] [-m] [-k masterenctype]\n"
645 "\t\t[-M masterkeyname] [-p port] [-P pid_file]\n"
646 "\t\t[-n] [-w numworkers] [/]\n\n"
648 "\t[-x db_args]* - Any number of database specific arguments.\n"
649 "\t\t\tLook at each database module documentation for "
650 "\t\t\tsupported arguments\n"),
657 initialize_realms(krb5_context kcontext, int argc, char **argv)
660 char *db_name = (char *) NULL;
661 char *lrealm = (char *) NULL;
662 char *mkey_name = (char *) NULL;
663 krb5_error_code retval;
664 krb5_enctype menctype = ENCTYPE_UNKNOWN;
665 kdc_realm_t *rdatap = NULL;
666 krb5_boolean manual = FALSE;
667 krb5_boolean def_restrict_anon;
668 char *default_udp_ports = 0;
669 char *default_tcp_ports = 0;
671 const char *hierarchy[3];
672 char *no_refrls = NULL;
673 char *host_based_srvcs = NULL;
674 int db_args_size = 0;
675 char **db_args = NULL;
679 if (!krb5_aprof_init(DEFAULT_KDC_PROFILE, KDC_PROFILE_ENV, &aprof)) {
680 hierarchy[0] = KRB5_CONF_KDCDEFAULTS;
681 hierarchy[1] = KRB5_CONF_KDC_PORTS;
682 hierarchy[2] = (char *) NULL;
683 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_udp_ports))
684 default_udp_ports = 0;
685 hierarchy[1] = KRB5_CONF_KDC_TCP_PORTS;
686 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_tcp_ports))
687 default_tcp_ports = 0;
688 hierarchy[1] = KRB5_CONF_MAX_DGRAM_REPLY_SIZE;
689 if (krb5_aprof_get_int32(aprof, hierarchy, TRUE, &max_dgram_reply_size))
690 max_dgram_reply_size = MAX_DGRAM_SIZE;
691 hierarchy[1] = KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT;
692 if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE, &def_restrict_anon))
693 def_restrict_anon = FALSE;
694 hierarchy[1] = KRB5_CONF_NO_HOST_REFERRAL;
695 if (krb5_aprof_get_string_all(aprof, hierarchy, &no_refrls))
698 krb5_match_config_pattern(no_refrls, KRB5_CONF_ASTERISK) == FALSE) {
699 hierarchy[1] = KRB5_CONF_HOST_BASED_SERVICES;
700 if (krb5_aprof_get_string_all(aprof, hierarchy, &host_based_srvcs))
701 host_based_srvcs = 0;
704 krb5_aprof_finish(aprof);
707 if (default_udp_ports == 0) {
708 default_udp_ports = strdup(DEFAULT_KDC_UDP_PORTLIST);
709 if (default_udp_ports == 0) {
710 fprintf(stderr, _(" KDC cannot initialize. Not enough memory\n"));
714 if (default_tcp_ports == 0) {
715 default_tcp_ports = strdup(DEFAULT_KDC_TCP_PORTLIST);
716 if (default_tcp_ports == 0) {
717 fprintf(stderr, _(" KDC cannot initialize. Not enough memory\n"));
723 * Loop through the option list. Each time we encounter a realm name,
724 * use the previously scanned options to fill in for defaults.
726 while ((c = getopt(argc, argv, "x:r:d:mM:k:R:e:P:p:s:nw:4:X3")) != -1) {
731 char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
734 fprintf(stderr, _("%s: KDC cannot initialize. Not enough "
735 "memory\n"), argv[0]);
741 db_args[db_args_size-1] = optarg;
742 db_args[db_args_size] = NULL;
745 case 'r': /* realm name for db */
746 if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) {
747 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
748 if ((retval = init_realm(rdatap, optarg, mkey_name,
749 menctype, default_udp_ports,
750 default_tcp_ports, manual,
751 def_restrict_anon, db_args,
752 no_refrls, host_based_srvcs))) {
753 fprintf(stderr, _("%s: cannot initialize realm %s - "
754 "see log file for details\n"),
758 kdc_realmlist[kdc_numrealms] = rdatap;
760 free(db_args), db_args=NULL, db_args_size = 0;
764 fprintf(stderr, _("%s: cannot initialize realm %s. Not "
765 "enough memory\n"), argv[0], optarg);
770 case 'd': /* pathname for db */
771 /* now db_name is not a seperate argument.
772 * It has to be passed as part of the db_args
774 if( db_name == NULL ) {
775 if (asprintf(&db_name, "dbname=%s", optarg) < 0) {
776 fprintf(stderr, _("%s: KDC cannot initialize. Not enough "
777 "memory\n"), argv[0]);
784 char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
787 fprintf(stderr, _("%s: KDC cannot initialize. Not enough "
788 "memory\n"), argv[0]);
794 db_args[db_args_size-1] = db_name;
795 db_args[db_args_size] = NULL;
797 case 'm': /* manual type-in of master key */
799 if (menctype == ENCTYPE_UNKNOWN)
800 menctype = ENCTYPE_DES_CBC_CRC;
802 case 'M': /* master key name in DB */
806 nofork++; /* don't detach from terminal */
808 case 'w': /* create multiple worker processes */
809 workers = atoi(optarg);
813 case 'k': /* enctype for master key */
814 if (krb5_string_to_enctype(optarg, &menctype))
815 com_err(argv[0], 0, _("invalid enctype %s"), optarg);
818 /* Replay cache name; defunct since we don't use a replay cache. */
824 if (default_udp_ports)
825 free(default_udp_ports);
826 default_udp_ports = strdup(optarg);
827 if (!default_udp_ports) {
828 fprintf(stderr, _(" KDC cannot initialize. Not enough "
833 if (default_tcp_ports)
834 free(default_tcp_ports);
835 default_tcp_ports = strdup(optarg);
849 * Check to see if we processed any realms.
851 if (kdc_numrealms == 0) {
852 /* no realm specified, use default realm */
853 if ((retval = krb5_get_default_realm(kcontext, &lrealm))) {
854 com_err(argv[0], retval,
855 _("while attempting to retrieve default realm"));
857 _("%s: %s, attempting to retrieve default realm\n"),
858 argv[0], krb5_get_error_message(kcontext, retval));
861 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
862 if ((retval = init_realm(rdatap, lrealm, mkey_name, menctype,
863 default_udp_ports, default_tcp_ports,
864 manual, def_restrict_anon, db_args,
865 no_refrls, host_based_srvcs))) {
866 fprintf(stderr, _("%s: cannot initialize realm %s - see log "
867 "file for details\n"), argv[0], lrealm);
870 kdc_realmlist[0] = rdatap;
873 krb5_free_default_realm(kcontext, lrealm);
876 /* Ensure that this is set for our first request. */
877 kdc_active_realm = kdc_realmlist[0];
878 if (default_udp_ports)
879 free(default_udp_ports);
880 if (default_tcp_ports)
881 free(default_tcp_ports);
886 if (host_based_srvcs)
887 free(host_based_srvcs);
894 static krb5_error_code
895 write_pid_file(const char *path)
900 file = fopen(path, "w");
903 pid = (unsigned long) getpid();
904 if (fprintf(file, "%ld\n", pid) < 0 || fclose(file) == EOF)
914 for (i = 0; i < kdc_numrealms; i++) {
915 finish_realm(kdc_realmlist[i]);
916 kdc_realmlist[i] = 0;
926 initialize database access (fetch master key, open DB)
933 determine packet type, dispatch to handling routine
940 clean up secrets, close db
947 int main(int argc, char **argv)
949 krb5_error_code retval;
950 krb5_context kcontext;
954 setlocale(LC_MESSAGES, "");
955 if (strrchr(argv[0], '/'))
956 argv[0] = strrchr(argv[0], '/')+1;
958 if (!(kdc_realmlist = (kdc_realm_t **) malloc(sizeof(kdc_realm_t *) *
959 KRB5_KDC_MAX_REALMS))) {
960 fprintf(stderr, _("%s: cannot get memory for realm list\n"), argv[0]);
963 memset(kdc_realmlist, 0,
964 (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS));
967 * A note about Kerberos contexts: This context, "kcontext", is used
968 * for the KDC operations, i.e. setup, network connection and error
969 * reporting. The per-realm operations use the "realm_context"
970 * associated with each realm.
972 retval = krb5int_init_context_kdc(&kcontext);
974 com_err(argv[0], retval, _("while initializing krb5"));
977 krb5_klog_init(kcontext, "kdc", argv[0], 1);
978 kdc_err_context = kcontext;
979 kdc_progname = argv[0];
980 /* N.B.: After this point, com_err sends output to the KDC log
981 file, and not to stderr. We use the kdc_err wrapper around
982 com_err to ensure that the error state exists in the context
983 known to the krb5_klog callback. */
985 initialize_kdc5_error_table();
988 * Scan through the argument list
990 initialize_realms(kcontext, argc, argv);
992 setup_signal_handlers();
994 load_preauth_plugins(kcontext);
995 load_authdata_plugins(kcontext);
997 retval = setup_sam();
999 kdc_err(kcontext, retval, _("while initializing SAM"));
1004 /* Handle each realm's ports */
1005 for (i=0; i<kdc_numrealms; i++) {
1006 char *cp = kdc_realmlist[i]->realm_ports;
1009 if (*cp == ',' || isspace((int) *cp)) {
1013 port = strtol(cp, &cp, 10);
1016 retval = loop_add_udp_port(port);
1018 goto net_init_error;
1021 cp = kdc_realmlist[i]->realm_tcp_ports;
1023 if (*cp == ',' || isspace((int) *cp)) {
1027 port = strtol(cp, &cp, 10);
1030 retval = loop_add_tcp_port(port);
1032 goto net_init_error;
1037 * Setup network listeners. Disallow network reconfig in response to
1038 * routing socket messages if we're using worker processes, since the
1039 * children won't be able to re-open the listener sockets. Hopefully our
1040 * platform has pktinfo support and doesn't need reconfigs.
1042 if ((retval = loop_setup_network(NULL, kdc_progname, (workers > 0)))) {
1044 kdc_err(kcontext, retval, _("while initializing network"));
1048 if (!nofork && daemon(0, 0)) {
1049 kdc_err(kcontext, errno, _("while detaching from tty"));
1053 if (pid_file != NULL) {
1054 retval = write_pid_file(pid_file);
1056 kdc_err(kcontext, retval, _("while creating PID file"));
1063 retval = create_workers(workers);
1065 kdc_err(kcontext, errno, _("creating worker processes"));
1068 /* We get here only in a worker child process; re-initialize realms. */
1069 initialize_realms(kcontext, argc, argv);
1071 krb5_klog_syslog(LOG_INFO, _("commencing operation"));
1073 fprintf(stderr, _("%s: starting...\n"), kdc_progname);
1074 if ((retval = loop_listen_and_process(0, kdc_progname, reset_for_hangup))) {
1075 kdc_err(kcontext, retval, _("while processing network requests"));
1078 loop_closedown_network();
1079 krb5_klog_syslog(LOG_INFO, _("shutting down"));
1080 unload_preauth_plugins(kcontext);
1081 unload_authdata_plugins(kcontext);
1082 krb5_klog_close(kdc_context);
1085 free(kdc_realmlist);
1087 kdc_free_lookaside(kcontext);
1089 krb5_free_context(kcontext);