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