4 * Copyright 1990 by the Massachusetts Institute of Technology.
6 * Export of this software from the United States of America may
7 * require a specific license from the United States Government.
8 * It is the responsibility of any person or organization contemplating
9 * export to obtain such a license before exporting.
11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12 * distribute this software and its documentation for any purpose and
13 * without fee is hereby granted, provided that the above copyright
14 * notice appear in all copies and that both that copyright notice and
15 * this permission notice appear in supporting documentation, and that
16 * the name of M.I.T. not be used in advertising or publicity pertaining
17 * to distribution of the software without specific, written prior
18 * permission. M.I.T. makes no representations about the suitability of
19 * this software for any purpose. It is provided "as is" without express
20 * or implied warranty.
23 * Main procedure body for the KDC server process.
35 #include "adm_proto.h"
41 #include <netinet/in.h>
44 kdc_realm_t *find_realm_data PROTOTYPE((char *, krb5_ui_4));
46 krb5_error_code setup_server_realm PROTOTYPE((krb5_principal));
48 void usage PROTOTYPE((char *));
50 krb5_sigtype request_exit PROTOTYPE((int));
52 void setup_signal_handlers PROTOTYPE((void));
54 void initialize_realms PROTOTYPE((krb5_context, int, char **));
56 void finish_realms PROTOTYPE((char *));
58 static int nofork = 0;
59 static char *kdc_current_rcname = (char *) NULL;
60 static int rkey_init_done = 0;
62 #define KRB5_KDC_MAX_REALMS 32
65 * Get port information for a realm. The precedence is:
66 * [realms]-><realm>-><name> in profile (if our hostname and has a port)
68 * /etc/services entry matching <service>
71 get_realm_port(ctx, realm, name, defport, service)
79 char our_host_name[MAXHOSTNAMELEN];
80 struct hostent *our_hostent;
81 struct servent *our_servent;
86 * Some preliminaries here. Get our hostname and our host entry.
90 if (!gethostname(our_host_name, sizeof(our_host_name)) &&
91 (our_hostent = gethostbyname(our_host_name))) {
92 const char *hierarchy[4];
95 hostlist = (char **) NULL;
96 hierarchy[0] = "realms";
99 hierarchy[3] = (char *) NULL;
100 if (!(kret = profile_get_values(ctx->profile, hierarchy, &hostlist))) {
107 cport = (char *) NULL;
108 for (hi=0; hostlist[hi]; hi++) {
110 * This knows a little too much about the format of profile
111 * entries. Shouldn't it just be some sort of tuple?
113 * The form is assumed to be:
114 * <name> = <hostname>[:<portname>[<whitespace>]]
117 cp = strchr(hostlist[hi], ' ');
120 cp = strchr(hostlist[hi], '\t');
123 cport = strchr(hostlist[hi], ':');
127 if (sscanf(cport, "%d", &pport) == 1) {
132 * We've stripped away the crud. Now check to see if the
133 * profile entry matches our hostname. If so, then this
134 * is the one to use. Additionally, check the host alias
137 if (!strcmp(hostlist[hi], our_hostent->h_name)) {
144 for (ai=0; our_hostent->h_aliases[ai]; ai++) {
145 if (!strcmp(hostlist[hi],
146 our_hostent->h_aliases[ai])) {
160 * If we didn't find an entry in the profile, then use the default.
161 * If it's no good, then attempt to find it in /etc/services.
165 /* Get the service entry out of /etc/services */
167 if ((our_servent = getservbyname(service, "udp")))
168 retval = ntohs(our_servent->s_port);
175 * initialize the replay cache.
178 kdc_initialize_rcache(kcontext, rcache_name)
179 krb5_context kcontext;
182 krb5_error_code retval;
186 rcname = (rcache_name) ? rcache_name : kdc_current_rcname;
189 if (!(retval = krb5_rc_resolve_full(kcontext, &kdc_rcache, rcname))) {
190 /* Recover or initialize the replay cache */
191 if (!(retval = krb5_rc_recover(kcontext, kdc_rcache)) ||
192 !(retval = krb5_rc_initialize(kcontext,
194 kcontext->clockskew))
196 /* Expunge the replay cache */
197 if (!(retval = krb5_rc_expunge(kcontext, kdc_rcache))) {
198 sname = kdc_current_rcname;
199 kdc_current_rcname = strdup(rcname);
205 krb5_rc_close(kcontext, kdc_rcache);
211 * Find the realm entry for a given realm.
214 find_realm_data(rname, rsize)
219 for (i=0; i<kdc_numrealms; i++) {
220 if ((rsize == strlen(kdc_realmlist[i]->realm_name)) &&
221 !strncmp(rname, kdc_realmlist[i]->realm_name, rsize))
222 return(kdc_realmlist[i]);
224 return((kdc_realm_t *) NULL);
228 setup_server_realm(sprinc)
229 krb5_principal sprinc;
231 krb5_error_code kret;
232 kdc_realm_t *newrealm;
235 if (kdc_numrealms > 1) {
236 if (!(newrealm = find_realm_data(sprinc->realm.data,
237 (krb5_ui_4) sprinc->realm.length)))
240 kdc_active_realm = newrealm;
243 kdc_active_realm = kdc_realmlist[0];
251 if (rdp->realm_dbname)
252 free(rdp->realm_dbname);
253 if (rdp->realm_mpname)
254 free(rdp->realm_mpname);
255 if (rdp->realm_stash)
256 free(rdp->realm_stash);
257 if (rdp->realm_ports)
258 free(rdp->realm_ports);
259 if (rdp->realm_kstypes)
260 free(rdp->realm_kstypes);
261 if (rdp->realm_keytab)
262 krb5_kt_close(rdp->realm_context, rdp->realm_keytab);
263 if (rdp->realm_context) {
264 if (rdp->realm_mprinc)
265 krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
266 if (rdp->realm_mkey.length && rdp->realm_mkey.contents) {
267 memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length);
268 free(rdp->realm_mkey.contents);
270 if (rdp->realm_tgskey.length && rdp->realm_tgskey.contents) {
271 memset(rdp->realm_tgskey.contents, 0, rdp->realm_tgskey.length);
272 free(rdp->realm_tgskey.contents);
274 if (rdp->realm_encblock.crypto_entry)
275 krb5_finish_key(rdp->realm_context, &rdp->realm_encblock);
276 krb5_db_fini(rdp->realm_context);
277 if (rdp->realm_tgsprinc)
278 krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
279 krb5_free_context(rdp->realm_context);
281 memset((char *) rdp, 0, sizeof(*rdp));
285 * Initialize a realm control structure from the alternate profile or from
286 * the specified defaults.
288 * After we're complete here, the essence of the realm is embodied in the
289 * realm data and we should be all set to begin operation for that realm.
291 static krb5_error_code
292 init_realm(progname, rdp, realm, def_dbname, def_mpname,
293 def_enctype, def_ports, def_manual)
299 krb5_enctype def_enctype;
301 krb5_boolean def_manual;
303 krb5_error_code kret;
305 krb5_db_entry db_entry;
308 krb5_boolean db_inited;
309 krb5_realm_params *rparams;
310 krb5_key_data *kdata;
311 krb5_key_salt_tuple *kslist;
316 memset((char *) rdp, 0, sizeof(kdc_realm_t));
322 rdp->realm_name = realm;
323 kret = krb5_init_context(&rdp->realm_context);
325 com_err(progname, kret, "while getting context for realm %s",
330 kret = krb5_read_realm_params(rdp->realm_context, rdp->realm_name,
331 (char *) NULL, (char *) NULL, &rparams);
333 com_err(progname, kret, "while reading realm parameters");
337 /* Handle profile file name */
338 if (rparams && rparams->realm_profile)
339 rdp->realm_profile = strdup(rparams->realm_profile);
341 /* Handle database name */
342 if (rparams && rparams->realm_dbname)
343 rdp->realm_dbname = strdup(rparams->realm_dbname);
345 rdp->realm_dbname = (def_dbname) ? strdup(def_dbname) :
346 strdup(DEFAULT_KDB_FILE);
348 /* Handle master key name */
349 if (rparams && rparams->realm_mkey_name)
350 rdp->realm_mpname = strdup(rparams->realm_mkey_name);
352 rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) :
353 strdup(KRB5_KDB_M_NAME);
355 /* Handle KDC port */
356 if (rparams && rparams->realm_kdc_ports)
357 rdp->realm_ports = strdup(rparams->realm_kdc_ports);
359 rdp->realm_ports = strdup(def_ports);
361 /* Handle stash file */
362 if (rparams && rparams->realm_stash_file) {
363 rdp->realm_stash = strdup(rparams->realm_stash_file);
368 /* Handle master key type */
369 if (rparams && rparams->realm_enctype_valid)
370 rdp->realm_mkey.enctype = (krb5_enctype) rparams->realm_enctype;
372 rdp->realm_mkey.enctype = manual ? def_enctype : ENCTYPE_UNKNOWN;
374 /* Handle ticket maximum life */
375 rdp->realm_maxlife = (rparams && rparams->realm_max_life_valid) ?
376 rparams->realm_max_life : KRB5_KDB_MAX_LIFE;
378 /* Handle ticket renewable maximum life */
379 rdp->realm_maxrlife = (rparams && rparams->realm_max_rlife_valid) ?
380 rparams->realm_max_rlife : KRB5_KDB_MAX_LIFE;
382 /* Handle key/salt list */
383 if (rparams && rparams->realm_num_keysalts) {
384 rdp->realm_kstypes = rparams->realm_keysalts;
385 rdp->realm_nkstypes = rparams->realm_num_keysalts;
386 rparams->realm_keysalts = NULL;
387 rparams->realm_num_keysalts = 0;
388 kslist = (krb5_key_salt_tuple *) rdp->realm_kstypes;
389 nkslist = rdp->realm_nkstypes;
392 * XXX Initialize default key/salt list.
394 if ((kslist = (krb5_key_salt_tuple *)
395 malloc(sizeof(krb5_key_salt_tuple)))) {
396 kslist->ks_enctype = ENCTYPE_DES_CBC_CRC;
397 kslist->ks_salttype = KRB5_KDB_SALTTYPE_NORMAL;
398 rdp->realm_kstypes = kslist;
399 rdp->realm_nkstypes = 1;
403 com_err(progname, ENOMEM,
404 "while setting up key/salt list for realm %s",
411 krb5_free_realm_params(rdp->realm_context, rparams);
414 * We've got our parameters, now go and setup our realm context.
417 /* Set the default realm of this context */
418 if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) {
419 com_err(progname, kret, "while setting default realm to %s",
424 /* Assemble and parse the master key name */
425 if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname,
426 rdp->realm_name, (char **) NULL,
427 &rdp->realm_mprinc))) {
428 com_err(progname, kret,
429 "while setting up master key name %s for realm %s",
430 rdp->realm_mpname, realm);
434 /* Select the specified encryption type */
435 /* krb5_db_fetch_mkey will setup the encblock for stashed keys */
437 krb5_use_enctype(rdp->realm_context, &rdp->realm_encblock,
438 rdp->realm_mkey.enctype);
441 * Get the master key.
443 if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc,
444 &rdp->realm_encblock, manual,
445 FALSE, rdp->realm_stash,
446 0, &rdp->realm_mkey))) {
447 com_err(progname, kret,
448 "while fetching master key %s for realm %s",
449 rdp->realm_mpname, realm);
453 /* Set and open the database. */
454 if (rdp->realm_dbname &&
455 (kret = krb5_db_set_name(rdp->realm_context, rdp->realm_dbname))) {
456 com_err(progname, kret,
457 "while setting database name to %s for realm %s",
458 rdp->realm_dbname, realm);
461 if ((kret = krb5_db_init(rdp->realm_context))) {
462 com_err(progname, kret,
463 "while initializing database for realm %s", realm);
468 /* Verify the master key */
469 if ((kret = krb5_db_verify_master_key(rdp->realm_context,
472 &rdp->realm_encblock))) {
473 com_err(progname, kret,
474 "while verifying master key for realm %s", realm);
478 /* Fetch the master key and get its version number */
480 kret = krb5_db_get_principal(rdp->realm_context, rdp->realm_mprinc,
481 &db_entry, &num2get, &more);
484 kret = KRB5_KDB_NOMASTERKEY;
487 krb5_db_free_principal(rdp->realm_context,
490 kret = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
495 com_err(progname, kret,
496 "while fetching master entry for realm %s", realm);
501 * Get the most recent master key. Search the key list in
502 * the order specified by the key/salt list.
504 kdata = (krb5_key_data *) NULL;
505 for (i=0; i<nkslist; i++) {
506 if (!(kret = krb5_dbe_find_enctype(rdp->realm_context,
508 kslist[i].ks_enctype,
515 com_err(progname, kret,
516 "while finding master key for realm %s",
520 rdp->realm_mkvno = kdata->key_data_kvno;
521 krb5_db_free_principal(rdp->realm_context, &db_entry, num2get);
523 /* Now preprocess the master key */
524 if ((kret = krb5_process_key(rdp->realm_context,
525 &rdp->realm_encblock,
526 &rdp->realm_mkey))) {
527 com_err(progname, kret,
528 "while processing master key for realm %s", realm);
532 if ((kret = krb5_db_set_mkey(rdp->realm_context,
533 &rdp->realm_encblock))) {
534 com_err(progname, kret,
535 "while setting master key for realm %s", realm);
539 /* Set up the keytab */
540 if ((kret = krb5_ktkdb_resolve(rdp->realm_context,
541 &rdp->realm_keytab))) {
542 com_err(progname, kret,
543 "while resolving kdb keytab for realm %s", realm);
547 /* Preformat the TGS name */
548 if ((kret = krb5_build_principal(rdp->realm_context, &rdp->realm_tgsprinc,
549 strlen(realm), realm, KRB5_TGS_NAME,
550 realm, (char *) NULL))) {
551 com_err(progname, kret,
552 "while building TGS name for realm %s", realm);
556 /* Get the TGS database entry */
558 if (!(kret = krb5_db_get_principal(rdp->realm_context,
564 kret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
567 krb5_db_free_principal(rdp->realm_context,
570 kret = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
575 com_err(progname, kret,
576 "while fetching TGS entry for realm %s", realm);
580 * Get the most recent TGS key. Search the key list in
581 * the order specified by the key/salt list.
583 kdata = (krb5_key_data *) NULL;
584 for (i=0; i<nkslist; i++) {
585 if (!(kret = krb5_dbe_find_enctype(rdp->realm_context,
587 kslist[i].ks_enctype,
594 com_err(progname, kret, "while finding TGS key for realm %s",
598 if (!(kret = krb5_dbekd_decrypt_key_data(rdp->realm_context,
599 &rdp->realm_encblock,
601 &rdp->realm_tgskey, NULL))){
602 rdp->realm_tgskvno = kdata->key_data_kvno;
604 krb5_db_free_principal(rdp->realm_context,
608 com_err(progname, kret,
609 "while decrypting TGS key for realm %s", realm);
613 if (!rkey_init_done) {
614 krb5_enctype enctype;
615 krb5_encrypt_block temp_eblock;
616 #ifdef KRB5_KRB4_COMPAT
617 krb5_keyblock *temp_key;
620 * If all that worked, then initialize the random key
623 for (enctype = 0; enctype <= krb5_max_enctype; enctype++) {
624 if (krb5_enctype_array[enctype] &&
625 !krb5_enctype_array[enctype]->random_sequence) {
626 krb5_use_enctype(rdp->realm_context, &temp_eblock, enctype);
627 if ((kret = krb5_init_random_key(
628 rdp->realm_context, &temp_eblock,
630 &krb5_enctype_array[enctype]->random_sequence))) {
631 com_err(progname, kret,
632 "while setting up random key generator for enctype %d--enctype disabled",
634 krb5_enctype_array[enctype] = 0;
636 #ifdef KRB5_KRB4_COMPAT
637 if (enctype == ENCTYPE_DES_CBC_CRC) {
638 if ((kret = krb5_random_key(
639 rdp->realm_context, &temp_eblock,
640 krb5_enctype_array[enctype]->random_sequence,
642 com_err(progname, kret,
643 "while initializing V4 random key generator");
645 (void) des_init_random_number_generator(temp_key->contents);
646 krb5_free_keyblock(rdp->realm_context, temp_key);
657 * If we choked, then clean up any dirt we may have dropped on the floor.
669 signal_requests_exit = 1;
679 setup_signal_handlers()
681 signal(SIGINT, request_exit);
682 signal(SIGHUP, request_exit);
683 signal(SIGTERM, request_exit);
692 fprintf(stderr, "usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-n]\n", name);
697 initialize_realms(kcontext, argc, argv)
698 krb5_context kcontext;
703 char *db_name = (char *) NULL;
704 char *mkey_name = (char *) NULL;
705 char *rcname = KDCRCACHE;
707 krb5_error_code retval;
708 krb5_enctype menctype = ENCTYPE_UNKNOWN;
710 krb5_boolean manual = FALSE;
711 char *default_ports = 0;
713 const char *hierarchy[3];
716 if (!krb5_aprof_init(DEFAULT_KDC_PROFILE, KDC_PROFILE_ENV, &aprof)) {
717 hierarchy[0] = "kdcdefaults";
718 hierarchy[1] = "kdc_ports";
719 hierarchy[2] = (char *) NULL;
720 if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_ports))
722 /* aprof_init can return 0 with aprof == NULL */
724 krb5_aprof_finish(aprof);
726 if (default_ports == 0)
727 default_ports = strdup(DEFAULT_KDC_PORTLIST);
730 * Loop through the option list. Each time we encounter a realm name,
731 * use the previously scanned options to fill in for defaults.
733 while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:s:n")) != EOF) {
735 case 'r': /* realm name for db */
736 if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) {
737 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
738 if ((retval = init_realm(argv[0], rdatap, optarg, db_name,
740 default_ports, manual))) {
741 fprintf(stderr,"%s: cannot initialize realm %s\n",
745 kdc_realmlist[kdc_numrealms] = rdatap;
750 case 'd': /* pathname for db */
753 case 'm': /* manual type-in of master key */
755 if (menctype == ENCTYPE_UNKNOWN)
756 menctype = ENCTYPE_DES_CBC_CRC;
758 case 'M': /* master key name in DB */
762 nofork++; /* don't detach from terminal */
764 case 'k': /* enctype for master key */
765 if (krb5_string_to_enctype(optarg, &menctype))
766 com_err(argv[0], 0, "invalid enctype %s", optarg);
774 default_ports = strdup(optarg);
784 * Check to see if we processed any realms.
786 if (kdc_numrealms == 0) {
787 /* no realm specified, use default realm */
788 if ((retval = krb5_get_default_realm(kcontext, &lrealm))) {
789 com_err(argv[0], retval,
790 "while attempting to retrieve default realm");
793 if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
794 if ((retval = init_realm(argv[0], rdatap, lrealm, db_name,
795 mkey_name, menctype, default_ports,
797 fprintf(stderr,"%s: cannot initialize realm %s\n",
801 kdc_realmlist[0] = rdatap;
808 * Now handle the replay cache.
810 if ((retval = kdc_initialize_rcache(kcontext, rcname))) {
811 com_err(argv[0], retval, "while initializing KDC replay cache");
816 /* Ensure that this is set for our first request. */
817 kdc_active_realm = kdc_realmlist[0];
830 for (i = 0; i < kdc_numrealms; i++)
831 finish_realm(kdc_realmlist[i]);
839 initialize database access (fetch master key, open DB)
846 determine packet type, dispatch to handling routine
853 clean up secrets, close db
864 krb5_error_code retval;
865 krb5_context kcontext;
869 if (strrchr(argv[0], '/'))
870 argv[0] = strrchr(argv[0], '/')+1;
872 if (!(kdc_realmlist = (kdc_realm_t **) malloc(sizeof(kdc_realm_t *) *
873 KRB5_KDC_MAX_REALMS))) {
874 fprintf(stderr, "%s: cannot get memory for realm list\n", argv[0]);
877 memset((char *) kdc_realmlist, 0,
878 (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS));
882 * A note about Kerberos contexts: This context, "kcontext", is used
883 * for the KDC operations, i.e. setup, network connection and error
884 * reporting. The per-realm operations use the "realm_context"
885 * associated with each realm.
887 retval = krb5_init_context(&kcontext);
889 com_err(argv[0], retval, "while initializing krb5");
892 krb5_klog_init(kcontext, "kdc", argv[0], 1);
895 * Scan through the argument list
897 initialize_realms(kcontext, argc, argv);
899 setup_signal_handlers();
901 if ((retval = setup_network(argv[0]))) {
902 com_err(argv[0], retval, "while initializing network");
903 finish_realms(argv[0]);
906 if (!nofork && daemon(0, 0)) {
907 com_err(argv[0], errno, "while detaching from tty");
908 finish_realms(argv[0]);
911 krb5_klog_syslog(LOG_INFO, "commencing operation");
912 if ((retval = listen_and_process(argv[0]))) {
913 com_err(argv[0], retval, "while processing network requests");
916 if ((retval = closedown_network(argv[0]))) {
917 com_err(argv[0], retval, "while shutting down network");
920 krb5_klog_syslog(LOG_INFO, "shutting down");
921 krb5_klog_close(kdc_context);
922 finish_realms(argv[0]);
923 krb5_free_context(kcontext);