diff options
| author | Marc Horowitz <marc@mit.edu> | 1996-07-22 20:49:46 +0000 |
|---|---|---|
| committer | Marc Horowitz <marc@mit.edu> | 1996-07-22 20:49:46 +0000 |
| commit | edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1 (patch) | |
| tree | 6c2974a97b448c040fa4a31708ec5e02f187526c /src/kadmin/create/kdb5_create.c | |
| parent | 013bb1391582ed9e653ae706e398ddb8d08cfcc9 (diff) | |
| download | krb5-edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1.tar.gz krb5-edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1.tar.xz krb5-edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1.zip | |
this commit includes all the changes on the OV_9510_INTEGRATION and
OV_MERGE branches. This includes, but is not limited to, the new openvision
admin system, and major changes to gssapi to add functionality, and bring
the implementation in line with rfc1964. before committing, the
code was built and tested for netbsd and solaris.
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@8774 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/kadmin/create/kdb5_create.c')
| -rw-r--r-- | src/kadmin/create/kdb5_create.c | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/src/kadmin/create/kdb5_create.c b/src/kadmin/create/kdb5_create.c new file mode 100644 index 000000000..8b167b6b9 --- /dev/null +++ b/src/kadmin/create/kdb5_create.c @@ -0,0 +1,536 @@ +/* + * admin/create/kdb5_create.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 KDC database. + */ + +#include <stdio.h> +#include <k5-int.h> +#include <kadm5/admin.h> + +enum ap_op { + NULL_KEY, /* setup null keys */ + MASTER_KEY, /* use master key as new key */ + TGT_KEY /* special handling for tgt key */ +}; + +krb5_key_salt_tuple def_kslist = { ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_NORMAL }; + +struct realm_info { + krb5_deltat max_life; + krb5_deltat max_rlife; + krb5_timestamp expiration; + krb5_flags flags; + krb5_encrypt_block *eblock; + krb5_pointer rseed; + krb5_int32 nkslist; + krb5_key_salt_tuple *kslist; +} rblock = { /* XXX */ + KRB5_KDB_MAX_LIFE, + KRB5_KDB_MAX_RLIFE, + KRB5_KDB_EXPIRATION, + KRB5_KDB_DEF_FLAGS, + (krb5_encrypt_block *) NULL, + (krb5_pointer) NULL, + 1, + &def_kslist +}; + +struct iterate_args { + krb5_context ctx; + struct realm_info *rblock; + krb5_db_entry *dbentp; +}; + +static krb5_error_code add_principal + PROTOTYPE((krb5_context, + krb5_principal, + enum ap_op, + struct realm_info *)); + +/* + * Steps in creating a database: + * + * 1) use the db calls to open/create a new database + * + * 2) get a realm name for the new db + * + * 3) get a master password for the new db; convert to an encryption key. + * + * 4) create various required entries in the database + * + * 5) close & exit + */ + +static void +usage(who, status) +char *who; +int status; +{ + fprintf(stderr, "usage: %s [-d dbpathname] [-r realmname] [-k enctype]\n\ +\t[-M mkeyname]\n", + who); + exit(status); +} + +krb5_keyblock master_keyblock; +krb5_principal master_princ; +krb5_encrypt_block master_encblock; +krb5_data master_salt; + +krb5_data tgt_princ_entries[] = { + {0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME}, + {0, 0, 0} }; + +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 */ +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 */ +}; + +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 */ +}; + +char *mkey_password = 0; +char *whoami; + +void +main(argc, argv) +int argc; +char *argv[]; +{ + extern char *optarg; + int optchar; + + krb5_error_code retval; + char *dbname = (char *) NULL; + char *realm = 0; + char *mkey_name = 0; + char *mkey_fullname; + char *defrealm; + char *pw_str = 0; + char *keyfile = 0; + int pw_size = 0; + int enctypedone = 0; + int do_stash = 0; + krb5_data pwd; + krb5_context context; + krb5_realm_params *rparams; + kadm5_config_params kadm5_params; + + memset(&kadm5_params, 0, sizeof(kadm5_params)); + + krb5_init_context(&context); + krb5_init_ets(context); + + if (strrchr(argv[0], '/')) + argv[0] = strrchr(argv[0], '/')+1; + whoami = argv[0]; + + kadm5_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD; + kadm5_params.mkey_from_kbd = 1; + + while ((optchar = getopt(argc, argv, "d:r:k:M:e:P:sf:")) != EOF) { + switch(optchar) { + case 'd': /* set db name */ + kadm5_params.dbname = dbname = optarg; + kadm5_params.mask |= KADM5_CONFIG_DBNAME; + break; + case 'r': + kadm5_params.realm = realm = optarg; + kadm5_params.mask |= KADM5_CONFIG_REALM; + break; + case 'k': + if (!krb5_string_to_enctype(optarg, &master_keyblock.enctype)){ + enctypedone++; + kadm5_params.enctype = master_keyblock.enctype; + kadm5_params.mask |= KADM5_CONFIG_ENCTYPE; + } + else + com_err(argv[0], 0, "%s is an invalid enctype", optarg); + break; + case 's': + do_stash++; + kadm5_params.mkey_from_kbd = 0; + break; + case 'f': + kadm5_params.stash_file = keyfile = optarg; + kadm5_params.mask |= KADM5_CONFIG_STASH_FILE; + break; + case 'M': /* master key name in DB */ + kadm5_params.mkey_name = mkey_name = optarg; + kadm5_params.mask |= KADM5_CONFIG_MKEY_NAME; + break; + case 'P': /* Only used for testing!!! */ + mkey_password = optarg; + break; + case '?': + default: + usage(argv[0], 1); + /*NOTREACHED*/ + } + } + + /* + * 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_enctype_valid && !enctypedone) { + master_keyblock.enctype = rparams->realm_enctype; + enctypedone++; + } + + /* 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; + + /* Get the value of the supported key/salt pairs */ + if (rparams->realm_num_keysalts) { + rblock.nkslist = rparams->realm_num_keysalts; + rblock.kslist = rparams->realm_keysalts; + rparams->realm_num_keysalts = 0; + rparams->realm_keysalts = (krb5_key_salt_tuple *) NULL; + } + + /* Get the value for the stash file */ + if (rparams->realm_stash_file && !keyfile) + keyfile = strdup(rparams->realm_stash_file); + + krb5_free_realm_params(context, rparams); + } + + if (!dbname) + dbname = DEFAULT_KDB_FILE; + + if (!enctypedone) + master_keyblock.enctype = DEFAULT_KDC_ENCTYPE; + + if (!valid_enctype(master_keyblock.enctype)) { + char tmp[32]; + if (krb5_enctype_to_string(master_keyblock.enctype, tmp, sizeof(tmp))) + com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP, + "while setting up enctype %d", master_keyblock.enctype); + else + com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP, tmp); + exit(1); + } + + krb5_use_enctype(context, &master_encblock, master_keyblock.enctype); + + retval = krb5_db_set_name(context, dbname); + if (!retval) retval = EEXIST; + + if (retval == EEXIST || retval == EACCES || retval == EPERM) { + /* it exists ! */ + com_err(argv[0], 0, "The database '%s' appears to already exist", + dbname); + exit(1); + } + if (!realm) { + if ((retval = krb5_get_default_realm(context, &defrealm))) { + com_err(argv[0], retval, "while retrieving default realm name"); + exit(1); + } + 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(argv[0], retval, "while setting up master key name"); + exit(1); + } + + 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 (!mkey_password) { + printf("You will be prompted for the database Master Password.\n"); + printf("It is important that you NOT FORGET this password.\n"); + fflush(stdout); + + pw_size = 1024; + pw_str = malloc(pw_size); + + retval = krb5_read_password(context, KRB5_KDC_MKEY_1, KRB5_KDC_MKEY_2, + pw_str, &pw_size); + if (retval) { + com_err(argv[0], retval, "while reading master key from keyboard"); + exit(1); + } + mkey_password = pw_str; + } + + pwd.data = mkey_password; + pwd.length = strlen(mkey_password); + retval = krb5_principal2salt(context, master_princ, &master_salt); + if (retval) { + com_err(argv[0], retval, "while calculated master key salt"); + exit(1); + } + if (retval = krb5_string_to_key(context, &master_encblock, + &master_keyblock, &pwd, &master_salt)) { + com_err(argv[0], retval, "while transforming master key from password"); + exit(1); + } + + if ((retval = krb5_process_key(context, &master_encblock, + &master_keyblock))) { + com_err(argv[0], retval, "while processing master key"); + exit(1); + } + + rblock.eblock = &master_encblock; + if ((retval = krb5_init_random_key(context, &master_encblock, + &master_keyblock, &rblock.rseed))) { + com_err(argv[0], retval, "while initializing random key generator"); + (void) krb5_finish_key(context, &master_encblock); + exit(1); + } + if ((retval = krb5_db_create(context, dbname))) { + (void) krb5_finish_key(context, &master_encblock); + (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); + com_err(argv[0], retval, "while creating database '%s'", + dbname); + exit(1); + } + if ((retval = krb5_db_set_name(context, dbname))) { + (void) krb5_finish_key(context, &master_encblock); + (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); + com_err(argv[0], retval, "while setting active database to '%s'", + dbname); + exit(1); + } + if ((retval = krb5_db_init(context))) { + (void) krb5_finish_key(context, &master_encblock); + (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); + com_err(argv[0], retval, "while initializing the database '%s'", + dbname); + exit(1); + } + + if ((retval = add_principal(context, master_princ, MASTER_KEY, &rblock)) || + (retval = add_principal(context, &tgt_princ, TGT_KEY, &rblock))) { + (void) krb5_db_fini(context); + (void) krb5_finish_key(context, &master_encblock); + (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed); + com_err(argv[0], retval, "while adding entries to the database"); + exit(1); + } + if (do_stash && + ((retval = krb5_db_store_mkey(context, keyfile, master_princ, + &master_keyblock)))) { + com_err(argv[0], errno, "while storing key"); + printf("Warning: couldn't stash master key.\n"); + } + /* clean up */ + (void) krb5_db_fini(context); + (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); + free(master_keyblock.contents); + if (pw_str) { + memset(pw_str, 0, pw_size); + free(pw_str); + } + free(master_salt.data); + + kadm5_create(&kadm5_params); + + exit(0); + +} + +static krb5_error_code +tgt_keysalt_iterate(ksent, ptr) + krb5_key_salt_tuple *ksent; + krb5_pointer ptr; +{ + krb5_context context; + krb5_error_code kret; + struct iterate_args *iargs; + krb5_keyblock random_keyblock, *key; + krb5_int32 ind; + krb5_encrypt_block random_encblock; + krb5_pointer rseed; + krb5_data pwd; + + iargs = (struct iterate_args *) ptr; + kret = 0; + + context = iargs->ctx; + + /* + * Convert the master key password into a key for this particular + * encryption system. + */ + krb5_use_enctype(context, &random_encblock, ksent->ks_enctype); + pwd.data = mkey_password; + pwd.length = strlen(mkey_password); + if (kret = krb5_string_to_key(context, &random_encblock, &random_keyblock, + &pwd, &master_salt)) + return kret; + if ((kret = krb5_init_random_key(context, &random_encblock, + &random_keyblock, &rseed))) + return kret; + + if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) { + ind = iargs->dbentp->n_key_data-1; + if (!(kret = krb5_random_key(context, + &random_encblock, rseed, + &key))) { + kret = krb5_dbekd_encrypt_key_data(context, + iargs->rblock->eblock, + key, + NULL, + 1, + &iargs->dbentp->key_data[ind]); + krb5_free_keyblock(context, key); + } + } + memset((char *)random_keyblock.contents, 0, random_keyblock.length); + free(random_keyblock.contents); + (void) krb5_finish_random_key(context, &random_encblock, &rseed); + return(kret); +} + +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_error_code retval; + krb5_db_entry entry; + + krb5_timestamp now; + struct iterate_args iargs; + + int nentries = 1; + + memset((char *) &entry, 0, sizeof(entry)); + + entry.len = KRB5_KDB_V1_BASE_LENGTH; + entry.attributes = pblock->flags; + entry.max_life = pblock->max_life; + entry.max_renewable_life = pblock->max_rlife; + entry.expiration = pblock->expiration; + + if ((retval = krb5_copy_principal(context, princ, &entry.princ))) + goto error_out; + + if ((retval = krb5_timeofday(context, &now))) + goto error_out; + + if ((retval = krb5_dbe_update_mod_princ_data(context, &entry, + now, &db_create_princ))) + goto error_out; + + switch (op) { + case MASTER_KEY: + if ((entry.key_data=(krb5_key_data*)malloc(sizeof(krb5_key_data))) + == NULL) + goto error_out; + memset((char *) entry.key_data, 0, sizeof(krb5_key_data)); + entry.n_key_data = 1; + + entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX; + if ((retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock, + &master_keyblock, NULL, + 1, entry.key_data))) + return retval; + break; + case TGT_KEY: + iargs.ctx = context; + iargs.rblock = pblock; + iargs.dbentp = &entry; + /* + * Iterate through the key/salt list, ignoring salt types. + */ + if ((retval = krb5_keysalt_iterate(pblock->kslist, + pblock->nkslist, + 1, + tgt_keysalt_iterate, + (krb5_pointer) &iargs))) + return retval; + break; + case NULL_KEY: + return EOPNOTSUPP; + default: + break; + } + + retval = krb5_db_put_principal(context, &entry, &nentries); + +error_out:; + krb5_dbe_free_contents(context, &entry); + return retval; +} |
