diff options
Diffstat (limited to 'crypto/kerberosIV/admin/kdb_util.c')
-rw-r--r-- | crypto/kerberosIV/admin/kdb_util.c | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/crypto/kerberosIV/admin/kdb_util.c b/crypto/kerberosIV/admin/kdb_util.c new file mode 100644 index 0000000..b221fdd --- /dev/null +++ b/crypto/kerberosIV/admin/kdb_util.c @@ -0,0 +1,496 @@ +/* + * Copyright 1987, 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * <mit-copyright.h>. + * + * Kerberos database manipulation utility. This program allows you to + * dump a kerberos database to an ascii readable file and load this + * file into the database. Read locking of the database is done during a + * dump operation. NO LOCKING is done during a load operation. Loads + * should happen with other processes shutdown. + * + * Written July 9, 1987 by Jeffrey I. Schiller + */ + +#include "adm_locl.h" + +RCSID("$Id: kdb_util.c,v 1.35 1997/05/07 00:57:45 assar Exp $"); + +static des_cblock master_key, new_master_key; +static des_key_schedule master_key_schedule, new_master_key_schedule; + +#define zaptime(foo) memset((foo), 0, sizeof(*(foo))) + +/* cv_key is a procedure which takes a principle and changes its key, + either for a new method of encrypting the keys, or a new master key. + if cv_key is null no transformation of key is done (other than net byte + order). */ + +struct callback_args { + void (*cv_key)(Principal *); + FILE *output_file; +}; + +static void +print_time(FILE *file, time_t timeval) +{ + struct tm *tm; + tm = gmtime(&timeval); + fprintf(file, " %04d%02d%02d%02d%02d", + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_hour, + tm->tm_min); +} + +static long +time_explode(char *cp) +{ + char wbuf[5]; + struct tm tp; + int local; + + zaptime(&tp); /* clear out the struct */ + + if (strlen(cp) > 10) { /* new format */ + strncpy(wbuf, cp, 4); + wbuf[4] = 0; + tp.tm_year = atoi(wbuf) - 1900; + 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 = 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(tm2time(tp, local)); +} + +static int +dump_db_1(void *arg, Principal *principal) +{ /* replace null strings with "*" */ + struct callback_args *a = (struct callback_args *)arg; + + if (principal->instance[0] == '\0') { + principal->instance[0] = '*'; + principal->instance[1] = '\0'; + } + if (principal->mod_name[0] == '\0') { + principal->mod_name[0] = '*'; + principal->mod_name[1] = '\0'; + } + if (principal->mod_instance[0] == '\0') { + principal->mod_instance[0] = '*'; + principal->mod_instance[1] = '\0'; + } + if (a->cv_key != NULL) { + (*a->cv_key) (principal); + } + fprintf(a->output_file, "%s %s %d %d %d %d %x %x", + principal->name, + principal->instance, + principal->max_life, + principal->kdc_key_ver, + principal->key_version, + principal->attributes, + (int)htonl (principal->key_low), + (int)htonl (principal->key_high)); + print_time(a->output_file, principal->exp_date); + print_time(a->output_file, principal->mod_date); + fprintf(a->output_file, " %s %s\n", + principal->mod_name, + principal->mod_instance); + return 0; +} + +static int +dump_db (char *db_file, FILE *output_file, void (*cv_key) (Principal *)) +{ + struct callback_args a; + + a.cv_key = cv_key; + a.output_file = output_file; + + kerb_db_iterate ((k_iter_proc_t)dump_db_1, &a); + return fflush(output_file); +} + +static int +add_file(void *db, FILE *file) +{ + int ret; + int lineno = 0; + char line[1024]; + unsigned long key[2]; /* yes, long */ + Principal pr; + + char exp_date[64], mod_date[64]; + + int life, kkvno, kvno; + + while(1){ + memset(&pr, 0, sizeof(pr)); + errno = 0; + if(fgets(line, sizeof(line), file) == NULL){ + if(errno != 0) + err (1, "fgets"); + break; + } + lineno++; + ret = sscanf(line, "%s %s %d %d %d %hd %lx %lx %s %s %s %s", + pr.name, pr.instance, + &life, &kkvno, &kvno, + &pr.attributes, + &key[0], &key[1], + exp_date, mod_date, + pr.mod_name, pr.mod_instance); + if(ret != 12){ + warnx("Line %d malformed (ignored)", lineno); + continue; + } + pr.key_low = ntohl (key[0]); + pr.key_high = ntohl (key[1]); + pr.max_life = life; + pr.kdc_key_ver = kkvno; + pr.key_version = kvno; + pr.exp_date = time_explode(exp_date); + pr.mod_date = time_explode(mod_date); + if (pr.instance[0] == '*') + pr.instance[0] = 0; + if (pr.mod_name[0] == '*') + pr.mod_name[0] = 0; + if (pr.mod_instance[0] == '*') + pr.mod_instance[0] = 0; + if (kerb_db_update(db, &pr, 1) != 1) { + warn ("store %s.%s aborted", + pr.name, pr.instance); + return 1; + } + } + return 0; +} + +static void +load_db (char *db_file, FILE *input_file) +{ + long *db; + int temp1; + int code; + char *temp_db_file; + + temp1 = strlen(db_file)+2; + temp_db_file = malloc (temp1); + strcpy(temp_db_file, db_file); + strcat(temp_db_file, "~"); + + /* Create the database */ + if ((code = kerb_db_create(temp_db_file)) != 0) + err (1, "creating temp database %s", temp_db_file); + kerb_db_set_name(temp_db_file); + db = kerb_db_begin_update(); + if (db == NULL) + err (1, "opening temp database %s", temp_db_file); + + if(add_file(db, input_file)) + errx (1, "Load aborted"); + + kerb_db_end_update(db); + if ((code = kerb_db_rename(temp_db_file, db_file)) != 0) + warn("database rename failed"); + fclose(input_file); + free(temp_db_file); +} + +static void +merge_db(char *db_file, FILE *input_file) +{ + void *db; + + db = kerb_db_begin_update(); + if(db == NULL) + err (1, "Couldn't open database"); + if(add_file(db, input_file)) + errx (1, "Merge aborted"); + kerb_db_end_update(db); +} + +static void +update_ok_file (char *file_name) +{ + /* handle slave locking/failure stuff */ + char *file_ok; + int fd; + static char ok[]=".dump_ok"; + + asprintf (&file_ok, "%s%s", file_name, ok); + if (file_ok == NULL) + errx (1, "out of memory"); + if ((fd = open(file_ok, O_WRONLY|O_CREAT|O_TRUNC, 0400)) < 0) + err (1, "Error creating %s", file_ok); + free(file_ok); + close(fd); +} + +static void +convert_key_new_master (Principal *p) +{ + des_cblock key; + + /* leave null keys alone */ + if ((p->key_low == 0) && (p->key_high == 0)) return; + + /* move current key to des_cblock for encryption, special case master key + since that's changing */ + if ((strncmp (p->name, KERB_M_NAME, ANAME_SZ) == 0) && + (strncmp (p->instance, KERB_M_INST, INST_SZ) == 0)) { + memcpy (key, new_master_key, sizeof(des_cblock)); + (p->key_version)++; + } else { + copy_to_key(&p->key_low, &p->key_high, key); + kdb_encrypt_key (&key, &key, &master_key, master_key_schedule, DES_DECRYPT); + } + + kdb_encrypt_key (&key, &key, &new_master_key, new_master_key_schedule, DES_ENCRYPT); + + copy_from_key(key, &(p->key_low), &(p->key_high)); + memset(key, 0, sizeof (key)); /* a little paranoia ... */ + + (p->kdc_key_ver)++; +} + +static void +clear_secrets (void) +{ + memset(master_key, 0, sizeof (des_cblock)); + memset(master_key_schedule, 0, sizeof (des_key_schedule)); + memset(new_master_key, 0, sizeof (des_cblock)); + memset(new_master_key_schedule, 0, sizeof (des_key_schedule)); +} + +static void +convert_new_master_key (char *db_file, FILE *out) +{ +#ifdef RANDOM_MKEY + errx (1, "Sorry, this function is not available with " + "the new master key scheme."); +#else + printf ("\n\nEnter the CURRENT master key."); + if (kdb_get_master_key (KDB_GET_PROMPT, &master_key, + master_key_schedule) != 0) { + clear_secrets (); + errx (1, "Couldn't get master key."); + } + + if (kdb_verify_master_key (&master_key, master_key_schedule, stderr) < 0) { + clear_secrets (); + exit (1); + } + + printf ("\n\nNow enter the NEW master key. Do not forget it!!"); + if (kdb_get_master_key (KDB_GET_TWICE, &new_master_key, + new_master_key_schedule) != 0) { + clear_secrets (); + errx (1, "Couldn't get new master key."); + } + + dump_db (db_file, out, convert_key_new_master); + { + char fname[128]; + snprintf(fname, sizeof(fname), "%s.new", MKEYFILE); + kdb_kstash(&new_master_key, fname); + } +#endif /* RANDOM_MKEY */ +} + +static void +convert_key_old_db (Principal *p) +{ + des_cblock key; + + /* leave null keys alone */ + if ((p->key_low == 0) && (p->key_high == 0)) return; + + copy_to_key(&p->key_low, &p->key_high, key); + +#ifndef NOENCRYPTION + des_pcbc_encrypt((des_cblock *)key,(des_cblock *)key, + (long)sizeof(des_cblock),master_key_schedule, + (des_cblock *)master_key_schedule, DES_DECRYPT); +#endif + + /* make new key, new style */ + kdb_encrypt_key (&key, &key, &master_key, master_key_schedule, DES_ENCRYPT); + + copy_from_key(key, &(p->key_low), &(p->key_high)); + memset(key, 0, sizeof (key)); /* a little paranoia ... */ +} + +static void +convert_old_format_db (char *db_file, FILE *out) +{ + des_cblock key_from_db; + Principal principal_data[1]; + int n, more; + + if (kdb_get_master_key (KDB_GET_PROMPT, &master_key, + master_key_schedule) != 0L) { + clear_secrets(); + errx (1, "Couldn't get master key."); + } + + /* can't call kdb_verify_master_key because this is an old style db */ + /* lookup the master key version */ + n = kerb_get_principal(KERB_M_NAME, KERB_M_INST, principal_data, + 1 /* only one please */, &more); + if ((n != 1) || more) + errx (1, "verify_master_key: Kerberos error on master key lookup, %d found.\n", n); + + /* set up the master key */ + fprintf(stderr, "Current Kerberos master key version is %d.\n", + principal_data[0].kdc_key_ver); + + /* + * now use the master key to decrypt (old style) the key in the db, had better + * be the same! + */ + copy_to_key(&principal_data[0].key_low, + &principal_data[0].key_high, + key_from_db); +#ifndef NOENCRYPTION + des_pcbc_encrypt(&key_from_db,&key_from_db,(long)sizeof(key_from_db), + master_key_schedule,(des_cblock *)master_key_schedule, DES_DECRYPT); +#endif + /* the decrypted database key had better equal the master key */ + + n = memcmp(master_key, key_from_db, sizeof(master_key)); + memset(key_from_db, 0, sizeof(key_from_db)); + + if (n) { + fprintf(stderr, "\n\07\07verify_master_key: Invalid master key, "); + fprintf(stderr, "does not match database.\n"); + exit (1); + } + + fprintf(stderr, "Master key verified.\n"); + + dump_db (db_file, out, convert_key_old_db); +} + +int +main(int argc, char **argv) +{ + int ret; + FILE *file; + enum { + OP_LOAD, + OP_MERGE, + OP_DUMP, + OP_SLAVE_DUMP, + OP_NEW_MASTER, + OP_CONVERT_OLD_DB + } op; + char *file_name; + char *db_name; + + set_progname (argv[0]); + + if (argc != 3 && argc != 4) { + fprintf(stderr, "Usage: %s operation file [database name].\n", + argv[0]); + fprintf(stderr, "Operation is one of: " + "load, merge, dump, slave_dump, new_master_key, " + "convert_old_db\n"); + exit(1); + } + if (argc == 3) + db_name = DBM_FILE; + else + db_name = argv[3]; + + ret = kerb_db_set_name (db_name); + + /* this makes starting slave servers ~14.3 times easier */ + if(ret && strcmp(argv[1], "load") == 0) + ret = kerb_db_create (db_name); + + if(ret) + err (1, "Can't open database"); + + if (!strcmp(argv[1], "load")) + op = OP_LOAD; + else if (!strcmp(argv[1], "merge")) + op = OP_MERGE; + else if (!strcmp(argv[1], "dump")) + op = OP_DUMP; + else if (!strcmp(argv[1], "slave_dump")) + op = OP_SLAVE_DUMP; + else if (!strcmp(argv[1], "new_master_key")) + op = OP_NEW_MASTER; + else if (!strcmp(argv[1], "convert_old_db")) + op = OP_CONVERT_OLD_DB; + else { + warnx ("%s is an invalid operation.", argv[1]); + warnx ("Valid operations are \"load\", \"merge\", " + "\"dump\", \"slave_dump\", \"new_master_key\", " + "and \"convert_old_db\""); + return 1; + } + + file_name = argv[2]; + file = fopen(file_name, (op == OP_LOAD || op == OP_MERGE) ? "r" : "w"); + if (file == NULL) + err (1, "open %s", argv[2]); + + switch (op) { + case OP_DUMP: + if ((dump_db (db_name, file, (void (*)(Principal *)) 0) == EOF) || + (fclose(file) == EOF)) + err (1, "%s", file_name); + break; + case OP_SLAVE_DUMP: + if ((dump_db (db_name, file, (void (*)(Principal *)) 0) == EOF) || + (fclose(file) == EOF)) + err (1, "%s", file_name); + update_ok_file (file_name); + break; + case OP_LOAD: + load_db (db_name, file); + break; + case OP_MERGE: + merge_db (db_name, file); + break; + case OP_NEW_MASTER: + convert_new_master_key (db_name, file); + printf("Don't forget to do a `kdb_util load %s' to reload the database!\n", file_name); + break; + case OP_CONVERT_OLD_DB: + convert_old_format_db (db_name, file); + printf("Don't forget to do a `kdb_util load %s' to reload the database!\n", file_name); + break; + } + return 0; +} |