/* * kadmin/dbutil/loadv4.c * * Copyright 1996 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * * Generate (from scratch) a Kerberos V5 KDC database, filling it in with the * entries from a V4 database. */ #ifdef KRB5_KRB4_COMPAT #include #include #include /* MKEYFILE is now defined in kdc.h */ #include static C_Block master_key; static Key_schedule master_key_schedule; static long master_key_version; static char *v4_mkeyfile = "/.k"; #include "k5-int.h" #include "com_err.h" #include #include #include /* ntohl */ #define PROGNAME argv[0] enum ap_op { NULL_KEY, /* setup null keys */ MASTER_KEY, /* use master key as new key */ RANDOM_KEY /* choose a random key */ }; struct realm_info { krb5_deltat max_life; krb5_deltat max_rlife; krb5_timestamp expiration; krb5_flags flags; krb5_encrypt_block *eblock; krb5_pointer rseed; }; static struct realm_info rblock = { /* XXX */ KRB5_KDB_MAX_LIFE, KRB5_KDB_MAX_RLIFE, KRB5_KDB_EXPIRATION, KRB5_KDB_DEF_FLAGS, 0 }; static int verbose = 0; static krb5_error_code add_principal PROTOTYPE((krb5_context, krb5_principal, enum ap_op, struct realm_info *)); static int v4init PROTOTYPE((char *, int, char *)); static krb5_error_code enter_in_v5_db PROTOTYPE((krb5_context, char *, Principal *)); static krb5_error_code process_v4_dump PROTOTYPE((krb5_context, char *, char *, long)); static krb5_error_code v4_dump_find_default PROTOTYPE((krb5_context, char *, char *, long *)); static krb5_error_code fixup_database PROTOTYPE((krb5_context, char *)); static int create_local_tgt = 0; static krb5_keyblock master_keyblock; static krb5_principal master_princ; static krb5_encrypt_block master_encblock; static krb5_data tgt_princ_entries[] = { {0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME}, {0, 0, 0} }; static krb5_data db_creator_entries[] = { {0, sizeof("db_creation")-1, "db_creation"} }; /* XXX knows about contents of krb5_principal, and that tgt names are of form TGT/REALM@REALM */ static krb5_principal_data tgt_princ = { 0, /* magic number */ {0, 0, 0}, /* krb5_data realm */ tgt_princ_entries, /* krb5_data *data */ 2, /* int length */ KRB5_NT_SRV_INST /* int type */ }; static krb5_principal_data db_create_princ = { 0, /* magic number */ {0, 0, 0}, /* krb5_data realm */ db_creator_entries, /* krb5_data *data */ 1, /* int length */ KRB5_NT_SRV_INST /* int type */ }; void load_v4db(argc, argv) int argc; char *argv[]; { krb5_error_code retval; /* The kdb library will default to this, but it is convenient to make it explicit (error reporting and temporary filename generation use it). */ char *dbname = DEFAULT_KDB_FILE; char *v4dumpfile = 0; char *realm = 0; char *mkey_name = 0; char *mkey_fullname; char *defrealm; int v4manual = 0; int read_mkey = 0; int tempdb = 0; char *tempdbname; krb5_context context; char *stash_file = (char *) NULL; int persist, op_ind; kadm5_config_params newparams; extern kadm5_config_params global_params; long exp_time = 0; krb5_init_context(&context); krb5_init_ets(context); if (strrchr(argv[0], '/')) argv[0] = strrchr(argv[0], '/')+1; persist = 1; op_ind = 1; while (persist && (op_ind < argc)) { if (!strcmp(argv[op_ind], "-T")) { create_local_tgt = 1; } else if (!strcmp(argv[op_ind], "-t")) { tempdb = 1; } else if (!strcmp(argv[op_ind], "-K")) { read_mkey = 1; } else if (!strcmp(argv[op_ind], "-v")) { verbose = 1; } else if (!strcmp(argv[op_ind], "-n")) { v4manual++; } else if (!strcmp(argv[op_ind], "-s")) { if ((argc - op_ind) >= 1) { v4_mkeyfile = argv[op_ind+1]; op_ind++; } else { usage(); } } else if ((argc - op_ind) >= 1) { v4dumpfile = argv[op_ind]; op_ind++; } else usage(); op_ind++; } realm = global_params.realm; dbname = global_params.dbname; mkey_name = global_params.mkey_name; master_keyblock.enctype = global_params.enctype; stash_file = strdup(global_params.stash_file); rblock.max_life = global_params.max_life; rblock.max_rlife = global_params.max_rlife; rblock.expiration = global_params.expiration; rblock.flags = global_params.flags; if (!v4dumpfile) { usage(); return; } if (!valid_enctype(master_keyblock.enctype)) { com_err(PROGNAME, KRB5_PROG_KEYTYPE_NOSUPP, "while setting up enctype %d", master_keyblock.enctype); return; } krb5_use_enctype(context, &master_encblock, master_keyblock.enctype); /* If the user has not requested locking, don't modify an existing database. */ if (! tempdb) { retval = krb5_db_set_name(context, dbname); if (retval != ENOENT) { fprintf(stderr, "%s: The v5 database appears to already exist.\n", PROGNAME); return; } tempdbname = dbname; } else { int dbnamelen = strlen(dbname); tempdbname = malloc(dbnamelen + 2); if (tempdbname == 0) { com_err(PROGNAME, ENOMEM, "allocating temporary filename"); return; } strcpy(tempdbname, dbname); tempdbname[dbnamelen] = '~'; tempdbname[dbnamelen+1] = 0; (void) kdb5_db_destroy(context, tempdbname); } if (!realm) { if (retval = krb5_get_default_realm(context, &defrealm)) { com_err(PROGNAME, retval, "while retrieving default realm name"); return; } realm = defrealm; } /* assemble & parse the master key name */ if (retval = krb5_db_setup_mkey_name(context, mkey_name, realm, &mkey_fullname, &master_princ)) { com_err(PROGNAME, retval, "while setting up master key name"); return; } krb5_princ_set_realm_data(context, &db_create_princ, realm); krb5_princ_set_realm_length(context, &db_create_princ, strlen(realm)); krb5_princ_set_realm_data(context, &tgt_princ, realm); krb5_princ_set_realm_length(context, &tgt_princ, strlen(realm)); krb5_princ_component(context, &tgt_princ,1)->data = realm; krb5_princ_component(context, &tgt_princ,1)->length = strlen(realm); printf("Initializing database '%s' for realm '%s',\n\ master key name '%s'\n", dbname, realm, mkey_fullname); if (read_mkey) { puts("You will be prompted for the version 5 database Master Password."); puts("It is important that you NOT FORGET this password."); fflush(stdout); } if (retval = krb5_db_fetch_mkey(context, master_princ, &master_encblock, read_mkey, read_mkey, stash_file, 0, &master_keyblock)) { com_err(PROGNAME, retval, "while reading master key"); return; } if (retval = krb5_process_key(context, &master_encblock, &master_keyblock)) { com_err(PROGNAME, retval, "while processing master key"); return; } rblock.eblock = &master_encblock; if (retval = krb5_init_random_key(context, &master_encblock, &master_keyblock, &rblock.rseed)) { com_err(PROGNAME, retval, "while initializing random key generator"); (void) krb5_finish_key(context, &master_encblock); return; } if (retval = krb5_db_create(context, tempdbname)) { (void) krb5_finish_key(context, &master_encblock); (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); (void) krb5_dbm_db_destroy(context, tempdbname); com_err(PROGNAME, retval, "while creating %sdatabase '%s'", tempdb ? "temporary " : "", tempdbname); return; } if (retval = krb5_db_set_name(context, tempdbname)) { (void) krb5_finish_key(context, &master_encblock); (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); (void) krb5_dbm_db_destroy(context, tempdbname); com_err(PROGNAME, retval, "while setting active database to '%s'", tempdbname); return; } if (v4init(PROGNAME, v4manual, v4dumpfile)) { (void) krb5_finish_key(context, &master_encblock); (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); (void) krb5_dbm_db_destroy(context, tempdbname); return; } if ((retval = krb5_db_init(context)) || (retval = krb5_dbm_db_open_database(context))) { (void) krb5_finish_key(context, &master_encblock); (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); (void) krb5_dbm_db_destroy(context, tempdbname); com_err(PROGNAME, retval, "while initializing the database '%s'", tempdbname); return; } if (retval = add_principal(context, master_princ, MASTER_KEY, &rblock)) { (void) krb5_db_fini(context); (void) krb5_finish_key(context, &master_encblock); (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); (void) krb5_dbm_db_destroy(context, tempdbname); com_err(PROGNAME, retval, "while adding K/M to the database"); return; } if (create_local_tgt && (retval = add_principal(context, &tgt_princ, RANDOM_KEY, &rblock))) { (void) krb5_db_fini(context); (void) krb5_finish_key(context, &master_encblock); (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); (void) krb5_dbm_db_destroy(context, tempdbname); com_err(PROGNAME, retval, "while adding TGT service to the database"); return; } retval = v4_dump_find_default(context, v4dumpfile, realm, &exp_time); if (retval) { com_err(PROGNAME, retval, "warning: default entry not found"); } retval = process_v4_dump(context, v4dumpfile, realm, exp_time); putchar('\n'); if (retval) com_err(PROGNAME, retval, "while translating entries to the database"); else { retval = fixup_database(context, realm); } /* clean up; rename temporary database if there were no errors */ if (retval == 0) { if (retval = krb5_db_fini (context)) com_err(PROGNAME, retval, "while shutting down database"); else if (tempdb && (retval = krb5_dbm_db_rename(context, tempdbname, dbname))) com_err(PROGNAME, retval, "while renaming temporary database"); } else { (void) krb5_db_fini (context); if (tempdb) (void) krb5_dbm_db_destroy (context, tempdbname); } (void) krb5_finish_key(context, &master_encblock); (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); memset((char *)master_keyblock.contents, 0, master_keyblock.length); /* * Cons up config params for new database; using the global_params * is just fine. */ newparams = global_params; /* * Always create the policy db, even if we are not loading a dump * file with policy info. */ if (!tempdb && (retval = osa_adb_create_policy_db(&newparams))) { com_err(PROGNAME, retval, "while creating policy database"); kadm5_free_config_params(context, &newparams); return; } /* * Create the magic principals in the database. */ if (retval = kadm5_create_magic_princs(&newparams, context)) { com_err(PROGNAME, retval, "while creating KADM5 principals"); return; } krb5_free_context(context); return; } static int v4init(pname, manual, dumpfile) char *pname; int manual; char *dumpfile; { int fd; int ok = 0; if (!manual) { fd = open(v4_mkeyfile, O_RDONLY, 0600); if (fd >= 0) { if (read(fd, master_key, sizeof(master_key)) == sizeof(master_key)) ok = 1; close(fd); } } if (!ok) { des_read_password(master_key, "V4 Kerberos master key: ", 0); printf("\n"); } key_sched(master_key, master_key_schedule); return 0; } static krb5_error_code enter_in_v5_db(context, realm, princ) krb5_context context; char *realm; Principal *princ; { krb5_db_entry entry; krb5_error_code retval; krb5_keyblock v4v5key; int nentries = 1; des_cblock v4key; char *name; krb5_timestamp mod_time; krb5_principal mod_princ; krb5_keysalt keysalt; /* don't convert local TGT if we created a TGT already.... */ if (create_local_tgt && !strcmp(princ->name, "krbtgt") && !strcmp(princ->instance, realm)) { if (verbose) printf("\nignoring local TGT: '%s.%s' ...", princ->name, princ->instance); return 0; } if (!strcmp(princ->name, KERB_M_NAME) && !strcmp(princ->instance, KERB_M_INST)) { des_cblock key_from_db; int val; /* here's our chance to verify the master key */ /* * use the master key to decrypt the key in the db, had better * be the same! */ memcpy(key_from_db, (char *)&princ->key_low, 4); memcpy(((char *) key_from_db) + 4, (char *)&princ->key_high, 4); pcbc_encrypt((C_Block *) &key_from_db, (C_Block *) &key_from_db, (long) sizeof(C_Block), master_key_schedule, (C_Block *) master_key, DECRYPT); val = memcmp((char *) master_key, (char *) key_from_db, sizeof(master_key)); memset((char *)key_from_db, 0, sizeof(key_from_db)); if (val) { return KRB5_KDB_BADMASTERKEY; } if (verbose) printf("\nignoring '%s.%s' ...", princ->name, princ->instance); return 0; } memset((char *) &entry, 0, sizeof(entry)); if (retval = krb5_425_conv_principal(context, princ->name, princ->instance, realm, &entry.princ)) return retval; if (verbose) { if (retval = krb5_unparse_name(context, entry.princ, &name)) name = strdup(""); if (verbose) printf("\ntranslating %s...", name); free(name); } if (retval = krb5_build_principal(context, &mod_princ, strlen(realm), realm, princ->mod_name, princ->mod_instance[0] ? princ->mod_instance : 0, 0)) { krb5_free_principal(context, entry.princ); return retval; } mod_time = princ->mod_date; entry.max_life = princ->max_life * 60 * 5; entry.max_renewable_life = rblock.max_rlife; entry.len = KRB5_KDB_V1_BASE_LENGTH; entry.expiration = princ->exp_date; entry.attributes = rblock.flags; /* XXX is there a way to convert the old attrs? */ memcpy((char *)v4key, (char *)&(princ->key_low), 4); memcpy((char *) (((char *) v4key) + 4), (char *)&(princ->key_high), 4); pcbc_encrypt((C_Block *) &v4key, (C_Block *) &v4key, (long) sizeof(C_Block), master_key_schedule, (C_Block *) master_key, DECRYPT); v4v5key.magic = KV5M_KEYBLOCK; v4v5key.contents = (krb5_octet *)v4key; v4v5key.enctype = ENCTYPE_DES_CBC_CRC; v4v5key.length = sizeof(v4key); retval = krb5_dbe_create_key_data(context, &entry); if (retval) { krb5_free_principal(context, entry.princ); krb5_free_principal(context, mod_princ); return retval; } keysalt.type = KRB5_KDB_SALTTYPE_V4; keysalt.data.length = 0; keysalt.data.data = (char *) NULL; retval = krb5_dbekd_encrypt_key_data(context, rblock.eblock, &v4v5key, &keysalt, princ->key_version, &entry.key_data[0]); if (!retval) retval = krb5_dbe_update_mod_princ_data(context, &entry, mod_time, mod_princ); if (!retval) retval = krb5_dbe_update_last_pwd_change(context, &entry, mod_time); if (retval) { krb5_db_free_principal(context, &entry, 1); krb5_free_principal(context, mod_princ); return retval; } memset((char *)v4key, 0, sizeof(v4key)); retval = krb5_db_put_principal(context, &entry, &nentries); if (!retval && !strcmp(princ->name, "krbtgt") && strcmp(princ->instance, realm) && princ->instance[0]) { krb5_free_principal(context, entry.princ); if (retval = krb5_build_principal(context, &entry.princ, strlen(princ->instance), princ->instance, "krbtgt", realm, 0)) return retval; retval = krb5_db_put_principal(context, &entry, &nentries); } krb5_db_free_principal(context, &entry, 1); krb5_free_principal(context, mod_princ); return retval; } static krb5_error_code add_principal(context, princ, op, pblock) krb5_context context; krb5_principal princ; enum ap_op op; struct realm_info *pblock; { krb5_db_entry entry; krb5_error_code retval; krb5_keyblock *rkey; int nentries = 1; krb5_timestamp mod_time; krb5_principal mod_princ; memset((char *) &entry, 0, sizeof(entry)); if (retval = krb5_copy_principal(context, princ, &entry.princ)) return(retval); entry.max_life = pblock->max_life; entry.max_renewable_life = pblock->max_rlife; entry.len = KRB5_KDB_V1_BASE_LENGTH; entry.expiration = pblock->expiration; if ((retval = krb5_timeofday(context, &mod_time))) { krb5_db_free_principal(context, &entry, 1); return retval; } entry.attributes = pblock->flags; if (retval = krb5_dbe_create_key_data(context, &entry)) { krb5_db_free_principal(context, &entry, 1); return(retval); } switch (op) { case MASTER_KEY: entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX; if (retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock, &master_keyblock, (krb5_keysalt *) NULL, 1, &entry.key_data[0])) { krb5_db_free_principal(context, &entry, 1); return retval; } break; case RANDOM_KEY: if (retval = krb5_random_key(context, pblock->eblock, pblock->rseed, &rkey)) { krb5_db_free_principal(context, &entry, 1); return retval; } if (retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock, rkey, (krb5_keysalt *) NULL, 1, &entry.key_data[0])) { krb5_db_free_principal(context, &entry, 1); return(retval); } krb5_free_keyblock(context, rkey); break; case NULL_KEY: return EOPNOTSUPP; default: break; } retval = krb5_dbe_update_mod_princ_data(context, &entry, mod_time, &db_create_princ); if (!retval) retval = krb5_db_put_principal(context, &entry, &nentries); krb5_db_free_principal(context, &entry, 1); return retval; } /* * Convert a struct tm * to a UNIX time. */ #define daysinyear(y) (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366))) #define SECSPERDAY 24*60*60 #define SECSPERHOUR 60*60 #define SECSPERMIN 60 static int cumdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; static int leapyear[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static int nonleapyear[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static long maketime(tp, local) register struct tm *tp; int local; { register long retval; int foo; int *marray; if (tp->tm_mon < 0 || tp->tm_mon > 11 || tp->tm_hour < 0 || tp->tm_hour > 23 || tp->tm_min < 0 || tp->tm_min > 59 || tp->tm_sec < 0 || tp->tm_sec > 59) /* out of range */ return 0; retval = 0; if (tp->tm_year < 1900) foo = tp->tm_year + 1900; else foo = tp->tm_year; if (foo < 1901 || foo > 2038) /* year is too small/large */ return 0; if (daysinyear(foo) == 366) { if (tp->tm_mon > 1) retval+= SECSPERDAY; /* add leap day */ marray = leapyear; } else marray = nonleapyear; if (tp->tm_mday < 0 || tp->tm_mday > marray[tp->tm_mon]) return 0; /* out of range */ while (--foo >= 1970) retval += daysinyear(foo) * SECSPERDAY; retval += cumdays[tp->tm_mon] * SECSPERDAY; retval += (tp->tm_mday-1) * SECSPERDAY; retval += tp->tm_hour * SECSPERHOUR + tp->tm_min * SECSPERMIN + tp->tm_sec; if (local) { /* need to use local time, so we retrieve timezone info */ struct timezone tz; struct timeval tv; if (gettimeofday(&tv, &tz) < 0) { /* some error--give up? */ return(retval); } retval += tz.tz_minuteswest * SECSPERMIN; } return(retval); } static long time_explode(cp) register char *cp; { char wbuf[5]; struct tm tp; int local; memset((char *)&tp, 0, sizeof(tp)); if (strlen(cp) > 10) { /* new format */ (void) strncpy(wbuf, cp, 4); wbuf[4] = 0; tp.tm_year = atoi(wbuf); cp += 4; /* step over the year */ local = 0; /* GMT */ } else { /* old format: local time, year is 2 digits, assuming 19xx */ wbuf[0] = *cp++; wbuf[1] = *cp++; wbuf[2] = 0; tp.tm_year = 1900 + atoi(wbuf); local = 1; /* local */ } wbuf[0] = *cp++; wbuf[1] = *cp++; wbuf[2] = 0; tp.tm_mon = atoi(wbuf)-1; wbuf[0] = *cp++; wbuf[1] = *cp++; tp.tm_mday = atoi(wbuf); wbuf[0] = *cp++; wbuf[1] = *cp++; tp.tm_hour = atoi(wbuf); wbuf[0] = *cp++; wbuf[1] = *cp++; tp.tm_min = atoi(wbuf); return(maketime(&tp, local)); } static krb5_error_code process_v4_dump(context, dumpfile, realm, default_exp_time) krb5_context context; char *dumpfile; char *realm; long default_exp_time; { krb5_error_code retval; FILE *input_file; Principal aprinc; char exp_date_str[50]; char mod_date_str[50]; int temp1, temp2, temp3; long time_explode(); input_file = fopen(dumpfile, "r"); if (!input_file) return errno; for (;;) { /* explicit break on eof from fscanf */ int nread; memset((char *)&aprinc, 0, sizeof(aprinc)); nread = fscanf(input_file, "%s %s %d %d %d %hd %x %x %s %s %s %s\n", aprinc.name, aprinc.instance, &temp1, &temp2, &temp3, &aprinc.attributes, &aprinc.key_low, &aprinc.key_high, exp_date_str, mod_date_str, aprinc.mod_name, aprinc.mod_instance); if (nread != 12) { retval = nread == EOF ? 0 : KRB5_KDB_DB_CORRUPT; break; } aprinc.key_low = ntohl (aprinc.key_low); aprinc.key_high = ntohl (aprinc.key_high); aprinc.max_life = (unsigned char) temp1; aprinc.kdc_key_ver = (unsigned char) temp2; aprinc.key_version = (unsigned char) temp3; aprinc.exp_date = time_explode(exp_date_str); if (aprinc.exp_date == default_exp_time) aprinc.exp_date = 0; aprinc.mod_date = time_explode(mod_date_str); if (aprinc.instance[0] == '*') aprinc.instance[0] = '\0'; if (aprinc.mod_name[0] == '*') aprinc.mod_name[0] = '\0'; if (aprinc.mod_instance[0] == '*') aprinc.mod_instance[0] = '\0'; if (retval = enter_in_v5_db(context, realm, &aprinc)) break; } (void) fclose(input_file); return retval; } static krb5_error_code v4_dump_find_default(context, dumpfile, realm, exptime) krb5_context context; char *dumpfile; char *realm; long *exptime; { krb5_error_code retval = 0; FILE *input_file; Principal aprinc; char exp_date_str[50]; char mod_date_str[50]; int temp1, temp2, temp3; long time_explode(); long foundtime, guess1, guess2; /* kdb_init is usually the only thing to touch the time in the default entry, and everything else just copies that time. If the site hasn't changed it, we can assume that "never" is an appropriate value for V5. There have been two values compiled in, typically: MIT V4 had the code principal.exp_date = 946702799; strncpy(principal.exp_date_txt, "12/31/99", DATE_SZ); Cygnus CNS V4 had the code principal.exp_date = 946702799+((365*10+3)*24*60*60); strncpy(principal.exp_date_txt, "12/31/2009", DATE_SZ); However, the dump files only store minutes -- so these values are 59 seconds high. Other values could be added later, but in practice these are likely to be the only ones. */ guess1 = 946702799-59; guess2 = 946702799+((365*10+3)*24*60*60); input_file = fopen(dumpfile, "r"); if (!input_file) return errno; for (;;) { /* explicit break on eof from fscanf */ int nread; memset((char *)&aprinc, 0, sizeof(aprinc)); nread = fscanf(input_file, "%s %s %d %d %d %hd %x %x %s %s %s %s\n", aprinc.name, aprinc.instance, &temp1, &temp2, &temp3, &aprinc.attributes, &aprinc.key_low, &aprinc.key_high, exp_date_str, mod_date_str, aprinc.mod_name, aprinc.mod_instance); if (nread != 12) { retval = nread == EOF ? 0 : KRB5_KDB_DB_CORRUPT; break; } if (!strcmp(aprinc.name, "default") && !strcmp(aprinc.instance, "*")) { foundtime = time_explode(exp_date_str); if (foundtime == guess1 || foundtime == guess2) *exptime = foundtime; if (verbose) { printf("\ndefault expiration found: "); if (foundtime == guess1) { printf("MIT or pre96q1 value (1999)"); } else if (foundtime == guess2) { printf("Cygnus CNS post 96q1 value (2009)"); } else { printf("non-default start time (%d,%s)", foundtime, exp_date_str); } } break; } } (void) fclose(input_file); return retval; } static krb5_error_code fixup_database(context, realm) krb5_context context; char * realm; { krb5_db_entry entry; krb5_error_code retval; int nprincs; krb5_boolean more; nprincs = 1; if (retval = krb5_db_get_principal(context, &tgt_princ, &entry, &nprincs, &more)) return retval; if (nprincs == 0) return 0; entry.attributes |= KRB5_KDB_SUPPORT_DESMD5; retval = krb5_db_put_principal(context, &entry, &nprincs); if (nprincs) krb5_db_free_principal(context, &entry, nprincs); return retval; } #else /* KRB5_KRB4_COMPAT */ void load_v4db(argc, argv) int argc; char *argv[]; { printf("This version of kdb5_util does not support the V4 load command.\n"); } #endif /* KRB5_KRB4_COMPAT */