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)
60extern int daemon(int, int);
61#endif
62
63void usage (char *);
64
65krb5_sigtype request_exit (int);
66krb5_sigtype request_hup  (int);
67
68void setup_signal_handlers (void);
69
70krb5_error_code setup_sam (void);
71
72void initialize_realms (krb5_context, int, char **);
73
74void finish_realms (char *);
75
76static int nofork = 0;
77static int rkey_init_done = 0;
78
79/* Solaris Kerberos: global here that other functions access */
80int max_tcp_data_connections;
81
82#ifdef POSIX_SIGNALS
83static 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 */
91kdc_realm_t *
92find_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
103krb5_error_code
104setup_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
122static void
123finish_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 */
160static krb5_error_code
161init_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
384krb5_sigtype
385request_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
396krb5_sigtype
397request_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
408void
409setup_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
431krb5_error_code
432setup_sam(void)
433{
434    return krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_MD5, &psr_key);
435}
436
437void
438usage(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
448void
449initialize_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
691void
692finish_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
728int 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