1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* kadmin/dbutil/kdb5_util.c - Administer a KDC database */
4 * (C) Copyright 1990,1991, 1996, 2008, 2009 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
27 * Copyright (C) 1998 by the FundsXpress, INC.
29 * All rights reserved.
31 * Export of this software from the United States of America may require
32 * a specific license from the United States Government. It is the
33 * responsibility of any person or organization contemplating export to
34 * obtain such a license before exporting.
36 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
37 * distribute this software and its documentation for any purpose and
38 * without fee is hereby granted, provided that the above copyright
39 * notice appear in all copies and that both that copyright notice and
40 * this permission notice appear in supporting documentation, and that
41 * the name of FundsXpress. not be used in advertising or publicity pertaining
42 * to distribution of the software without specific, written prior
43 * permission. FundsXpress makes no representations about the suitability of
44 * this software for any purpose. It is provided "as is" without express
45 * or implied warranty.
47 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
49 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
52 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
53 * Use is subject to license terms.
57 #include <kadm5/admin.h>
59 #include <adm_proto.h>
61 #include "kdb5_util.h"
64 * XXX Ick, ick, ick. These global variables shouldn't be global....
66 char *mkey_password = 0;
69 * I can't figure out any way for this not to be global, given how ss
74 krb5_context util_context;
75 kadm5_config_params global_params;
80 _("Usage: kdb5_util [-x db_args]* [-r realm] [-d dbname] "
81 "[-k mkeytype] [-M mkeyname]\n"
82 "\t [-kv mkeyVNO] [-sf stashfilename] [-m] cmd "
86 "\tstash [-f keyfile]\n"
87 "\tdump [-old|-ov|-b6|-b7|-r13|-r18] [-verbose]\n"
88 "\t [-mkey_convert] [-new_mkey_file mkey_file]\n"
89 "\t [-rev] [-recurse] [filename [princs...]]\n"
90 "\tload [-old|-ov|-b6|-b7|-r13|-r18] [-verbose] [-update] "
92 "\tark [-e etype_list] principal\n"
93 "\tadd_mkey [-e etype] [-s]\n"
94 "\tuse_mkey kvno [time]\n"
96 /* avoid a string length compiler warning */
98 _("\tupdate_princ_encryption [-f] [-n] [-v] [princ-pattern]\n"
99 "\tpurge_mkeys [-f] [-n] [-v]\n"
100 "\ttabdump [-H] [-c] [-e] [-n] [-o outfile] dumptype\n"
101 "\nwhere,\n\t[-x db_args]* - any number of database specific "
103 "\t\t\tLook at each database documentation for supported "
108 krb5_keyblock master_keyblock;
109 krb5_kvno master_kvno; /* fetched */
110 extern krb5_principal master_princ;
112 krb5_db_entry *master_entry = NULL;
113 int valid_master_key = 0;
116 krb5_boolean manual_mkey = FALSE;
117 krb5_boolean dbactive = FALSE;
119 static int open_db_and_mkey(void);
121 static void add_random_key(int, char **);
123 typedef void (*cmd_func)(int, char **);
130 {"create", kdb5_create, 0},
131 {"destroy", kdb5_destroy, 1}, /* 1 opens the kdb */
132 {"stash", kdb5_stash, 1},
133 {"dump", dump_db, 1},
134 {"load", load_db, 0},
135 {"ark", add_random_key, 1},
136 {"add_mkey", kdb5_add_mkey, 1},
137 {"use_mkey", kdb5_use_mkey, 1},
138 {"list_mkeys", kdb5_list_mkeys, 1},
139 {"update_princ_encryption", kdb5_update_princ_encryption, 1},
140 {"purge_mkeys", kdb5_purge_mkeys, 1},
141 {"tabdump", tabdump, 1},
145 static struct _cmd_table *cmd_lookup(name)
148 struct _cmd_table *cmd = cmd_table;
150 if (strcmp(cmd->name, name) == 0)
159 #define ARG_VAL (--argc > 0 ? (koptarg = *(++argv)) : (char *)(usage(), NULL))
161 char **db5util_db_args = NULL;
162 int db5util_db_args_size = 0;
164 static void extended_com_err_fn (const char *myprog, errcode_t code,
165 const char *fmt, va_list args)
169 emsg = krb5_get_error_message (util_context, code);
170 fprintf (stderr, "%s: %s ", myprog, emsg);
171 krb5_free_error_message (util_context, emsg);
173 fprintf (stderr, "%s: ", myprog);
175 vfprintf (stderr, fmt, args);
176 fprintf (stderr, "\n");
179 int add_db_arg(char *arg)
182 db5util_db_args_size++;
183 temp = realloc(db5util_db_args,
184 sizeof(char *) * (db5util_db_args_size + 1));
187 db5util_db_args = temp;
188 db5util_db_args[db5util_db_args_size-1] = arg;
189 db5util_db_args[db5util_db_args_size] = NULL;
197 struct _cmd_table *cmd = NULL;
198 char *koptarg, **cmd_argv;
199 char *db_name_tmp = NULL;
201 krb5_error_code retval;
203 setlocale(LC_ALL, "");
204 set_com_err_hook(extended_com_err_fn);
207 * Ensure that "progname" is set before calling com_err.
209 progname = (strrchr(argv[0], '/') ?
210 strrchr(argv[0], '/') + 1 : argv[0]);
212 retval = kadm5_init_krb5_context(&util_context);
214 com_err (progname, retval, _("while initializing Kerberos code"));
218 cmd_argv = (char **) malloc(sizeof(char *)*argc);
219 if (cmd_argv == NULL) {
220 com_err(progname, ENOMEM, _("while creating sub-command arguments"));
223 memset(cmd_argv, 0, sizeof(char *)*argc);
228 if (strcmp(*argv, "-P") == 0 && ARG_VAL) {
229 mkey_password = koptarg;
231 } else if (strcmp(*argv, "-d") == 0 && ARG_VAL) {
232 global_params.dbname = koptarg;
233 global_params.mask |= KADM5_CONFIG_DBNAME;
235 if (asprintf(&db_name_tmp, "dbname=%s", global_params.dbname) < 0)
237 com_err(progname, ENOMEM,
238 _("while parsing command arguments"));
242 if (!add_db_arg(db_name_tmp)) {
243 com_err(progname, ENOMEM,
244 _("while parsing command arguments\n"));
248 } else if (strcmp(*argv, "-x") == 0 && ARG_VAL) {
249 if (!add_db_arg(koptarg)) {
250 com_err(progname, ENOMEM,
251 _("while parsing command arguments\n"));
255 } else if (strcmp(*argv, "-r") == 0 && ARG_VAL) {
256 global_params.realm = koptarg;
257 global_params.mask |= KADM5_CONFIG_REALM;
258 /* not sure this is really necessary */
259 if ((retval = krb5_set_default_realm(util_context,
260 global_params.realm))) {
261 com_err(progname, retval,
262 _("while setting default realm name"));
265 } else if (strcmp(*argv, "-k") == 0 && ARG_VAL) {
266 if (krb5_string_to_enctype(koptarg, &global_params.enctype)) {
267 com_err(progname, EINVAL, _(": %s is an invalid enctype"),
271 global_params.mask |= KADM5_CONFIG_ENCTYPE;
272 } else if (strcmp(*argv, "-kv") == 0 && ARG_VAL) {
273 global_params.kvno = (krb5_kvno) atoi(koptarg);
274 if (global_params.kvno == IGNORE_VNO) {
275 com_err(progname, EINVAL, _(": %s is an invalid mkeyVNO"),
279 global_params.mask |= KADM5_CONFIG_KVNO;
280 } else if (strcmp(*argv, "-M") == 0 && ARG_VAL) {
281 global_params.mkey_name = koptarg;
282 global_params.mask |= KADM5_CONFIG_MKEY_NAME;
283 } else if (strcmp(*argv, "-sf") == 0 && ARG_VAL) {
284 global_params.stash_file = koptarg;
285 global_params.mask |= KADM5_CONFIG_STASH_FILE;
286 } else if (strcmp(*argv, "-m") == 0) {
288 global_params.mkey_from_kbd = 1;
289 global_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
290 } else if (cmd_lookup(*argv) != NULL) {
291 if (cmd_argv[0] == NULL)
296 cmd_argv[cmd_argc++] = *argv;
301 if (cmd_argv[0] == NULL)
304 if( !util_context->default_realm )
307 retval = krb5_get_default_realm(util_context, &temp);
310 com_err(progname, retval, _("while getting default realm"));
313 krb5_free_default_realm(util_context, temp);
316 retval = kadm5_get_config_params(util_context, 1,
317 &global_params, &global_params);
319 com_err(progname, retval,
320 _("while retreiving configuration parameters"));
325 * Dump creates files which should not be world-readable. It is
326 * easiest to do a single umask call here.
330 master_keyblock.enctype = global_params.enctype;
331 if ((master_keyblock.enctype != ENCTYPE_UNKNOWN) &&
332 (!krb5_c_valid_enctype(master_keyblock.enctype))) {
333 com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
334 "while setting up enctype %d", master_keyblock.enctype);
337 cmd = cmd_lookup(cmd_argv[0]);
338 if (cmd->opendb && open_db_and_mkey())
341 if (global_params.iprop_enabled == TRUE)
342 ulog_set_role(util_context, IPROP_MASTER);
344 ulog_set_role(util_context, IPROP_NULL);
346 (*cmd->func)(cmd_argc, cmd_argv);
351 if( db5util_db_args )
352 free(db5util_db_args);
355 kadm5_free_config_params(util_context, &global_params);
356 krb5_free_context(util_context);
363 * This function is no longer used in kdb5_util (and it would no
364 * longer work, anyway).
366 void set_dbname(argc, argv)
370 krb5_error_code retval;
373 com_err(argv[0], 0, _("Too few arguments"));
374 com_err(progname, 0, _("Usage: %s dbpathname realmname"), argv[0]);
379 if ((retval = krb5_db_fini(util_context)) && retval!= KRB5_KDB_DBNOTINITED) {
380 com_err(progname, retval, _("while closing previous database"));
384 if (valid_master_key) {
385 krb5_free_keyblock_contents(util_context, &master_keyblock);
386 master_keyblock.contents = NULL;
387 valid_master_key = 0;
389 krb5_free_principal(util_context, master_princ);
394 (void) set_dbname_help(progname, argv[1]);
400 * open_db_and_mkey: Opens the KDC and policy database, and sets the
401 * global master_* variables. Sets dbactive to TRUE if the databases
402 * are opened, and valid_master_key to 1 if the global master
403 * variables are set properly. Returns 0 on success, and 1 on
404 * failure, but it is not considered a failure if the master key
405 * cannot be fetched (the master key stash file may not exist when the
408 static int open_db_and_mkey()
410 krb5_error_code retval;
411 krb5_data scratch, pwd, seed;
414 valid_master_key = 0;
416 if ((retval = krb5_db_open(util_context, db5util_db_args,
417 KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN))) {
418 com_err(progname, retval, _("while initializing database"));
423 /* assemble & parse the master key name */
425 if ((retval = krb5_db_setup_mkey_name(util_context,
426 global_params.mkey_name,
428 &mkey_fullname, &master_princ))) {
429 com_err(progname, retval, _("while setting up master key name"));
433 if ((retval = krb5_db_get_principal(util_context, master_princ, 0,
435 com_err(progname, retval, _("while retrieving master entry"));
437 (void) krb5_db_fini(util_context);
441 if (global_params.mask & KADM5_CONFIG_KVNO)
442 master_kvno = global_params.kvno; /* user specified */
444 master_kvno = IGNORE_VNO;
446 /* the databases are now open, and the master principal exists */
450 pwd.data = mkey_password;
451 pwd.length = strlen(mkey_password);
452 retval = krb5_principal2salt(util_context, master_princ, &scratch);
454 com_err(progname, retval, _("while calculated master key salt"));
459 /* If no encryption type is set, use the default */
460 if (master_keyblock.enctype == ENCTYPE_UNKNOWN)
461 master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
462 if (!krb5_c_valid_enctype(master_keyblock.enctype))
463 com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
464 "while setting up enctype %d",
465 master_keyblock.enctype);
467 retval = krb5_c_string_to_key(util_context, master_keyblock.enctype,
468 &pwd, &scratch, &master_keyblock);
470 com_err(progname, retval,
471 _("while transforming master key from password"));
479 if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
480 master_keyblock.enctype,
482 global_params.stash_file,
484 0, &master_keyblock))) {
485 com_err(progname, retval, _("while reading master key"));
486 com_err(progname, 0, _("Warning: proceeding without master key"));
492 if ((retval = krb5_db_fetch_mkey_list(util_context, master_princ,
493 &master_keyblock))) {
494 com_err(progname, retval, "while getting master key list");
495 com_err(progname, 0, "Warning: proceeding without master key list");
500 seed.length = master_keyblock.length;
501 seed.data = (char *) master_keyblock.contents;
503 if ((retval = krb5_c_random_seed(util_context, &seed))) {
504 com_err(progname, retval, _("while seeding random number generator"));
506 memset(master_keyblock.contents, 0, master_keyblock.length);
507 krb5_free_keyblock_contents(util_context, &master_keyblock);
511 if (global_params.iprop_enabled) {
512 if (ulog_map(util_context, global_params.iprop_logfile,
513 global_params.iprop_ulogsize)) {
514 fprintf(stderr, _("%s: Could not map log\n"), progname);
520 valid_master_key = 1;
532 krb5_error_code retval;
533 static krb5_boolean finished = 0;
537 ulog_fini(util_context);
538 retval = krb5_db_fini(util_context);
539 zapfree(master_keyblock.contents, master_keyblock.length);
540 krb5_free_principal(util_context, master_princ);
542 if (retval && retval != KRB5_KDB_DBNOTINITED) {
543 com_err(progname, retval, _("while closing database"));
551 add_random_key(argc, argv)
556 krb5_principal princ;
557 krb5_db_entry *dbent;
560 krb5_key_salt_tuple *keysalts = NULL;
561 krb5_int32 num_keysalts = 0;
567 krb5_keyblock *tmp_mkey;
571 for (argv++, argc--; *argv; argv++, argc--) {
572 if (!strcmp(*argv, "-e")) {
582 ret = krb5_parse_name(util_context, pr_str, &princ);
584 com_err(me, ret, _("while parsing principal name %s"), pr_str);
588 ret = krb5_db_get_principal(util_context, princ, 0, &dbent);
590 com_err(me, ret, _("while fetching principal %s"), pr_str);
594 ret = krb5_string_to_keysalts(ks_str,
599 com_err(me, ret, _("while parsing keysalts %s"), ks_str);
603 if (!num_keysalts || keysalts == NULL) {
604 num_keysalts = global_params.num_keysalts;
605 keysalts = global_params.keysalts;
610 /* Find the mkey used to protect the existing keys */
611 ret = krb5_dbe_find_mkey(util_context, dbent, &tmp_mkey);
613 com_err(me, ret, _("while finding mkey"));
614 krb5_db_free_principal(util_context, dbent);
619 ret = krb5_dbe_ark(util_context, tmp_mkey, keysalts, num_keysalts, dbent);
623 com_err(me, ret, "while randomizing principal %s", pr_str);
624 krb5_db_free_principal(util_context, dbent);
628 dbent->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
629 ret = krb5_timeofday(util_context, &now);
631 com_err(me, ret, _("while getting time"));
632 krb5_db_free_principal(util_context, dbent);
636 ret = krb5_dbe_update_last_pwd_change(util_context, dbent, now);
638 com_err(me, ret, _("while setting changetime"));
639 krb5_db_free_principal(util_context, dbent);
643 ret = krb5_db_put_principal(util_context, dbent);
644 krb5_db_free_principal(util_context, dbent);
646 com_err(me, ret, _("while saving principal %s"), pr_str);
650 printf(_("%s changed\n"), pr_str);