summaryrefslogtreecommitdiff
path: root/src/kadmin/dbutil/kdb5_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kadmin/dbutil/kdb5_util.c')
-rw-r--r--src/kadmin/dbutil/kdb5_util.c651
1 files changed, 651 insertions, 0 deletions
diff --git a/src/kadmin/dbutil/kdb5_util.c b/src/kadmin/dbutil/kdb5_util.c
new file mode 100644
index 0000000000000..000b5595c9faa
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_util.c
@@ -0,0 +1,651 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* kadmin/dbutil/kdb5_util.c - Administer a KDC database */
+/*
+ * (C) Copyright 1990,1991, 1996, 2008, 2009 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. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * 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.
+ */
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <locale.h>
+#include <adm_proto.h>
+#include <time.h>
+#include "kdb5_util.h"
+
+/*
+ * XXX Ick, ick, ick. These global variables shouldn't be global....
+ */
+char *mkey_password = 0;
+
+/*
+ * I can't figure out any way for this not to be global, given how ss
+ * works.
+ */
+
+int exit_status = 0;
+krb5_context util_context;
+kadm5_config_params global_params;
+
+void usage()
+{
+ fprintf(stderr,
+ _("Usage: kdb5_util [-x db_args]* [-r realm] [-d dbname] "
+ "[-k mkeytype] [-M mkeyname]\n"
+ "\t [-kv mkeyVNO] [-sf stashfilename] [-m] cmd "
+ "[cmd_options]\n"
+ "\tcreate [-s]\n"
+ "\tdestroy [-f]\n"
+ "\tstash [-f keyfile]\n"
+ "\tdump [-old|-ov|-b6|-b7|-r13|-r18] [-verbose]\n"
+ "\t [-mkey_convert] [-new_mkey_file mkey_file]\n"
+ "\t [-rev] [-recurse] [filename [princs...]]\n"
+ "\tload [-old|-ov|-b6|-b7|-r13|-r18] [-verbose] [-update] "
+ "filename\n"
+ "\tark [-e etype_list] principal\n"
+ "\tadd_mkey [-e etype] [-s]\n"
+ "\tuse_mkey kvno [time]\n"
+ "\tlist_mkeys\n"));
+ /* avoid a string length compiler warning */
+ fprintf(stderr,
+ _("\tupdate_princ_encryption [-f] [-n] [-v] [princ-pattern]\n"
+ "\tpurge_mkeys [-f] [-n] [-v]\n"
+ "\ttabdump [-H] [-c] [-e] [-n] [-o outfile] dumptype\n"
+ "\nwhere,\n\t[-x db_args]* - any number of database specific "
+ "arguments.\n"
+ "\t\t\tLook at each database documentation for supported "
+ "arguments\n"));
+ exit(1);
+}
+
+krb5_keyblock master_keyblock;
+krb5_kvno master_kvno; /* fetched */
+extern krb5_principal master_princ;
+char *mkey_fullname;
+krb5_db_entry *master_entry = NULL;
+int valid_master_key = 0;
+
+char *progname;
+krb5_boolean manual_mkey = FALSE;
+krb5_boolean dbactive = FALSE;
+
+static int open_db_and_mkey(void);
+
+static void add_random_key(int, char **);
+
+typedef void (*cmd_func)(int, char **);
+
+struct _cmd_table {
+ char *name;
+ cmd_func func;
+ int opendb;
+} cmd_table[] = {
+ {"create", kdb5_create, 0},
+ {"destroy", kdb5_destroy, 1}, /* 1 opens the kdb */
+ {"stash", kdb5_stash, 1},
+ {"dump", dump_db, 1},
+ {"load", load_db, 0},
+ {"ark", add_random_key, 1},
+ {"add_mkey", kdb5_add_mkey, 1},
+ {"use_mkey", kdb5_use_mkey, 1},
+ {"list_mkeys", kdb5_list_mkeys, 1},
+ {"update_princ_encryption", kdb5_update_princ_encryption, 1},
+ {"purge_mkeys", kdb5_purge_mkeys, 1},
+ {"tabdump", tabdump, 1},
+ {NULL, NULL, 0},
+};
+
+static struct _cmd_table *cmd_lookup(name)
+ char *name;
+{
+ struct _cmd_table *cmd = cmd_table;
+ while (cmd->name) {
+ if (strcmp(cmd->name, name) == 0)
+ return cmd;
+ else
+ cmd++;
+ }
+
+ return NULL;
+}
+
+#define ARG_VAL (--argc > 0 ? (koptarg = *(++argv)) : (char *)(usage(), NULL))
+
+char **db5util_db_args = NULL;
+int db5util_db_args_size = 0;
+
+static void extended_com_err_fn (const char *myprog, errcode_t code,
+ const char *fmt, va_list args)
+{
+ const char *emsg;
+ if (code) {
+ emsg = krb5_get_error_message (util_context, code);
+ fprintf (stderr, "%s: %s ", myprog, emsg);
+ krb5_free_error_message (util_context, emsg);
+ } else {
+ fprintf (stderr, "%s: ", myprog);
+ }
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, "\n");
+}
+
+int add_db_arg(char *arg)
+{
+ char **temp;
+ db5util_db_args_size++;
+ temp = realloc(db5util_db_args,
+ sizeof(char *) * (db5util_db_args_size + 1));
+ if (temp == NULL)
+ return 0;
+ db5util_db_args = temp;
+ db5util_db_args[db5util_db_args_size-1] = arg;
+ db5util_db_args[db5util_db_args_size] = NULL;
+ return 1;
+}
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct _cmd_table *cmd = NULL;
+ char *koptarg, **cmd_argv;
+ char *db_name_tmp = NULL;
+ int cmd_argc;
+ krb5_error_code retval;
+
+ setlocale(LC_ALL, "");
+ set_com_err_hook(extended_com_err_fn);
+
+ /*
+ * Ensure that "progname" is set before calling com_err.
+ */
+ progname = (strrchr(argv[0], '/') ?
+ strrchr(argv[0], '/') + 1 : argv[0]);
+
+ retval = kadm5_init_krb5_context(&util_context);
+ if (retval) {
+ com_err (progname, retval, _("while initializing Kerberos code"));
+ exit(1);
+ }
+
+ cmd_argv = (char **) malloc(sizeof(char *)*argc);
+ if (cmd_argv == NULL) {
+ com_err(progname, ENOMEM, _("while creating sub-command arguments"));
+ exit(1);
+ }
+ memset(cmd_argv, 0, sizeof(char *)*argc);
+ cmd_argc = 1;
+
+ argv++; argc--;
+ while (*argv) {
+ if (strcmp(*argv, "-P") == 0 && ARG_VAL) {
+ mkey_password = koptarg;
+ manual_mkey = TRUE;
+ } else if (strcmp(*argv, "-d") == 0 && ARG_VAL) {
+ global_params.dbname = koptarg;
+ global_params.mask |= KADM5_CONFIG_DBNAME;
+
+ if (asprintf(&db_name_tmp, "dbname=%s", global_params.dbname) < 0)
+ {
+ com_err(progname, ENOMEM,
+ _("while parsing command arguments"));
+ exit(1);
+ }
+
+ if (!add_db_arg(db_name_tmp)) {
+ com_err(progname, ENOMEM,
+ _("while parsing command arguments\n"));
+ exit(1);
+ }
+
+ } else if (strcmp(*argv, "-x") == 0 && ARG_VAL) {
+ if (!add_db_arg(koptarg)) {
+ com_err(progname, ENOMEM,
+ _("while parsing command arguments\n"));
+ exit(1);
+ }
+
+ } else if (strcmp(*argv, "-r") == 0 && ARG_VAL) {
+ global_params.realm = koptarg;
+ global_params.mask |= KADM5_CONFIG_REALM;
+ /* not sure this is really necessary */
+ if ((retval = krb5_set_default_realm(util_context,
+ global_params.realm))) {
+ com_err(progname, retval,
+ _("while setting default realm name"));
+ exit(1);
+ }
+ } else if (strcmp(*argv, "-k") == 0 && ARG_VAL) {
+ 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;
+ } else if (strcmp(*argv, "-sf") == 0 && ARG_VAL) {
+ global_params.stash_file = koptarg;
+ global_params.mask |= KADM5_CONFIG_STASH_FILE;
+ } else if (strcmp(*argv, "-m") == 0) {
+ manual_mkey = TRUE;
+ global_params.mkey_from_kbd = 1;
+ global_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
+ } else if (cmd_lookup(*argv) != NULL) {
+ if (cmd_argv[0] == NULL)
+ cmd_argv[0] = *argv;
+ else
+ usage();
+ } else {
+ cmd_argv[cmd_argc++] = *argv;
+ }
+ argv++; argc--;
+ }
+
+ if (cmd_argv[0] == NULL)
+ usage();
+
+ if( !util_context->default_realm )
+ {
+ char *temp = NULL;
+ retval = krb5_get_default_realm(util_context, &temp);
+ if( retval )
+ {
+ com_err(progname, retval, _("while getting default realm"));
+ exit(1);
+ }
+ krb5_free_default_realm(util_context, temp);
+ }
+
+ retval = kadm5_get_config_params(util_context, 1,
+ &global_params, &global_params);
+ if (retval) {
+ com_err(progname, retval,
+ _("while retreiving configuration parameters"));
+ exit(1);
+ }
+
+ /*
+ * Dump creates files which should not be world-readable. It is
+ * easiest to do a single umask call here.
+ */
+ (void) umask(077);
+
+ master_keyblock.enctype = global_params.enctype;
+ if ((master_keyblock.enctype != ENCTYPE_UNKNOWN) &&
+ (!krb5_c_valid_enctype(master_keyblock.enctype))) {
+ com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
+ "while setting up enctype %d", master_keyblock.enctype);
+ }
+
+ cmd = cmd_lookup(cmd_argv[0]);
+ if (cmd->opendb && open_db_and_mkey())
+ return exit_status;
+
+ if (global_params.iprop_enabled == TRUE)
+ ulog_set_role(util_context, IPROP_MASTER);
+ else
+ ulog_set_role(util_context, IPROP_NULL);
+
+ (*cmd->func)(cmd_argc, cmd_argv);
+
+ if( db_name_tmp )
+ free( db_name_tmp );
+
+ if( db5util_db_args )
+ free(db5util_db_args);
+
+ quit();
+ kadm5_free_config_params(util_context, &global_params);
+ krb5_free_context(util_context);
+ free(cmd_argv);
+ return exit_status;
+}
+
+#if 0
+/*
+ * This function is no longer used in kdb5_util (and it would no
+ * longer work, anyway).
+ */
+void set_dbname(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+
+ if (argc < 3) {
+ com_err(argv[0], 0, _("Too few arguments"));
+ com_err(progname, 0, _("Usage: %s dbpathname realmname"), argv[0]);
+ exit_status++;
+ return;
+ }
+ if (dbactive) {
+ if ((retval = krb5_db_fini(util_context)) && retval!= KRB5_KDB_DBNOTINITED) {
+ com_err(progname, retval, _("while closing previous database"));
+ exit_status++;
+ return;
+ }
+ if (valid_master_key) {
+ krb5_free_keyblock_contents(util_context, &master_keyblock);
+ master_keyblock.contents = NULL;
+ valid_master_key = 0;
+ }
+ krb5_free_principal(util_context, master_princ);
+ free(mkey_fullname);
+ dbactive = FALSE;
+ }
+
+ (void) set_dbname_help(progname, argv[1]);
+ return;
+}
+#endif
+
+/*
+ * open_db_and_mkey: Opens the KDC and policy database, and sets the
+ * global master_* variables. Sets dbactive to TRUE if the databases
+ * are opened, and valid_master_key to 1 if the global master
+ * variables are set properly. Returns 0 on success, and 1 on
+ * failure, but it is not considered a failure if the master key
+ * cannot be fetched (the master key stash file may not exist when the
+ * program is run).
+ */
+static int open_db_and_mkey()
+{
+ krb5_error_code retval;
+ krb5_data scratch, pwd, seed;
+
+ dbactive = FALSE;
+ valid_master_key = 0;
+
+ if ((retval = krb5_db_open(util_context, db5util_db_args,
+ KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN))) {
+ com_err(progname, retval, _("while initializing database"));
+ exit_status++;
+ return(1);
+ }
+
+ /* assemble & parse the master key name */
+
+ if ((retval = krb5_db_setup_mkey_name(util_context,
+ global_params.mkey_name,
+ global_params.realm,
+ &mkey_fullname, &master_princ))) {
+ com_err(progname, retval, _("while setting up master key name"));
+ exit_status++;
+ return(1);
+ }
+ if ((retval = krb5_db_get_principal(util_context, master_princ, 0,
+ &master_entry))) {
+ com_err(progname, retval, _("while retrieving master entry"));
+ exit_status++;
+ (void) krb5_db_fini(util_context);
+ return(1);
+ }
+
+ if (global_params.mask & KADM5_CONFIG_KVNO)
+ master_kvno = global_params.kvno; /* user specified */
+ else
+ master_kvno = IGNORE_VNO;
+
+ /* the databases are now open, and the master principal exists */
+ dbactive = TRUE;
+
+ if (mkey_password) {
+ pwd.data = mkey_password;
+ pwd.length = strlen(mkey_password);
+ retval = krb5_principal2salt(util_context, master_princ, &scratch);
+ if (retval) {
+ com_err(progname, retval, _("while calculated master key salt"));
+ exit_status++;
+ return(1);
+ }
+
+ /* If no encryption type is set, use the default */
+ 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);
+
+ retval = krb5_c_string_to_key(util_context, master_keyblock.enctype,
+ &pwd, &scratch, &master_keyblock);
+ if (retval) {
+ com_err(progname, retval,
+ _("while transforming master key from password"));
+ exit_status++;
+ return(1);
+ }
+ 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,
+ &master_kvno,
+ 0, &master_keyblock))) {
+ com_err(progname, retval, _("while reading master key"));
+ com_err(progname, 0, _("Warning: proceeding without master key"));
+ exit_status++;
+ return(0);
+ }
+ }
+
+ if ((retval = krb5_db_fetch_mkey_list(util_context, master_princ,
+ &master_keyblock))) {
+ com_err(progname, retval, "while getting master key list");
+ com_err(progname, 0, "Warning: proceeding without master key list");
+ exit_status++;
+ return(0);
+ }
+
+ seed.length = master_keyblock.length;
+ seed.data = (char *) master_keyblock.contents;
+
+ if ((retval = krb5_c_random_seed(util_context, &seed))) {
+ com_err(progname, retval, _("while seeding random number generator"));
+ exit_status++;
+ memset(master_keyblock.contents, 0, master_keyblock.length);
+ krb5_free_keyblock_contents(util_context, &master_keyblock);
+ return(1);
+ }
+
+ if (global_params.iprop_enabled) {
+ if (ulog_map(util_context, global_params.iprop_logfile,
+ global_params.iprop_ulogsize)) {
+ fprintf(stderr, _("%s: Could not map log\n"), progname);
+ exit_status++;
+ return(1);
+ }
+ }
+
+ valid_master_key = 1;
+ dbactive = TRUE;
+ return 0;
+}
+
+#ifdef HAVE_GETCWD
+#undef getwd
+#endif
+
+int
+quit()
+{
+ krb5_error_code retval;
+ static krb5_boolean finished = 0;
+
+ if (finished)
+ return 0;
+ ulog_fini(util_context);
+ retval = krb5_db_fini(util_context);
+ zapfree(master_keyblock.contents, master_keyblock.length);
+ krb5_free_principal(util_context, master_princ);
+ finished = TRUE;
+ if (retval && retval != KRB5_KDB_DBNOTINITED) {
+ com_err(progname, retval, _("while closing database"));
+ exit_status++;
+ return 1;
+ }
+ return 0;
+}
+
+static void
+add_random_key(argc, argv)
+ int argc;
+ char **argv;
+{
+ krb5_error_code ret;
+ krb5_principal princ;
+ krb5_db_entry *dbent;
+ krb5_timestamp now;
+
+ krb5_key_salt_tuple *keysalts = NULL;
+ krb5_int32 num_keysalts = 0;
+
+ int free_keysalts;
+ char *me = progname;
+ char *ks_str = NULL;
+ char *pr_str;
+ krb5_keyblock *tmp_mkey;
+
+ if (argc < 2)
+ usage();
+ for (argv++, argc--; *argv; argv++, argc--) {
+ if (!strcmp(*argv, "-e")) {
+ argv++; argc--;
+ ks_str = *argv;
+ continue;
+ } else
+ break;
+ }
+ if (argc < 1)
+ usage();
+ pr_str = *argv;
+ ret = krb5_parse_name(util_context, pr_str, &princ);
+ if (ret) {
+ com_err(me, ret, _("while parsing principal name %s"), pr_str);
+ exit_status++;
+ return;
+ }
+ ret = krb5_db_get_principal(util_context, princ, 0, &dbent);
+ if (ret) {
+ com_err(me, ret, _("while fetching principal %s"), pr_str);
+ exit_status++;
+ return;
+ }
+ ret = krb5_string_to_keysalts(ks_str,
+ NULL, NULL, 0,
+ &keysalts,
+ &num_keysalts);
+ if (ret) {
+ com_err(me, ret, _("while parsing keysalts %s"), ks_str);
+ exit_status++;
+ return;
+ }
+ if (!num_keysalts || keysalts == NULL) {
+ num_keysalts = global_params.num_keysalts;
+ keysalts = global_params.keysalts;
+ free_keysalts = 0;
+ } else
+ free_keysalts = 1;
+
+ /* Find the mkey used to protect the existing keys */
+ ret = krb5_dbe_find_mkey(util_context, dbent, &tmp_mkey);
+ if (ret) {
+ com_err(me, ret, _("while finding mkey"));
+ krb5_db_free_principal(util_context, dbent);
+ exit_status++;
+ return;
+ }
+
+ ret = krb5_dbe_ark(util_context, tmp_mkey, keysalts, num_keysalts, dbent);
+ if (free_keysalts)
+ free(keysalts);
+ if (ret) {
+ com_err(me, ret, "while randomizing principal %s", pr_str);
+ krb5_db_free_principal(util_context, dbent);
+ exit_status++;
+ return;
+ }
+ dbent->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+ ret = krb5_timeofday(util_context, &now);
+ if (ret) {
+ com_err(me, ret, _("while getting time"));
+ krb5_db_free_principal(util_context, dbent);
+ exit_status++;
+ return;
+ }
+ ret = krb5_dbe_update_last_pwd_change(util_context, dbent, now);
+ if (ret) {
+ com_err(me, ret, _("while setting changetime"));
+ krb5_db_free_principal(util_context, dbent);
+ exit_status++;
+ return;
+ }
+ ret = krb5_db_put_principal(util_context, dbent);
+ krb5_db_free_principal(util_context, dbent);
+ if (ret) {
+ com_err(me, ret, _("while saving principal %s"), pr_str);
+ exit_status++;
+ return;
+ }
+ printf(_("%s changed\n"), pr_str);
+}