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