From 36b0618997fd316a4f8fff8878c12e30839606a6 Mon Sep 17 00:00:00 2001 From: Paul Park Date: Fri, 23 Jun 1995 14:01:45 +0000 Subject: Multiple realm support git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6137 dc483132-0cff-0310-8789-dd5450dbe970 --- src/kdc/main.c | 828 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 586 insertions(+), 242 deletions(-) (limited to 'src/kdc/main.c') diff --git a/src/kdc/main.c b/src/kdc/main.c index b7c460be7..475bf652b 100644 --- a/src/kdc/main.c +++ b/src/kdc/main.c @@ -36,6 +36,477 @@ #include "adm_proto.h" static int nofork = 0; +static char *kdc_current_rcname = (char *) NULL; +static int rkey_init_done = 0; + +#define KRB5_KDC_MAX_REALMS 32 + +/* + * initialize the replay cache. + */ +krb5_error_code +kdc_initialize_rcache(kcontext, rcache_name) + krb5_context kcontext; + char *rcache_name; +{ + krb5_error_code retval; + extern krb5_deltat krb5_clockskew; + char *rcname; + char *sname; + + rcname = (rcache_name) ? rcache_name : kdc_current_rcname; + if (!rcname) + rcname = KDCRCACHE; + if (!(retval = krb5_rc_resolve_full(kcontext, &kdc_rcache, rcname))) { + /* Recover or initialize the replay cache */ + if (!(retval = krb5_rc_recover(kcontext, kdc_rcache)) || + !(retval = krb5_rc_initialize(kcontext, + kdc_rcache, + krb5_clockskew)) + ) { + /* Expunge the replay cache */ + if (!(retval = krb5_rc_expunge(kcontext, kdc_rcache))) { + sname = kdc_current_rcname; + kdc_current_rcname = strdup(rcname); + if (sname) + free(sname); + } + } + if (retval) + krb5_rc_close(kcontext, kdc_rcache); + } + return(retval); +} + +/* + * Find the realm entry for a given realm. + */ +kdc_realm_t * +find_realm_data(rname, rsize) + char *rname; + krb5_ui_4 rsize; +{ + int i; + for (i=0; irealm_name)) && + !strncmp(rname, kdc_realmlist[i]->realm_name, rsize)) + return(kdc_realmlist[i]); + } + return((kdc_realm_t *) NULL); +} + +krb5_error_code +setup_server_realm(sprinc) + krb5_principal sprinc; +{ + krb5_error_code kret; + kdc_realm_t *newrealm; + + kret = 0; + if (kdc_numrealms > 1) { + if (!(newrealm = find_realm_data(sprinc->realm.data, + (krb5_ui_4) sprinc->realm.length))) + kret = ENOENT; + else + kdc_active_realm = newrealm; + } + else + kdc_active_realm = kdc_realmlist[0]; + return(kret); +} + +static void +finish_realm(rdp) + kdc_realm_t *rdp; +{ + if (rdp->realm_dbname) + free(rdp->realm_dbname); + if (rdp->realm_mpname) + free(rdp->realm_mpname); + if (rdp->realm_stash) + free(rdp->realm_stash); + if (rdp->realm_context) { + if (rdp->realm_mprinc) + krb5_free_principal(rdp->realm_context, rdp->realm_mprinc); + if (rdp->realm_mkey.length && rdp->realm_mkey.contents) + krb5_free_keyblock(rdp->realm_context, &rdp->realm_mkey); + krb5_db_fini(rdp->realm_context); + if (rdp->realm_tgsprinc) + krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc); + krb5_free_context(rdp->realm_context); + } + memset((char *) rdp, 0, sizeof(*rdp)); +} + +/* + * Initialize a realm control structure from the alternate profile or from + * the specified defaults. + * + * After we're complete here, the essence of the realm is embodied in the + * realm data and we should be all set to begin operation for that realm. + */ +static krb5_error_code +init_realm(progname, rdp, altp, realm, def_dbname, def_mpname, + def_keytype, def_port, def_enctype, def_manual) + char *progname; + kdc_realm_t *rdp; + krb5_pointer altp; + char *realm; + char *def_dbname; + char *def_mpname; + krb5_keytype def_keytype; + krb5_int32 def_port; + krb5_enctype def_enctype; + krb5_boolean def_manual; +{ + krb5_error_code kret; + char *hierarchy[4]; + krb5_boolean manual; + krb5_db_entry db_entry; + int num2get; + krb5_boolean more; + krb5_boolean db_inited; + krb5_int32 ibuf; + krb5_enctype etype; + + kret = EINVAL; + db_inited = 0; + memset((char *) rdp, 0, sizeof(kdc_realm_t)); + if (realm) { + rdp->realm_name = realm; + if (!(kret = krb5_init_context(&rdp->realm_context))) { + hierarchy[0] = realm; + hierarchy[1] = "database_name"; + hierarchy[2] = (char *) NULL; + /* + * Attempt to get the real value for the database file. + */ + if (!altp || (kret = krb5_aprof_get_string(altp, + hierarchy, + TRUE, + &rdp->realm_dbname))) + rdp->realm_dbname = (def_dbname) ? strdup(def_dbname) : + strdup(DEFAULT_KDB_FILE); + + /* + * Attempt to get the real value for the master key name. + */ + hierarchy[1] = "master_key_name"; + if (!altp || (kret = krb5_aprof_get_string(altp, + hierarchy, + TRUE, + &rdp->realm_mpname))) + rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) : + KRB5_KDB_M_NAME; + + /* + * Attempt to get the real value for the master key type. + */ + hierarchy[1] = "master_key_type"; + if (!altp || (kret = krb5_aprof_get_int32(altp, + hierarchy, + TRUE, + &ibuf))) + rdp->realm_mkey.keytype = (def_keytype) ? def_keytype : + KEYTYPE_DES; + else + rdp->realm_mkey.keytype = (krb5_keytype) ibuf; + + /* + * Attempt to get the real value for the primary port. + */ + hierarchy[1] = "port"; + if (!altp || (kret = krb5_aprof_get_int32(altp, + hierarchy, + TRUE, + &rdp->realm_pport))) + rdp->realm_pport = (def_port) ? def_port : KRB5_DEFAULT_PORT; + + /* + * Attempt to get the real value for the encryption type. + */ + hierarchy[1] = "encryption_type"; + if (!altp || (kret = krb5_aprof_get_int32(altp, + hierarchy, + TRUE, + &ibuf))) + etype = (def_enctype) ? def_enctype : DEFAULT_KDC_ETYPE; + else + etype = (krb5_enctype) ibuf; + + if (!valid_etype(etype)) { + com_err(progname, KRB5_PROG_ETYPE_NOSUPP, + "while setting up etype %d", etype); + exit(1); + } + /* + * Attempt to get the real value for the stash file. + */ + hierarchy[1] = "key_stash_file"; + if (!altp || (kret = krb5_aprof_get_string(altp, + hierarchy, + TRUE, + &rdp->realm_stash))) + manual = def_manual; + else + manual = FALSE; + + /* + * Attempt to get the real value for the maximum ticket life. + */ + hierarchy[1] = "max_life"; + if (!altp || (kret = krb5_aprof_get_deltat(altp, + hierarchy, + TRUE, + &rdp->realm_maxlife))) + rdp->realm_maxlife = KRB5_KDB_MAX_LIFE; + + /* + * Attempt to get the real value for the maximum renewable ticket + * life. + */ + hierarchy[1] = "max_renewable_life"; + if (!altp || (kret = krb5_aprof_get_deltat(altp, + hierarchy, + TRUE, + &rdp->realm_maxrlife))) + rdp->realm_maxrlife = KRB5_KDB_MAX_RLIFE; + + /* + * We've got our parameters, now go and setup our realm context. + */ + + /* Set the default realm of this context */ + if (kret = krb5_set_default_realm(rdp->realm_context, realm)) { + com_err(progname, kret, "while setting default realm to %s", + realm); + goto whoops; + } + + /* Assemble and parse the master key name */ + if (kret = krb5_db_setup_mkey_name(rdp->realm_context, + rdp->realm_mpname, + rdp->realm_name, + (char **) NULL, + &rdp->realm_mprinc)) { + com_err(progname, kret, + "while setting up master key name %s for realm %s", + rdp->realm_mpname, realm); + goto whoops; + } + + /* Select the specified encryption type */ + krb5_use_cstype(rdp->realm_context, &rdp->realm_encblock, etype); + + /* + * If there's a stash file, then we have to go get the key + * manually because krb5_db_fetch_mkey() doesn't let us supply + * where we've stashed the master key. + */ + if (rdp->realm_stash) { + FILE *sfile; + krb5_ui_2 keytype; + + if (sfile = fopen(rdp->realm_stash, "r")) { + if ((fread((krb5_pointer) &keytype, 2, 1, sfile) != 1) || + (fread((krb5_pointer) &rdp->realm_mkey.length, + sizeof(rdp->realm_mkey.length), + 1, + sfile) != 1) || + (!(rdp->realm_mkey.contents = (krb5_octet *) + malloc(rdp->realm_mkey.length))) || + (fread((krb5_pointer) rdp->realm_mkey.contents, + sizeof(krb5_octet), + rdp->realm_mkey.length, sfile) != + rdp->realm_mkey.length)) { + com_err(progname, KRB5_KDB_CANTREAD_STORED, + "while reading stash file %s for realm %s", + rdp->realm_stash, realm); + fclose(sfile); + goto whoops; + } + rdp->realm_mkey.keytype = keytype; + fclose(sfile); + } + else { + com_err(progname, errno, + "while opening stash file %s for realm %s", + rdp->realm_stash, realm); + goto whoops; + } + } + else { + /* + * No stash, fetch it. + */ + if (kret = krb5_db_fetch_mkey(rdp->realm_context, + rdp->realm_mprinc, + &rdp->realm_encblock, + manual, + FALSE, + 0, + &rdp->realm_mkey)) { + com_err(progname, kret, + "while fetching master key %s for realm %s", + rdp->realm_mpname, realm); + goto whoops; + } + } + + /* Set and open the database. */ + if (rdp->realm_dbname && + (kret = krb5_db_set_name(rdp->realm_context, + rdp->realm_dbname))) { + com_err(progname, kret, + "while setting database name to %s for realm %s", + rdp->realm_dbname, realm); + goto whoops; + } + if (kret = krb5_db_init(rdp->realm_context)) { + com_err(progname, kret, + "while initializing database for realm %s", realm); + goto whoops; + } + else + db_inited = 1; + + /* Verify the master key */ + if (kret = krb5_db_verify_master_key(rdp->realm_context, + rdp->realm_mprinc, + &rdp->realm_mkey, + &rdp->realm_encblock)) { + com_err(progname, kret, + "while verifying master key for realm %s", realm); + goto whoops; + } + + /* Fetch the master key and get its version number */ + num2get = 1; + if (!(kret = krb5_db_get_principal(rdp->realm_context, + rdp->realm_mprinc, + &db_entry, + &num2get, + &more))) { + if (num2get != 1) + kret = KRB5_KDB_NOMASTERKEY; + else { + if (more) { + krb5_db_free_principal(rdp->realm_context, + &db_entry, + num2get); + kret = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE; + } + } + } + if (kret) { + com_err(progname, kret, + "while fetching master entry for realm %s", realm); + goto whoops; + } + else { + rdp->realm_mkvno = db_entry.kvno; + krb5_db_free_principal(rdp->realm_context, + &db_entry, + num2get); + } + + /* Now preprocess the master key */ + if (kret = krb5_process_key(rdp->realm_context, + &rdp->realm_encblock, + &rdp->realm_mkey)) { + com_err(progname, kret, + "while processing master key for realm %s", realm); + goto whoops; + } + + /* Preformat the TGS name */ + if (kret = krb5_build_principal(rdp->realm_context, + &rdp->realm_tgsprinc, + strlen(realm), + realm, + KRB5_TGS_NAME, + realm, + (char *) NULL)) { + com_err(progname, kret, + "while building TGS name for realm %s", realm); + goto whoops; + } + + /* Get the TGS database entry */ + num2get = 1; + if (!(kret = krb5_db_get_principal(rdp->realm_context, + rdp->realm_tgsprinc, + &db_entry, + &num2get, + &more))) { + if (num2get != 1) + kret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + else { + if (more) { + krb5_db_free_principal(rdp->realm_context, + &db_entry, + num2get); + kret = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE; + } + } + } + if (kret) { + com_err(progname, kret, + "while fetching TGS entry for realm %s", realm); + goto whoops; + } + else { + if (!(kret = krb5_kdb_decrypt_key(rdp->realm_context, + &rdp->realm_encblock, + &db_entry.key, + &rdp->realm_tgskey))) { + rdp->realm_tgskvno = db_entry.kvno; + } + krb5_db_free_principal(rdp->realm_context, + &db_entry, + num2get); + if (kret) { + com_err(progname, kret, + "while decrypting TGS key for realm %s", realm); + goto whoops; + } + } + if (!rkey_init_done) { + /* + * If all that worked, then initialize the random key + * generators. + */ + for (etype = 0; etype <= krb5_max_cryptosystem; etype++) { + if (krb5_csarray[etype]) { + if ((kret = (*krb5_csarray[etype]->system-> + init_random_key) + (&rdp->realm_mkey, + &krb5_csarray[etype]->random_sequence))) { + com_err(progname, kret, + "while setting up random key generator for etype %d--etype disabled", + etype); + krb5_csarray[etype] = 0; + } + } + } + rkey_init_done = 1; + } + } + else { + com_err(progname, kret, "while getting context for realm %s", + realm); + goto whoops; + } + } + whoops: + /* + * If we choked, then clean up any dirt we may have dropped on the floor. + */ + if (kret) { + finish_realm(rdp); + } + return(kret); +} krb5_sigtype request_exit() @@ -68,31 +539,56 @@ char *name; } void -process_args(argc, argv) -int argc; -char **argv; +initialize_realms(kcontext, altp, argc, argv) + krb5_context kcontext; + krb5_pointer altp; + int argc; + char **argv; { - int c; - krb5_boolean manual = FALSE; - int keytypedone = 0; - char *db_realm = 0; - char *mkey_name = 0; - char *rcname = 0; - char *lrealm; - krb5_error_code retval, retval2; - krb5_enctype kdc_etype = DEFAULT_KDC_ETYPE; - krb5_enctype etype; - extern krb5_deltat krb5_clockskew; + int c; + char *db_name = (char *) NULL; + char *mkey_name = (char *) NULL; + char *rcname = KDCRCACHE; + char *lrealm; + krb5_error_code retval, retval2; + krb5_keytype mkeytype = KEYTYPE_DES; + krb5_enctype kdc_etype = DEFAULT_KDC_ETYPE; + kdc_realm_t *rdatap; + krb5_boolean manual = FALSE; + krb5_int32 pport; extern char *optarg; + /* + * Loop through the option list. Each time we encounter a realm name, + * use the previously scanned options to fill in for defaults. + */ while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:n")) != EOF) { switch(c) { case 'r': /* realm name for db */ - db_realm = optarg; + if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) { + if (rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t))) { + if (retval = init_realm(argv[0], + rdatap, + altp, + optarg, + db_name, + mkey_name, + mkeytype, + pport, + kdc_etype, + manual)) { + fprintf(stderr,"%s: cannot initialize realm %s\n", + argv[0], optarg); + exit(1); + } + kdc_realmlist[kdc_numrealms] = rdatap; + kdc_numrealms++; + } + } break; case 'd': /* pathname for db */ - dbm_db_name = optarg; + db_name = optarg; break; case 'm': /* manual type-in of master key */ manual = TRUE; @@ -104,14 +600,13 @@ char **argv; nofork++; /* don't detach from terminal */ break; case 'k': /* keytype for master key */ - master_keyblock.keytype = atoi(optarg); - keytypedone++; + mkeytype = atoi(optarg); break; case 'R': rcname = optarg; break; case 'p': - primary_port = atoi(optarg); + pport = atoi(optarg); break; case 'e': kdc_etype = atoi(optarg); @@ -122,226 +617,59 @@ char **argv; exit(1); } } - if (!db_realm) { + + /* + * Check to see if we processed any realms. + */ + if (kdc_numrealms == 0) { /* no realm specified, use default realm */ - if ((retval = krb5_get_default_realm(kdc_context, &lrealm))) { + if ((retval = krb5_get_default_realm(kcontext, &lrealm))) { com_err(argv[0], retval, "while attempting to retrieve default realm"); exit(1); } - db_realm = lrealm; - } - - if (!mkey_name) - mkey_name = KRB5_KDB_M_NAME; - - if (!keytypedone) - master_keyblock.keytype = KEYTYPE_DES; - - if (!rcname) - rcname = KDCRCACHE; - if ((retval = krb5_rc_resolve_full(kdc_context, &kdc_rcache, rcname))) { - com_err(argv[0], retval, "while resolving replay cache '%s'", rcname); - exit(1); - } - if ((retval = krb5_rc_recover(kdc_context, kdc_rcache)) && - (retval2 = krb5_rc_initialize(kdc_context, kdc_rcache, krb5_clockskew))) { - com_err(argv[0], retval, "while recovering replay cache '%s:%s'", - kdc_rcache->ops->type, - krb5_rc_get_name(kdc_context, kdc_rcache)); - com_err(argv[0], retval2, "while initializing replay cache '%s:%s'", - kdc_rcache->ops->type, - krb5_rc_get_name(kdc_context, kdc_rcache)); - exit(1); - } - if ((retval = krb5_rc_expunge(kdc_context, kdc_rcache))) { - com_err(argv[0], retval, "while expunging replay cache '%s:%s'", - kdc_rcache->ops->type, - krb5_rc_get_name(kdc_context, kdc_rcache)); - exit(1); - } - /* assemble & parse the master key name */ - - if ((retval = krb5_db_setup_mkey_name(kdc_context, mkey_name, - db_realm, (char **) 0, - &master_princ))) { - com_err(argv[0], retval, "while setting up master key name"); - (void) krb5_rc_close(kdc_context, kdc_rcache); - exit(1); + if (rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t))) { + if (retval = init_realm(argv[0], + rdatap, + altp, + lrealm, + db_name, + mkey_name, + mkeytype, + pport, + kdc_etype, + manual)) { + fprintf(stderr,"%s: cannot initialize realm %s\n", + argv[0], lrealm); + exit(1); + } + kdc_realmlist[0] = rdatap; + kdc_numrealms++; + } } - if (!valid_etype(kdc_etype)) { - com_err(argv[0], KRB5_PROG_ETYPE_NOSUPP, - "while setting up etype %d", kdc_etype); + /* + * Now handle the replay cache. + */ + if (retval = kdc_initialize_rcache(kcontext, rcname)) { + com_err(argv[0], retval, + "while initializing KDC replay cache"); exit(1); } - krb5_use_cstype(kdc_context, &master_encblock, kdc_etype); - - if ((retval = krb5_db_fetch_mkey(kdc_context, master_princ, - &master_encblock, manual, - FALSE, /* only read it once, if at all */ - 0, &master_keyblock))) { - com_err(argv[0], retval, "while fetching master key"); - (void) krb5_rc_close(kdc_context, kdc_rcache); - exit(1); - } - /* initialize random key generators */ - for (etype = 0; etype <= krb5_max_cryptosystem; etype++) { - if (krb5_csarray[etype]) { - if ((retval = (*krb5_csarray[etype]->system-> - init_random_key)(&master_keyblock, - &krb5_csarray[etype]->random_sequence))) { - com_err(argv[0], retval, "while setting up random key generator for etype %d--etype disabled", etype); - krb5_csarray[etype] = 0; - } - } - } + /* Ensure that this is set for our first request. */ + kdc_active_realm = kdc_realmlist[0]; return; } void -finish_args(prog) -char *prog; +finish_realms(prog) + char *prog; { - char *rtype, *rname; - krb5_error_code retval; - - if (kdc_rcache) { - if (kdc_rcache->ops && kdc_rcache->ops->type) - rtype = strdup(kdc_rcache->ops->type); - else - rtype = strdup("Unknown_rcache_type"); - rname = strdup(krb5_rc_get_name(kdc_context, kdc_rcache)); - if ((retval = krb5_rc_close(kdc_context, kdc_rcache))) { - com_err(prog, retval, "while closing replay cache '%s:%s'", - rtype, rname); - } - free(rtype); - free(rname); - } - return; -} - + int i; -krb5_error_code -init_db(dbname, masterkeyname, masterkeyblock) -char *dbname; -krb5_principal masterkeyname; -krb5_keyblock *masterkeyblock; -{ - krb5_error_code retval; - int nprincs; - krb5_boolean more; - krb5_db_entry server; -#ifdef KRB5_KRB4_COMPAT - extern unsigned char master_key_version; -#endif - - /* set db name if appropriate */ - if (dbname && (retval = krb5_db_set_name(kdc_context, dbname))) - return(retval); - - /* initialize database */ - if ((retval = krb5_db_init(kdc_context))) - return(retval); - - if ((retval = krb5_db_verify_master_key(kdc_context, masterkeyname, - masterkeyblock, - &master_encblock))) { - master_encblock.crypto_entry = 0; - return(retval); - } - -#ifdef KRB5_KRB4_COMPAT - /* get the master key, to extract the master key version number */ - nprincs = 1; - if ((retval = krb5_db_get_principal(kdc_context, masterkeyname, - &server, &nprincs, &more))) { - return(retval); - } - if (nprincs != 1) { - if (nprincs) - krb5_db_free_principal(kdc_context, &server, nprincs); - return(KRB5_KDB_NOMASTERKEY); - } else if (more) { - krb5_db_free_principal(kdc_context, &server, nprincs); - return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE); - } - master_key_version = server.kvno; - krb5_db_free_principal(kdc_context, &server, nprincs); -#endif - - /* do any necessary key pre-processing */ - if ((retval = krb5_process_key(kdc_context, &master_encblock, - masterkeyblock))) { - master_encblock.crypto_entry = 0; - (void) krb5_db_fini(kdc_context); - return(retval); - } - - /* fetch the TGS key, and hold onto it; this is an efficiency hack */ - - /* the master key name here is from the master_princ global, - so we can safely share its substructure */ - - krb5_princ_set_realm(kdc_context, tgs_server, - krb5_princ_realm(kdc_context, masterkeyname)); - /* tgs_server[0] is init data */ - *krb5_princ_component(kdc_context, tgs_server, 1) = - *krb5_princ_realm(kdc_context, masterkeyname); - - nprincs = 1; - if ((retval = krb5_db_get_principal(kdc_context, tgs_server, - &server, &nprincs, &more))) { - return(retval); - } - if (more) { - krb5_db_free_principal(kdc_context, &server, nprincs); - (void) krb5_finish_key(kdc_context, &master_encblock); - memset((char *)&master_encblock, 0, sizeof(master_encblock)); - (void) krb5_db_fini(kdc_context ); - return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE); - } else if (nprincs != 1) { - krb5_db_free_principal(kdc_context, &server, nprincs); - (void) krb5_finish_key(kdc_context, &master_encblock); - memset((char *)&master_encblock, 0, sizeof(master_encblock)); - (void) krb5_db_fini(kdc_context ); - return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN); - } - /* convert server.key into a real key (it may be encrypted - in the database) */ - if ((retval = KDB_CONVERT_KEY_OUTOF_DB(kdc_context, &server.key, - &tgs_key))) { - krb5_db_free_principal(kdc_context, &server, nprincs); - (void) krb5_finish_key(kdc_context, &master_encblock); - memset((char *)&master_encblock, 0, sizeof(master_encblock)); - (void) krb5_db_fini(kdc_context ); - return retval; - } - tgs_kvno = server.kvno; - krb5_db_free_principal(kdc_context, &server, nprincs); - return 0; -} - -krb5_error_code -closedown_db() -{ - krb5_error_code retval; - - /* clean up master key stuff */ - retval = krb5_finish_key(kdc_context, &master_encblock); - - memset((char *)&master_encblock, 0, sizeof(master_encblock)); - - memset((char *)tgs_key.contents, 0, tgs_key.length); - - /* close database */ - if (retval) { - (void) krb5_db_fini(kdc_context ); - return retval; - } else - return (krb5_db_fini(kdc_context)); + for (i=0; i