From: Paul Park Date: Fri, 25 Aug 1995 21:46:33 +0000 (+0000) Subject: Add v4 dump load logic from kdb5_convert X-Git-Tag: krb5-1.0-beta6~1263 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=d9a90a300ff904d2a345673f3a8ed206440949e3;p=krb5.git Add v4 dump load logic from kdb5_convert git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6592 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/admin/edit/.Sanitize b/src/admin/edit/.Sanitize index e77eeb0f5..9e105839d 100644 --- a/src/admin/edit/.Sanitize +++ b/src/admin/edit/.Sanitize @@ -35,6 +35,7 @@ kdb5_ed_ct.ct kdb5_edit.M kdb5_edit.c kdb5_edit.h +loadv4.c ss_wrapper.c tcl_wrapper.c util.c diff --git a/src/admin/edit/ChangeLog b/src/admin/edit/ChangeLog index 486803c9c..80c858739 100644 --- a/src/admin/edit/ChangeLog +++ b/src/admin/edit/ChangeLog @@ -1,3 +1,11 @@ + +Fri Aug 25 17:37:33 EDT 1995 Paul Park (pjpark@mit.edu) + * dumpv4.c - Fix handle_keys(). It was trying to recreate work that + has already been done. + * Makefile.in, .Sanitize, loadv4.c, kdb5_ed_ct.ct - Add lddb4, the + command to load a v4 dump file. This is basically, kdb5_ + convert reconstituted to fit within the framework of kdb5_edit. + Thu Aug 24 19:28:39 1995 Theodore Y. Ts'o * .Sanitize: Update file list diff --git a/src/admin/edit/Makefile.in b/src/admin/edit/Makefile.in index dd976ffc7..3d6c6546e 100644 --- a/src/admin/edit/Makefile.in +++ b/src/admin/edit/Makefile.in @@ -10,6 +10,7 @@ OBJS= kdb5_edit.o \ util.o \ dump.o \ dumpv4.o \ + loadv4.o \ ss_wrapper.o \ $(LIBOBJS) @@ -19,7 +20,8 @@ SRCS= $(srcdir)/kdb5_edit.c \ $(srcdir)/util.c \ $(srcdir)/dump.c \ $(srcdir)/ss_wrapper.c \ - $(srcdir)/dumpv4.c + $(srcdir)/dumpv4.c \ + $(srcdir)/loadv4.c all:: kdb5_edit diff --git a/src/admin/edit/kdb5_ed_ct.ct b/src/admin/edit/kdb5_ed_ct.ct index f00af1e76..84ef78ce5 100644 --- a/src/admin/edit/kdb5_ed_ct.ct +++ b/src/admin/edit/kdb5_ed_ct.ct @@ -66,6 +66,9 @@ request dump_v4db, "Dump database entries to a V4 slave dump file", request load_db, "Load database entries from a file", load_db, lddb; +request load_v4db, "Load database entries from a V4 slave dump file", + load_v4db, lddb4; + request set_dbname, "Change database name", set_dbname, sdbn; diff --git a/src/admin/edit/loadv4.c b/src/admin/edit/loadv4.c new file mode 100644 index 000000000..6374ea5a2 --- /dev/null +++ b/src/admin/edit/loadv4.c @@ -0,0 +1,888 @@ +/* + * admin/edit/loadv4.c + * + * Copyright 1990,1991 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. + */ + +#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; + +#include "k5-int.h" +#include "com_err.h" +#include "adm.h" +#include "adm_proto.h" +#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 *, 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 *)); +static krb5_error_code fixup_database PROTOTYPE((krb5_context, char *)); + +static int create_local_tgt = 0; + +static void +usage(who, status) +char *who; +int status; +{ + fprintf(stderr, "usage: %s [-d v5dbpathname] [-t] [-n] [-r realmname] [-K] [-k keytype]\n\ +\t[-e etype] [-M mkeyname] -f inputfile\n", + who); + return; +} + +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 *v4dbname = 0; + char *v4dumpfile = 0; + char *realm = 0; + char *mkey_name = 0; + char *mkey_fullname; + char *defrealm; + int keytypedone = 0; + int v4manual = 0; + int read_mkey = 0; + int tempdb = 0; + char *tempdbname; + krb5_context context; + char *stash_file = (char *) NULL; + krb5_realm_params *rparams; + int persist, op_ind; + + krb5_enctype etype = 0xffff; + + 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], "-d") && ((argc - op_ind) >= 2)) { + dbname = argv[op_ind+1]; + op_ind++; + } + else 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], "-r") && ((argc - op_ind) >= 2)) { + realm = argv[op_ind+1]; + op_ind++; + } + 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], "-k") && ((argc - op_ind) >= 2)) { + if (!krb5_string_to_keytype(argv[op_ind+1], + &master_keyblock.keytype)) + keytypedone++; + else + com_err(argv[0], 0, "%s is an invalid keytype", + argv[op_ind+1]); + op_ind++; + } + else if (!strcmp(argv[op_ind], "-M") && ((argc - op_ind) >= 2)) { + mkey_name = argv[op_ind+1]; + op_ind++; + } + else if (!strcmp(argv[op_ind], "-e") && ((argc - op_ind) >= 2)) { + if (krb5_string_to_enctype(argv[op_ind+1], &etype)) + com_err(argv[0], 0, "%s is an invalid encryption type", + argv[op_ind+1]); + op_ind++; + } + else if (!strcmp(argv[op_ind], "-n")) { + v4manual++; + } + else if (!strcmp(argv[op_ind], "-f") && ((argc - op_ind) >= 2)) { + if (v4dbname) { + usage(PROGNAME, 1); + return; + } + v4dumpfile = argv[op_ind+1]; + op_ind++; + } + else + persist = 0; + op_ind++; + } + + /* + * Attempt to read the KDC profile. If we do, then read appropriate values + * from it and augment values supplied on the command line. + */ + if (!(retval = krb5_read_realm_params(context, + realm, + (char *) NULL, + (char *) NULL, + &rparams))) { + /* Get the value for the database */ + if (rparams->realm_dbname && !dbname) + dbname = strdup(rparams->realm_dbname); + + /* Get the value for the master key name */ + if (rparams->realm_mkey_name && !mkey_name) + mkey_name = strdup(rparams->realm_mkey_name); + + /* Get the value for the master key type */ + if (rparams->realm_keytype_valid && !keytypedone) { + master_keyblock.keytype = rparams->realm_keytype; + keytypedone++; + } + + /* Get the value for the encryption type */ + if (rparams->realm_enctype_valid && (etype == 0xffff)) + etype = rparams->realm_enctype; + + /* Get the value for the stashfile */ + if (rparams->realm_stash_file) + stash_file = strdup(rparams->realm_stash_file); + + /* Get the value for maximum ticket lifetime. */ + if (rparams->realm_max_life_valid) + rblock.max_life = rparams->realm_max_life; + + /* Get the value for maximum renewable ticket lifetime. */ + if (rparams->realm_max_rlife_valid) + rblock.max_rlife = rparams->realm_max_rlife; + + /* Get the value for the default principal expiration */ + if (rparams->realm_expiration_valid) + rblock.expiration = rparams->realm_expiration; + + /* Get the value for the default principal flags */ + if (rparams->realm_flags_valid) + rblock.flags = rparams->realm_flags; + + krb5_free_realm_params(context, rparams); + } + + if (!v4dumpfile) { + usage(PROGNAME, 1); + return; + } + + if (!keytypedone) + master_keyblock.keytype = DEFAULT_KDC_KEYTYPE; + + if (!valid_keytype(master_keyblock.keytype)) { + com_err(PROGNAME, KRB5_PROG_KEYTYPE_NOSUPP, + "while setting up keytype %d", master_keyblock.keytype); + return; + } + + if (etype == 0xffff) + etype = DEFAULT_KDC_ETYPE; + + if (!valid_etype(etype)) { + com_err(PROGNAME, KRB5_PROG_ETYPE_NOSUPP, + "while setting up etype %d", etype); + return; + } + krb5_use_cstype(context, &master_encblock, etype); + + /* 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, v4dbname, 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 = process_v4_dump(context, v4dumpfile, realm); + 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); + krb5_free_context(context); + return; +} + +static int +v4init(pname, name, manual, dumpfile) +char *pname, *name; +int manual; +char *dumpfile; +{ + des_read_password(master_key, "Kerberos master key: ", 1); + 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_tl_mod_princ 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.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_princ.mod_date = princ->mod_date; + + entry.max_life = princ->max_life * 60 * 5; + entry.max_renewable_life = rblock.max_rlife; + entry.mkvno = 1; + 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.etype = master_keyblock.etype; + v4v5key.contents = (krb5_octet *)v4key; + v4v5key.keytype = KEYTYPE_DES; + 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.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_encode_mod_princ_data(context, &mod_princ, &entry); + if (retval) { + krb5_db_free_principal(context, &entry, 1); + krb5_free_principal(context, mod_princ.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.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_tl_mod_princ 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.mkvno = 1; + entry.len = KRB5_KDB_V1_BASE_LENGTH; + entry.expiration = pblock->expiration; + if (retval = krb5_copy_principal(context, &db_create_princ, + &mod_princ.mod_princ)) { + krb5_free_principal(context, entry.princ); + return(retval); + } + + if ((retval = krb5_timeofday(context, &mod_princ.mod_date)) || + (retval = krb5_copy_principal(context, &db_create_princ, + &mod_princ.mod_princ))) { + krb5_free_principal(context, mod_princ.mod_princ); + krb5_db_free_principal(context, &entry, 1); + return retval; + } + entry.attributes = pblock->flags; + + if (retval = krb5_dbe_create_key_data(context, &entry)) { + krb5_free_principal(context, mod_princ.mod_princ); + 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_free_principal(context, mod_princ.mod_princ); + 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_free_principal(context, mod_princ.mod_princ); + 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_free_principal(context, mod_princ.mod_princ); + 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_encode_mod_princ_data(context, &mod_princ, &entry); + if (!retval) + retval = krb5_db_put_principal(context, &entry, &nentries); + krb5_db_free_principal(context, &entry, 1); + krb5_free_principal(context, mod_princ.mod_princ); + 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) +krb5_context context; +char *dumpfile; +char *realm; +{ + 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); + 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 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; +} + +