Home | History | Annotate | Download | only in krb5kdc
      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 *
     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
    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
    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
    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