26
26
* Main procedure body for the KDC server process.
29
* Copyright (c) 2006-2008, Novell, Inc.
30
* All rights reserved.
32
* Redistribution and use in source and binary forms, with or without
33
* modification, are permitted provided that the following conditions are met:
35
* * Redistributions of source code must retain the above copyright notice,
36
* this list of conditions and the following disclaimer.
37
* * Redistributions in binary form must reproduce the above copyright
38
* notice, this list of conditions and the following disclaimer in the
39
* documentation and/or other materials provided with the distribution.
40
* * The copyright holder's name is not used to endorse or promote products
41
* derived from this software without specific prior written permission.
43
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
44
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
47
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
48
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
49
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
51
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
53
* POSSIBILITY OF SUCH DAMAGE.
30
57
#include <syslog.h>
75
98
#define KRB5_KDC_MAX_REALMS 32
100
static krb5_context kdc_err_context;
101
static const char *kdc_progname;
104
* We use krb5_klog_init to set up a com_err callback to log error
105
* messages. The callback also pulls the error message out of the
106
* context we pass to krb5_klog_init; however, we use realm-specific
107
* contexts for most of our krb5 library calls, so the error message
108
* isn't present in the global context. This wrapper ensures that the
109
* error message state from the call context is copied into the
110
* context known by krb5_klog. call_context can be NULL if the error
111
* code did not come from a krb5 library function.
114
kdc_err(krb5_context call_context, errcode_t code, const char *fmt, ...)
119
krb5_copy_error_message(kdc_err_context, call_context);
121
com_err_va(kdc_progname, code, fmt, ap);
78
126
* Find the realm entry for a given realm.
123
171
free(rdp->realm_tcp_ports);
124
172
if (rdp->realm_keytab)
125
173
krb5_kt_close(rdp->realm_context, rdp->realm_keytab);
174
if (rdp->realm_host_based_services)
175
free(rdp->realm_host_based_services);
176
if (rdp->realm_no_host_referral)
177
free(rdp->realm_no_host_referral);
126
178
if (rdp->realm_context) {
127
179
if (rdp->realm_mprinc)
128
180
krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
129
181
if (rdp->realm_mkey.length && rdp->realm_mkey.contents) {
182
/* XXX shouldn't memset be zap for safety? */
130
183
memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length);
131
184
free(rdp->realm_mkey.contents);
187
krb5_dbe_free_key_list(rdp->realm_context, rdp->mkey_list);
133
188
krb5_db_fini(rdp->realm_context);
134
189
if (rdp->realm_tgsprinc)
135
190
krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
197
static krb5_error_code
198
handle_referral_params(krb5_realm_params *rparams,
199
char *no_refrls, char *host_based_srvcs,
202
krb5_error_code retval = 0;
203
if (no_refrls && krb5_match_config_pattern(no_refrls, KRB5_CONF_ASTERISK) == TRUE) {
204
rdp->realm_no_host_referral = strdup(KRB5_CONF_ASTERISK);
205
if (!rdp->realm_no_host_referral)
208
if (rparams && rparams->realm_no_host_referral) {
209
if (krb5_match_config_pattern(rparams->realm_no_host_referral, KRB5_CONF_ASTERISK) == TRUE) {
210
rdp->realm_no_host_referral = strdup(KRB5_CONF_ASTERISK);
211
if (!rdp->realm_no_host_referral)
213
} else if (no_refrls && (asprintf(&(rdp->realm_no_host_referral), "%s%s%s%s%s",
214
" ", no_refrls," ",rparams->realm_no_host_referral, " ") < 0))
216
else if (asprintf(&(rdp->realm_no_host_referral),"%s%s%s", " ",
217
rparams->realm_no_host_referral, " ") < 0)
219
} else if( no_refrls != NULL) {
220
if ( asprintf(&(rdp->realm_no_host_referral),"%s%s%s", " ", no_refrls, " ") < 0)
223
rdp->realm_no_host_referral = NULL;
226
if (rdp->realm_no_host_referral && krb5_match_config_pattern(rdp->realm_no_host_referral, KRB5_CONF_ASTERISK) == TRUE) {
227
rdp->realm_host_based_services = NULL;
231
if (host_based_srvcs && (krb5_match_config_pattern(host_based_srvcs, KRB5_CONF_ASTERISK) == TRUE)) {
232
rdp->realm_host_based_services = strdup(KRB5_CONF_ASTERISK);
233
if (!rdp->realm_host_based_services)
236
if (rparams && rparams->realm_host_based_services) {
237
if (krb5_match_config_pattern(rparams->realm_host_based_services, KRB5_CONF_ASTERISK) == TRUE) {
238
rdp->realm_host_based_services = strdup(KRB5_CONF_ASTERISK);
239
if (!rdp->realm_host_based_services)
241
} else if (host_based_srvcs) {
242
if (asprintf(&(rdp->realm_host_based_services), "%s%s%s%s%s",
243
" ", host_based_srvcs," ",rparams->realm_host_based_services, " ") < 0)
245
} else if (asprintf(&(rdp->realm_host_based_services),"%s%s%s", " ",
246
rparams->realm_host_based_services, " ") < 0)
248
} else if (host_based_srvcs) {
249
if (asprintf(&(rdp->realm_host_based_services),"%s%s%s", " ", host_based_srvcs, " ") < 0)
252
rdp->realm_host_based_services = NULL;
143
258
* Initialize a realm control structure from the alternate profile or from
144
259
* the specified defaults.
147
262
* realm data and we should be all set to begin operation for that realm.
149
264
static krb5_error_code
150
init_realm(char *progname, kdc_realm_t *rdp, char *realm,
151
char *def_mpname, krb5_enctype def_enctype, char *def_udp_ports,
152
char *def_tcp_ports, krb5_boolean def_manual, char **db_args)
265
init_realm(kdc_realm_t *rdp, char *realm, char *def_mpname,
266
krb5_enctype def_enctype, char *def_udp_ports, char *def_tcp_ports,
267
krb5_boolean def_manual, char **db_args, char *no_refrls,
268
char *host_based_srvcs)
154
270
krb5_error_code kret;
155
271
krb5_boolean manual;
156
272
krb5_realm_params *rparams;
274
krb5_kvno mkvno = IGNORE_VNO;
158
276
memset((char *) rdp, 0, sizeof(kdc_realm_t));
164
282
rdp->realm_name = realm;
165
283
kret = krb5int_init_context_kdc(&rdp->realm_context);
167
com_err(progname, kret, "while getting context for realm %s",
285
kdc_err(NULL, kret, "while getting context for realm %s", realm);
172
289
kret = krb5_read_realm_params(rdp->realm_context, rdp->realm_name,
175
com_err(progname, kret, "while reading realm parameters");
292
kdc_err(rdp->realm_context, kret, "while reading realm parameters");
179
296
/* Handle profile file name */
180
if (rparams && rparams->realm_profile)
297
if (rparams && rparams->realm_profile) {
181
298
rdp->realm_profile = strdup(rparams->realm_profile);
299
if (!rdp->realm_profile) {
183
305
/* Handle master key name */
184
306
if (rparams && rparams->realm_mkey_name)
187
309
rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) :
188
310
strdup(KRB5_KDB_M_NAME);
311
if (!rdp->realm_mpname) {
190
316
/* Handle KDC ports */
191
317
if (rparams && rparams->realm_kdc_ports)
192
318
rdp->realm_ports = strdup(rparams->realm_kdc_ports);
194
320
rdp->realm_ports = strdup(def_udp_ports);
321
if (!rdp->realm_ports) {
195
325
if (rparams && rparams->realm_kdc_tcp_ports)
196
326
rdp->realm_tcp_ports = strdup(rparams->realm_kdc_tcp_ports);
198
328
rdp->realm_tcp_ports = strdup(def_tcp_ports);
329
if (!rdp->realm_tcp_ports) {
200
333
/* Handle stash file */
201
334
if (rparams && rparams->realm_stash_file) {
202
335
rdp->realm_stash = strdup(rparams->realm_stash_file);
336
if (!rdp->realm_stash) {
205
342
manual = def_manual;
234
376
/* Set the default realm of this context */
235
377
if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) {
236
com_err(progname, kret, "while setting default realm to %s",
378
kdc_err(rdp->realm_context, kret, "while setting default realm to %s",
241
383
/* first open the database before doing anything */
242
#ifdef KRBCONF_KDC_MODIFIES_KDB
243
if ((kret = krb5_db_open(rdp->realm_context, db_args,
244
KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_KDC))) {
384
#ifdef KRBCONF_KDC_MODIFIES_KDB
385
kdb_open_flags = KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_KDC;
246
if ((kret = krb5_db_open(rdp->realm_context, db_args,
247
KRB5_KDB_OPEN_RO | KRB5_KDB_SRV_TYPE_KDC))) {
387
kdb_open_flags = KRB5_KDB_OPEN_RO | KRB5_KDB_SRV_TYPE_KDC;
249
com_err(progname, kret,
389
if ((kret = krb5_db_open(rdp->realm_context, db_args, kdb_open_flags))) {
390
kdc_err(rdp->realm_context, kret,
250
391
"while initializing database for realm %s", realm);
255
396
if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname,
256
397
rdp->realm_name, (char **) NULL,
257
398
&rdp->realm_mprinc))) {
258
com_err(progname, kret,
399
kdc_err(rdp->realm_context, kret,
259
400
"while setting up master key name %s for realm %s",
260
401
rdp->realm_mpname, realm);
265
* Get the master key.
406
* Get the master key (note, may not be the most current mkey).
267
408
if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc,
268
409
rdp->realm_mkey.enctype, manual,
269
410
FALSE, rdp->realm_stash,
270
0, &rdp->realm_mkey))) {
271
com_err(progname, kret,
411
&mkvno, NULL, &rdp->realm_mkey))) {
412
kdc_err(rdp->realm_context, kret,
272
413
"while fetching master key %s for realm %s",
273
414
rdp->realm_mpname, realm);
417
#if 0 /************** Begin IFDEF'ed OUT *******************************/
419
* Commenting krb5_db_verify_master_key out because it requires the most
420
* current mkey which may not be the case here. The call to
421
* krb5_db_fetch_mkey_list() will end up verifying that the mkey is viable
277
424
/* Verify the master key */
278
425
if ((kret = krb5_db_verify_master_key(rdp->realm_context,
279
426
rdp->realm_mprinc,
280
428
&rdp->realm_mkey))) {
281
com_err(progname, kret,
429
kdc_err(rdp->realm_context, kret,
282
430
"while verifying master key for realm %s", realm);
433
#endif /**************** END IFDEF'ed OUT *******************************/
435
if ((kret = krb5_db_fetch_mkey_list(rdp->realm_context, rdp->realm_mprinc,
436
&rdp->realm_mkey, mkvno, &rdp->mkey_list))) {
437
kdc_err(rdp->realm_context, kret,
438
"while fetching master keys list for realm %s", realm);
286
442
if ((kret = krb5_db_set_mkey(rdp->realm_context, &rdp->realm_mkey))) {
287
com_err(progname, kret,
443
kdc_err(rdp->realm_context, kret,
288
444
"while setting master key for realm %s", realm);
447
kret = krb5_db_set_mkey_list(rdp->realm_context, rdp->mkey_list);
449
kdc_err(rdp->realm_context, kret,
450
"while setting master key list for realm %s", realm);
292
454
/* Set up the keytab */
293
455
if ((kret = krb5_ktkdb_resolve(rdp->realm_context, NULL,
294
456
&rdp->realm_keytab))) {
295
com_err(progname, kret,
457
kdc_err(rdp->realm_context, kret,
296
458
"while resolving kdb keytab for realm %s", realm);
301
463
if ((kret = krb5_build_principal(rdp->realm_context, &rdp->realm_tgsprinc,
302
464
strlen(realm), realm, KRB5_TGS_NAME,
303
465
realm, (char *) NULL))) {
304
com_err(progname, kret,
466
kdc_err(rdp->realm_context, kret,
305
467
"while building TGS name for realm %s", realm);
309
471
if (!rkey_init_done) {
311
#ifdef KRB5_KRB4_COMPAT
312
krb5_keyblock temp_key;
315
474
* If all that worked, then initialize the random key
319
478
seed.length = rdp->realm_mkey.length;
320
seed.data = rdp->realm_mkey.contents;
479
seed.data = (char *)rdp->realm_mkey.contents;
322
481
if ((kret = krb5_c_random_add_entropy(rdp->realm_context,
323
482
KRB5_C_RANDSOURCE_TRUSTEDPARTY, &seed)))
326
#ifdef KRB5_KRB4_COMPAT
327
if ((kret = krb5_c_make_random_key(rdp->realm_context,
328
ENCTYPE_DES_CBC_CRC, &temp_key))) {
329
com_err(progname, kret,
330
"while initializing V4 random key generator");
334
(void) des_init_random_number_generator(temp_key.contents);
335
krb5_free_keyblock_contents(rdp->realm_context, &temp_key);
337
485
rkey_init_done = 1;
404
552
usage(char *name)
406
fprintf(stderr, "usage: %s [-x db_args]* [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-4 v4mode] [-X] [-n]\n"
407
"\nwhere,\n\t[-x db_args]* - any number of database specific arguments.\n"
408
"\t\t\tLook at each database documentation for supported arguments\n",
554
fprintf(stderr, "usage: %s [-x db_args]* [-d dbpathname] [-r dbrealmname]\n\t\t[-R replaycachename] [-m] [-k masterenctype] [-M masterkeyname]\n\t\t[-p port] [-n]\n"
555
"\nwhere,\n\t[-x db_args]* - Any number of database specific arguments. Look at\n"
556
"\t\t\teach database module documentation for supported\n\t\t\targuments\n",
417
565
char *db_name = (char *) NULL;
566
char *lrealm = (char *) NULL;
418
567
char *mkey_name = (char *) NULL;
419
568
char *rcname = KDCRCACHE;
421
569
krb5_error_code retval;
422
570
krb5_enctype menctype = ENCTYPE_UNKNOWN;
571
kdc_realm_t *rdatap = NULL;
424
572
krb5_boolean manual = FALSE;
425
573
char *default_udp_ports = 0;
426
574
char *default_tcp_ports = 0;
427
575
krb5_pointer aprof;
428
576
const char *hierarchy[3];
429
577
char **db_args = NULL;
578
char *no_refrls = NULL;
579
char *host_based_srvcs = NULL;
430
580
int db_args_size = 0;
432
#ifdef KRB5_KRB4_COMPAT
435
582
extern char *optarg;
437
584
if (!krb5_aprof_init(DEFAULT_KDC_PROFILE, KDC_PROFILE_ENV, &aprof)) {
438
hierarchy[0] = "kdcdefaults";
439
hierarchy[1] = "kdc_ports";
585
hierarchy[0] = KRB5_CONF_KDCDEFAULTS;
586
hierarchy[1] = KRB5_CONF_KDC_PORTS;
440
587
hierarchy[2] = (char *) NULL;
441
588
if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_udp_ports))
442
589
default_udp_ports = 0;
443
hierarchy[1] = "kdc_tcp_ports";
590
hierarchy[1] = KRB5_CONF_KDC_TCP_PORTS;
444
591
if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_tcp_ports))
445
592
default_tcp_ports = 0;
446
#ifdef KRB5_KRB4_COMPAT
447
hierarchy[1] = "v4_mode";
448
if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &v4mode))
593
hierarchy[1] = KRB5_CONF_MAX_DGRAM_REPLY_SIZE;
594
if (krb5_aprof_get_int32(aprof, hierarchy, TRUE, &max_dgram_reply_size))
595
max_dgram_reply_size = MAX_DGRAM_SIZE;
596
hierarchy[1] = KRB5_CONF_NO_HOST_REFERRAL;
597
if (krb5_aprof_get_string_all(aprof, hierarchy, &no_refrls))
599
if (!no_refrls || krb5_match_config_pattern(no_refrls, KRB5_CONF_ASTERISK) == FALSE) {
600
hierarchy[1] = KRB5_CONF_HOST_BASED_SERVICES;
601
if (krb5_aprof_get_string_all(aprof, hierarchy, &host_based_srvcs))
602
host_based_srvcs = 0;
451
605
/* aprof_init can return 0 with aprof == NULL */
453
607
krb5_aprof_finish(aprof);
455
if (default_udp_ports == 0)
610
if (default_udp_ports == 0) {
456
611
default_udp_ports = strdup(DEFAULT_KDC_UDP_PORTLIST);
457
if (default_tcp_ports == 0)
458
default_tcp_ports = strdup(DEFAULT_KDC_TCP_PORTLIST);
612
if (default_udp_ports == 0) {
613
fprintf(stderr," KDC cannot initialize. Not enough memory\n");
617
if (default_tcp_ports == 0) {
618
default_tcp_ports = strdup(DEFAULT_KDC_TCP_PORTLIST);
619
if (default_tcp_ports == 0) {
620
fprintf(stderr," KDC cannot initialize. Not enough memory\n");
460
626
* Loop through the option list. Each time we encounter a realm name,
461
627
* use the previously scanned options to fill in for defaults.
482
648
case 'r': /* realm name for db */
483
649
if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) {
484
650
if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
485
if ((retval = init_realm(argv[0], rdatap, optarg,
488
default_tcp_ports, manual, db_args))) {
651
if ((retval = init_realm(rdatap, optarg, mkey_name,
652
menctype, default_udp_ports,
653
default_tcp_ports, manual, db_args,
654
no_refrls, host_based_srvcs))) {
489
655
fprintf(stderr,"%s: cannot initialize realm %s - see log file for details\n",
490
656
argv[0], optarg);
505
671
case 'd': /* pathname for db */
506
672
/* now db_name is not a seperate argument. It has to be passed as part of the db_args */
507
if( db_name == NULL )
509
db_name = malloc(sizeof("dbname=") + strlen(optarg));
510
if( db_name == NULL )
512
fprintf(stderr,"%s: KDC cannot initialize. Not enough memory\n",
673
if( db_name == NULL ) {
674
if (asprintf(&db_name, "dbname=%s", optarg) < 0) {
676
"%s: KDC cannot initialize. Not enough memory\n",
517
sprintf( db_name, "dbname=%s", optarg);
602
752
if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
603
if ((retval = init_realm(argv[0], rdatap, lrealm,
604
mkey_name, menctype, default_udp_ports,
605
default_tcp_ports, manual, db_args))) {
753
if ((retval = init_realm(rdatap, lrealm, mkey_name, menctype,
754
default_udp_ports, default_tcp_ports,
755
manual, db_args, no_refrls,
756
host_based_srvcs))) {
606
757
fprintf(stderr,"%s: cannot initialize realm %s - see log file for details\n",
607
758
argv[0], lrealm);
705
860
krb5_klog_init(kcontext, "kdc", argv[0], 1);
861
kdc_err_context = kcontext;
862
kdc_progname = argv[0];
706
863
/* N.B.: After this point, com_err sends output to the KDC log
707
file, and not to stderr. */
864
file, and not to stderr. We use the kdc_err wrapper around
865
com_err to ensure that the error state exists in the context
866
known to the krb5_klog callback. */
709
868
initialize_kdc5_error_table();
716
875
setup_signal_handlers();
718
877
load_preauth_plugins(kcontext);
878
load_authdata_plugins(kcontext);
720
880
retval = setup_sam();
722
com_err(argv[0], retval, "while initializing SAM");
723
finish_realms(argv[0]);
882
kdc_err(kcontext, retval, "while initializing SAM");
727
if ((retval = setup_network(argv[0]))) {
728
com_err(argv[0], retval, "while initializing network");
729
finish_realms(argv[0]);
887
if ((retval = setup_network())) {
888
kdc_err(kcontext, retval, "while initializing network");
732
892
if (!nofork && daemon(0, 0)) {
733
com_err(argv[0], errno, "while detaching from tty");
734
finish_realms(argv[0]);
893
kdc_err(kcontext, errno, "while detaching from tty");
737
897
krb5_klog_syslog(LOG_INFO, "commencing operation");
738
if ((retval = listen_and_process(argv[0]))) {
739
com_err(argv[0], retval, "while processing network requests");
898
if ((retval = listen_and_process())) {
899
kdc_err(kcontext, retval, "while processing network requests");
742
if ((retval = closedown_network(argv[0]))) {
743
com_err(argv[0], retval, "while shutting down network");
902
if ((retval = closedown_network())) {
903
kdc_err(kcontext, retval, "while shutting down network");
746
906
krb5_klog_syslog(LOG_INFO, "shutting down");
747
907
unload_preauth_plugins(kcontext);
908
unload_authdata_plugins(kcontext);
748
909
krb5_klog_close(kdc_context);
749
finish_realms(argv[0]);
750
911
if (kdc_realmlist)
751
912
free(kdc_realmlist);
752
913
#ifdef USE_RCACHE