tests tests/resolve tests/asn.1 tests/create tests/hammer
tests/verify tests/gssapi tests/dejagnu tests/threads tests/shlib
- tests/gss-threads tests/misc
+ tests/gss-threads tests/misc tests/mkeystash_compat
util/collected-client-lib
)
void krb5int_free_srv_dns_data(struct srv_dns_entry *);
#endif
+/* value to use when requesting a keytab entry and KVNO doesn't matter */
+#define IGNORE_VNO 0
+/* value to use when requesting a keytab entry and enctype doesn't matter */
+#define IGNORE_ENCTYPE 0
+
/*
* Convenience function for structure magic number
*/
krb5_error_code krb5_db_free_master_key ( krb5_context kcontext,
krb5_keyblock *key );
krb5_error_code krb5_db_store_master_key ( krb5_context kcontext,
- char *db_arg,
+ char *keyfile,
krb5_principal mname,
+ krb5_kvno kvno,
krb5_keyblock *key,
char *master_pwd);
krb5_error_code krb5_db_fetch_mkey ( krb5_context context,
krb5_boolean fromkeyboard,
krb5_boolean twice,
char *db_args,
+ krb5_kvno *kvno,
krb5_data *salt,
krb5_keyblock *key);
-krb5_error_code krb5_db_verify_master_key ( krb5_context kcontext,
+krb5_error_code krb5_db_verify_master_key ( krb5_context kcontext,
krb5_principal mprinc,
- krb5_keyblock *mkey );
+ krb5_kvno kvno,
+ krb5_keyblock *mkey );
krb5_error_code
krb5_dbe_find_enctype( krb5_context kcontext,
krb5_db_entry *dbentp,
krb5_def_store_mkey( krb5_context context,
char *keyfile,
krb5_principal mname,
+ krb5_kvno kvno,
krb5_keyblock *key,
char *master_pwd);
krb5_db_def_fetch_mkey( krb5_context context,
krb5_principal mname,
krb5_keyblock *key,
- int *kvno,
+ krb5_kvno *kvno,
char *db_args);
krb5_error_code
-krb5_def_verify_master_key( krb5_context context,
+krb5_def_verify_master_key( krb5_context context,
krb5_principal mprinc,
+ krb5_kvno kvno,
krb5_keyblock *mkey);
krb5_error_code kdb_def_set_mkey ( krb5_context kcontext,
int i, j;
krb5_key_data new_key_data, *key_data;
krb5_boolean is_mkey;
+ krb5_kvno kvno;
is_mkey = krb5_principal_compare(context, master_princ, db_entry->princ);
return retval;
memset(&new_key_data, 0, sizeof(new_key_data));
- key_ptr = is_mkey ? &new_master_keyblock : &v5plainkey;
+
+ if (is_mkey) {
+ key_ptr = &new_master_keyblock;
+ /* override mkey princ's kvno */
+ if (global_params.mask & KADM5_CONFIG_KVNO)
+ kvno = global_params.kvno;
+ else
+ kvno = (krb5_kvno) key_data->key_data_kvno;
+ } else {
+ key_ptr = &v5plainkey;
+ kvno = (krb5_kvno) key_data->key_data_kvno;
+ }
+
retval = krb5_dbekd_encrypt_key_data(context, &new_master_keyblock,
key_ptr, &keysalt,
- key_data->key_data_kvno,
+ (int) kvno,
&new_key_data);
if (retval)
return retval;
master_princ,
master_keyblock.enctype,
TRUE, FALSE,
- (char *) NULL, 0,
+ (char *) NULL,
+ NULL, NULL,
&master_keyblock);
if (retval) {
com_err(progname, retval,
}
retval = krb5_db_verify_master_key(util_context,
master_princ,
+ IGNORE_VNO,
&master_keyblock);
if (retval) {
com_err(progname, retval,
new_master_keyblock.enctype = global_params.enctype;
if (new_master_keyblock.enctype == ENCTYPE_UNKNOWN)
new_master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
- if (!new_mkey_file)
+
+ if (new_mkey_file) {
+ krb5_kvno kt_kvno;
+
+ if (global_params.mask & KADM5_CONFIG_KVNO)
+ kt_kvno = global_params.kvno;
+ else
+ kt_kvno = IGNORE_VNO;
+
+ if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
+ new_master_keyblock.enctype,
+ FALSE,
+ FALSE,
+ new_mkey_file,
+ &kt_kvno,
+ NULL,
+ &new_master_keyblock))) {
+ com_err(progname, retval, "while reading new master key");
+ exit(1);
+ }
+ } else {
printf("Please enter new master key....\n");
- if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
- new_master_keyblock.enctype,
- (new_mkey_file == 0) ?
- (krb5_boolean) 1 : 0,
- TRUE,
- new_mkey_file, 0,
- &new_master_keyblock))) {
- com_err(progname, retval, "while reading new master key");
- exit(1);
+ if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
+ new_master_keyblock.enctype,
+ TRUE,
+ TRUE,
+ NULL, NULL, NULL,
+ &new_master_keyblock))) {
+ com_err(progname, retval, "while reading new master key");
+ exit(1);
+ }
}
}
int do_stash = 0;
krb5_data pwd, seed;
kdb_log_context *log_ctx;
+ krb5_kvno mkey_kvno;
while ((optchar = getopt(argc, argv, "s")) != -1) {
switch(optchar) {
* it; delete the file below if it was not requested. DO NOT EXIT
* BEFORE DELETING THE KEYFILE if do_stash is not set.
*/
+
+ /*
+ * Determine the kvno to use, it must be that used to create the master key
+ * princ.
+ */
+ if (global_params.mask & KADM5_CONFIG_KVNO)
+ mkey_kvno = global_params.kvno; /* user specified */
+ else
+ mkey_kvno = 1; /* Default */
+
retval = krb5_db_store_master_key(util_context,
global_params.stash_file,
master_princ,
+ mkey_kvno,
&master_keyblock,
mkey_password);
if (retval) {
{
krb5_error_code retval;
krb5_db_entry entry;
+ krb5_kvno mkey_kvno;
krb5_timestamp now;
struct iterate_args iargs;
memset((char *) entry.key_data, 0, sizeof(krb5_key_data));
entry.n_key_data = 1;
+ if (global_params.mask & KADM5_CONFIG_KVNO)
+ mkey_kvno = global_params.kvno; /* user specified */
+ else
+ mkey_kvno = 1; /* Default */
entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
if ((retval = krb5_dbekd_encrypt_key_data(context, pblock->key,
&master_keyblock, NULL,
- 1, entry.key_data)))
+ mkey_kvno, entry.key_data)))
return retval;
break;
case TGT_KEY:
char *mkey_fullname;
char *keyfile = 0;
krb5_context context;
+ krb5_kvno mkey_kvno;
retval = kadm5_init_krb5_context(&context);
if( retval )
exit_status++; return;
}
+ if (global_params.mask & KADM5_CONFIG_KVNO)
+ mkey_kvno = global_params.kvno; /* user specified */
+ else
+ mkey_kvno = IGNORE_VNO; /* use whatever krb5_db_fetch_mkey finds */
+
/* TRUE here means read the keyboard, but only once */
retval = krb5_db_fetch_mkey(context, master_princ,
master_keyblock.enctype,
TRUE, FALSE, (char *) NULL,
- 0, &master_keyblock);
+ &mkey_kvno,
+ NULL, &master_keyblock);
if (retval) {
com_err(progname, retval, "while reading master key");
(void) krb5_db_fini(context);
}
retval = krb5_db_verify_master_key(context, master_princ,
+ mkey_kvno,
&master_keyblock);
if (retval) {
com_err(progname, retval, "while verifying master key");
}
retval = krb5_db_store_master_key(context, keyfile, master_princ,
- &master_keyblock, NULL);
+ mkey_kvno, &master_keyblock, NULL);
if (retval) {
com_err(progname, errno, "while storing key");
memset((char *)master_keyblock.contents, 0, master_keyblock.length);
.B kdb5_util
[\fB\-r\fP\ \fIrealm\fP] [\fB\-d\fP\ \fIdbname\fP]
[\fB\-k\fP\ \fImkeytype\fP] [\fB\-M\fP\ \fImkeyname\fP]
+[\fB\-kv\fP\ \fImkeyVNO\fP]
[\fB\-sf\fP\ \fIstashfilename\fP]
[\fB\-m\fP]
.I command
that given in
.IR kdc.conf .
.TP
+\fB\-kv\fP\ \fImkeyVNO\fP
+Specifies the version number of the master key in the database; the default is
+1. Note that 0 is not allowed.
+.TP
\fB\-M\fP\ \fImkeyname\fP
principal name for the master key in the database; the default is
that given in
{
fprintf(stderr, "Usage: "
"kdb5_util [-x db_args]* [-r realm] [-d dbname] [-k mkeytype] [-M mkeyname]\n"
- "\t [-sf stashfilename] [-m] cmd [cmd_options]\n"
+ "\t [-kv mkeyVNO] [-sf stashfilename] [-m] cmd [cmd_options]\n"
"\tcreate [-s]\n"
"\tdestroy [-f]\n"
"\tstash [-f keyfile]\n"
}
memset(cmd_argv, 0, sizeof(char *)*argc);
cmd_argc = 1;
-
+
argv++; argc--;
while (*argv) {
if (strcmp(*argv, "-P") == 0 && ARG_VAL) {
exit(1);
}
} else if (strcmp(*argv, "-k") == 0 && ARG_VAL) {
- if (krb5_string_to_enctype(koptarg, &global_params.enctype))
- com_err(progname, 0, "%s is an invalid enctype", koptarg);
- else
+ if (krb5_string_to_enctype(koptarg, &global_params.enctype)) {
+ com_err(progname, EINVAL, ": %s is an invalid enctype", koptarg);
+ exit(1);
+ } else
global_params.mask |= KADM5_CONFIG_ENCTYPE;
+ } else if (strcmp(*argv, "-kv") == 0 && ARG_VAL) {
+ global_params.kvno = (krb5_kvno) atoi(koptarg);
+ if (global_params.kvno == IGNORE_VNO) {
+ com_err(progname, EINVAL, ": %s is an invalid mkeyVNO", koptarg);
+ exit(1);
+ } else
+ global_params.mask |= KADM5_CONFIG_KVNO;
} else if (strcmp(*argv, "-M") == 0 && ARG_VAL) {
global_params.mkey_name = koptarg;
global_params.mask |= KADM5_CONFIG_MKEY_NAME;
int nentries;
krb5_boolean more;
krb5_data scratch, pwd, seed;
+ krb5_kvno kvno;
dbactive = FALSE;
valid_master_key = 0;
return(1);
}
+ if (global_params.mask & KADM5_CONFIG_KVNO)
+ kvno = global_params.kvno; /* user specified */
+ else
+ kvno = (krb5_kvno) master_entry.key_data->key_data_kvno;
+
krb5_db_free_principal(util_context, &master_entry, nentries);
/* the databases are now open, and the master principal exists */
}
/* If no encryption type is set, use the default */
- if (master_keyblock.enctype == ENCTYPE_UNKNOWN) {
+ if (master_keyblock.enctype == ENCTYPE_UNKNOWN)
master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
- if (!krb5_c_valid_enctype(master_keyblock.enctype))
- com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
- "while setting up enctype %d",
- master_keyblock.enctype);
- }
+ if (!krb5_c_valid_enctype(master_keyblock.enctype))
+ com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
+ "while setting up enctype %d",
+ master_keyblock.enctype);
retval = krb5_c_string_to_key(util_context, master_keyblock.enctype,
&pwd, &scratch, &master_keyblock);
}
free(scratch.data);
mkey_password = 0;
+
} else if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
master_keyblock.enctype,
manual_mkey, FALSE,
global_params.stash_file,
+ &kvno,
0, &master_keyblock))) {
com_err(progname, retval, "while reading master key");
com_err(progname, 0, "Warning: proceeding without master key");
return(0);
}
if ((retval = krb5_db_verify_master_key(util_context, master_princ,
- &master_keyblock))) {
+ kvno, &master_keyblock))) {
com_err(progname, retval, "while verifying master key");
exit_status++;
krb5_free_keyblock_contents(util_context, &master_keyblock);
if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc,
rdp->realm_mkey.enctype, manual,
FALSE, rdp->realm_stash,
- 0, &rdp->realm_mkey))) {
+ NULL, NULL, &rdp->realm_mkey))) {
com_err(progname, kret,
"while fetching master key %s for realm %s",
rdp->realm_mpname, realm);
/* Verify the master key */
if ((kret = krb5_db_verify_master_key(rdp->realm_context,
rdp->realm_mprinc,
+ IGNORE_VNO,
&rdp->realm_mkey))) {
com_err(progname, kret,
"while verifying master key for realm %s", realm);
#define KADM5_CONFIG_POLL_TIME 0x04000000
#define KADM5_CONFIG_IPROP_LOGFILE 0x08000000
#define KADM5_CONFIG_IPROP_PORT 0x10000000
+#define KADM5_CONFIG_KVNO 0x20000000
/*
* permission bits
*/
krb5_flags flags;
krb5_key_salt_tuple *keysalts;
krb5_int32 num_keysalts;
-
+ krb5_kvno kvno;
bool_t iprop_enabled;
uint32_t iprop_ulogsize;
krb5_deltat iprop_poll_time;
params.realm = lrealm;
params.mask |= KADM5_CONFIG_REALM;
}
+
+ if (params_in->mask & KADM5_CONFIG_KVNO) {
+ params.kvno = params_in->kvno;
+ params.mask |= KADM5_CONFIG_KVNO;
+ }
/*
* XXX These defaults should to work on both client and
* server. kadm5_get_config_params can be implemented as a
master_keyblock.enctype, from_kbd,
FALSE /* only prompt once */,
handle->params.stash_file,
+ NULL /* don't care about kvno */,
NULL /* I'm not sure about this,
but it's what the kdc does --marc */,
&master_keyblock);
goto done;
if ((ret = krb5_db_verify_master_key(handle->context, master_princ,
- &master_keyblock))) {
+ IGNORE_VNO, &master_keyblock))) {
krb5_db_fini(handle->context);
return ret;
}
[config_params {KADM5_CONFIG_MKEY_NAME} does/not/exist] \
$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
server_handle
- } "KDB_NOMASTERKEY"
+ } "KRB5_KDB_CANTREAD_STORED"
}
if {! $RPC} test108
krb5_error_code
krb5_db_store_master_key(krb5_context kcontext,
- char *db_arg,
+ char *keyfile,
krb5_principal mname,
+ krb5_kvno kvno,
krb5_keyblock * key, char *master_pwd)
{
krb5_error_code status = 0;
}
status = dal_handle->lib_handle->vftabl.store_master_key(kcontext,
- db_arg,
+ keyfile,
mname,
+ kvno,
key, master_pwd);
get_errmsg(kcontext, status);
kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2;
krb5_error_code
-krb5_db_fetch_mkey(krb5_context context,
- krb5_principal mname,
- krb5_enctype etype,
- krb5_boolean fromkeyboard,
- krb5_boolean twice,
- char *db_args, krb5_data * salt, krb5_keyblock * key)
+krb5_db_fetch_mkey(krb5_context context,
+ krb5_principal mname,
+ krb5_enctype etype,
+ krb5_boolean fromkeyboard,
+ krb5_boolean twice,
+ char * db_args,
+ krb5_kvno * kvno,
+ krb5_data * salt,
+ krb5_keyblock * key)
{
krb5_error_code retval;
char password[BUFSIZ];
krb5_data pwd;
unsigned int size = sizeof(password);
- int kvno;
krb5_keyblock tmp_key;
memset(&tmp_key, 0, sizeof(tmp_key));
retval =
krb5_c_string_to_key(context, etype, &pwd, salt ? salt : &scratch,
key);
+ /*
+ * If a kvno pointer was passed in and it dereferences the IGNORE_VNO
+ * value then it should be assigned the value of the kvno associated
+ * with the current mkey princ key if that princ entry is available
+ * otherwise assign 1 which is the default kvno value for the mkey
+ * princ.
+ */
+ if (kvno != NULL && *kvno == IGNORE_VNO) {
+ int nentries = 1;
+ krb5_boolean more;
+ krb5_error_code rc;
+ krb5_db_entry master_entry;
+
+ rc = krb5_db_get_principal(context, mname,
+ &master_entry, &nentries, &more);
+
+ if (rc == 0 && nentries == 1 && more == FALSE)
+ *kvno = (krb5_kvno) master_entry.key_data->key_data_kvno;
+ else
+ *kvno = 1;
+
+ if (rc == 0 && nentries)
+ krb5_db_free_principal(context, &master_entry, nentries);
+ }
if (!salt)
krb5_xfree(scratch.data);
retval = dal_handle->lib_handle->vftabl.fetch_master_key(context,
mname,
&tmp_key,
- &kvno,
+ kvno,
db_args);
get_errmsg(context, retval);
kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
}
krb5_error_code
-krb5_db_verify_master_key(krb5_context kcontext,
- krb5_principal mprinc, krb5_keyblock * mkey)
+krb5_db_verify_master_key(krb5_context kcontext,
+ krb5_principal mprinc,
+ krb5_kvno kvno,
+ krb5_keyblock * mkey)
{
krb5_error_code status = 0;
kdb5_dal_handle *dal_handle;
}
status = dal_handle->lib_handle->vftabl.verify_master_key(kcontext,
- mprinc, mkey);
+ mprinc,
+ kvno,
+ mkey);
get_errmsg(kcontext, status);
kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
krb5_error_code (*store_master_key) (krb5_context kcontext,
char *db_arg,
krb5_principal mname,
+ krb5_kvno kvno,
krb5_keyblock *key,
char *master_pwd);
krb5_error_code (*fetch_master_key) (krb5_context kcontext,
krb5_principal mname,
krb5_keyblock *key,
- int *kvno,
+ krb5_kvno *kvno,
char *db_args);
krb5_error_code (*verify_master_key) (krb5_context kcontext,
krb5_principal mprinc,
+ krb5_kvno kvno,
krb5_keyblock *mkey);
krb5_error_code (*dbe_search_enctype) (krb5_context kcontext,
#endif
krb5_error_code
-krb5_def_store_mkey(context, keyfile, mname, key, master_pwd)
- krb5_context context;
- char *keyfile;
- krb5_principal mname;
- krb5_keyblock *key;
- char *master_pwd;
+krb5_def_store_mkey(krb5_context context,
+ char *keyfile,
+ krb5_principal mname,
+ krb5_kvno kvno,
+ krb5_keyblock *key,
+ char *master_pwd)
{
- FILE *kf;
krb5_error_code retval = 0;
- krb5_ui_2 enctype;
- krb5_ui_4 keylength;
char defkeyfile[MAXPATHLEN+1];
+ char *tmp_ktname = NULL, *tmp_ktpath;
krb5_data *realm = krb5_princ_realm(context, mname);
-#if HAVE_UMASK
- mode_t oumask;
-#endif
+ krb5_keytab kt;
+ krb5_keytab_entry new_entry;
+ struct stat stb;
+ int statrc;
if (!keyfile) {
- (void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB);
- (void) strncat(defkeyfile, realm->data,
- min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1,
- realm->length));
- defkeyfile[sizeof(defkeyfile) - 1] = '\0';
- keyfile = defkeyfile;
+ (void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB);
+ (void) strncat(defkeyfile, realm->data,
+ min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1,
+ realm->length));
+ defkeyfile[sizeof(defkeyfile) - 1] = '\0';
+ keyfile = defkeyfile;
}
-#if HAVE_UMASK
- oumask = umask(077);
-#endif
-#ifdef ANSI_STDIO
- if (!(kf = fopen(keyfile, "wb")))
-#else
- if (!(kf = fopen(keyfile, "w")))
-#endif
- {
- int e = errno;
-#if HAVE_UMASK
- (void) umask(oumask);
-#endif
- krb5_set_error_message (context, e,
- "%s accessing file '%s'",
- error_message (e), keyfile);
- return e;
+ /*
+ * XXX making the assumption that the keyfile is in a dir that requires root
+ * privilege to write to thus making timing attacks unlikely.
+ */
+ if ((statrc = stat(keyfile, &stb)) >= 0) {
+ /* if keyfile exists it better be a regular file */
+ if (!S_ISREG(stb.st_mode)) {
+ retval = EINVAL;
+ krb5_set_error_message (context, retval,
+ "keyfile (%s) is not a regular file: %s",
+ keyfile, error_message(retval));
+ goto out;
+ }
}
- set_cloexec_file(kf);
-#if BIG_ENDIAN_MASTER_KEY
- enctype = htons((uint16_t) key->enctype);
- keylength = htonl((uint32_t) key->length);
-#else
- enctype = key->enctype;
- keylength = key->length;
-#endif
- if ((fwrite((krb5_pointer) &enctype,
- 2, 1, kf) != 1) ||
- (fwrite((krb5_pointer) &keylength,
- sizeof(keylength), 1, kf) != 1) ||
- (fwrite((krb5_pointer) key->contents,
- sizeof(key->contents[0]), (unsigned) key->length,
- kf) != key->length)) {
- retval = errno;
- (void) fclose(kf);
- } else if (fclose(kf) == EOF)
- retval = errno;
-#if HAVE_UMASK
- (void) umask(oumask);
-#endif
+
+ /* Use temp keytab file name in case creation of keytab fails */
+
+ /* create temp file template for use by mktemp() */
+ if ((retval = asprintf(&tmp_ktname, "WRFILE:%s_XXXXXX", keyfile)) < 0) {
+ krb5_set_error_message (context, retval,
+ "Could not create temp keytab file name.");
+ goto out;
+ }
+
+ if (mktemp(tmp_ktname) == NULL) {
+ retval = errno;
+ krb5_set_error_message (context, retval,
+ "Could not create temp stash file: %s",
+ error_message(errno));
+ goto out;
+ }
+
+ /* create new stash keytab using temp file name */
+ retval = krb5_kt_resolve(context, tmp_ktname, &kt);
+ if (retval != 0)
+ goto out;
+
+ memset((char *) &new_entry, 0, sizeof(new_entry));
+ new_entry.principal = mname;
+ new_entry.key = *key;
+ new_entry.vno = kvno;
+
+ /*
+ * Set tmp_ktpath to point to the keyfile path (skip WRFILE:). Subtracting
+ * 1 to account for NULL terminator in sizeof calculation of a string
+ * constant. Used further down.
+ */
+ tmp_ktpath = tmp_ktname + (sizeof("WRFILE:") - 1);
+
+ retval = krb5_kt_add_entry(context, kt, &new_entry);
+ if (retval != 0) {
+ /* delete tmp keyfile if it exists and an error occurrs */
+ if (stat(keyfile, &stb) >= 0)
+ (void) unlink(tmp_ktpath);
+ } else {
+ /* rename original keyfile to original filename */
+ if (rename(tmp_ktpath, keyfile) < 0) {
+ retval = errno;
+ krb5_set_error_message (context, retval,
+ "rename of temporary keyfile (%s) to (%s) failed: %s",
+ tmp_ktpath, keyfile, error_message(errno));
+ }
+ }
+
+out:
+ if (tmp_ktname != NULL)
+ free(tmp_ktname);
+
return retval;
}
-
-krb5_error_code
-krb5_db_def_fetch_mkey( krb5_context context,
- krb5_principal mname,
- krb5_keyblock *key,
- int *kvno,
- char *db_args)
+static krb5_error_code
+krb5_db_def_fetch_mkey_stash(krb5_context context,
+ const char *keyfile,
+ krb5_keyblock *key,
+ krb5_kvno *kvno)
{
- krb5_error_code retval;
+ krb5_error_code retval = 0;
krb5_ui_2 enctype;
krb5_ui_4 keylength;
- char defkeyfile[MAXPATHLEN+1];
- krb5_data *realm = krb5_princ_realm(context, mname);
FILE *kf = NULL;
- retval = 0;
- key->magic = KV5M_KEYBLOCK;
- (void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB);
- (void) strncat(defkeyfile, realm->data,
- min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1,
- realm->length));
- defkeyfile[sizeof(defkeyfile) - 1] = '\0';
-
#ifdef ANSI_STDIO
- if (!(kf = fopen((db_args) ? db_args : defkeyfile, "rb")))
+ if (!(kf = fopen(keyfile, "rb")))
#else
- if (!(kf = fopen((db_args) ? db_args : defkeyfile, "r")))
+ if (!(kf = fopen(keyfile, "r")))
#endif
return KRB5_KDB_CANTREAD_STORED;
set_cloexec_file(kf);
#else
key->length = keylength;
#endif
-
+
if (!key->length || ((int) key->length) < 0) {
retval = KRB5_KDB_BADSTORED_MKEY;
goto errout;
goto errout;
}
- if (fread((krb5_pointer) key->contents,
- sizeof(key->contents[0]), key->length, kf)
- != key->length) {
+ if (fread((krb5_pointer) key->contents, sizeof(key->contents[0]),
+ key->length, kf) != key->length) {
retval = KRB5_KDB_CANTREAD_STORED;
memset(key->contents, 0, key->length);
free(key->contents);
} else
retval = 0;
- *kvno = 0;
+ /*
+ * Note, the old stash format did not store the kvno and at this point it
+ * can be assumed to be 1 as is the case for the mkey princ. If the kvno is
+ * passed in and isn't ignore_vno just leave it alone as this could cause
+ * verifcation trouble if the mkey princ is using a kvno other than 1.
+ */
+ if (kvno && *kvno == IGNORE_VNO)
+ *kvno = 1;
errout:
(void) fclose(kf);
return retval;
+}
+static krb5_error_code
+krb5_db_def_fetch_mkey_keytab(krb5_context context,
+ const char *keyfile,
+ krb5_principal mname,
+ krb5_keyblock *key,
+ krb5_kvno *kvno)
+{
+ krb5_error_code retval = 0;
+ krb5_keytab kt;
+ krb5_keytab_entry kt_ent;
+ krb5_enctype enctype = IGNORE_ENCTYPE;
+
+ if ((retval = krb5_kt_resolve(context, keyfile, &kt)) != 0)
+ goto errout;
+
+ /* override default */
+ if (key->enctype != ENCTYPE_UNKNOWN)
+ enctype = key->enctype;
+
+ if ((retval = krb5_kt_get_entry(context, kt, mname,
+ kvno ? *kvno : IGNORE_VNO,
+ enctype,
+ &kt_ent)) == 0) {
+
+ if (key->enctype == ENCTYPE_UNKNOWN)
+ key->enctype = kt_ent.key.enctype;
+
+ if (((int) kt_ent.key.length) < 0) {
+ retval = KRB5_KDB_BADSTORED_MKEY;
+ krb5_kt_free_entry(context, &kt_ent);
+ goto errout;
+ }
+
+ key->length = kt_ent.key.length;
+
+ /*
+ * If a kvno pointer was passed in and it dereferences the
+ * IGNORE_VNO value then it should be assigned the value of the kvno
+ * found in the keytab otherwise the KNVO specified should be the
+ * same as the one returned from the keytab.
+ */
+ if (kvno != NULL && *kvno == IGNORE_VNO)
+ *kvno = kt_ent.vno;
+
+ /*
+ * kt_ent will be free'd so need to allocate and copy key contents for
+ * output to caller.
+ */
+ if (!(key->contents = (krb5_octet *)malloc(key->length))) {
+ retval = ENOMEM;
+ krb5_kt_free_entry(context, &kt_ent);
+ goto errout;
+ }
+ memcpy(key->contents, kt_ent.key.contents, kt_ent.key.length);
+ krb5_kt_free_entry(context, &kt_ent);
+ }
+
+errout:
+ return retval;
}
+krb5_error_code
+krb5_db_def_fetch_mkey(krb5_context context,
+ krb5_principal mname,
+ krb5_keyblock *key,
+ krb5_kvno *kvno,
+ char *db_args)
+{
+ krb5_error_code retval_ofs = 0, retval_kt = 0;
+ char keyfile[MAXPATHLEN+1];
+ krb5_data *realm = krb5_princ_realm(context, mname);
+
+ key->magic = KV5M_KEYBLOCK;
+
+ if (db_args != NULL) {
+ (void) strncpy(keyfile, db_args, sizeof(keyfile));
+ } else {
+ (void) strcpy(keyfile, DEFAULT_KEYFILE_STUB);
+ (void) strncat(keyfile, realm->data,
+ min(sizeof(keyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1,
+ realm->length));
+ }
+ /* null terminate no matter what */
+ keyfile[sizeof(keyfile) - 1] = '\0';
+
+ /* assume the master key is in a keytab */
+ retval_kt = krb5_db_def_fetch_mkey_keytab(context, keyfile, mname, key, kvno);
+ if (retval_kt != 0) {
+ /*
+ * If it's not in a keytab, fall back and try getting the mkey from the
+ * older stash file format.
+ */
+ retval_ofs = krb5_db_def_fetch_mkey_stash(context, keyfile, key, kvno);
+ }
+
+ if (retval_kt != 0 && retval_ofs != 0) {
+ /*
+ * Error, not able to get mkey from either file format. Note, in order
+ * to try to return a more correct error, the logic below is assuming
+ * that if either of the stash reading functions returned
+ * KRB5_KDB_BADSTORED_MKEY then this is probably the real error.
+ */
+ krb5_set_error_message (context, KRB5_KDB_CANTREAD_STORED,
+ "Can not fetch master key either from keytab (error: %s) or old "
+ "format (error %s).", error_message(retval_kt),
+ error_message(retval_ofs));
+ return KRB5_KDB_CANTREAD_STORED;
+ } else {
+ return 0;
+ }
+}
krb5_error_code
-krb5_def_verify_master_key(context, mprinc, mkey)
- krb5_context context;
- krb5_principal mprinc;
- krb5_keyblock *mkey;
+krb5_def_verify_master_key(krb5_context context,
+ krb5_principal mprinc,
+ krb5_kvno kvno,
+ krb5_keyblock *mkey)
{
krb5_error_code retval;
krb5_db_entry master_entry;
retval = KRB5_KDB_BADMASTERKEY;
}
+ if (kvno != IGNORE_VNO &&
+ kvno != (krb5_kvno) master_entry.key_data->key_data_kvno) {
+ retval = KRB5_KDB_BADMASTERKEY;
+ krb5_set_error_message (context, retval,
+ "User specified mkeyVNO (%u) does not match master key princ's KVNO (%u)",
+ kvno, master_entry.key_data->key_data_kvno);
+ }
+
memset((char *)tempkey.contents, 0, tempkey.length);
krb5_xfree(tempkey.contents);
krb5_db_free_principal(context, &master_entry, nprinc);
/*
* Constants
*/
-#define IGNORE_VNO 0
-#define IGNORE_ENCTYPE 0
#define KRB5_KT_VNO_1 0x0501 /* krb v5, keytab version 1 (DCE compat) */
#define KRB5_KT_VNO 0x0502 /* krb v5, keytab version 2 (standard) */
/*
* Constants
*/
-#define IGNORE_VNO 0
-#define IGNORE_ENCTYPE 0
/*
* Types
/*
* Constants
*/
-#define IGNORE_VNO 0
-#define IGNORE_ENCTYPE 0
#define KRB5_KT_VNO_1 0x0501 /* krb v5, keytab version 1 (DCE compat) */
#define KRB5_KT_VNO 0x0502 /* krb v5, keytab version 2 (standard) */
/* Stash the master key only if '-s' option is specified */
if (do_stash || global_params.mask & KADM5_CONFIG_STASH_FILE) {
+ krb5_kvno mkey_kvno;
+ /*
+ * Determine the kvno to use, it must be that used to create the master
+ * key princ.
+ */
+ if (global_params.mask & KADM5_CONFIG_KVNO)
+ mkey_kvno = global_params.kvno; /* user specified */
+ else
+ mkey_kvno = 1; /* Default */
+
retval = krb5_def_store_mkey(util_context,
global_params.stash_file,
master_princ,
+ mkey_kvno,
&master_keyblock, NULL);
if (retval) {
com_err(progname, errno, "while storing key");
Specifies the URI of the LDAP server.
.SH COMMANDS
.TP
-\fBcreate\fP [\fB\-subtrees\fP\ \fIsubtree_dn_list\fP] [\fB\-sscope\fP\ \fIsearch_scope\fP] [\fB\-containerref\fP\ \fIcontainer_reference_dn\fP] [\fB\-k\fP\ \fImkeytype\fP] [\fB\-m\fP|\fB\-P\fP\ \fIpassword\fP|\fB\-sf\fP\ \fIstashfilename\fP] [\fB\-s\fP] [\fB\-r\fP\ \fIrealm\fP] [\fB\-kdcdn\fP\ \fIkdc_service_list\fP] [\fB\-admindn\fP\ \fIadmin_service_list\fP] [\fB\-maxtktlife\fP\ \fImax_ticket_life\fP] [\fB\-maxrenewlife\fP\ \fImax_renewable_ticket_life\fP] [\fIticket_flags\fP]
+\fBcreate\fP [\fB\-subtrees\fP\ \fIsubtree_dn_list\fP] [\fB\-sscope\fP\ \fIsearch_scope\fP] [\fB\-containerref\fP\ \fIcontainer_reference_dn\fP] [\fB\-k\fP\ \fImkeytype\fP] [\fB\-kv\fP\ \fImkeyVNO\fP] [\fB\-m\fP|\fB\-P\fP\ \fIpassword\fP|\fB\-sf\fP\ \fIstashfilename\fP] [\fB\-s\fP] [\fB\-r\fP\ \fIrealm\fP] [\fB\-kdcdn\fP\ \fIkdc_service_list\fP] [\fB\-admindn\fP\ \fIadmin_service_list\fP] [\fB\-maxtktlife\fP\ \fImax_ticket_life\fP] [\fB\-maxrenewlife\fP\ \fImax_renewable_ticket_life\fP] [\fIticket_flags\fP]
Creates realm in directory. Options:
.RS
.TP
that given in
.IR kdc.conf .
.TP
+\fB\-kv\fP\ \fImkeyVNO\fP
+Specifies the version number of the master key in the database; the default is
+1. Note that 0 is not allowed.
+.TP
\fB\-m\fP
Specifies that the master database password should be read from the TTY
rather than fetched from a file on the disk.
"\t\t[-kdcdn kdc_service_list] [-admindn admin_service_list]\n"
"\t\t[-pwddn passwd_service_list]\n"
#endif
-"\t\t[-m|-P password|-sf stashfilename] [-k mkeytype] [-s]\n"
+"\t\t[-m|-P password|-sf stashfilename] [-k mkeytype] [-kv mkeyVNO] [-s]\n"
"\t\t[-maxtktlife max_ticket_life] [-maxrenewlife max_renewable_ticket_life]\n"
"\t\t[ticket_flags] [-r realm]\n"
goto cleanup;
}
} else if (strcmp(*argv, "-k") == 0 && ARG_VAL) {
- if (krb5_string_to_enctype(koptarg, &global_params.enctype))
- com_err(progname, 0, "%s is an invalid enctype", koptarg);
- else
+ if (krb5_string_to_enctype(koptarg, &global_params.enctype)) {
+ com_err(progname, EINVAL, ": %s is an invalid enctype", koptarg);
+ exit_status++;
+ goto cleanup;
+ } else
global_params.mask |= KADM5_CONFIG_ENCTYPE;
+ } else if (strcmp(*argv, "-kv") == 0 && ARG_VAL) {
+ global_params.kvno = (krb5_kvno) atoi(koptarg);
+ if (global_params.kvno == IGNORE_VNO) {
+ com_err(progname, EINVAL, ": %s is an invalid mkeyVNO", koptarg);
+ exit_status++;
+ goto cleanup;
+ } else
+ global_params.mask |= KADM5_CONFIG_KVNO;
} else if (strcmp(*argv, "-M") == 0 && ARG_VAL) {
global_params.mkey_name = koptarg;
global_params.mask |= KADM5_CONFIG_MKEY_NAME;
myfulldir=tests
BUILDTOP=$(REL)..
SUBDIRS = resolve asn.1 create hammer verify gssapi dejagnu shlib \
- gss-threads misc
+ gss-threads misc mkeystash_compat
RUN_SETUP = @KRB5_RUN_ENV@ KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=krb5.conf
KRB5_RUN_ENV= @KRB5_RUN_ENV@
} else {
if ((retval = krb5_db_fetch_mkey(test_context, master_princ,
master_keyblock.enctype, manual_mkey,
- FALSE, 0, NULL, &master_keyblock))) {
+ FALSE, 0, NULL, NULL,
+ &master_keyblock))) {
com_err(pname, retval, "while reading master key");
return(1);
}
free(args[0]);
if ((retval = krb5_db_verify_master_key(test_context, master_princ,
- &master_keyblock))){
+ IGNORE_VNO, &master_keyblock))){
com_err(pname, retval, "while verifying master key");
(void) krb5_db_fini(test_context);
return(1);
--- /dev/null
+thisconfigdir=../..
+mydir=tests/mkeystash_compat
+myfulldir=tests/mkeystash_compat
+BUILDTOP=$(REL)..$(S)..
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=krb5.conf
+KRB5_RUN_ENV= @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+OBJS = bigendian.o
+SRCS = $(srcdir)/bigendian.c
+
+TEST_DB = ./testdb
+TEST_REALM = FOO.TEST.REALM
+TEST_MKEY = footes
+
+KADMIN_OPTS= -d $(TEST_DB) -r $(TEST_REALM)
+KDB_OPTS= $(KADMIN_OPTS) -P $(TEST_MKEY)
+
+check-unix:: mkeystash_check
+
+bigendian: $(OUTPRE)bigendian.$(OBJEXT) $(SUPPORT_DEPLIB)
+ $(CC_LINK) $(ALL_CFLAGS) -o bigendian $(OUTPRE)bigendian.$(OBJEXT)
+
+kdc.conf: Makefile
+ rm -rf kdc.conf
+ @echo "[realms]" > kdc.conf
+ @echo "$(TEST_REALM) = {" >> kdc.conf
+ @echo " key_stash_file = `pwd`/stash_file" >> kdc.conf
+ @echo "}" >> kdc.conf
+
+krb5.conf: Makefile
+ cat $(SRCTOP)/config-files/krb5.conf > krb5.new
+
+# Verify that the mkey stash code is backward compat with old/non-keytab stashfile format
+mkeystash_check: kdc.conf krb5.conf bigendian
+ $(RM) $(TEST_DB)* stash_file
+ $(RUN_SETUP) $(VALGRIND) ../../kadmin/dbutil/kdb5_util $(KDB_OPTS) create -s
+ # overwrite keytab stash file with old format stash, depends on endianness of current test system
+ ./bigendian && cp $(srcdir)/old_stash_bendian stash_file || cp $(srcdir)/old_stash_lendian stash_file
+ # getprinc will fail if old stash file can not be read
+ $(RUN_SETUP) $(VALGRIND) ../../kadmin/cli/kadmin.local $(KADMIN_OPTS) -q 'getprinc K/M'
+ $(RUN_SETUP) $(VALGRIND) ../../kadmin/dbutil/kdb5_util $(KDB_OPTS) destroy -f
+ $(RM) $(TEST_DB)* stash_file
+
+clean::
+ $(RM) kdc.conf
+
--- /dev/null
+#include <stdio.h>
+
+/*
+ * Test to see if system is bigendian
+ * Returns 0 if it is big endian
+ * 1 if it is little endian
+ */
+int main()
+{
+ int int_var = 1;
+ unsigned char *char_array = (unsigned char*)&int_var;
+
+ if (char_array[0] == 0)
+ return 0; /* big endian */
+ else
+ return 1; /* little endian */
+}
} else {
if ((retval = krb5_db_fetch_mkey(context, master_princ,
master_keyblock.enctype,
- manual_mkey, FALSE, (char *) NULL, 0,
- &master_keyblock))) {
+ manual_mkey, FALSE, (char *) NULL,
+ NULL, NULL,
+ &master_keyblock))) {
com_err(pname, retval, "while reading master key");
return(1);
}
return(1);
}
if ((retval = krb5_db_verify_master_key(context, master_princ,
- &master_keyblock))) {
+ IGNORE_VNO, &master_keyblock))) {
com_err(pname, retval, "while verifying master key");
(void) krb5_db_fini(context);
return(1);