Path: blob/main/crypto/krb5/src/kadmin/dbutil/kdb5_util.c
34907 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* kadmin/dbutil/kdb5_util.c - Administer a KDC database */2/*3* (C) Copyright 1990,1991, 1996, 2008, 2009 by the Massachusetts Institute of Technology.4* All Rights Reserved.5*6* Export of this software from the United States of America may7* require a specific license from the United States Government.8* It is the responsibility of any person or organization contemplating9* export to obtain such a license before exporting.10*11* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and12* distribute this software and its documentation for any purpose and13* without fee is hereby granted, provided that the above copyright14* notice appear in all copies and that both that copyright notice and15* this permission notice appear in supporting documentation, and that16* the name of M.I.T. not be used in advertising or publicity pertaining17* to distribution of the software without specific, written prior18* permission. Furthermore if you modify this software you must label19* your software as modified software and not distribute it in such a20* fashion that it might be confused with the original M.I.T. software.21* M.I.T. makes no representations about the suitability of22* this software for any purpose. It is provided "as is" without express23* or implied warranty.24*/25/*26* Copyright (C) 1998 by the FundsXpress, INC.27*28* All rights reserved.29*30* Export of this software from the United States of America may require31* a specific license from the United States Government. It is the32* responsibility of any person or organization contemplating export to33* obtain such a license before exporting.34*35* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and36* distribute this software and its documentation for any purpose and37* without fee is hereby granted, provided that the above copyright38* notice appear in all copies and that both that copyright notice and39* this permission notice appear in supporting documentation, and that40* the name of FundsXpress. not be used in advertising or publicity pertaining41* to distribution of the software without specific, written prior42* permission. FundsXpress makes no representations about the suitability of43* this software for any purpose. It is provided "as is" without express44* or implied warranty.45*46* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR47* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED48* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.49*/50/*51* Copyright 2009 Sun Microsystems, Inc. All rights reserved.52* Use is subject to license terms.53*/5455#include <k5-int.h>56#include <kadm5/admin.h>57#include <locale.h>58#include <adm_proto.h>59#include <time.h>60#include "kdb5_util.h"6162/*63* XXX Ick, ick, ick. These global variables shouldn't be global....64*/65char *mkey_password = 0;6667/*68* I can't figure out any way for this not to be global, given how ss69* works.70*/7172int exit_status = 0;73krb5_context util_context;74kadm5_config_params global_params;7576void usage(void)77{78fprintf(stderr,79_("Usage: kdb5_util [-r realm] [-d dbname] "80"[-k mkeytype] [-kv mkeyVNO]\n"81"\t [-M mkeyname] [-m] [-sf stashfilename] "82"[-P password]\n"83"\t [-x db_args]* cmd [cmd_options]\n"84"\tcreate [-s]\n"85"\tdestroy [-f]\n"86"\tstash [-f keyfile]\n"87"\tdump [-b7|-r13|-r18] [-verbose]\n"88"\t [-mkey_convert] [-new_mkey_file mkey_file]\n"89"\t [-rev] [-recurse] [filename [princs...]]\n"90"\tload [-b7|-r13|-r18] [-hash] [-verbose] [-update] "91"filename\n"92"\tark [-e etype_list] principal\n"93"\tadd_mkey [-e etype] [-s]\n"94"\tuse_mkey kvno [time]\n"95"\tlist_mkeys\n"));96/* avoid a string length compiler warning */97fprintf(stderr,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 "102"arguments.\n"103"\t\t\tLook at each database documentation for supported "104"arguments\n"));105exit(1);106}107108krb5_keyblock master_keyblock;109krb5_kvno master_kvno; /* fetched */110extern krb5_principal master_princ;111char *mkey_fullname;112krb5_db_entry *master_entry = NULL;113int valid_master_key = 0;114115char *progname;116krb5_boolean manual_mkey = FALSE;117krb5_boolean dbactive = FALSE;118119static int open_db_and_mkey(void);120121static void add_random_key(int, char **);122123typedef void (*cmd_func)(int, char **);124125struct _cmd_table {126char *name;127cmd_func func;128int opendb;129} cmd_table[] = {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},142{NULL, NULL, 0},143};144145static struct _cmd_table *146cmd_lookup(char *name)147{148struct _cmd_table *cmd = cmd_table;149while (cmd->name) {150if (strcmp(cmd->name, name) == 0)151return cmd;152else153cmd++;154}155156return NULL;157}158159#define ARG_VAL (--argc > 0 ? (koptarg = *(++argv)) : (char *)(usage(), NULL))160161char **db5util_db_args = NULL;162size_t db5util_db_args_size = 0;163164static void165extended_com_err_fn(const char *myprog, errcode_t code, const char *fmt,166va_list args)167{168const char *emsg;169if (code) {170emsg = krb5_get_error_message (util_context, code);171fprintf (stderr, "%s: %s ", myprog, emsg);172krb5_free_error_message (util_context, emsg);173} else {174fprintf (stderr, "%s: ", myprog);175}176vfprintf (stderr, fmt, args);177fprintf (stderr, "\n");178}179180int181add_db_arg(char *arg)182{183char **temp;184db5util_db_args_size++;185temp = realloc(db5util_db_args,186sizeof(char *) * (db5util_db_args_size + 1));187if (temp == NULL)188return 0;189db5util_db_args = temp;190db5util_db_args[db5util_db_args_size-1] = arg;191db5util_db_args[db5util_db_args_size] = NULL;192return 1;193}194195int196main(int argc, char *argv[])197{198struct _cmd_table *cmd = NULL;199char *koptarg, **cmd_argv;200char *db_name_tmp = NULL;201int cmd_argc;202krb5_error_code retval;203204setlocale(LC_ALL, "");205set_com_err_hook(extended_com_err_fn);206207/*208* Ensure that "progname" is set before calling com_err.209*/210progname = (strrchr(argv[0], '/') ?211strrchr(argv[0], '/') + 1 : argv[0]);212213retval = kadm5_init_krb5_context(&util_context);214if (retval) {215com_err (progname, retval, _("while initializing Kerberos code"));216exit(1);217}218219cmd_argv = (char **) malloc(sizeof(char *)*argc);220if (cmd_argv == NULL) {221com_err(progname, ENOMEM, _("while creating sub-command arguments"));222exit(1);223}224memset(cmd_argv, 0, sizeof(char *)*argc);225cmd_argc = 0;226227argv++; argc--;228while (*argv) {229if (strcmp(*argv, "-P") == 0 && ARG_VAL) {230mkey_password = koptarg;231manual_mkey = TRUE;232} else if (strcmp(*argv, "-d") == 0 && ARG_VAL) {233global_params.dbname = koptarg;234global_params.mask |= KADM5_CONFIG_DBNAME;235236if (asprintf(&db_name_tmp, "dbname=%s", global_params.dbname) < 0)237{238com_err(progname, ENOMEM,239_("while parsing command arguments"));240exit(1);241}242243if (!add_db_arg(db_name_tmp)) {244com_err(progname, ENOMEM,245_("while parsing command arguments\n"));246exit(1);247}248249} else if (strcmp(*argv, "-x") == 0 && ARG_VAL) {250if (!add_db_arg(koptarg)) {251com_err(progname, ENOMEM,252_("while parsing command arguments\n"));253exit(1);254}255256} else if (strcmp(*argv, "-r") == 0 && ARG_VAL) {257global_params.realm = koptarg;258global_params.mask |= KADM5_CONFIG_REALM;259/* not sure this is really necessary */260if ((retval = krb5_set_default_realm(util_context,261global_params.realm))) {262com_err(progname, retval,263_("while setting default realm name"));264exit(1);265}266} else if (strcmp(*argv, "-k") == 0 && ARG_VAL) {267if (krb5_string_to_enctype(koptarg, &global_params.enctype)) {268com_err(progname, EINVAL, _(": %s is an invalid enctype"),269koptarg);270exit(1);271} else272global_params.mask |= KADM5_CONFIG_ENCTYPE;273} else if (strcmp(*argv, "-kv") == 0 && ARG_VAL) {274global_params.kvno = (krb5_kvno) atoi(koptarg);275if (global_params.kvno == IGNORE_VNO) {276com_err(progname, EINVAL, _(": %s is an invalid mkeyVNO"),277koptarg);278exit(1);279} else280global_params.mask |= KADM5_CONFIG_KVNO;281} else if (strcmp(*argv, "-M") == 0 && ARG_VAL) {282global_params.mkey_name = koptarg;283global_params.mask |= KADM5_CONFIG_MKEY_NAME;284} else if (strcmp(*argv, "-sf") == 0 && ARG_VAL) {285global_params.stash_file = koptarg;286global_params.mask |= KADM5_CONFIG_STASH_FILE;287} else if (strcmp(*argv, "-m") == 0) {288manual_mkey = TRUE;289global_params.mkey_from_kbd = 1;290global_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;291} else {292cmd_argv[cmd_argc++] = *argv;293}294argv++; argc--;295}296297if (cmd_argv[0] == NULL)298usage();299cmd = cmd_lookup(cmd_argv[0]);300if (cmd == NULL)301usage();302303if( !util_context->default_realm )304{305char *temp = NULL;306retval = krb5_get_default_realm(util_context, &temp);307if( retval )308{309com_err(progname, retval, _("while getting default realm"));310exit(1);311}312krb5_free_default_realm(util_context, temp);313}314315retval = kadm5_get_config_params(util_context, 1,316&global_params, &global_params);317if (retval) {318com_err(progname, retval,319_("while retrieving configuration parameters"));320exit(1);321}322323/*324* Dump creates files which should not be world-readable. It is325* easiest to do a single umask call here.326*/327(void) umask(077);328329master_keyblock.enctype = global_params.enctype;330if ((master_keyblock.enctype != ENCTYPE_UNKNOWN) &&331(!krb5_c_valid_enctype(master_keyblock.enctype))) {332com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,333"while setting up enctype %d", master_keyblock.enctype);334}335336if (cmd->opendb && open_db_and_mkey())337return exit_status;338339if (global_params.iprop_enabled == TRUE)340ulog_set_role(util_context, IPROP_PRIMARY);341else342ulog_set_role(util_context, IPROP_NULL);343344(*cmd->func)(cmd_argc, cmd_argv);345346if( db_name_tmp )347free( db_name_tmp );348349if( db5util_db_args )350free(db5util_db_args);351352quit();353kadm5_free_config_params(util_context, &global_params);354krb5_free_context(util_context);355free(cmd_argv);356return exit_status;357}358359/*360* open_db_and_mkey: Opens the KDC and policy database, and sets the361* global master_* variables. Sets dbactive to TRUE if the databases362* are opened, and valid_master_key to 1 if the global master363* variables are set properly. Returns 0 on success, and 1 on364* failure, but it is not considered a failure if the master key365* cannot be fetched (the master key stash file may not exist when the366* program is run).367*/368static int369open_db_and_mkey(void)370{371krb5_error_code retval;372krb5_data scratch, pwd, seed;373374dbactive = FALSE;375valid_master_key = 0;376377if ((retval = krb5_db_open(util_context, db5util_db_args,378KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN))) {379com_err(progname, retval, _("while initializing database"));380exit_status++;381return(1);382}383384/* assemble & parse the master key name */385386if ((retval = krb5_db_setup_mkey_name(util_context,387global_params.mkey_name,388global_params.realm,389&mkey_fullname, &master_princ))) {390com_err(progname, retval, _("while setting up master key name"));391exit_status++;392return(1);393}394if ((retval = krb5_db_get_principal(util_context, master_princ, 0,395&master_entry))) {396com_err(progname, retval, _("while retrieving master entry"));397exit_status++;398(void) krb5_db_fini(util_context);399return(1);400}401402if (global_params.mask & KADM5_CONFIG_KVNO)403master_kvno = global_params.kvno; /* user specified */404else405master_kvno = IGNORE_VNO;406407/* the databases are now open, and the master principal exists */408dbactive = TRUE;409410if (mkey_password) {411pwd.data = mkey_password;412pwd.length = strlen(mkey_password);413retval = krb5_principal2salt(util_context, master_princ, &scratch);414if (retval) {415com_err(progname, retval, _("while calculated master key salt"));416exit_status++;417return(1);418}419420/* If no encryption type is set, use the default */421if (master_keyblock.enctype == ENCTYPE_UNKNOWN)422master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;423if (!krb5_c_valid_enctype(master_keyblock.enctype))424com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,425"while setting up enctype %d",426master_keyblock.enctype);427428retval = krb5_c_string_to_key(util_context, master_keyblock.enctype,429&pwd, &scratch, &master_keyblock);430if (retval) {431com_err(progname, retval,432_("while transforming master key from password"));433exit_status++;434return(1);435}436free(scratch.data);437mkey_password = 0;438439} else {440if ((retval = krb5_db_fetch_mkey(util_context, master_princ,441master_keyblock.enctype,442manual_mkey, FALSE,443global_params.stash_file,444&master_kvno,4450, &master_keyblock))) {446com_err(progname, retval, _("while reading master key"));447com_err(progname, 0, _("Warning: proceeding without master key"));448exit_status++;449return(0);450}451}452453if ((retval = krb5_db_fetch_mkey_list(util_context, master_princ,454&master_keyblock))) {455com_err(progname, retval, "while getting master key list");456com_err(progname, 0, "Warning: proceeding without master key list");457exit_status++;458return(0);459}460461seed.length = master_keyblock.length;462seed.data = (char *) master_keyblock.contents;463464if ((retval = krb5_c_random_seed(util_context, &seed))) {465com_err(progname, retval, _("while seeding random number generator"));466exit_status++;467memset(master_keyblock.contents, 0, master_keyblock.length);468krb5_free_keyblock_contents(util_context, &master_keyblock);469return(1);470}471472if (global_params.iprop_enabled) {473if (ulog_map(util_context, global_params.iprop_logfile,474global_params.iprop_ulogsize)) {475fprintf(stderr, _("%s: Could not map log\n"), progname);476exit_status++;477return(1);478}479}480481valid_master_key = 1;482dbactive = TRUE;483return 0;484}485486#ifdef HAVE_GETCWD487#undef getwd488#endif489490int491quit(void)492{493krb5_error_code retval;494static krb5_boolean finished = 0;495496if (finished)497return 0;498ulog_fini(util_context);499retval = krb5_db_fini(util_context);500zapfree(master_keyblock.contents, master_keyblock.length);501krb5_free_principal(util_context, master_princ);502finished = TRUE;503if (retval && retval != KRB5_KDB_DBNOTINITED) {504com_err(progname, retval, _("while closing database"));505exit_status++;506return 1;507}508return 0;509}510511static void512add_random_key(int argc, char **argv)513{514krb5_error_code ret;515krb5_principal princ;516krb5_db_entry *dbent;517krb5_timestamp now;518519krb5_key_salt_tuple *keysalts = NULL;520krb5_int32 num_keysalts = 0;521522int free_keysalts;523char *me = progname;524char *ks_str = "";525char *pr_str;526krb5_keyblock *tmp_mkey;527528if (argc < 2)529usage();530for (argv++, argc--; *argv; argv++, argc--) {531if (!strcmp(*argv, "-e")) {532argv++; argc--;533ks_str = *argv;534continue;535} else536break;537}538if (argc < 1)539usage();540pr_str = *argv;541ret = krb5_parse_name(util_context, pr_str, &princ);542if (ret) {543com_err(me, ret, _("while parsing principal name %s"), pr_str);544exit_status++;545return;546}547ret = krb5_db_get_principal(util_context, princ, 0, &dbent);548if (ret) {549com_err(me, ret, _("while fetching principal %s"), pr_str);550exit_status++;551return;552}553ret = krb5_string_to_keysalts(ks_str,554NULL, NULL, 0,555&keysalts,556&num_keysalts);557if (ret) {558com_err(me, ret, _("while parsing keysalts %s"), ks_str);559exit_status++;560return;561}562if (!num_keysalts || keysalts == NULL) {563num_keysalts = global_params.num_keysalts;564keysalts = global_params.keysalts;565free_keysalts = 0;566} else567free_keysalts = 1;568569/* Find the mkey used to protect the existing keys */570ret = krb5_dbe_find_mkey(util_context, dbent, &tmp_mkey);571if (ret) {572com_err(me, ret, _("while finding mkey"));573krb5_db_free_principal(util_context, dbent);574exit_status++;575return;576}577578ret = krb5_dbe_ark(util_context, tmp_mkey, keysalts, num_keysalts, dbent);579if (free_keysalts)580free(keysalts);581if (ret) {582com_err(me, ret, "while randomizing principal %s", pr_str);583krb5_db_free_principal(util_context, dbent);584exit_status++;585return;586}587dbent->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;588ret = krb5_timeofday(util_context, &now);589if (ret) {590com_err(me, ret, _("while getting time"));591krb5_db_free_principal(util_context, dbent);592exit_status++;593return;594}595ret = krb5_dbe_update_last_pwd_change(util_context, dbent, now);596if (ret) {597com_err(me, ret, _("while setting changetime"));598krb5_db_free_principal(util_context, dbent);599exit_status++;600return;601}602603dbent->mask |= KADM5_ATTRIBUTES | KADM5_KEY_DATA | KADM5_TL_DATA;604605ret = krb5_db_put_principal(util_context, dbent);606krb5_db_free_principal(util_context, dbent);607if (ret) {608com_err(me, ret, _("while saving principal %s"), pr_str);609exit_status++;610return;611}612printf(_("%s changed\n"), pr_str);613}614615616