xref: /freebsd/crypto/krb5/src/kdc/main.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* kdc/main.c - Main procedure body for the KDC server process */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright 1990,2001,2008,2009,2016 by the Massachusetts Institute of
5*7f2fe78bSCy Schubert  * Technology.
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert  *   require a specific license from the United States Government.
9*7f2fe78bSCy Schubert  *   It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert  *   export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert  *
12*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert  * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert  * permission.  Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert  * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
24*7f2fe78bSCy Schubert  * or implied warranty.
25*7f2fe78bSCy Schubert  */
26*7f2fe78bSCy Schubert 
27*7f2fe78bSCy Schubert #include "k5-int.h"
28*7f2fe78bSCy Schubert #include "com_err.h"
29*7f2fe78bSCy Schubert #include <kadm5/admin.h>
30*7f2fe78bSCy Schubert #include "adm_proto.h"
31*7f2fe78bSCy Schubert #include "kdc_util.h"
32*7f2fe78bSCy Schubert #include "kdc_audit.h"
33*7f2fe78bSCy Schubert #include "extern.h"
34*7f2fe78bSCy Schubert #include "policy.h"
35*7f2fe78bSCy Schubert #include "kdc5_err.h"
36*7f2fe78bSCy Schubert #include "kdb_kt.h"
37*7f2fe78bSCy Schubert #include "net-server.h"
38*7f2fe78bSCy Schubert #ifdef HAVE_NETINET_IN_H
39*7f2fe78bSCy Schubert #include <netinet/in.h>
40*7f2fe78bSCy Schubert #endif
41*7f2fe78bSCy Schubert 
42*7f2fe78bSCy Schubert #include <locale.h>
43*7f2fe78bSCy Schubert #include <syslog.h>
44*7f2fe78bSCy Schubert #include <signal.h>
45*7f2fe78bSCy Schubert #include <netdb.h>
46*7f2fe78bSCy Schubert #include <unistd.h>
47*7f2fe78bSCy Schubert #include <ctype.h>
48*7f2fe78bSCy Schubert #include <sys/wait.h>
49*7f2fe78bSCy Schubert 
50*7f2fe78bSCy Schubert #if defined(NEED_DAEMON_PROTO)
51*7f2fe78bSCy Schubert extern int daemon(int, int);
52*7f2fe78bSCy Schubert #endif
53*7f2fe78bSCy Schubert 
54*7f2fe78bSCy Schubert static void usage (char *);
55*7f2fe78bSCy Schubert 
56*7f2fe78bSCy Schubert static void initialize_realms(krb5_context kcontext, int argc, char **argv,
57*7f2fe78bSCy Schubert                               int *tcp_listen_backlog_out);
58*7f2fe78bSCy Schubert 
59*7f2fe78bSCy Schubert static void finish_realms (void);
60*7f2fe78bSCy Schubert 
61*7f2fe78bSCy Schubert static int nofork = 0;
62*7f2fe78bSCy Schubert static int workers = 0;
63*7f2fe78bSCy Schubert static int time_offset = 0;
64*7f2fe78bSCy Schubert static const char *pid_file = NULL;
65*7f2fe78bSCy Schubert static volatile int signal_received = 0;
66*7f2fe78bSCy Schubert static volatile int sighup_received = 0;
67*7f2fe78bSCy Schubert 
68*7f2fe78bSCy Schubert #define KRB5_KDC_MAX_REALMS     32
69*7f2fe78bSCy Schubert 
70*7f2fe78bSCy Schubert static const char *kdc_progname;
71*7f2fe78bSCy Schubert 
72*7f2fe78bSCy Schubert /*
73*7f2fe78bSCy Schubert  * Static server_handle for this file.  Other code will get access to
74*7f2fe78bSCy Schubert  * it through the application handle that net-server.c uses.
75*7f2fe78bSCy Schubert  */
76*7f2fe78bSCy Schubert static struct server_handle shandle;
77*7f2fe78bSCy Schubert 
78*7f2fe78bSCy Schubert /*
79*7f2fe78bSCy Schubert  * We use krb5_klog_init to set up a com_err callback to log error
80*7f2fe78bSCy Schubert  * messages.  The callback also pulls the error message out of the
81*7f2fe78bSCy Schubert  * context we pass to krb5_klog_init; however, we use realm-specific
82*7f2fe78bSCy Schubert  * contexts for most of our krb5 library calls, so the error message
83*7f2fe78bSCy Schubert  * isn't present in the global context.  This wrapper ensures that the
84*7f2fe78bSCy Schubert  * error message state from the call context is copied into the
85*7f2fe78bSCy Schubert  * context known by krb5_klog.  call_context can be NULL if the error
86*7f2fe78bSCy Schubert  * code did not come from a krb5 library function.
87*7f2fe78bSCy Schubert  */
88*7f2fe78bSCy Schubert void
kdc_err(krb5_context call_context,errcode_t code,const char * fmt,...)89*7f2fe78bSCy Schubert kdc_err(krb5_context call_context, errcode_t code, const char *fmt, ...)
90*7f2fe78bSCy Schubert {
91*7f2fe78bSCy Schubert     va_list ap;
92*7f2fe78bSCy Schubert 
93*7f2fe78bSCy Schubert     if (call_context)
94*7f2fe78bSCy Schubert         krb5_copy_error_message(shandle.kdc_err_context, call_context);
95*7f2fe78bSCy Schubert     va_start(ap, fmt);
96*7f2fe78bSCy Schubert     com_err_va(kdc_progname, code, fmt, ap);
97*7f2fe78bSCy Schubert     va_end(ap);
98*7f2fe78bSCy Schubert }
99*7f2fe78bSCy Schubert 
100*7f2fe78bSCy Schubert /*
101*7f2fe78bSCy Schubert  * Find the realm entry for a given realm.
102*7f2fe78bSCy Schubert  */
103*7f2fe78bSCy Schubert kdc_realm_t *
find_realm_data(struct server_handle * handle,char * rname,krb5_ui_4 rsize)104*7f2fe78bSCy Schubert find_realm_data(struct server_handle *handle, char *rname, krb5_ui_4 rsize)
105*7f2fe78bSCy Schubert {
106*7f2fe78bSCy Schubert     int i;
107*7f2fe78bSCy Schubert     kdc_realm_t **kdc_realmlist = handle->kdc_realmlist;
108*7f2fe78bSCy Schubert     int kdc_numrealms = handle->kdc_numrealms;
109*7f2fe78bSCy Schubert 
110*7f2fe78bSCy Schubert     for (i=0; i<kdc_numrealms; i++) {
111*7f2fe78bSCy Schubert         if ((rsize == strlen(kdc_realmlist[i]->realm_name)) &&
112*7f2fe78bSCy Schubert             !strncmp(rname, kdc_realmlist[i]->realm_name, rsize))
113*7f2fe78bSCy Schubert             return(kdc_realmlist[i]);
114*7f2fe78bSCy Schubert     }
115*7f2fe78bSCy Schubert     return((kdc_realm_t *) NULL);
116*7f2fe78bSCy Schubert }
117*7f2fe78bSCy Schubert 
118*7f2fe78bSCy Schubert kdc_realm_t *
setup_server_realm(struct server_handle * handle,krb5_principal sprinc)119*7f2fe78bSCy Schubert setup_server_realm(struct server_handle *handle, krb5_principal sprinc)
120*7f2fe78bSCy Schubert {
121*7f2fe78bSCy Schubert     kdc_realm_t         *newrealm;
122*7f2fe78bSCy Schubert     kdc_realm_t **kdc_realmlist = handle->kdc_realmlist;
123*7f2fe78bSCy Schubert     int kdc_numrealms = handle->kdc_numrealms;
124*7f2fe78bSCy Schubert 
125*7f2fe78bSCy Schubert     if (sprinc == NULL)
126*7f2fe78bSCy Schubert         return NULL;
127*7f2fe78bSCy Schubert 
128*7f2fe78bSCy Schubert     if (kdc_numrealms > 1) {
129*7f2fe78bSCy Schubert         newrealm = find_realm_data(handle, sprinc->realm.data,
130*7f2fe78bSCy Schubert                                    sprinc->realm.length);
131*7f2fe78bSCy Schubert     } else {
132*7f2fe78bSCy Schubert         newrealm = kdc_realmlist[0];
133*7f2fe78bSCy Schubert     }
134*7f2fe78bSCy Schubert     if (newrealm != NULL) {
135*7f2fe78bSCy Schubert         krb5_klog_set_context(newrealm->realm_context);
136*7f2fe78bSCy Schubert         shandle.kdc_err_context = newrealm->realm_context;
137*7f2fe78bSCy Schubert     }
138*7f2fe78bSCy Schubert     return newrealm;
139*7f2fe78bSCy Schubert }
140*7f2fe78bSCy Schubert 
141*7f2fe78bSCy Schubert static void
finish_realm(kdc_realm_t * rdp)142*7f2fe78bSCy Schubert finish_realm(kdc_realm_t *rdp)
143*7f2fe78bSCy Schubert {
144*7f2fe78bSCy Schubert     if (rdp->realm_name)
145*7f2fe78bSCy Schubert         free(rdp->realm_name);
146*7f2fe78bSCy Schubert     if (rdp->realm_mpname)
147*7f2fe78bSCy Schubert         free(rdp->realm_mpname);
148*7f2fe78bSCy Schubert     if (rdp->realm_stash)
149*7f2fe78bSCy Schubert         free(rdp->realm_stash);
150*7f2fe78bSCy Schubert     if (rdp->realm_listen)
151*7f2fe78bSCy Schubert         free(rdp->realm_listen);
152*7f2fe78bSCy Schubert     if (rdp->realm_tcp_listen)
153*7f2fe78bSCy Schubert         free(rdp->realm_tcp_listen);
154*7f2fe78bSCy Schubert     if (rdp->realm_keytab)
155*7f2fe78bSCy Schubert         krb5_kt_close(rdp->realm_context, rdp->realm_keytab);
156*7f2fe78bSCy Schubert     if (rdp->realm_hostbased)
157*7f2fe78bSCy Schubert         free(rdp->realm_hostbased);
158*7f2fe78bSCy Schubert     if (rdp->realm_no_referral)
159*7f2fe78bSCy Schubert         free(rdp->realm_no_referral);
160*7f2fe78bSCy Schubert     if (rdp->realm_context) {
161*7f2fe78bSCy Schubert         if (rdp->realm_mprinc)
162*7f2fe78bSCy Schubert             krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
163*7f2fe78bSCy Schubert         zapfree(rdp->realm_mkey.contents, rdp->realm_mkey.length);
164*7f2fe78bSCy Schubert         krb5_db_fini(rdp->realm_context);
165*7f2fe78bSCy Schubert         if (rdp->realm_tgsprinc)
166*7f2fe78bSCy Schubert             krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
167*7f2fe78bSCy Schubert         krb5_free_context(rdp->realm_context);
168*7f2fe78bSCy Schubert     }
169*7f2fe78bSCy Schubert     zapfree(rdp, sizeof(*rdp));
170*7f2fe78bSCy Schubert }
171*7f2fe78bSCy Schubert 
172*7f2fe78bSCy Schubert /* Set *val_out to an allocated string containing val1 and/or val2, separated
173*7f2fe78bSCy Schubert  * by a space if both are set, or NULL if neither is set. */
174*7f2fe78bSCy Schubert static krb5_error_code
combine(const char * val1,const char * val2,char ** val_out)175*7f2fe78bSCy Schubert combine(const char *val1, const char *val2, char **val_out)
176*7f2fe78bSCy Schubert {
177*7f2fe78bSCy Schubert     if (val1 == NULL && val2 == NULL) {
178*7f2fe78bSCy Schubert         *val_out = NULL;
179*7f2fe78bSCy Schubert     } else if (val1 != NULL && val2 != NULL) {
180*7f2fe78bSCy Schubert         if (asprintf(val_out, "%s %s", val1, val2) < 0) {
181*7f2fe78bSCy Schubert             *val_out = NULL;
182*7f2fe78bSCy Schubert             return ENOMEM;
183*7f2fe78bSCy Schubert         }
184*7f2fe78bSCy Schubert     } else {
185*7f2fe78bSCy Schubert         *val_out = strdup((val1 != NULL) ? val1 : val2);
186*7f2fe78bSCy Schubert         if (*val_out == NULL)
187*7f2fe78bSCy Schubert             return ENOMEM;
188*7f2fe78bSCy Schubert     }
189*7f2fe78bSCy Schubert     return 0;
190*7f2fe78bSCy Schubert }
191*7f2fe78bSCy Schubert 
192*7f2fe78bSCy Schubert /*
193*7f2fe78bSCy Schubert  * Initialize a realm control structure from the alternate profile or from
194*7f2fe78bSCy Schubert  * the specified defaults.
195*7f2fe78bSCy Schubert  *
196*7f2fe78bSCy Schubert  * After we're complete here, the essence of the realm is embodied in the
197*7f2fe78bSCy Schubert  * realm data and we should be all set to begin operation for that realm.
198*7f2fe78bSCy Schubert  */
199*7f2fe78bSCy Schubert static  krb5_error_code
init_realm(kdc_realm_t * rdp,krb5_pointer aprof,char * realm,char * def_mpname,krb5_enctype def_enctype,char * def_udp_listen,char * def_tcp_listen,krb5_boolean def_manual,krb5_boolean def_restrict_anon,char ** db_args,char * no_referral,char * hostbased)200*7f2fe78bSCy Schubert init_realm(kdc_realm_t * rdp, krb5_pointer aprof, char *realm,
201*7f2fe78bSCy Schubert            char *def_mpname, krb5_enctype def_enctype, char *def_udp_listen,
202*7f2fe78bSCy Schubert            char *def_tcp_listen, krb5_boolean def_manual,
203*7f2fe78bSCy Schubert            krb5_boolean def_restrict_anon, char **db_args, char *no_referral,
204*7f2fe78bSCy Schubert            char *hostbased)
205*7f2fe78bSCy Schubert {
206*7f2fe78bSCy Schubert     krb5_error_code     kret;
207*7f2fe78bSCy Schubert     krb5_boolean        manual;
208*7f2fe78bSCy Schubert     int                 kdb_open_flags;
209*7f2fe78bSCy Schubert     char                *svalue = NULL;
210*7f2fe78bSCy Schubert     const char          *hierarchy[4];
211*7f2fe78bSCy Schubert     krb5_kvno       mkvno = IGNORE_VNO;
212*7f2fe78bSCy Schubert     char ename[32];
213*7f2fe78bSCy Schubert 
214*7f2fe78bSCy Schubert     memset(rdp, 0, sizeof(kdc_realm_t));
215*7f2fe78bSCy Schubert     if (!realm) {
216*7f2fe78bSCy Schubert         kret = EINVAL;
217*7f2fe78bSCy Schubert         goto whoops;
218*7f2fe78bSCy Schubert     }
219*7f2fe78bSCy Schubert 
220*7f2fe78bSCy Schubert     if (def_enctype != ENCTYPE_UNKNOWN &&
221*7f2fe78bSCy Schubert         krb5int_c_deprecated_enctype(def_enctype)) {
222*7f2fe78bSCy Schubert         if (krb5_enctype_to_name(def_enctype, FALSE, ename, sizeof(ename)))
223*7f2fe78bSCy Schubert             ename[0] = '\0';
224*7f2fe78bSCy Schubert         fprintf(stderr,
225*7f2fe78bSCy Schubert                 _("Requested master password enctype %s in %s is "
226*7f2fe78bSCy Schubert                   "DEPRECATED!\n"),
227*7f2fe78bSCy Schubert                 ename, realm);
228*7f2fe78bSCy Schubert     }
229*7f2fe78bSCy Schubert 
230*7f2fe78bSCy Schubert     hierarchy[0] = KRB5_CONF_REALMS;
231*7f2fe78bSCy Schubert     hierarchy[1] = realm;
232*7f2fe78bSCy Schubert     hierarchy[3] = NULL;
233*7f2fe78bSCy Schubert 
234*7f2fe78bSCy Schubert     rdp->realm_name = strdup(realm);
235*7f2fe78bSCy Schubert     if (rdp->realm_name == NULL) {
236*7f2fe78bSCy Schubert         kret = ENOMEM;
237*7f2fe78bSCy Schubert         goto whoops;
238*7f2fe78bSCy Schubert     }
239*7f2fe78bSCy Schubert     kret = krb5int_init_context_kdc(&rdp->realm_context);
240*7f2fe78bSCy Schubert     if (kret) {
241*7f2fe78bSCy Schubert         kdc_err(NULL, kret, _("while getting context for realm %s"), realm);
242*7f2fe78bSCy Schubert         goto whoops;
243*7f2fe78bSCy Schubert     }
244*7f2fe78bSCy Schubert     if (time_offset != 0)
245*7f2fe78bSCy Schubert         (void)krb5_set_time_offsets(rdp->realm_context, time_offset, 0);
246*7f2fe78bSCy Schubert 
247*7f2fe78bSCy Schubert     /* Handle master key name */
248*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_MASTER_KEY_NAME;
249*7f2fe78bSCy Schubert     if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &rdp->realm_mpname)) {
250*7f2fe78bSCy Schubert         rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) :
251*7f2fe78bSCy Schubert             strdup(KRB5_KDB_M_NAME);
252*7f2fe78bSCy Schubert     }
253*7f2fe78bSCy Schubert     if (!rdp->realm_mpname) {
254*7f2fe78bSCy Schubert         kret = ENOMEM;
255*7f2fe78bSCy Schubert         goto whoops;
256*7f2fe78bSCy Schubert     }
257*7f2fe78bSCy Schubert 
258*7f2fe78bSCy Schubert     /* Handle KDC addresses/ports */
259*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_KDC_LISTEN;
260*7f2fe78bSCy Schubert     if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &rdp->realm_listen)) {
261*7f2fe78bSCy Schubert         /* Try the old kdc_ports configuration option. */
262*7f2fe78bSCy Schubert         hierarchy[2] = KRB5_CONF_KDC_PORTS;
263*7f2fe78bSCy Schubert         if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &rdp->realm_listen))
264*7f2fe78bSCy Schubert             rdp->realm_listen = strdup(def_udp_listen);
265*7f2fe78bSCy Schubert     }
266*7f2fe78bSCy Schubert     if (!rdp->realm_listen) {
267*7f2fe78bSCy Schubert         kret = ENOMEM;
268*7f2fe78bSCy Schubert         goto whoops;
269*7f2fe78bSCy Schubert     }
270*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_KDC_TCP_LISTEN;
271*7f2fe78bSCy Schubert     if (krb5_aprof_get_string(aprof, hierarchy, TRUE,
272*7f2fe78bSCy Schubert                               &rdp->realm_tcp_listen)) {
273*7f2fe78bSCy Schubert         /* Try the old kdc_tcp_ports configuration option. */
274*7f2fe78bSCy Schubert         hierarchy[2] = KRB5_CONF_KDC_TCP_PORTS;
275*7f2fe78bSCy Schubert         if (krb5_aprof_get_string(aprof, hierarchy, TRUE,
276*7f2fe78bSCy Schubert                                   &rdp->realm_tcp_listen))
277*7f2fe78bSCy Schubert             rdp->realm_tcp_listen = strdup(def_tcp_listen);
278*7f2fe78bSCy Schubert     }
279*7f2fe78bSCy Schubert     if (!rdp->realm_tcp_listen) {
280*7f2fe78bSCy Schubert         kret = ENOMEM;
281*7f2fe78bSCy Schubert         goto whoops;
282*7f2fe78bSCy Schubert     }
283*7f2fe78bSCy Schubert     /* Handle stash file */
284*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_KEY_STASH_FILE;
285*7f2fe78bSCy Schubert     if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &rdp->realm_stash))
286*7f2fe78bSCy Schubert         manual = def_manual;
287*7f2fe78bSCy Schubert     else
288*7f2fe78bSCy Schubert         manual = FALSE;
289*7f2fe78bSCy Schubert 
290*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT;
291*7f2fe78bSCy Schubert     if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE,
292*7f2fe78bSCy Schubert                                &rdp->realm_restrict_anon))
293*7f2fe78bSCy Schubert         rdp->realm_restrict_anon = def_restrict_anon;
294*7f2fe78bSCy Schubert 
295*7f2fe78bSCy Schubert     /* Handle master key type */
296*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_MASTER_KEY_TYPE;
297*7f2fe78bSCy Schubert     if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &svalue) ||
298*7f2fe78bSCy Schubert         krb5_string_to_enctype(svalue, &rdp->realm_mkey.enctype))
299*7f2fe78bSCy Schubert         rdp->realm_mkey.enctype = manual ? def_enctype : ENCTYPE_UNKNOWN;
300*7f2fe78bSCy Schubert     free(svalue);
301*7f2fe78bSCy Schubert     svalue = NULL;
302*7f2fe78bSCy Schubert 
303*7f2fe78bSCy Schubert     /* Handle reject-bad-transit flag */
304*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_REJECT_BAD_TRANSIT;
305*7f2fe78bSCy Schubert     if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE,
306*7f2fe78bSCy Schubert                                 &rdp->realm_reject_bad_transit))
307*7f2fe78bSCy Schubert         rdp->realm_reject_bad_transit = TRUE;
308*7f2fe78bSCy Schubert 
309*7f2fe78bSCy Schubert     /* Handle ticket maximum life */
310*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_MAX_LIFE;
311*7f2fe78bSCy Schubert     if (krb5_aprof_get_deltat(aprof, hierarchy, TRUE, &rdp->realm_maxlife))
312*7f2fe78bSCy Schubert         rdp->realm_maxlife = KRB5_KDB_MAX_LIFE;
313*7f2fe78bSCy Schubert 
314*7f2fe78bSCy Schubert     /* Handle ticket renewable maximum life */
315*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_MAX_RENEWABLE_LIFE;
316*7f2fe78bSCy Schubert     if (krb5_aprof_get_deltat(aprof, hierarchy, TRUE, &rdp->realm_maxrlife))
317*7f2fe78bSCy Schubert         rdp->realm_maxrlife = KRB5_KDB_MAX_RLIFE;
318*7f2fe78bSCy Schubert 
319*7f2fe78bSCy Schubert     /* Handle KDC referrals */
320*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_NO_HOST_REFERRAL;
321*7f2fe78bSCy Schubert     (void)krb5_aprof_get_string_all(aprof, hierarchy, &svalue);
322*7f2fe78bSCy Schubert     kret = combine(no_referral, svalue, &rdp->realm_no_referral);
323*7f2fe78bSCy Schubert     if (kret)
324*7f2fe78bSCy Schubert         goto whoops;
325*7f2fe78bSCy Schubert     free(svalue);
326*7f2fe78bSCy Schubert     svalue = NULL;
327*7f2fe78bSCy Schubert 
328*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_HOST_BASED_SERVICES;
329*7f2fe78bSCy Schubert     (void)krb5_aprof_get_string_all(aprof, hierarchy, &svalue);
330*7f2fe78bSCy Schubert     kret = combine(hostbased, svalue, &rdp->realm_hostbased);
331*7f2fe78bSCy Schubert     if (kret)
332*7f2fe78bSCy Schubert         goto whoops;
333*7f2fe78bSCy Schubert     free(svalue);
334*7f2fe78bSCy Schubert     svalue = NULL;
335*7f2fe78bSCy Schubert 
336*7f2fe78bSCy Schubert     hierarchy[2] = KRB5_CONF_DISABLE_PAC;
337*7f2fe78bSCy Schubert     if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE,
338*7f2fe78bSCy Schubert                                &rdp->realm_disable_pac))
339*7f2fe78bSCy Schubert         rdp->realm_disable_pac = FALSE;
340*7f2fe78bSCy Schubert 
341*7f2fe78bSCy Schubert     /*
342*7f2fe78bSCy Schubert      * We've got our parameters, now go and setup our realm context.
343*7f2fe78bSCy Schubert      */
344*7f2fe78bSCy Schubert 
345*7f2fe78bSCy Schubert     /* Set the default realm of this context */
346*7f2fe78bSCy Schubert     if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) {
347*7f2fe78bSCy Schubert         kdc_err(rdp->realm_context, kret,
348*7f2fe78bSCy Schubert                 _("while setting default realm to %s"), realm);
349*7f2fe78bSCy Schubert         goto whoops;
350*7f2fe78bSCy Schubert     }
351*7f2fe78bSCy Schubert 
352*7f2fe78bSCy Schubert     /* first open the database  before doing anything */
353*7f2fe78bSCy Schubert     kdb_open_flags = KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_KDC;
354*7f2fe78bSCy Schubert     if ((kret = krb5_db_open(rdp->realm_context, db_args, kdb_open_flags))) {
355*7f2fe78bSCy Schubert         kdc_err(rdp->realm_context, kret,
356*7f2fe78bSCy Schubert                 _("while initializing database for realm %s"), realm);
357*7f2fe78bSCy Schubert         goto whoops;
358*7f2fe78bSCy Schubert     }
359*7f2fe78bSCy Schubert 
360*7f2fe78bSCy Schubert     /* Assemble and parse the master key name */
361*7f2fe78bSCy Schubert     if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname,
362*7f2fe78bSCy Schubert                                         rdp->realm_name, (char **) NULL,
363*7f2fe78bSCy Schubert                                         &rdp->realm_mprinc))) {
364*7f2fe78bSCy Schubert         kdc_err(rdp->realm_context, kret,
365*7f2fe78bSCy Schubert                 _("while setting up master key name %s for realm %s"),
366*7f2fe78bSCy Schubert                 rdp->realm_mpname, realm);
367*7f2fe78bSCy Schubert         goto whoops;
368*7f2fe78bSCy Schubert     }
369*7f2fe78bSCy Schubert 
370*7f2fe78bSCy Schubert     /*
371*7f2fe78bSCy Schubert      * Get the master key (note, may not be the most current mkey).
372*7f2fe78bSCy Schubert      */
373*7f2fe78bSCy Schubert     if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc,
374*7f2fe78bSCy Schubert                                    rdp->realm_mkey.enctype, manual,
375*7f2fe78bSCy Schubert                                    FALSE, rdp->realm_stash,
376*7f2fe78bSCy Schubert                                    &mkvno, NULL, &rdp->realm_mkey))) {
377*7f2fe78bSCy Schubert         kdc_err(rdp->realm_context, kret,
378*7f2fe78bSCy Schubert                 _("while fetching master key %s for realm %s"),
379*7f2fe78bSCy Schubert                 rdp->realm_mpname, realm);
380*7f2fe78bSCy Schubert         goto whoops;
381*7f2fe78bSCy Schubert     }
382*7f2fe78bSCy Schubert 
383*7f2fe78bSCy Schubert     if (krb5int_c_deprecated_enctype(rdp->realm_mkey.enctype)) {
384*7f2fe78bSCy Schubert         if (krb5_enctype_to_name(rdp->realm_mkey.enctype, FALSE, ename,
385*7f2fe78bSCy Schubert                                  sizeof(ename)))
386*7f2fe78bSCy Schubert             ename[0] = '\0';
387*7f2fe78bSCy Schubert         fprintf(stderr, _("Stash file %s uses DEPRECATED enctype %s!\n"),
388*7f2fe78bSCy Schubert                 rdp->realm_stash, ename);
389*7f2fe78bSCy Schubert     }
390*7f2fe78bSCy Schubert 
391*7f2fe78bSCy Schubert     if ((kret = krb5_db_fetch_mkey_list(rdp->realm_context, rdp->realm_mprinc,
392*7f2fe78bSCy Schubert                                         &rdp->realm_mkey))) {
393*7f2fe78bSCy Schubert         kdc_err(rdp->realm_context, kret,
394*7f2fe78bSCy Schubert                 _("while fetching master keys list for realm %s"), realm);
395*7f2fe78bSCy Schubert         goto whoops;
396*7f2fe78bSCy Schubert     }
397*7f2fe78bSCy Schubert 
398*7f2fe78bSCy Schubert 
399*7f2fe78bSCy Schubert     /* Set up the keytab */
400*7f2fe78bSCy Schubert     if ((kret = krb5_ktkdb_resolve(rdp->realm_context, NULL,
401*7f2fe78bSCy Schubert                                    &rdp->realm_keytab))) {
402*7f2fe78bSCy Schubert         kdc_err(rdp->realm_context, kret,
403*7f2fe78bSCy Schubert                 _("while resolving kdb keytab for realm %s"), realm);
404*7f2fe78bSCy Schubert         goto whoops;
405*7f2fe78bSCy Schubert     }
406*7f2fe78bSCy Schubert 
407*7f2fe78bSCy Schubert     /* Preformat the TGS name */
408*7f2fe78bSCy Schubert     if ((kret = krb5_build_principal(rdp->realm_context, &rdp->realm_tgsprinc,
409*7f2fe78bSCy Schubert                                      strlen(realm), realm, KRB5_TGS_NAME,
410*7f2fe78bSCy Schubert                                      realm, (char *) NULL))) {
411*7f2fe78bSCy Schubert         kdc_err(rdp->realm_context, kret,
412*7f2fe78bSCy Schubert                 _("while building TGS name for realm %s"), realm);
413*7f2fe78bSCy Schubert         goto whoops;
414*7f2fe78bSCy Schubert     }
415*7f2fe78bSCy Schubert 
416*7f2fe78bSCy Schubert whoops:
417*7f2fe78bSCy Schubert     /*
418*7f2fe78bSCy Schubert      * If we choked, then clean up any dirt we may have dropped on the floor.
419*7f2fe78bSCy Schubert      */
420*7f2fe78bSCy Schubert     if (kret) {
421*7f2fe78bSCy Schubert 
422*7f2fe78bSCy Schubert         finish_realm(rdp);
423*7f2fe78bSCy Schubert     }
424*7f2fe78bSCy Schubert     return(kret);
425*7f2fe78bSCy Schubert }
426*7f2fe78bSCy Schubert 
427*7f2fe78bSCy Schubert static void
on_monitor_signal(int signo)428*7f2fe78bSCy Schubert on_monitor_signal(int signo)
429*7f2fe78bSCy Schubert {
430*7f2fe78bSCy Schubert     signal_received = signo;
431*7f2fe78bSCy Schubert }
432*7f2fe78bSCy Schubert 
433*7f2fe78bSCy Schubert static void
on_monitor_sighup(int signo)434*7f2fe78bSCy Schubert on_monitor_sighup(int signo)
435*7f2fe78bSCy Schubert {
436*7f2fe78bSCy Schubert     sighup_received = 1;
437*7f2fe78bSCy Schubert }
438*7f2fe78bSCy Schubert 
439*7f2fe78bSCy Schubert /*
440*7f2fe78bSCy Schubert  * Kill the worker subprocesses given by pids[0..bound-1], skipping any which
441*7f2fe78bSCy Schubert  * are set to -1, and wait for them to exit (so that we know the ports are no
442*7f2fe78bSCy Schubert  * longer in use).
443*7f2fe78bSCy Schubert  */
444*7f2fe78bSCy Schubert static void
terminate_workers(pid_t * pids,int bound)445*7f2fe78bSCy Schubert terminate_workers(pid_t *pids, int bound)
446*7f2fe78bSCy Schubert {
447*7f2fe78bSCy Schubert     int i, status, num_active = 0;
448*7f2fe78bSCy Schubert     pid_t pid;
449*7f2fe78bSCy Schubert 
450*7f2fe78bSCy Schubert     /* Kill the active worker pids. */
451*7f2fe78bSCy Schubert     for (i = 0; i < bound; i++) {
452*7f2fe78bSCy Schubert         if (pids[i] == -1)
453*7f2fe78bSCy Schubert             continue;
454*7f2fe78bSCy Schubert         kill(pids[i], SIGTERM);
455*7f2fe78bSCy Schubert         num_active++;
456*7f2fe78bSCy Schubert     }
457*7f2fe78bSCy Schubert 
458*7f2fe78bSCy Schubert     /* Wait for them to exit. */
459*7f2fe78bSCy Schubert     while (num_active > 0) {
460*7f2fe78bSCy Schubert         pid = wait(&status);
461*7f2fe78bSCy Schubert         if (pid >= 0)
462*7f2fe78bSCy Schubert             num_active--;
463*7f2fe78bSCy Schubert     }
464*7f2fe78bSCy Schubert }
465*7f2fe78bSCy Schubert 
466*7f2fe78bSCy Schubert /*
467*7f2fe78bSCy Schubert  * Create num worker processes and return successfully in each child.  The
468*7f2fe78bSCy Schubert  * parent process will act as a supervisor and will only return from this
469*7f2fe78bSCy Schubert  * function in error cases.
470*7f2fe78bSCy Schubert  */
471*7f2fe78bSCy Schubert static krb5_error_code
create_workers(verto_ctx * ctx,int num)472*7f2fe78bSCy Schubert create_workers(verto_ctx *ctx, int num)
473*7f2fe78bSCy Schubert {
474*7f2fe78bSCy Schubert     krb5_error_code retval;
475*7f2fe78bSCy Schubert     int i, status;
476*7f2fe78bSCy Schubert     pid_t pid, *pids;
477*7f2fe78bSCy Schubert #ifdef POSIX_SIGNALS
478*7f2fe78bSCy Schubert     struct sigaction s_action;
479*7f2fe78bSCy Schubert #endif /* POSIX_SIGNALS */
480*7f2fe78bSCy Schubert 
481*7f2fe78bSCy Schubert     /*
482*7f2fe78bSCy Schubert      * Setup our signal handlers which will forward to the children.
483*7f2fe78bSCy Schubert      * These handlers will be overridden in the child processes.
484*7f2fe78bSCy Schubert      */
485*7f2fe78bSCy Schubert #ifdef POSIX_SIGNALS
486*7f2fe78bSCy Schubert     (void) sigemptyset(&s_action.sa_mask);
487*7f2fe78bSCy Schubert     s_action.sa_flags = 0;
488*7f2fe78bSCy Schubert     s_action.sa_handler = on_monitor_signal;
489*7f2fe78bSCy Schubert     (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL);
490*7f2fe78bSCy Schubert     (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL);
491*7f2fe78bSCy Schubert     (void) sigaction(SIGQUIT, &s_action, (struct sigaction *) NULL);
492*7f2fe78bSCy Schubert     s_action.sa_handler = on_monitor_sighup;
493*7f2fe78bSCy Schubert     (void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL);
494*7f2fe78bSCy Schubert #else  /* POSIX_SIGNALS */
495*7f2fe78bSCy Schubert     signal(SIGINT, on_monitor_signal);
496*7f2fe78bSCy Schubert     signal(SIGTERM, on_monitor_signal);
497*7f2fe78bSCy Schubert     signal(SIGQUIT, on_monitor_signal);
498*7f2fe78bSCy Schubert     signal(SIGHUP, on_monitor_sighup);
499*7f2fe78bSCy Schubert #endif /* POSIX_SIGNALS */
500*7f2fe78bSCy Schubert 
501*7f2fe78bSCy Schubert     /* Create child worker processes; return in each child. */
502*7f2fe78bSCy Schubert     krb5_klog_syslog(LOG_INFO, _("creating %d worker processes"), num);
503*7f2fe78bSCy Schubert     pids = calloc(num, sizeof(pid_t));
504*7f2fe78bSCy Schubert     if (pids == NULL)
505*7f2fe78bSCy Schubert         return ENOMEM;
506*7f2fe78bSCy Schubert     for (i = 0; i < num; i++) {
507*7f2fe78bSCy Schubert         pid = fork();
508*7f2fe78bSCy Schubert         if (pid == 0) {
509*7f2fe78bSCy Schubert             free(pids);
510*7f2fe78bSCy Schubert             if (!verto_reinitialize(ctx)) {
511*7f2fe78bSCy Schubert                 krb5_klog_syslog(LOG_ERR,
512*7f2fe78bSCy Schubert                                  _("Unable to reinitialize main loop"));
513*7f2fe78bSCy Schubert                 return ENOMEM;
514*7f2fe78bSCy Schubert             }
515*7f2fe78bSCy Schubert             retval = loop_setup_signals(ctx, &shandle, reset_for_hangup);
516*7f2fe78bSCy Schubert             if (retval) {
517*7f2fe78bSCy Schubert                 krb5_klog_syslog(LOG_ERR, _("Unable to initialize signal "
518*7f2fe78bSCy Schubert                                             "handlers in pid %d"), pid);
519*7f2fe78bSCy Schubert                 return retval;
520*7f2fe78bSCy Schubert             }
521*7f2fe78bSCy Schubert 
522*7f2fe78bSCy Schubert             /* Avoid race condition */
523*7f2fe78bSCy Schubert             if (signal_received)
524*7f2fe78bSCy Schubert                 exit(0);
525*7f2fe78bSCy Schubert 
526*7f2fe78bSCy Schubert             /* Return control to main() in the new worker process. */
527*7f2fe78bSCy Schubert             return 0;
528*7f2fe78bSCy Schubert         }
529*7f2fe78bSCy Schubert         if (pid == -1) {
530*7f2fe78bSCy Schubert             /* Couldn't fork enough times. */
531*7f2fe78bSCy Schubert             status = errno;
532*7f2fe78bSCy Schubert             terminate_workers(pids, i);
533*7f2fe78bSCy Schubert             free(pids);
534*7f2fe78bSCy Schubert             return status;
535*7f2fe78bSCy Schubert         }
536*7f2fe78bSCy Schubert         pids[i] = pid;
537*7f2fe78bSCy Schubert     }
538*7f2fe78bSCy Schubert 
539*7f2fe78bSCy Schubert     /* We're going to use our own main loop here. */
540*7f2fe78bSCy Schubert     loop_free(ctx);
541*7f2fe78bSCy Schubert 
542*7f2fe78bSCy Schubert     /* Supervise the worker processes. */
543*7f2fe78bSCy Schubert     while (!signal_received) {
544*7f2fe78bSCy Schubert         /* Wait until a worker process exits or we get a signal. */
545*7f2fe78bSCy Schubert         pid = wait(&status);
546*7f2fe78bSCy Schubert         if (pid >= 0) {
547*7f2fe78bSCy Schubert             krb5_klog_syslog(LOG_ERR, _("worker %ld exited with status %d"),
548*7f2fe78bSCy Schubert                              (long) pid, status);
549*7f2fe78bSCy Schubert 
550*7f2fe78bSCy Schubert             /* Remove the pid from the table. */
551*7f2fe78bSCy Schubert             for (i = 0; i < num; i++) {
552*7f2fe78bSCy Schubert                 if (pids[i] == pid)
553*7f2fe78bSCy Schubert                     pids[i] = -1;
554*7f2fe78bSCy Schubert             }
555*7f2fe78bSCy Schubert 
556*7f2fe78bSCy Schubert             /* When one worker process exits, terminate them all, so that KDC
557*7f2fe78bSCy Schubert              * crashes behave similarly with or without worker processes. */
558*7f2fe78bSCy Schubert             break;
559*7f2fe78bSCy Schubert         }
560*7f2fe78bSCy Schubert 
561*7f2fe78bSCy Schubert         /* Propagate HUP signal to worker processes if we received one. */
562*7f2fe78bSCy Schubert         if (sighup_received) {
563*7f2fe78bSCy Schubert             sighup_received = 0;
564*7f2fe78bSCy Schubert             for (i = 0; i < num; i++) {
565*7f2fe78bSCy Schubert                 if (pids[i] != -1)
566*7f2fe78bSCy Schubert                     kill(pids[i], SIGHUP);
567*7f2fe78bSCy Schubert             }
568*7f2fe78bSCy Schubert         }
569*7f2fe78bSCy Schubert     }
570*7f2fe78bSCy Schubert     if (signal_received)
571*7f2fe78bSCy Schubert         krb5_klog_syslog(LOG_INFO, _("signal %d received in supervisor"),
572*7f2fe78bSCy Schubert                          signal_received);
573*7f2fe78bSCy Schubert 
574*7f2fe78bSCy Schubert     terminate_workers(pids, num);
575*7f2fe78bSCy Schubert     free(pids);
576*7f2fe78bSCy Schubert     exit(0);
577*7f2fe78bSCy Schubert }
578*7f2fe78bSCy Schubert 
579*7f2fe78bSCy Schubert static void
usage(char * name)580*7f2fe78bSCy Schubert usage(char *name)
581*7f2fe78bSCy Schubert {
582*7f2fe78bSCy Schubert     fprintf(stderr,
583*7f2fe78bSCy Schubert             _("usage: %s [-x db_args]* [-d dbpathname] [-r dbrealmname]\n"
584*7f2fe78bSCy Schubert               "\t\t[-T time_offset] [-m] [-k masterenctype]\n"
585*7f2fe78bSCy Schubert               "\t\t[-M masterkeyname] [-p port] [-P pid_file]\n"
586*7f2fe78bSCy Schubert               "\t\t[-n] [-w numworkers] [/]\n\n"
587*7f2fe78bSCy Schubert               "where,\n"
588*7f2fe78bSCy Schubert               "\t[-x db_args]* - Any number of database specific arguments.\n"
589*7f2fe78bSCy Schubert               "\t\t\tLook at each database module documentation for "
590*7f2fe78bSCy Schubert               "\t\t\tsupported arguments\n"),
591*7f2fe78bSCy Schubert             name);
592*7f2fe78bSCy Schubert     exit(1);
593*7f2fe78bSCy Schubert }
594*7f2fe78bSCy Schubert 
595*7f2fe78bSCy Schubert 
596*7f2fe78bSCy Schubert static void
initialize_realms(krb5_context kcontext,int argc,char ** argv,int * tcp_listen_backlog_out)597*7f2fe78bSCy Schubert initialize_realms(krb5_context kcontext, int argc, char **argv,
598*7f2fe78bSCy Schubert                   int *tcp_listen_backlog_out)
599*7f2fe78bSCy Schubert {
600*7f2fe78bSCy Schubert     int                 c;
601*7f2fe78bSCy Schubert     char                *db_name = (char *) NULL;
602*7f2fe78bSCy Schubert     char                *lrealm = (char *) NULL;
603*7f2fe78bSCy Schubert     char                *mkey_name = (char *) NULL;
604*7f2fe78bSCy Schubert     krb5_error_code     retval;
605*7f2fe78bSCy Schubert     krb5_enctype        menctype = ENCTYPE_UNKNOWN;
606*7f2fe78bSCy Schubert     kdc_realm_t         *rdatap = NULL;
607*7f2fe78bSCy Schubert     krb5_boolean        manual = FALSE;
608*7f2fe78bSCy Schubert     krb5_boolean        def_restrict_anon;
609*7f2fe78bSCy Schubert     char                *def_udp_listen = NULL;
610*7f2fe78bSCy Schubert     char                *def_tcp_listen = NULL;
611*7f2fe78bSCy Schubert     krb5_pointer        aprof = kcontext->profile;
612*7f2fe78bSCy Schubert     const char          *hierarchy[3];
613*7f2fe78bSCy Schubert     char                *no_referral = NULL;
614*7f2fe78bSCy Schubert     char                *hostbased = NULL;
615*7f2fe78bSCy Schubert     int                  db_args_size = 0;
616*7f2fe78bSCy Schubert     char                **db_args = NULL;
617*7f2fe78bSCy Schubert 
618*7f2fe78bSCy Schubert     extern char *optarg;
619*7f2fe78bSCy Schubert 
620*7f2fe78bSCy Schubert     hierarchy[0] = KRB5_CONF_KDCDEFAULTS;
621*7f2fe78bSCy Schubert     hierarchy[1] = KRB5_CONF_KDC_LISTEN;
622*7f2fe78bSCy Schubert     hierarchy[2] = NULL;
623*7f2fe78bSCy Schubert     if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &def_udp_listen)) {
624*7f2fe78bSCy Schubert         hierarchy[1] = KRB5_CONF_KDC_PORTS;
625*7f2fe78bSCy Schubert         if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &def_udp_listen))
626*7f2fe78bSCy Schubert             def_udp_listen = NULL;
627*7f2fe78bSCy Schubert     }
628*7f2fe78bSCy Schubert     hierarchy[1] = KRB5_CONF_KDC_TCP_LISTEN;
629*7f2fe78bSCy Schubert     if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &def_tcp_listen)) {
630*7f2fe78bSCy Schubert         hierarchy[1] = KRB5_CONF_KDC_TCP_PORTS;
631*7f2fe78bSCy Schubert         if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &def_tcp_listen))
632*7f2fe78bSCy Schubert             def_tcp_listen = NULL;
633*7f2fe78bSCy Schubert     }
634*7f2fe78bSCy Schubert     hierarchy[1] = KRB5_CONF_KDC_MAX_DGRAM_REPLY_SIZE;
635*7f2fe78bSCy Schubert     if (krb5_aprof_get_int32(aprof, hierarchy, TRUE, &max_dgram_reply_size))
636*7f2fe78bSCy Schubert         max_dgram_reply_size = MAX_DGRAM_SIZE;
637*7f2fe78bSCy Schubert     if (tcp_listen_backlog_out != NULL) {
638*7f2fe78bSCy Schubert         hierarchy[1] = KRB5_CONF_KDC_TCP_LISTEN_BACKLOG;
639*7f2fe78bSCy Schubert         if (krb5_aprof_get_int32(aprof, hierarchy, TRUE,
640*7f2fe78bSCy Schubert                                  tcp_listen_backlog_out))
641*7f2fe78bSCy Schubert             *tcp_listen_backlog_out = DEFAULT_TCP_LISTEN_BACKLOG;
642*7f2fe78bSCy Schubert     }
643*7f2fe78bSCy Schubert     hierarchy[1] = KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT;
644*7f2fe78bSCy Schubert     if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE, &def_restrict_anon))
645*7f2fe78bSCy Schubert         def_restrict_anon = FALSE;
646*7f2fe78bSCy Schubert     hierarchy[1] = KRB5_CONF_NO_HOST_REFERRAL;
647*7f2fe78bSCy Schubert     if (krb5_aprof_get_string_all(aprof, hierarchy, &no_referral))
648*7f2fe78bSCy Schubert         no_referral = 0;
649*7f2fe78bSCy Schubert     hierarchy[1] = KRB5_CONF_HOST_BASED_SERVICES;
650*7f2fe78bSCy Schubert     if (krb5_aprof_get_string_all(aprof, hierarchy, &hostbased))
651*7f2fe78bSCy Schubert         hostbased = 0;
652*7f2fe78bSCy Schubert 
653*7f2fe78bSCy Schubert     if (def_udp_listen == NULL) {
654*7f2fe78bSCy Schubert         def_udp_listen = strdup(DEFAULT_KDC_UDP_PORTLIST);
655*7f2fe78bSCy Schubert         if (def_udp_listen == NULL) {
656*7f2fe78bSCy Schubert             fprintf(stderr, _(" KDC cannot initialize. Not enough memory\n"));
657*7f2fe78bSCy Schubert             exit(1);
658*7f2fe78bSCy Schubert         }
659*7f2fe78bSCy Schubert     }
660*7f2fe78bSCy Schubert     if (def_tcp_listen == NULL) {
661*7f2fe78bSCy Schubert         def_tcp_listen = strdup(DEFAULT_KDC_TCP_PORTLIST);
662*7f2fe78bSCy Schubert         if (def_tcp_listen == NULL) {
663*7f2fe78bSCy Schubert             fprintf(stderr, _(" KDC cannot initialize. Not enough memory\n"));
664*7f2fe78bSCy Schubert             exit(1);
665*7f2fe78bSCy Schubert         }
666*7f2fe78bSCy Schubert     }
667*7f2fe78bSCy Schubert 
668*7f2fe78bSCy Schubert     /*
669*7f2fe78bSCy Schubert      * Loop through the option list.  Each time we encounter a realm name, use
670*7f2fe78bSCy Schubert      * the previously scanned options to fill in for defaults.  We do this
671*7f2fe78bSCy Schubert      * twice if worker processes are used, so we must initialize optind.
672*7f2fe78bSCy Schubert      */
673*7f2fe78bSCy Schubert     optind = 1;
674*7f2fe78bSCy Schubert     while ((c = getopt(argc, argv, "x:r:d:mM:k:R:P:p:nw:4:T:X3")) != -1) {
675*7f2fe78bSCy Schubert         switch(c) {
676*7f2fe78bSCy Schubert         case 'x':
677*7f2fe78bSCy Schubert             db_args_size++;
678*7f2fe78bSCy Schubert             {
679*7f2fe78bSCy Schubert                 char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
680*7f2fe78bSCy Schubert                 if( temp == NULL )
681*7f2fe78bSCy Schubert                 {
682*7f2fe78bSCy Schubert                     fprintf(stderr, _("%s: KDC cannot initialize. Not enough "
683*7f2fe78bSCy Schubert                                       "memory\n"), argv[0]);
684*7f2fe78bSCy Schubert                     exit(1);
685*7f2fe78bSCy Schubert                 }
686*7f2fe78bSCy Schubert 
687*7f2fe78bSCy Schubert                 db_args = temp;
688*7f2fe78bSCy Schubert             }
689*7f2fe78bSCy Schubert             db_args[db_args_size-1] = optarg;
690*7f2fe78bSCy Schubert             db_args[db_args_size]   = NULL;
691*7f2fe78bSCy Schubert             break;
692*7f2fe78bSCy Schubert 
693*7f2fe78bSCy Schubert         case 'r':                       /* realm name for db */
694*7f2fe78bSCy Schubert             if (!find_realm_data(&shandle, optarg, (krb5_ui_4) strlen(optarg))) {
695*7f2fe78bSCy Schubert                 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
696*7f2fe78bSCy Schubert                     retval = init_realm(rdatap, aprof, optarg, mkey_name,
697*7f2fe78bSCy Schubert                                         menctype, def_udp_listen,
698*7f2fe78bSCy Schubert                                         def_tcp_listen, manual,
699*7f2fe78bSCy Schubert                                         def_restrict_anon, db_args,
700*7f2fe78bSCy Schubert                                         no_referral, hostbased);
701*7f2fe78bSCy Schubert                     if (retval) {
702*7f2fe78bSCy Schubert                         fprintf(stderr, _("%s: cannot initialize realm %s - "
703*7f2fe78bSCy Schubert                                           "see log file for details\n"),
704*7f2fe78bSCy Schubert                                 argv[0], optarg);
705*7f2fe78bSCy Schubert                         exit(1);
706*7f2fe78bSCy Schubert                     }
707*7f2fe78bSCy Schubert                     shandle.kdc_realmlist[shandle.kdc_numrealms] = rdatap;
708*7f2fe78bSCy Schubert                     shandle.kdc_numrealms++;
709*7f2fe78bSCy Schubert                     free(db_args), db_args=NULL, db_args_size = 0;
710*7f2fe78bSCy Schubert                 }
711*7f2fe78bSCy Schubert                 else
712*7f2fe78bSCy Schubert                 {
713*7f2fe78bSCy Schubert                     fprintf(stderr, _("%s: cannot initialize realm %s. Not "
714*7f2fe78bSCy Schubert                                       "enough memory\n"), argv[0], optarg);
715*7f2fe78bSCy Schubert                     exit(1);
716*7f2fe78bSCy Schubert                 }
717*7f2fe78bSCy Schubert             }
718*7f2fe78bSCy Schubert             break;
719*7f2fe78bSCy Schubert         case 'd':                       /* pathname for db */
720*7f2fe78bSCy Schubert             /* now db_name is not a separate argument.
721*7f2fe78bSCy Schubert              * It has to be passed as part of the db_args
722*7f2fe78bSCy Schubert              */
723*7f2fe78bSCy Schubert             if( db_name == NULL ) {
724*7f2fe78bSCy Schubert                 if (asprintf(&db_name, "dbname=%s", optarg) < 0) {
725*7f2fe78bSCy Schubert                     fprintf(stderr, _("%s: KDC cannot initialize. Not enough "
726*7f2fe78bSCy Schubert                                       "memory\n"), argv[0]);
727*7f2fe78bSCy Schubert                     exit(1);
728*7f2fe78bSCy Schubert                 }
729*7f2fe78bSCy Schubert             }
730*7f2fe78bSCy Schubert 
731*7f2fe78bSCy Schubert             db_args_size++;
732*7f2fe78bSCy Schubert             {
733*7f2fe78bSCy Schubert                 char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
734*7f2fe78bSCy Schubert                 if( temp == NULL )
735*7f2fe78bSCy Schubert                 {
736*7f2fe78bSCy Schubert                     fprintf(stderr, _("%s: KDC cannot initialize. Not enough "
737*7f2fe78bSCy Schubert                                       "memory\n"), argv[0]);
738*7f2fe78bSCy Schubert                     exit(1);
739*7f2fe78bSCy Schubert                 }
740*7f2fe78bSCy Schubert 
741*7f2fe78bSCy Schubert                 db_args = temp;
742*7f2fe78bSCy Schubert             }
743*7f2fe78bSCy Schubert             db_args[db_args_size-1] = db_name;
744*7f2fe78bSCy Schubert             db_args[db_args_size]   = NULL;
745*7f2fe78bSCy Schubert             break;
746*7f2fe78bSCy Schubert         case 'm':                       /* manual type-in of master key */
747*7f2fe78bSCy Schubert             manual = TRUE;
748*7f2fe78bSCy Schubert             if (menctype == ENCTYPE_UNKNOWN)
749*7f2fe78bSCy Schubert                 menctype = DEFAULT_KDC_ENCTYPE;
750*7f2fe78bSCy Schubert             break;
751*7f2fe78bSCy Schubert         case 'M':                       /* master key name in DB */
752*7f2fe78bSCy Schubert             mkey_name = optarg;
753*7f2fe78bSCy Schubert             break;
754*7f2fe78bSCy Schubert         case 'n':
755*7f2fe78bSCy Schubert             nofork++;                   /* don't detach from terminal */
756*7f2fe78bSCy Schubert             break;
757*7f2fe78bSCy Schubert         case 'w':                       /* create multiple worker processes */
758*7f2fe78bSCy Schubert             workers = atoi(optarg);
759*7f2fe78bSCy Schubert             if (workers <= 0)
760*7f2fe78bSCy Schubert                 usage(argv[0]);
761*7f2fe78bSCy Schubert             break;
762*7f2fe78bSCy Schubert         case 'k':                       /* enctype for master key */
763*7f2fe78bSCy Schubert             if (krb5_string_to_enctype(optarg, &menctype))
764*7f2fe78bSCy Schubert                 com_err(argv[0], 0, _("invalid enctype %s"), optarg);
765*7f2fe78bSCy Schubert             break;
766*7f2fe78bSCy Schubert         case 'R':
767*7f2fe78bSCy Schubert             /* Replay cache name; defunct since we don't use a replay cache. */
768*7f2fe78bSCy Schubert             break;
769*7f2fe78bSCy Schubert         case 'P':
770*7f2fe78bSCy Schubert             pid_file = optarg;
771*7f2fe78bSCy Schubert             break;
772*7f2fe78bSCy Schubert         case 'p':
773*7f2fe78bSCy Schubert             free(def_udp_listen);
774*7f2fe78bSCy Schubert             free(def_tcp_listen);
775*7f2fe78bSCy Schubert             def_udp_listen = strdup(optarg);
776*7f2fe78bSCy Schubert             def_tcp_listen = strdup(optarg);
777*7f2fe78bSCy Schubert             if (def_udp_listen == NULL || def_tcp_listen == NULL) {
778*7f2fe78bSCy Schubert                 fprintf(stderr, _(" KDC cannot initialize. Not enough "
779*7f2fe78bSCy Schubert                                   "memory\n"));
780*7f2fe78bSCy Schubert                 exit(1);
781*7f2fe78bSCy Schubert             }
782*7f2fe78bSCy Schubert             break;
783*7f2fe78bSCy Schubert         case 'T':
784*7f2fe78bSCy Schubert             time_offset = atoi(optarg);
785*7f2fe78bSCy Schubert             break;
786*7f2fe78bSCy Schubert         case '4':
787*7f2fe78bSCy Schubert             break;
788*7f2fe78bSCy Schubert         case 'X':
789*7f2fe78bSCy Schubert             break;
790*7f2fe78bSCy Schubert         case '?':
791*7f2fe78bSCy Schubert         default:
792*7f2fe78bSCy Schubert             usage(argv[0]);
793*7f2fe78bSCy Schubert         }
794*7f2fe78bSCy Schubert     }
795*7f2fe78bSCy Schubert 
796*7f2fe78bSCy Schubert     /*
797*7f2fe78bSCy Schubert      * Check to see if we processed any realms.
798*7f2fe78bSCy Schubert      */
799*7f2fe78bSCy Schubert     if (shandle.kdc_numrealms == 0) {
800*7f2fe78bSCy Schubert         /* no realm specified, use default realm */
801*7f2fe78bSCy Schubert         if ((retval = krb5_get_default_realm(kcontext, &lrealm))) {
802*7f2fe78bSCy Schubert             com_err(argv[0], retval,
803*7f2fe78bSCy Schubert                     _("while attempting to retrieve default realm"));
804*7f2fe78bSCy Schubert             fprintf (stderr,
805*7f2fe78bSCy Schubert                      _("%s: %s, attempting to retrieve default realm\n"),
806*7f2fe78bSCy Schubert                      argv[0], krb5_get_error_message(kcontext, retval));
807*7f2fe78bSCy Schubert             exit(1);
808*7f2fe78bSCy Schubert         }
809*7f2fe78bSCy Schubert         if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
810*7f2fe78bSCy Schubert             retval = init_realm(rdatap, aprof, lrealm, mkey_name, menctype,
811*7f2fe78bSCy Schubert                                 def_udp_listen, def_tcp_listen, manual,
812*7f2fe78bSCy Schubert                                 def_restrict_anon, db_args, no_referral,
813*7f2fe78bSCy Schubert                                 hostbased);
814*7f2fe78bSCy Schubert             if (retval) {
815*7f2fe78bSCy Schubert                 fprintf(stderr, _("%s: cannot initialize realm %s - see log "
816*7f2fe78bSCy Schubert                                   "file for details\n"), argv[0], lrealm);
817*7f2fe78bSCy Schubert                 exit(1);
818*7f2fe78bSCy Schubert             }
819*7f2fe78bSCy Schubert             shandle.kdc_realmlist[0] = rdatap;
820*7f2fe78bSCy Schubert             shandle.kdc_numrealms++;
821*7f2fe78bSCy Schubert         }
822*7f2fe78bSCy Schubert         krb5_free_default_realm(kcontext, lrealm);
823*7f2fe78bSCy Schubert     }
824*7f2fe78bSCy Schubert 
825*7f2fe78bSCy Schubert     if (def_udp_listen)
826*7f2fe78bSCy Schubert         free(def_udp_listen);
827*7f2fe78bSCy Schubert     if (def_tcp_listen)
828*7f2fe78bSCy Schubert         free(def_tcp_listen);
829*7f2fe78bSCy Schubert     if (db_args)
830*7f2fe78bSCy Schubert         free(db_args);
831*7f2fe78bSCy Schubert     if (db_name)
832*7f2fe78bSCy Schubert         free(db_name);
833*7f2fe78bSCy Schubert     if (hostbased)
834*7f2fe78bSCy Schubert         free(hostbased);
835*7f2fe78bSCy Schubert     if (no_referral)
836*7f2fe78bSCy Schubert         free(no_referral);
837*7f2fe78bSCy Schubert 
838*7f2fe78bSCy Schubert     return;
839*7f2fe78bSCy Schubert }
840*7f2fe78bSCy Schubert 
841*7f2fe78bSCy Schubert static krb5_error_code
write_pid_file(const char * path)842*7f2fe78bSCy Schubert write_pid_file(const char *path)
843*7f2fe78bSCy Schubert {
844*7f2fe78bSCy Schubert     FILE *file;
845*7f2fe78bSCy Schubert     unsigned long pid;
846*7f2fe78bSCy Schubert 
847*7f2fe78bSCy Schubert     file = fopen(path, "w");
848*7f2fe78bSCy Schubert     if (file == NULL)
849*7f2fe78bSCy Schubert         return errno;
850*7f2fe78bSCy Schubert     pid = (unsigned long) getpid();
851*7f2fe78bSCy Schubert     if (fprintf(file, "%ld\n", pid) < 0 || fclose(file) == EOF)
852*7f2fe78bSCy Schubert         return errno;
853*7f2fe78bSCy Schubert     return 0;
854*7f2fe78bSCy Schubert }
855*7f2fe78bSCy Schubert 
856*7f2fe78bSCy Schubert static void
finish_realms()857*7f2fe78bSCy Schubert finish_realms()
858*7f2fe78bSCy Schubert {
859*7f2fe78bSCy Schubert     int i;
860*7f2fe78bSCy Schubert 
861*7f2fe78bSCy Schubert     for (i = 0; i < shandle.kdc_numrealms; i++) {
862*7f2fe78bSCy Schubert         finish_realm(shandle.kdc_realmlist[i]);
863*7f2fe78bSCy Schubert         shandle.kdc_realmlist[i] = 0;
864*7f2fe78bSCy Schubert     }
865*7f2fe78bSCy Schubert     shandle.kdc_numrealms = 0;
866*7f2fe78bSCy Schubert }
867*7f2fe78bSCy Schubert 
868*7f2fe78bSCy Schubert /*
869*7f2fe78bSCy Schubert   outline:
870*7f2fe78bSCy Schubert 
871*7f2fe78bSCy Schubert   process args & setup
872*7f2fe78bSCy Schubert 
873*7f2fe78bSCy Schubert   initialize database access (fetch master key, open DB)
874*7f2fe78bSCy Schubert 
875*7f2fe78bSCy Schubert   initialize network
876*7f2fe78bSCy Schubert 
877*7f2fe78bSCy Schubert   loop:
878*7f2fe78bSCy Schubert   listen for packet
879*7f2fe78bSCy Schubert 
880*7f2fe78bSCy Schubert   determine packet type, dispatch to handling routine
881*7f2fe78bSCy Schubert   (AS or TGS (or V4?))
882*7f2fe78bSCy Schubert 
883*7f2fe78bSCy Schubert   reflect response
884*7f2fe78bSCy Schubert 
885*7f2fe78bSCy Schubert   exit on signal
886*7f2fe78bSCy Schubert 
887*7f2fe78bSCy Schubert   clean up secrets, close db
888*7f2fe78bSCy Schubert 
889*7f2fe78bSCy Schubert   shut down network
890*7f2fe78bSCy Schubert 
891*7f2fe78bSCy Schubert   exit
892*7f2fe78bSCy Schubert */
893*7f2fe78bSCy Schubert 
main(int argc,char ** argv)894*7f2fe78bSCy Schubert int main(int argc, char **argv)
895*7f2fe78bSCy Schubert {
896*7f2fe78bSCy Schubert     krb5_error_code     retval;
897*7f2fe78bSCy Schubert     krb5_context        kcontext;
898*7f2fe78bSCy Schubert     kdc_realm_t *realm;
899*7f2fe78bSCy Schubert     verto_ctx *ctx;
900*7f2fe78bSCy Schubert     int tcp_listen_backlog;
901*7f2fe78bSCy Schubert     int errout = 0;
902*7f2fe78bSCy Schubert     int i;
903*7f2fe78bSCy Schubert 
904*7f2fe78bSCy Schubert     setlocale(LC_ALL, "");
905*7f2fe78bSCy Schubert     if (strrchr(argv[0], '/'))
906*7f2fe78bSCy Schubert         argv[0] = strrchr(argv[0], '/')+1;
907*7f2fe78bSCy Schubert 
908*7f2fe78bSCy Schubert     shandle.kdc_realmlist = malloc(sizeof(kdc_realm_t *) *
909*7f2fe78bSCy Schubert                                    KRB5_KDC_MAX_REALMS);
910*7f2fe78bSCy Schubert     if (shandle.kdc_realmlist == NULL) {
911*7f2fe78bSCy Schubert         fprintf(stderr, _("%s: cannot get memory for realm list\n"), argv[0]);
912*7f2fe78bSCy Schubert         exit(1);
913*7f2fe78bSCy Schubert     }
914*7f2fe78bSCy Schubert     memset(shandle.kdc_realmlist, 0,
915*7f2fe78bSCy Schubert            (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS));
916*7f2fe78bSCy Schubert 
917*7f2fe78bSCy Schubert     /*
918*7f2fe78bSCy Schubert      * A note about Kerberos contexts: This context, "kcontext", is used
919*7f2fe78bSCy Schubert      * for the KDC operations, i.e. setup, network connection and error
920*7f2fe78bSCy Schubert      * reporting.  The per-realm operations use the "realm_context"
921*7f2fe78bSCy Schubert      * associated with each realm.
922*7f2fe78bSCy Schubert      */
923*7f2fe78bSCy Schubert     retval = krb5int_init_context_kdc(&kcontext);
924*7f2fe78bSCy Schubert     if (retval) {
925*7f2fe78bSCy Schubert         com_err(argv[0], retval, _("while initializing krb5"));
926*7f2fe78bSCy Schubert         exit(1);
927*7f2fe78bSCy Schubert     }
928*7f2fe78bSCy Schubert     krb5_klog_init(kcontext, "kdc", argv[0], 1);
929*7f2fe78bSCy Schubert     shandle.kdc_err_context = kcontext;
930*7f2fe78bSCy Schubert     kdc_progname = argv[0];
931*7f2fe78bSCy Schubert     /* N.B.: After this point, com_err sends output to the KDC log
932*7f2fe78bSCy Schubert        file, and not to stderr.  We use the kdc_err wrapper around
933*7f2fe78bSCy Schubert        com_err to ensure that the error state exists in the context
934*7f2fe78bSCy Schubert        known to the krb5_klog callback. */
935*7f2fe78bSCy Schubert 
936*7f2fe78bSCy Schubert     initialize_kdc5_error_table();
937*7f2fe78bSCy Schubert 
938*7f2fe78bSCy Schubert     /*
939*7f2fe78bSCy Schubert      * Scan through the argument list
940*7f2fe78bSCy Schubert      */
941*7f2fe78bSCy Schubert     initialize_realms(kcontext, argc, argv, &tcp_listen_backlog);
942*7f2fe78bSCy Schubert 
943*7f2fe78bSCy Schubert #ifndef NOCACHE
944*7f2fe78bSCy Schubert     retval = kdc_init_lookaside(kcontext);
945*7f2fe78bSCy Schubert     if (retval) {
946*7f2fe78bSCy Schubert         kdc_err(kcontext, retval, _("while initializing lookaside cache"));
947*7f2fe78bSCy Schubert         finish_realms();
948*7f2fe78bSCy Schubert         return 1;
949*7f2fe78bSCy Schubert     }
950*7f2fe78bSCy Schubert #endif
951*7f2fe78bSCy Schubert 
952*7f2fe78bSCy Schubert     ctx = loop_init(VERTO_EV_TYPE_NONE);
953*7f2fe78bSCy Schubert     if (!ctx) {
954*7f2fe78bSCy Schubert         kdc_err(kcontext, ENOMEM, _("while creating main loop"));
955*7f2fe78bSCy Schubert         finish_realms();
956*7f2fe78bSCy Schubert         return 1;
957*7f2fe78bSCy Schubert     }
958*7f2fe78bSCy Schubert 
959*7f2fe78bSCy Schubert     load_preauth_plugins(&shandle, kcontext, ctx);
960*7f2fe78bSCy Schubert     load_authdata_plugins(kcontext);
961*7f2fe78bSCy Schubert     retval = load_kdcpolicy_plugins(kcontext);
962*7f2fe78bSCy Schubert     if (retval) {
963*7f2fe78bSCy Schubert         kdc_err(kcontext, retval, _("while loading KDC policy plugin"));
964*7f2fe78bSCy Schubert         finish_realms();
965*7f2fe78bSCy Schubert         return 1;
966*7f2fe78bSCy Schubert     }
967*7f2fe78bSCy Schubert 
968*7f2fe78bSCy Schubert     /* Add each realm's listener addresses to the loop. */
969*7f2fe78bSCy Schubert     for (i = 0; i < shandle.kdc_numrealms; i++) {
970*7f2fe78bSCy Schubert         realm = shandle.kdc_realmlist[i];
971*7f2fe78bSCy Schubert         if (*realm->realm_listen != '\0') {
972*7f2fe78bSCy Schubert             retval = loop_add_udp_address(KRB5_DEFAULT_PORT,
973*7f2fe78bSCy Schubert                                           realm->realm_listen);
974*7f2fe78bSCy Schubert             if (retval)
975*7f2fe78bSCy Schubert                 goto net_init_error;
976*7f2fe78bSCy Schubert         }
977*7f2fe78bSCy Schubert         if (*realm->realm_tcp_listen != '\0') {
978*7f2fe78bSCy Schubert             retval = loop_add_tcp_address(KRB5_DEFAULT_PORT,
979*7f2fe78bSCy Schubert                                           realm->realm_tcp_listen);
980*7f2fe78bSCy Schubert             if (retval)
981*7f2fe78bSCy Schubert                 goto net_init_error;
982*7f2fe78bSCy Schubert         }
983*7f2fe78bSCy Schubert     }
984*7f2fe78bSCy Schubert 
985*7f2fe78bSCy Schubert     if (workers == 0) {
986*7f2fe78bSCy Schubert         retval = loop_setup_signals(ctx, &shandle, reset_for_hangup);
987*7f2fe78bSCy Schubert         if (retval) {
988*7f2fe78bSCy Schubert             kdc_err(kcontext, retval, _("while initializing signal handlers"));
989*7f2fe78bSCy Schubert             finish_realms();
990*7f2fe78bSCy Schubert             return 1;
991*7f2fe78bSCy Schubert         }
992*7f2fe78bSCy Schubert     }
993*7f2fe78bSCy Schubert     if ((retval = loop_setup_network(ctx, &shandle, kdc_progname,
994*7f2fe78bSCy Schubert                                      tcp_listen_backlog))) {
995*7f2fe78bSCy Schubert     net_init_error:
996*7f2fe78bSCy Schubert         kdc_err(kcontext, retval, _("while initializing network"));
997*7f2fe78bSCy Schubert         finish_realms();
998*7f2fe78bSCy Schubert         return 1;
999*7f2fe78bSCy Schubert     }
1000*7f2fe78bSCy Schubert 
1001*7f2fe78bSCy Schubert     /* Clean up realms for now and reinitialize them after daemonizing, since
1002*7f2fe78bSCy Schubert      * some KDB modules are not fork-safe. */
1003*7f2fe78bSCy Schubert     finish_realms();
1004*7f2fe78bSCy Schubert 
1005*7f2fe78bSCy Schubert     if (!nofork && daemon(0, 0)) {
1006*7f2fe78bSCy Schubert         kdc_err(kcontext, errno, _("while detaching from tty"));
1007*7f2fe78bSCy Schubert         return 1;
1008*7f2fe78bSCy Schubert     }
1009*7f2fe78bSCy Schubert     if (pid_file != NULL) {
1010*7f2fe78bSCy Schubert         retval = write_pid_file(pid_file);
1011*7f2fe78bSCy Schubert         if (retval) {
1012*7f2fe78bSCy Schubert             kdc_err(kcontext, retval, _("while creating PID file"));
1013*7f2fe78bSCy Schubert             finish_realms();
1014*7f2fe78bSCy Schubert             return 1;
1015*7f2fe78bSCy Schubert         }
1016*7f2fe78bSCy Schubert     }
1017*7f2fe78bSCy Schubert     if (workers > 0) {
1018*7f2fe78bSCy Schubert         retval = create_workers(ctx, workers);
1019*7f2fe78bSCy Schubert         if (retval) {
1020*7f2fe78bSCy Schubert             kdc_err(kcontext, errno, _("creating worker processes"));
1021*7f2fe78bSCy Schubert             return 1;
1022*7f2fe78bSCy Schubert         }
1023*7f2fe78bSCy Schubert     }
1024*7f2fe78bSCy Schubert 
1025*7f2fe78bSCy Schubert     initialize_realms(kcontext, argc, argv, NULL);
1026*7f2fe78bSCy Schubert 
1027*7f2fe78bSCy Schubert     /* Initialize audit system and audit KDC startup. */
1028*7f2fe78bSCy Schubert     retval = load_audit_modules(kcontext);
1029*7f2fe78bSCy Schubert     if (retval) {
1030*7f2fe78bSCy Schubert         kdc_err(kcontext, retval, _("while loading audit plugin module(s)"));
1031*7f2fe78bSCy Schubert         finish_realms();
1032*7f2fe78bSCy Schubert         return 1;
1033*7f2fe78bSCy Schubert     }
1034*7f2fe78bSCy Schubert     krb5_klog_syslog(LOG_INFO, _("commencing operation"));
1035*7f2fe78bSCy Schubert     if (nofork)
1036*7f2fe78bSCy Schubert         fprintf(stderr, _("%s: starting...\n"), kdc_progname);
1037*7f2fe78bSCy Schubert     kau_kdc_start(kcontext, TRUE);
1038*7f2fe78bSCy Schubert 
1039*7f2fe78bSCy Schubert     verto_run(ctx);
1040*7f2fe78bSCy Schubert     kau_kdc_stop(kcontext, TRUE);
1041*7f2fe78bSCy Schubert     krb5_klog_syslog(LOG_INFO, _("shutting down"));
1042*7f2fe78bSCy Schubert     unload_preauth_plugins(kcontext);
1043*7f2fe78bSCy Schubert     unload_authdata_plugins(kcontext);
1044*7f2fe78bSCy Schubert     unload_kdcpolicy_plugins(kcontext);
1045*7f2fe78bSCy Schubert     unload_audit_modules(kcontext);
1046*7f2fe78bSCy Schubert     krb5_klog_close(kcontext);
1047*7f2fe78bSCy Schubert     finish_realms();
1048*7f2fe78bSCy Schubert     if (shandle.kdc_realmlist)
1049*7f2fe78bSCy Schubert         free(shandle.kdc_realmlist);
1050*7f2fe78bSCy Schubert #ifndef NOCACHE
1051*7f2fe78bSCy Schubert     kdc_free_lookaside(kcontext);
1052*7f2fe78bSCy Schubert #endif
1053*7f2fe78bSCy Schubert     loop_free(ctx);
1054*7f2fe78bSCy Schubert     krb5_free_context(kcontext);
1055*7f2fe78bSCy Schubert     return errout;
1056*7f2fe78bSCy Schubert }
1057