xref: /titanic_50/usr/src/cmd/krb5/krb5kdc/main.c (revision 159d09a20817016f09b3ea28d1bdada4a336bb91)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 
7 /*
8  * kdc/main.c
9  *
10  * Copyright 1990,2001 by the Massachusetts Institute of Technology.
11  *
12  * Export of this software from the United States of America may
13  *   require a specific license from the United States Government.
14  *   It is the responsibility of any person or organization contemplating
15  *   export to obtain such a license before exporting.
16  *
17  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18  * distribute this software and its documentation for any purpose and
19  * without fee is hereby granted, provided that the above copyright
20  * notice appear in all copies and that both that copyright notice and
21  * this permission notice appear in supporting documentation, and that
22  * the name of M.I.T. not be used in advertising or publicity pertaining
23  * to distribution of the software without specific, written prior
24  * permission.  Furthermore if you modify this software you must label
25  * your software as modified software and not distribute it in such a
26  * fashion that it might be confused with the original M.I.T. software.
27  * M.I.T. makes no representations about the suitability of
28  * this software for any purpose.  It is provided "as is" without express
29  * or implied warranty.
30  *
31  *
32  * Main procedure body for the KDC server process.
33  */
34 
35 #include <stdio.h>
36 #include <syslog.h>
37 #include <signal.h>
38 #include <errno.h>
39 #include <netdb.h>
40 
41 #include "k5-int.h"
42 #include "com_err.h"
43 #include "adm.h"
44 #include "adm_proto.h"
45 #include "kdc_util.h"
46 #include "extern.h"
47 #include "kdc5_err.h"
48 #include <libintl.h>
49 #include <locale.h>
50 
51 #ifdef HAVE_NETINET_IN_H
52 #include <netinet/in.h>
53 #endif
54 
55 #ifdef KRB5_KRB4_COMPAT
56 #include <des.h>
57 #endif
58 
59 #if defined(NEED_DAEMON_PROTO)
60 extern int daemon(int, int);
61 #endif
62 
63 void usage (char *);
64 
65 krb5_sigtype request_exit (int);
66 krb5_sigtype request_hup  (int);
67 
68 void setup_signal_handlers (void);
69 
70 krb5_error_code setup_sam (void);
71 
72 void initialize_realms (krb5_context, int, char **);
73 
74 void finish_realms (char *);
75 
76 static int nofork = 0;
77 static int rkey_init_done = 0;
78 
79 /* Solaris Kerberos: global here that other functions access */
80 int max_tcp_data_connections;
81 
82 #ifdef POSIX_SIGNALS
83 static struct sigaction s_action;
84 #endif /* POSIX_SIGNALS */
85 
86 #define	KRB5_KDC_MAX_REALMS	32
87 
88 /*
89  * Find the realm entry for a given realm.
90  */
91 kdc_realm_t *
find_realm_data(char * rname,krb5_ui_4 rsize)92 find_realm_data(char *rname, krb5_ui_4 rsize)
93 {
94     int i;
95     for (i=0; i<kdc_numrealms; i++) {
96 	if ((rsize == strlen(kdc_realmlist[i]->realm_name)) &&
97 	    !strncmp(rname, kdc_realmlist[i]->realm_name, rsize))
98 	    return(kdc_realmlist[i]);
99     }
100     return((kdc_realm_t *) NULL);
101 }
102 
103 krb5_error_code
setup_server_realm(krb5_principal sprinc)104 setup_server_realm(krb5_principal sprinc)
105 {
106     krb5_error_code	kret;
107     kdc_realm_t		*newrealm;
108 
109     kret = 0;
110     if (kdc_numrealms > 1) {
111 	if (!(newrealm = find_realm_data(sprinc->realm.data,
112 					 (krb5_ui_4) sprinc->realm.length)))
113 	    kret = ENOENT;
114 	else
115 	    kdc_active_realm = newrealm;
116     }
117     else
118 	kdc_active_realm = kdc_realmlist[0];
119     return(kret);
120 }
121 
122 static void
finish_realm(kdc_realm_t * rdp)123 finish_realm(kdc_realm_t *rdp)
124 {
125     if (rdp->realm_dbname)
126 	free(rdp->realm_dbname);
127     if (rdp->realm_mpname)
128 	free(rdp->realm_mpname);
129     if (rdp->realm_stash)
130 	free(rdp->realm_stash);
131     if (rdp->realm_ports)
132 	free(rdp->realm_ports);
133     if (rdp->realm_tcp_ports)
134 	free(rdp->realm_tcp_ports);
135     if (rdp->realm_keytab)
136 	krb5_kt_close(rdp->realm_context, rdp->realm_keytab);
137     if (rdp->realm_context) {
138 	if (rdp->realm_mprinc)
139 	    krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
140 	if (rdp->realm_mkey.length && rdp->realm_mkey.contents) {
141 	    memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length);
142 	    free(rdp->realm_mkey.contents);
143 	}
144 	krb5_db_fini(rdp->realm_context);
145 	if (rdp->realm_tgsprinc)
146 	    krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
147 	krb5_free_context(rdp->realm_context);
148     }
149     memset((char *) rdp, 0, sizeof(*rdp));
150     free(rdp);
151 }
152 
153 /*
154  * Initialize a realm control structure from the alternate profile or from
155  * the specified defaults.
156  *
157  * After we're complete here, the essence of the realm is embodied in the
158  * realm data and we should be all set to begin operation for that realm.
159  */
160 static krb5_error_code
init_realm(krb5_context kcontext,char * progname,kdc_realm_t * rdp,char * realm,char * def_mpname,krb5_enctype def_enctype,char * def_udp_ports,char * def_tcp_ports,krb5_boolean def_manual,char ** db_args)161 init_realm(krb5_context kcontext, char *progname, kdc_realm_t *rdp, char *realm,
162 	   char *def_mpname, krb5_enctype def_enctype, char *def_udp_ports,
163 	   char *def_tcp_ports, krb5_boolean def_manual, char **db_args)
164 {
165     krb5_error_code	kret;
166     krb5_boolean	manual;
167     krb5_realm_params	*rparams;
168 
169     memset((char *) rdp, 0, sizeof(kdc_realm_t));
170     if (!realm) {
171 	kret = EINVAL;
172 	goto whoops;
173     }
174 
175     rdp->realm_name = realm;
176     kret = krb5int_init_context_kdc(&rdp->realm_context);
177     if (kret) {
178 	com_err(progname, kret, gettext("while getting context for realm %s"),
179 		realm);
180 	goto whoops;
181     }
182 
183     /*
184      * Solaris Kerberos:
185      * Set the current context to that of the realm being init'ed
186      */
187     krb5_klog_set_context(rdp->realm_context);
188 
189     kret = krb5_read_realm_params(rdp->realm_context, rdp->realm_name,
190 				  &rparams);
191     if (kret) {
192 	com_err(progname, kret, gettext("while reading realm parameters"));
193 	goto whoops;
194     }
195 
196     /* Handle profile file name */
197     if (rparams && rparams->realm_profile)
198 	rdp->realm_profile = strdup(rparams->realm_profile);
199 
200     /* Handle master key name */
201     if (rparams && rparams->realm_mkey_name)
202 	rdp->realm_mpname = strdup(rparams->realm_mkey_name);
203     else
204 	rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) :
205 	    strdup(KRB5_KDB_M_NAME);
206 
207     /* Handle KDC ports */
208     if (rparams && rparams->realm_kdc_ports)
209 	rdp->realm_ports = strdup(rparams->realm_kdc_ports);
210     else
211 	rdp->realm_ports = strdup(def_udp_ports);
212     if (rparams && rparams->realm_kdc_tcp_ports)
213 	rdp->realm_tcp_ports = strdup(rparams->realm_kdc_tcp_ports);
214     else
215 	rdp->realm_tcp_ports = strdup(def_tcp_ports);
216 
217     /* Handle stash file */
218     if (rparams && rparams->realm_stash_file) {
219 	rdp->realm_stash = strdup(rparams->realm_stash_file);
220 	manual = FALSE;
221     } else
222 	manual = def_manual;
223 
224     /* Handle master key type */
225     if (rparams && rparams->realm_enctype_valid)
226 	rdp->realm_mkey.enctype = (krb5_enctype) rparams->realm_enctype;
227     else
228 	rdp->realm_mkey.enctype = manual ? def_enctype : ENCTYPE_UNKNOWN;
229 
230     /* Handle reject-bad-transit flag */
231     if (rparams && rparams->realm_reject_bad_transit_valid)
232 	rdp->realm_reject_bad_transit = rparams->realm_reject_bad_transit;
233     else
234 	rdp->realm_reject_bad_transit = 1;
235 
236     /* Handle ticket maximum life */
237     rdp->realm_maxlife = (rparams && rparams->realm_max_life_valid) ?
238 	rparams->realm_max_life : KRB5_KDB_MAX_LIFE;
239 
240     /* Handle ticket renewable maximum life */
241     rdp->realm_maxrlife = (rparams && rparams->realm_max_rlife_valid) ?
242 	rparams->realm_max_rlife : KRB5_KDB_MAX_RLIFE;
243 
244     if (rparams)
245 	krb5_free_realm_params(rdp->realm_context, rparams);
246 
247     /*
248      * We've got our parameters, now go and setup our realm context.
249      */
250 
251     /* Set the default realm of this context */
252     if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) {
253 	com_err(progname, kret, gettext("while setting default realm to %s"),
254 		realm);
255 	goto whoops;
256     }
257 
258     /* first open the database  before doing anything */
259 #ifdef KRBCONF_KDC_MODIFIES_KDB
260     if ((kret = krb5_db_open(rdp->realm_context, db_args,
261 			     KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_KDC))) {
262 #else
263     if ((kret = krb5_db_open(rdp->realm_context, db_args,
264 			     KRB5_KDB_OPEN_RO | KRB5_KDB_SRV_TYPE_KDC))) {
265 #endif
266 	/*
267 	 * Solaris Kerberos:
268 	 * Make sure that error messages are printed using gettext
269 	 */
270 	com_err(progname, kret,
271 	    gettext("while initializing database for realm %s"), realm);
272 	goto whoops;
273     }
274 
275     /* Assemble and parse the master key name */
276     if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname,
277 					rdp->realm_name, (char **) NULL,
278 					&rdp->realm_mprinc))) {
279 	com_err(progname, kret,
280 		gettext("while setting up master key name %s for realm %s"),
281 		rdp->realm_mpname, realm);
282 	goto whoops;
283     }
284 
285     /*
286      * Get the master key.
287      */
288     if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc,
289 				   rdp->realm_mkey.enctype, manual,
290 				   FALSE, rdp->realm_stash,
291 				   0, &rdp->realm_mkey))) {
292 	com_err(progname, kret,
293 		gettext("while fetching master key %s for realm %s"),
294 		rdp->realm_mpname, 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 
375     /*
376      * Solaris Kerberos:
377      * Set the current context back to the general context
378      */
379     krb5_klog_set_context(kcontext);
380 
381     return(kret);
382 }
383 
384 krb5_sigtype
385 request_exit(int signo)
386 {
387     signal_requests_exit = 1;
388 
389 #ifdef POSIX_SIGTYPE
390     return;
391 #else
392     return(0);
393 #endif
394 }
395 
396 krb5_sigtype
397 request_hup(int signo)
398 {
399     signal_requests_hup = 1;
400 
401 #ifdef POSIX_SIGTYPE
402     return;
403 #else
404     return(0);
405 #endif
406 }
407 
408 void
409 setup_signal_handlers(void)
410 {
411 #ifdef POSIX_SIGNALS
412     (void) sigemptyset(&s_action.sa_mask);
413     s_action.sa_flags = 0;
414     s_action.sa_handler = request_exit;
415     (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL);
416     (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL);
417     s_action.sa_handler = request_hup;
418     (void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL);
419     s_action.sa_handler = SIG_IGN;
420     (void) sigaction(SIGPIPE, &s_action, (struct sigaction *) NULL);
421 #else  /* POSIX_SIGNALS */
422     signal(SIGINT, request_exit);
423     signal(SIGTERM, request_exit);
424     signal(SIGHUP, request_hup);
425     signal(SIGPIPE, SIG_IGN);
426 #endif /* POSIX_SIGNALS */
427 
428     return;
429 }
430 
431 krb5_error_code
432 setup_sam(void)
433 {
434     return krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_MD5, &psr_key);
435 }
436 
437 void
438 usage(char *name)
439 {
440     fprintf(stderr, gettext("usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-n]\n"), name);
441     fprintf(stderr, "usage: %s [-x db_args]* [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-X] [-n]\n"
442 	    "\nwhere,\n\t[-x db_args]* - any number of database specific arguments.\n"
443 	    "\t\t\tLook at each database documentation for supported arguments\n",
444 	    name);
445     return;
446 }
447 
448 void
449 initialize_realms(krb5_context kcontext, int argc, char **argv)
450 {
451     int 		c;
452     char		*db_name = (char *) NULL;
453     char		*mkey_name = (char *) NULL;
454     char		*rcname = KDCRCACHE;
455     char		*lrealm = NULL;
456     krb5_error_code	retval;
457     krb5_enctype	menctype = ENCTYPE_UNKNOWN;
458     kdc_realm_t		*rdatap;
459     krb5_boolean	manual = FALSE;
460     char		*default_udp_ports = 0;
461     char		*default_tcp_ports = 0;
462     krb5_pointer	aprof;
463     const char		*hierarchy[3];
464     char               **db_args      = NULL;
465     int                  db_args_size = 0;
466 
467 #ifdef KRB5_KRB4_COMPAT
468     char                *v4mode = 0;
469 #endif
470     extern char *optarg;
471 
472     if (!krb5_aprof_init(DEFAULT_KDC_PROFILE, KDC_PROFILE_ENV, &aprof)) {
473 	hierarchy[0] = "kdcdefaults";
474 	hierarchy[1] = "kdc_ports";
475 	hierarchy[2] = (char *) NULL;
476 	if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_udp_ports))
477 	    default_udp_ports = 0;
478 	hierarchy[1] = "kdc_tcp_ports";
479 	if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_tcp_ports))
480 	    default_tcp_ports = 0;
481 	hierarchy[1] = "kdc_max_tcp_connections";
482 	if (krb5_aprof_get_int32(aprof, hierarchy, TRUE,
483 		&max_tcp_data_connections)) {
484 	    max_tcp_data_connections = DEFAULT_KDC_TCP_CONNECTIONS;
485 	} else if (max_tcp_data_connections < MIN_KDC_TCP_CONNECTIONS) {
486 	    max_tcp_data_connections = DEFAULT_KDC_TCP_CONNECTIONS;
487 	}
488 #ifdef KRB5_KRB4_COMPAT
489 	hierarchy[1] = "v4_mode";
490 	if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &v4mode))
491 	    v4mode = 0;
492 #endif
493 	/* aprof_init can return 0 with aprof == NULL */
494 	if (aprof)
495 	     krb5_aprof_finish(aprof);
496     }
497     if (default_udp_ports == 0)
498 	default_udp_ports = strdup(DEFAULT_KDC_UDP_PORTLIST);
499     if (default_tcp_ports == 0)
500 	default_tcp_ports = strdup(DEFAULT_KDC_TCP_PORTLIST);
501     /*
502      * Loop through the option list.  Each time we encounter a realm name,
503      * use the previously scanned options to fill in for defaults.
504      */
505     while ((c = getopt(argc, argv, "x:r:d:mM:k:R:e:p:s:n4:X3")) != -1) {
506 	switch(c) {
507 	case 'x':
508 	    db_args_size++;
509 	    {
510 		char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
511 		if( temp == NULL )
512 		{
513 			/* Solaris Kerberos: Keep error messages consistent */
514 		    com_err(argv[0], errno, gettext("while initializing KDC"));
515 		    exit(1);
516 		}
517 
518 		db_args = temp;
519 	    }
520 	    db_args[db_args_size-1] = optarg;
521 	    db_args[db_args_size]   = NULL;
522 	  break;
523 
524 	case 'r':			/* realm name for db */
525 	    if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) {
526 		if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
527 		    if ((retval = init_realm(kcontext, argv[0], rdatap, optarg,
528 					     mkey_name, menctype,
529 					     default_udp_ports,
530 					     default_tcp_ports, manual, db_args))) {
531 			/* Solaris Kerberos: Keep error messages consistent */
532 			com_err(argv[0], retval, gettext("while initializing realm %s"), optarg);
533 			exit(1);
534 		    }
535 		    kdc_realmlist[kdc_numrealms] = rdatap;
536 		    kdc_numrealms++;
537 		    free(db_args), db_args=NULL, db_args_size = 0;
538 		}
539 		else
540 		{
541 			/* Solaris Kerberos: Keep error messages consistent */
542 			com_err(argv[0], errno, gettext("while initializing realm %s"), optarg);
543 			exit(1);
544 		}
545 	    }
546 	    break;
547 	case 'd':			/* pathname for db */
548 	    /* now db_name is not a seperate argument. It has to be passed as part of the db_args */
549 	    if( db_name == NULL )
550 	    {
551 		db_name = malloc(sizeof("dbname=") + strlen(optarg));
552 		if( db_name == NULL )
553 		{
554 			/* Solaris Kerberos: Keep error messages consistent */
555 			com_err(argv[0], errno, gettext("while initializing KDC"));
556 			exit(1);
557 		}
558 
559 		sprintf( db_name, "dbname=%s", optarg);
560 	    }
561 
562 	    db_args_size++;
563 	    {
564 		char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
565 		if( temp == NULL )
566 		{
567 			/* Solaris Kerberos: Keep error messages consistent */
568 		    com_err(argv[0], errno, gettext("while initializing KDC"));
569 		    exit(1);
570 		}
571 
572 		db_args = temp;
573 	    }
574 	    db_args[db_args_size-1] = db_name;
575 	    db_args[db_args_size]   = NULL;
576 	    break;
577 	case 'm':			/* manual type-in of master key */
578 	    manual = TRUE;
579 	    if (menctype == ENCTYPE_UNKNOWN)
580 		menctype = ENCTYPE_DES_CBC_CRC;
581 	    break;
582 	case 'M':			/* master key name in DB */
583 	    mkey_name = optarg;
584 	    break;
585 	case 'n':
586 	    nofork++;			/* don't detach from terminal */
587 	    break;
588 	case 'k':			/* enctype for master key */
589 		/* Solaris Kerberos: Keep error messages consistent */
590 	    if (retval = krb5_string_to_enctype(optarg, &menctype))
591 		com_err(argv[0], retval,
592 		    gettext("while converting %s to an enctype"), optarg);
593 	    break;
594 	case 'R':
595 	    rcname = optarg;
596 	    break;
597 	case 'p':
598 	    if (default_udp_ports)
599 		free(default_udp_ports);
600 	    default_udp_ports = strdup(optarg);
601 
602 	    if (default_tcp_ports)
603 		free(default_tcp_ports);
604 	    default_tcp_ports = strdup(optarg);
605 
606 	    break;
607 	case '4':
608 #ifdef KRB5_KRB4_COMPAT
609 	    if (v4mode)
610 		free(v4mode);
611 	    v4mode = strdup(optarg);
612 #endif
613 	    break;
614 	case 'X':
615 #ifdef KRB5_KRB4_COMPAT
616 		enable_v4_crossrealm(argv[0]);
617 #endif
618 		break;
619 	case '?':
620 	default:
621 	    usage(argv[0]);
622 	    exit(1);
623 	}
624     }
625 
626 #ifdef KRB5_KRB4_COMPAT
627     /*
628      * Setup the v4 mode
629      */
630     process_v4_mode(argv[0], v4mode);
631     free(v4mode);
632 #endif
633 
634     /*
635      * Check to see if we processed any realms.
636      */
637     if (kdc_numrealms == 0) {
638 	/* no realm specified, use default realm */
639 	if ((retval = krb5_get_default_realm(kcontext, &lrealm))) {
640 	    com_err(argv[0], retval,
641 		gettext("while attempting to retrieve default realm"));
642 	/* Solaris Kerberos: avoid double logging */
643 #if 0
644 	    fprintf (stderr, "%s: %s, %s", argv[0], error_message (retval),
645 		gettext("attempting to retrieve default realm\n"));
646 #endif
647 	    exit(1);
648 	}
649 	if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
650 	    if ((retval = init_realm(kcontext, argv[0], rdatap, lrealm,
651 				     mkey_name, menctype, default_udp_ports,
652 				     default_tcp_ports, manual, db_args))) {
653 		/* Solaris Kerberos: Keep error messages consistent */
654 		com_err(argv[0], retval, gettext("while initializing realm %s"), lrealm);
655 		exit(1);
656 	    }
657 	    kdc_realmlist[0] = rdatap;
658 	    kdc_numrealms++;
659 	} else {
660     	    if (lrealm)
661 		free(lrealm);
662 	}
663     }
664 
665 #ifdef USE_RCACHE
666     /*
667      * Now handle the replay cache.
668      */
669     if ((retval = kdc_initialize_rcache(kcontext, rcname))) {
670 	com_err(argv[0], retval, gettext("while initializing KDC replay cache '%s'"),
671 		rcname);
672 	exit(1);
673     }
674 #endif
675 
676     /* Ensure that this is set for our first request. */
677     kdc_active_realm = kdc_realmlist[0];
678 
679     if (default_udp_ports)
680 	free(default_udp_ports);
681     if (default_tcp_ports)
682 	free(default_tcp_ports);
683     if (db_args)
684 	free(db_args);
685     if (db_name)
686 	free(db_name);
687 
688     return;
689 }
690 
691 void
692 finish_realms(char *prog)
693 {
694     int i;
695 
696     for (i = 0; i < kdc_numrealms; i++) {
697 	finish_realm(kdc_realmlist[i]);
698 	kdc_realmlist[i] = 0;
699     }
700 }
701 
702 /*
703  outline:
704 
705  process args & setup
706 
707  initialize database access (fetch master key, open DB)
708 
709  initialize network
710 
711  loop:
712  	listen for packet
713 
714 	determine packet type, dispatch to handling routine
715 		(AS or TGS (or V4?))
716 
717 	reflect response
718 
719 	exit on signal
720 
721  clean up secrets, close db
722 
723  shut down network
724 
725  exit
726  */
727 
728 int main(int argc, char **argv)
729 {
730     krb5_error_code	retval;
731     krb5_context	kcontext;
732     int errout = 0;
733 
734     krb5_boolean log_stderr_set;
735 
736     (void) setlocale(LC_ALL, "");
737 
738 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
739 #define	TEXT_DOMAIN	"KRB5KDC_TEST"	/* Use this only if it weren't */
740 #endif
741 
742     (void) textdomain(TEXT_DOMAIN);
743 
744     if (strrchr(argv[0], '/'))
745 	argv[0] = strrchr(argv[0], '/')+1;
746 
747     if (!(kdc_realmlist = (kdc_realm_t **) malloc(sizeof(kdc_realm_t *) *
748 						  KRB5_KDC_MAX_REALMS))) {
749 	fprintf(stderr, gettext("%s: cannot get memory for realm list\n"), argv[0]);
750 	exit(1);
751     }
752     memset((char *) kdc_realmlist, 0,
753 	   (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS));
754 
755     /*
756      * A note about Kerberos contexts: This context, "kcontext", is used
757      * for the KDC operations, i.e. setup, network connection and error
758      * reporting.  The per-realm operations use the "realm_context"
759      * associated with each realm.
760      */
761     retval = krb5int_init_context_kdc(&kcontext);
762     if (retval) {
763 	    com_err(argv[0], retval, gettext("while initializing krb5"));
764 	    exit(1);
765     }
766     krb5_klog_init(kcontext, "kdc", argv[0], 1);
767 
768     /*
769      * Solaris Kerberos:
770      * In the early stages of krb5kdc it is desirable to log error messages
771      * to stderr as well as any other logging locations specified in config
772      * files.
773      */
774      log_stderr_set = krb5_klog_logging_to_stderr();
775      if (log_stderr_set != TRUE) {
776      	krb5_klog_add_stderr();
777      }
778 
779     /* initialize_kdc5_error_table();  SUNWresync121 XXX */
780 
781     /*
782      * Scan through the argument list
783      */
784     initialize_realms(kcontext, argc, argv);
785 
786     setup_signal_handlers();
787 
788     load_preauth_plugins(kcontext);
789 
790     retval = setup_sam();
791     if (retval) {
792 	com_err(argv[0], retval, gettext("while initializing SAM"));
793 	finish_realms(argv[0]);
794 	return 1;
795     }
796 
797     if ((retval = setup_network(argv[0]))) {
798 	com_err(argv[0], retval, gettext("while initializing network"));
799 	finish_realms(argv[0]);
800 	return 1;
801     }
802 
803     /* Solaris Kerberos: Remove the extra stderr logging */
804     if (log_stderr_set != TRUE)
805 	krb5_klog_remove_stderr();
806 
807     /*
808      * Solaris Kerberos:
809      * List the logs (FILE, STDERR, etc) which are currently being
810      * logged to and print that to stderr. Useful when trying to
811      * track down a failure via SMF.
812      */
813     if (retval = krb5_klog_list_logs(argv[0])) {
814 	com_err(argv[0], retval, gettext("while listing logs"));
815 	if (log_stderr_set != TRUE) {
816 		fprintf(stderr, gettext("%s: %s while listing logs\n"),
817 		    argv[0], error_message(retval));
818 	}
819     }
820 
821     if (!nofork && daemon(0, 0)) {
822 	com_err(argv[0], errno, gettext("while detaching from tty"));
823 	if (log_stderr_set != TRUE) {
824 		fprintf(stderr, gettext("%s: %s while detaching from tty\n"),
825 		  argv[0], strerror(errno));
826 	}
827 	finish_realms(argv[0]);
828 	return 1;
829     }
830     if (retval = krb5_klog_syslog(LOG_INFO, "commencing operation")) {
831 	com_err(argv[0], retval, gettext("while logging message"));
832 	errout++;
833 	};
834 
835     if ((retval = listen_and_process(argv[0]))) {
836 	com_err(argv[0], retval, gettext("while processing network requests"));
837 	errout++;
838     }
839     if ((retval = closedown_network(argv[0]))) {
840 	com_err(argv[0], retval, gettext("while shutting down network"));
841 	errout++;
842     }
843     krb5_klog_syslog(LOG_INFO, "shutting down");
844     unload_preauth_plugins(kcontext);
845     krb5_klog_close(kdc_context);
846     finish_realms(argv[0]);
847     if (kdc_realmlist)
848       free(kdc_realmlist);
849 #ifdef USE_RCACHE
850     (void) krb5_rc_close(kcontext, kdc_rcache);
851 #endif
852 #ifndef NOCACHE
853     kdc_free_lookaside(kcontext);
854 #endif
855     krb5_free_context(kcontext);
856     return errout;
857 }
858 
859 
860 
861 
862