xref: /onnv-gate/usr/src/cmd/krb5/kadmin/dbutil/kdb5_create.c (revision 1692:d9031cb1a5a8)
10Sstevel@tonic-gate /*
2*1692Ssemery  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
70Sstevel@tonic-gate 
80Sstevel@tonic-gate /*
90Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
100Sstevel@tonic-gate  *
110Sstevel@tonic-gate  *	Openvision retains the copyright to derivative works of
120Sstevel@tonic-gate  *	this source code.  Do *NOT* create a derivative of this
130Sstevel@tonic-gate  *	source code before consulting with your legal department.
140Sstevel@tonic-gate  *	Do *NOT* integrate *ANY* of this source code into another
150Sstevel@tonic-gate  *	product before consulting with your legal department.
160Sstevel@tonic-gate  *
170Sstevel@tonic-gate  *	For further information, read the top-level Openvision
180Sstevel@tonic-gate  *	copyright which is contained in the top-level MIT Kerberos
190Sstevel@tonic-gate  *	copyright.
200Sstevel@tonic-gate  *
210Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
220Sstevel@tonic-gate  *
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * admin/create/kdb5_create.c
280Sstevel@tonic-gate  *
290Sstevel@tonic-gate  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
300Sstevel@tonic-gate  * All Rights Reserved.
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * Export of this software from the United States of America may
330Sstevel@tonic-gate  *   require a specific license from the United States Government.
340Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
350Sstevel@tonic-gate  *   export to obtain such a license before exporting.
360Sstevel@tonic-gate  *
370Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
380Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
390Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
400Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
410Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
420Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
430Sstevel@tonic-gate  * to distribution of the software without specific, written prior
440Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
450Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
460Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
470Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
480Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
490Sstevel@tonic-gate  * or implied warranty.
500Sstevel@tonic-gate  *
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  * Generate (from scratch) a Kerberos KDC database.
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate  *  Yes, I know this is a hack, but we need admin.h without including the
570Sstevel@tonic-gate  *  rpc.h header. Additionally, our rpc.h header brings in
580Sstevel@tonic-gate  *  a des.h header which causes other problems.
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate #define	_RPC_RPC_H
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #include <stdio.h>
630Sstevel@tonic-gate #define KDB5_DISPATCH
640Sstevel@tonic-gate #define KRB5_KDB5_DBM__
650Sstevel@tonic-gate #include <k5-int.h>
660Sstevel@tonic-gate /* #define these to avoid an indirection function; for future implementations,
670Sstevel@tonic-gate    these may be redirected from a dispatch table/routine */
680Sstevel@tonic-gate #define krb5_dbm_db_set_name krb5_db_set_name
690Sstevel@tonic-gate #define krb5_dbm_db_set_nonblocking krb5_db_set_nonblocking
700Sstevel@tonic-gate #define krb5_dbm_db_init krb5_db_init
710Sstevel@tonic-gate #define krb5_dbm_db_get_age krb5_db_get_age
720Sstevel@tonic-gate #define krb5_dbm_db_create krb5_db_create
730Sstevel@tonic-gate #define krb5_dbm_db_rename krb5_db_rename
740Sstevel@tonic-gate #define krb5_dbm_db_get_principal krb5_db_get_principal
750Sstevel@tonic-gate #define krb5_dbm_db_free_principal krb5_db_free_principal
760Sstevel@tonic-gate #define krb5_dbm_db_put_principal krb5_db_put_principal
770Sstevel@tonic-gate #define krb5_dbm_db_delete_principal krb5_db_delete_principal
780Sstevel@tonic-gate #define krb5_dbm_db_lock krb5_db_lock
790Sstevel@tonic-gate #define krb5_dbm_db_unlock krb5_db_unlock
800Sstevel@tonic-gate #define krb5_dbm_db_set_lockmode krb5_db_set_lockmode
810Sstevel@tonic-gate #define krb5_dbm_db_close_database krb5_db_close_database
820Sstevel@tonic-gate #define krb5_dbm_db_open_database krb5_db_open_database
830Sstevel@tonic-gate 
840Sstevel@tonic-gate #include <kadm5/admin.h>
850Sstevel@tonic-gate #include <rpc/types.h>
860Sstevel@tonic-gate #include <rpc/xdr.h>
870Sstevel@tonic-gate #include <kadm5/adb.h>
880Sstevel@tonic-gate #include <libintl.h>
890Sstevel@tonic-gate #include "kdb5_util.h"
900Sstevel@tonic-gate 
910Sstevel@tonic-gate enum ap_op {
920Sstevel@tonic-gate     NULL_KEY,				/* setup null keys */
930Sstevel@tonic-gate     MASTER_KEY,				/* use master key as new key */
940Sstevel@tonic-gate     TGT_KEY				/* special handling for tgt key */
950Sstevel@tonic-gate };
960Sstevel@tonic-gate 
970Sstevel@tonic-gate krb5_key_salt_tuple def_kslist =
980Sstevel@tonic-gate 	{ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_NORMAL};
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate struct realm_info {
1010Sstevel@tonic-gate     krb5_deltat max_life;
1020Sstevel@tonic-gate     krb5_deltat max_rlife;
1030Sstevel@tonic-gate     krb5_timestamp expiration;
1040Sstevel@tonic-gate     krb5_flags flags;
1050Sstevel@tonic-gate     krb5_keyblock *key;
1060Sstevel@tonic-gate     krb5_int32 nkslist;
1070Sstevel@tonic-gate     krb5_key_salt_tuple *kslist;
1080Sstevel@tonic-gate } rblock = { /* XXX */
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate     KRB5_KDB_MAX_LIFE,
1110Sstevel@tonic-gate     KRB5_KDB_MAX_RLIFE,
1120Sstevel@tonic-gate     KRB5_KDB_EXPIRATION,
1130Sstevel@tonic-gate     KRB5_KDB_DEF_FLAGS,
1140Sstevel@tonic-gate     (krb5_keyblock *) NULL,
1150Sstevel@tonic-gate     1,
1160Sstevel@tonic-gate     &def_kslist
1170Sstevel@tonic-gate };
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate struct iterate_args {
1200Sstevel@tonic-gate     krb5_context	ctx;
1210Sstevel@tonic-gate     struct realm_info	*rblock;
1220Sstevel@tonic-gate     krb5_db_entry	*dbentp;
1230Sstevel@tonic-gate };
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate static krb5_error_code add_principal(krb5_context,
1260Sstevel@tonic-gate 		krb5_principal,
1270Sstevel@tonic-gate 		enum ap_op,
1280Sstevel@tonic-gate 		struct realm_info *,
1290Sstevel@tonic-gate 		krb5_keyblock *);
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate /*
1320Sstevel@tonic-gate  * Steps in creating a database:
1330Sstevel@tonic-gate  *
1340Sstevel@tonic-gate  * 1) use the db calls to open/create a new database
1350Sstevel@tonic-gate  *
1360Sstevel@tonic-gate  * 2) get a realm name for the new db
1370Sstevel@tonic-gate  *
1380Sstevel@tonic-gate  * 3) get a master password for the new db; convert to an encryption key.
1390Sstevel@tonic-gate  *
1400Sstevel@tonic-gate  * 4) create various required entries in the database
1410Sstevel@tonic-gate  *
1420Sstevel@tonic-gate  * 5) close & exit
1430Sstevel@tonic-gate  */
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate extern krb5_principal master_princ;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate krb5_data tgt_princ_entries[] = {
1480Sstevel@tonic-gate 	{0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME},
1490Sstevel@tonic-gate 	{0, 0, 0} };
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate krb5_data db_creator_entries[] = {
1520Sstevel@tonic-gate 	{0, sizeof("db_creation")-1, "db_creation"} };
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate  * XXX knows about contents of krb5_principal, and that tgt names
1560Sstevel@tonic-gate  * are of form TGT/REALM@REALM
1570Sstevel@tonic-gate  */
1580Sstevel@tonic-gate krb5_principal_data tgt_princ = {
1590Sstevel@tonic-gate         0,					/* magic number */
1600Sstevel@tonic-gate 	{0, 0, 0},				/* krb5_data realm */
1610Sstevel@tonic-gate 	tgt_princ_entries,			/* krb5_data *data */
1620Sstevel@tonic-gate 	2,					/* int length */
1630Sstevel@tonic-gate 	KRB5_NT_SRV_INST			/* int type */
1640Sstevel@tonic-gate };
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate krb5_principal_data db_create_princ = {
1670Sstevel@tonic-gate         0,					/* magic number */
1680Sstevel@tonic-gate 	{0, 0, 0},				/* krb5_data realm */
1690Sstevel@tonic-gate 	db_creator_entries,			/* krb5_data *data */
1700Sstevel@tonic-gate 	1,					/* int length */
1710Sstevel@tonic-gate 	KRB5_NT_SRV_INST			/* int type */
1720Sstevel@tonic-gate };
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate extern char *mkey_password;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate extern char *progname;
1770Sstevel@tonic-gate extern int exit_status;
1780Sstevel@tonic-gate extern osa_adb_policy_t policy_db;
1790Sstevel@tonic-gate extern kadm5_config_params global_params;
1800Sstevel@tonic-gate extern krb5_context util_context;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate void
1830Sstevel@tonic-gate kdb5_create(argc, argv)
1840Sstevel@tonic-gate    int argc;
1850Sstevel@tonic-gate    char *argv[];
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate     int optchar;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate     krb5_error_code retval;
1900Sstevel@tonic-gate     char *mkey_fullname;
1910Sstevel@tonic-gate     char *pw_str = 0;
1920Sstevel@tonic-gate     unsigned int pw_size = 0;
1930Sstevel@tonic-gate     int do_stash = 0;
1940Sstevel@tonic-gate     krb5_int32 crflags = KRB5_KDB_CREATE_BTREE;
1950Sstevel@tonic-gate     krb5_data pwd, seed;
1960Sstevel@tonic-gate     kdb_log_context *log_ctx;
1970Sstevel@tonic-gate     krb5_keyblock mkey;
1980Sstevel@tonic-gate     krb5_data master_salt = { 0, NULL };
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate     if (strrchr(argv[0], '/'))
2010Sstevel@tonic-gate 	argv[0] = strrchr(argv[0], '/')+1;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate     while ((optchar = getopt(argc, argv, "s")) != -1) {
2040Sstevel@tonic-gate 	switch(optchar) {
2050Sstevel@tonic-gate 	case 's':
2060Sstevel@tonic-gate 	    do_stash++;
2070Sstevel@tonic-gate 	    break;
2080Sstevel@tonic-gate 	case 'h':
2090Sstevel@tonic-gate 	    crflags = KRB5_KDB_CREATE_HASH;
2100Sstevel@tonic-gate 	case '?':
2110Sstevel@tonic-gate 	default:
2120Sstevel@tonic-gate 	    usage();
2130Sstevel@tonic-gate 	    return;
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate     }
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate     rblock.max_life = global_params.max_life;
2180Sstevel@tonic-gate     rblock.max_rlife = global_params.max_rlife;
2190Sstevel@tonic-gate     rblock.expiration = global_params.expiration;
2200Sstevel@tonic-gate     rblock.flags = global_params.flags;
2210Sstevel@tonic-gate     rblock.nkslist = global_params.num_keysalts;
2220Sstevel@tonic-gate     rblock.kslist = global_params.keysalts;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate     log_ctx = util_context->kdblog_context;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate     retval = krb5_db_set_name(util_context, global_params.dbname);
2270Sstevel@tonic-gate 	if (!retval)
2280Sstevel@tonic-gate 		retval = EEXIST;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate     if (retval == EEXIST || retval == EACCES || retval == EPERM) {
2310Sstevel@tonic-gate 	/* it exists ! */
2320Sstevel@tonic-gate 		com_err(argv[0], 0,
2330Sstevel@tonic-gate 			gettext("The database '%s' appears to already exist"),
2340Sstevel@tonic-gate 		global_params.dbname);
2350Sstevel@tonic-gate 		exit_status++;
2360Sstevel@tonic-gate 		return;
2370Sstevel@tonic-gate     }
2380Sstevel@tonic-gate     /* assemble & parse the master key name */
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate     if ((retval = krb5_db_setup_mkey_name(util_context,
2410Sstevel@tonic-gate 					  global_params.mkey_name,
2420Sstevel@tonic-gate 					  global_params.realm,
2430Sstevel@tonic-gate 					  &mkey_fullname, &master_princ))) {
2440Sstevel@tonic-gate 		com_err(argv[0], retval,
2450Sstevel@tonic-gate 			gettext("while setting up master key name"));
2460Sstevel@tonic-gate 		exit_status++;
2470Sstevel@tonic-gate 		return;
2480Sstevel@tonic-gate     }
2490Sstevel@tonic-gate 	krb5_princ_set_realm_data(util_context,
2500Sstevel@tonic-gate 				&db_create_princ, global_params.realm);
2510Sstevel@tonic-gate 	krb5_princ_set_realm_length(util_context,
2520Sstevel@tonic-gate 				    &db_create_princ,
2530Sstevel@tonic-gate 				    strlen(global_params.realm));
2540Sstevel@tonic-gate 	krb5_princ_set_realm_data(util_context,
2550Sstevel@tonic-gate 				&tgt_princ, global_params.realm);
2560Sstevel@tonic-gate 	krb5_princ_set_realm_length(util_context,
2570Sstevel@tonic-gate 				    &tgt_princ, strlen(global_params.realm));
2580Sstevel@tonic-gate 	krb5_princ_component(util_context, &tgt_princ, 1)->data =
2590Sstevel@tonic-gate 	    global_params.realm;
2600Sstevel@tonic-gate 	krb5_princ_component(util_context, &tgt_princ, 1)->length =
2610Sstevel@tonic-gate 	    strlen(global_params.realm);
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	printf(gettext("Initializing database '%s' for realm '%s',\n"
2640Sstevel@tonic-gate 			"master key name '%s'\n"),
2650Sstevel@tonic-gate 	   global_params.dbname, global_params.realm, mkey_fullname);
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate     if (!mkey_password) {
2680Sstevel@tonic-gate 	printf(gettext("You will be prompted for the "
2690Sstevel@tonic-gate 			"database Master Password.\n"));
2700Sstevel@tonic-gate 	printf(gettext("It is important that you NOT FORGET this password.\n"));
2710Sstevel@tonic-gate 	fflush(stdout);
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	pw_size = 1024;
2740Sstevel@tonic-gate 	pw_str = malloc(pw_size);
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	retval = krb5_read_password(util_context,
277*1692Ssemery 			    gettext("Enter KDC database master key"),
2780Sstevel@tonic-gate 			    gettext("Re-enter KDC database "
279*1692Ssemery 				    "master key to verify"),
2800Sstevel@tonic-gate 			    pw_str, &pw_size);
2810Sstevel@tonic-gate 	if (retval) {
2820Sstevel@tonic-gate 		com_err(argv[0], retval,
2830Sstevel@tonic-gate 		    gettext("while reading master key from keyboard"));
2840Sstevel@tonic-gate 		exit_status++;
2850Sstevel@tonic-gate 		return;
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 	mkey_password = pw_str;
2880Sstevel@tonic-gate     }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate     pwd.data = mkey_password;
2910Sstevel@tonic-gate     pwd.length = strlen(mkey_password);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate     retval = krb5_principal2salt(util_context, master_princ, &master_salt);
2940Sstevel@tonic-gate     if (retval) {
2950Sstevel@tonic-gate 	com_err(argv[0], retval,
2960Sstevel@tonic-gate 		gettext("while calculated master key salt"));
2970Sstevel@tonic-gate 	exit_status++;
2980Sstevel@tonic-gate 	goto cleanup;
2990Sstevel@tonic-gate     }
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate     if (retval = krb5_c_string_to_key(util_context, global_params.enctype,
3020Sstevel@tonic-gate 			      &pwd, &master_salt, &mkey)) {
3030Sstevel@tonic-gate 	com_err(argv[0], retval,
3040Sstevel@tonic-gate 	    gettext("while transforming master key from password"));
3050Sstevel@tonic-gate 	exit_status++;
3060Sstevel@tonic-gate 	goto cleanup;
3070Sstevel@tonic-gate     }
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate     retval = krb5_copy_keyblock(util_context, &mkey, &rblock.key);
3100Sstevel@tonic-gate     if (retval) {
3110Sstevel@tonic-gate 	com_err(argv[0], retval, gettext("while copying master key"));
3120Sstevel@tonic-gate 	exit_status++;
3130Sstevel@tonic-gate 	goto cleanup;
3140Sstevel@tonic-gate     }
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate     seed.length = mkey.length;
3170Sstevel@tonic-gate     seed.data = (char *)mkey.contents;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate     if ((retval = krb5_c_random_seed(util_context, &seed))) {
3200Sstevel@tonic-gate 	com_err(argv[0], retval,
3210Sstevel@tonic-gate 		gettext("while initializing random key generator"));
3220Sstevel@tonic-gate 	exit_status++;
3230Sstevel@tonic-gate 	goto cleanup;
3240Sstevel@tonic-gate     }
3250Sstevel@tonic-gate     if ((retval = krb5_db_create(util_context,
3260Sstevel@tonic-gate 				 global_params.dbname, crflags))) {
3270Sstevel@tonic-gate 	com_err(argv[0], retval,
3280Sstevel@tonic-gate 		gettext("while creating database '%s'"),
3290Sstevel@tonic-gate 		global_params.dbname);
3300Sstevel@tonic-gate 	exit_status++;
3310Sstevel@tonic-gate 	goto cleanup;
3320Sstevel@tonic-gate     }
3330Sstevel@tonic-gate     if (retval = krb5_db_fini(util_context)) {
3340Sstevel@tonic-gate 	com_err(argv[0], retval,
3350Sstevel@tonic-gate 		gettext("while closing current database"));
3360Sstevel@tonic-gate 	exit_status++;
3370Sstevel@tonic-gate 	goto cleanup;
3380Sstevel@tonic-gate     }
3390Sstevel@tonic-gate     if ((retval = krb5_db_set_name(util_context, global_params.dbname))) {
3400Sstevel@tonic-gate 	com_err(argv[0], retval,
3410Sstevel@tonic-gate 		gettext("while setting active database to '%s'"),
3420Sstevel@tonic-gate                global_params.dbname);
3430Sstevel@tonic-gate 	exit_status++;
3440Sstevel@tonic-gate 	goto cleanup;
3450Sstevel@tonic-gate     }
3460Sstevel@tonic-gate     if ((retval = krb5_db_init(util_context))) {
3470Sstevel@tonic-gate 	com_err(argv[0], retval,
3480Sstevel@tonic-gate 		gettext("while initializing the database '%s'"),
3490Sstevel@tonic-gate 	global_params.dbname);
3500Sstevel@tonic-gate 	exit_status++;
3510Sstevel@tonic-gate 	goto cleanup;
3520Sstevel@tonic-gate     }
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate     if (log_ctx && log_ctx->iproprole) {
3550Sstevel@tonic-gate 	if (retval = ulog_map(util_context, &global_params, FKCOMMAND)) {
3560Sstevel@tonic-gate 		com_err(argv[0], retval,
3570Sstevel@tonic-gate 			gettext("while creating update log"));
3580Sstevel@tonic-gate 		exit_status++;
3590Sstevel@tonic-gate 		goto cleanup;
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	/*
3630Sstevel@tonic-gate 	 * We're reinitializing the update log in case one already
3640Sstevel@tonic-gate 	 * existed, but this should never happen.
3650Sstevel@tonic-gate 	 */
3660Sstevel@tonic-gate 	(void) memset(log_ctx->ulog, 0, sizeof (kdb_hlog_t));
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	log_ctx->ulog->kdb_hmagic = KDB_HMAGIC;
3690Sstevel@tonic-gate 	log_ctx->ulog->db_version_num = KDB_VERSION;
3700Sstevel@tonic-gate 	log_ctx->ulog->kdb_state = KDB_STABLE;
3710Sstevel@tonic-gate 	log_ctx->ulog->kdb_block = ULOG_BLOCK;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	/*
3740Sstevel@tonic-gate 	 * Since we're creating a new db we shouldn't worry about
3750Sstevel@tonic-gate 	 * adding the initial principals since any slave might as well
3760Sstevel@tonic-gate 	 * do full resyncs from this newly created db.
3770Sstevel@tonic-gate 	 */
3780Sstevel@tonic-gate 	log_ctx->iproprole = IPROP_NULL;
3790Sstevel@tonic-gate     }
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate     if ((retval = add_principal(util_context,
3820Sstevel@tonic-gate 		    master_princ, MASTER_KEY, &rblock, &mkey)) ||
3830Sstevel@tonic-gate 	(retval = add_principal(util_context,
3840Sstevel@tonic-gate 			    &tgt_princ, TGT_KEY, &rblock, &mkey))) {
3850Sstevel@tonic-gate 	(void) krb5_db_fini(util_context);
3860Sstevel@tonic-gate 	com_err(argv[0], retval,
3870Sstevel@tonic-gate 	    gettext("while adding entries to the database"));
3880Sstevel@tonic-gate 	exit_status++;
3890Sstevel@tonic-gate 	goto cleanup;
3900Sstevel@tonic-gate     }
3910Sstevel@tonic-gate     /*
3920Sstevel@tonic-gate      * Always stash the master key so kadm5_create does not prompt for
3930Sstevel@tonic-gate      * it; delete the file below if it was not requested.  DO NOT EXIT
3940Sstevel@tonic-gate      * BEFORE DELETING THE KEYFILE if do_stash is not set.
3950Sstevel@tonic-gate      */
3960Sstevel@tonic-gate     if (retval = krb5_db_store_mkey(util_context,
3970Sstevel@tonic-gate 				    global_params.stash_file,
3980Sstevel@tonic-gate 				    master_princ,
3990Sstevel@tonic-gate 				    &mkey)) {
4000Sstevel@tonic-gate 	com_err(argv[0], errno, gettext("while storing key"));
4010Sstevel@tonic-gate 	printf(gettext("Warning: couldn't stash master key.\n"));
4020Sstevel@tonic-gate     }
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate     if (pw_str)
4050Sstevel@tonic-gate 	memset(pw_str, 0, pw_size);
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate     if (kadm5_create(&global_params)) {
4080Sstevel@tonic-gate 	if (!do_stash)
4090Sstevel@tonic-gate 		unlink(global_params.stash_file);
4100Sstevel@tonic-gate 	exit_status++;
4110Sstevel@tonic-gate 	goto cleanup;
4120Sstevel@tonic-gate     }
4130Sstevel@tonic-gate     if (!do_stash)
4140Sstevel@tonic-gate 	unlink(global_params.stash_file);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate cleanup:
4170Sstevel@tonic-gate     if (pw_str) {
4180Sstevel@tonic-gate 	if (mkey_password == pw_str)
4190Sstevel@tonic-gate 		mkey_password = NULL;
4200Sstevel@tonic-gate 	free(pw_str);
4210Sstevel@tonic-gate     }
4220Sstevel@tonic-gate     if (master_salt.data)
4230Sstevel@tonic-gate 	free(master_salt.data);
4240Sstevel@tonic-gate     krb5_free_keyblock_contents(util_context, rblock.key);
4250Sstevel@tonic-gate     krb5_free_keyblock_contents(util_context, &mkey);
4260Sstevel@tonic-gate     (void) krb5_db_fini(util_context);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate     return;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate static krb5_error_code
4330Sstevel@tonic-gate tgt_keysalt_iterate(ksent, ptr)
4340Sstevel@tonic-gate     krb5_key_salt_tuple	*ksent;
4350Sstevel@tonic-gate     krb5_pointer	ptr;
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate     krb5_context	context;
4380Sstevel@tonic-gate     krb5_error_code	kret;
4390Sstevel@tonic-gate     struct iterate_args	*iargs;
4400Sstevel@tonic-gate     krb5_keyblock	key;
4410Sstevel@tonic-gate     krb5_int32		ind;
4420Sstevel@tonic-gate     krb5_pointer rseed;
4430Sstevel@tonic-gate     krb5_data	pwd;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate     iargs = (struct iterate_args *) ptr;
4460Sstevel@tonic-gate     kret = 0;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate     context = iargs->ctx;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate     /*
4510Sstevel@tonic-gate      * Convert the master key password into a key for this particular
4520Sstevel@tonic-gate      * encryption system.
4530Sstevel@tonic-gate      */
4540Sstevel@tonic-gate     pwd.data = mkey_password;
4550Sstevel@tonic-gate     pwd.length = strlen(mkey_password);
4560Sstevel@tonic-gate     if (kret = krb5_c_random_seed(context, &pwd))
4570Sstevel@tonic-gate 	return kret;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate     if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) {
4600Sstevel@tonic-gate 	ind = iargs->dbentp->n_key_data-1;
4610Sstevel@tonic-gate 	if (!(kret = krb5_c_make_random_key(context, ksent->ks_enctype,
4620Sstevel@tonic-gate 					    &key))) {
4630Sstevel@tonic-gate 	    kret = krb5_dbekd_encrypt_key_data(context,
4640Sstevel@tonic-gate 					       iargs->rblock->key,
4650Sstevel@tonic-gate 					       &key,
4660Sstevel@tonic-gate 					       NULL,
4670Sstevel@tonic-gate 					       1,
4680Sstevel@tonic-gate 					       &iargs->dbentp->key_data[ind]);
4690Sstevel@tonic-gate 	    krb5_free_keyblock_contents(context, &key);
4700Sstevel@tonic-gate 	}
4710Sstevel@tonic-gate     }
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate     return(kret);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate static krb5_error_code
4770Sstevel@tonic-gate add_principal(krb5_context context,
4780Sstevel@tonic-gate     krb5_principal princ,
4790Sstevel@tonic-gate     enum ap_op op,
4800Sstevel@tonic-gate     struct realm_info *pblock,
4810Sstevel@tonic-gate     krb5_keyblock *mkey)
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate     krb5_error_code 	  retval;
4840Sstevel@tonic-gate     krb5_db_entry 	  entry;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate     krb5_timestamp	  now;
4870Sstevel@tonic-gate     struct iterate_args	  iargs;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate     int			  nentries = 1;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate     memset((char *) &entry, 0, sizeof(entry));
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate     entry.len = KRB5_KDB_V1_BASE_LENGTH;
4940Sstevel@tonic-gate     entry.attributes = pblock->flags;
4950Sstevel@tonic-gate     entry.max_life = pblock->max_life;
4960Sstevel@tonic-gate     entry.max_renewable_life = pblock->max_rlife;
4970Sstevel@tonic-gate     entry.expiration = pblock->expiration;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate     if ((retval = krb5_copy_principal(context, princ, &entry.princ)))
5000Sstevel@tonic-gate 	goto error_out;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate     if ((retval = krb5_timeofday(context, &now)))
5030Sstevel@tonic-gate 	goto error_out;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate     if ((retval = krb5_dbe_update_mod_princ_data(context, &entry,
5060Sstevel@tonic-gate 						 now, &db_create_princ)))
5070Sstevel@tonic-gate 	goto error_out;
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate     switch (op) {
5100Sstevel@tonic-gate     case MASTER_KEY:
5110Sstevel@tonic-gate 	entry.key_data = (krb5_key_data *) malloc(sizeof (krb5_key_data));
5120Sstevel@tonic-gate 	if (entry.key_data == NULL)
5130Sstevel@tonic-gate 	    goto error_out;
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	memset((char *) entry.key_data, 0, sizeof(krb5_key_data));
5160Sstevel@tonic-gate 	entry.n_key_data = 1;
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
5190Sstevel@tonic-gate 	if ((retval = krb5_dbekd_encrypt_key_data(context, pblock->key,
5200Sstevel@tonic-gate 				  mkey, NULL, 1, entry.key_data)))
5210Sstevel@tonic-gate 		goto error_out;
5220Sstevel@tonic-gate 	break;
5230Sstevel@tonic-gate     case TGT_KEY:
5240Sstevel@tonic-gate 	iargs.ctx = context;
5250Sstevel@tonic-gate 	iargs.rblock = pblock;
5260Sstevel@tonic-gate 	iargs.dbentp = &entry;
5270Sstevel@tonic-gate 	/*
5280Sstevel@tonic-gate 	 * Iterate through the key/salt list, ignoring salt types.
5290Sstevel@tonic-gate 	 */
5300Sstevel@tonic-gate 	if ((retval = krb5_keysalt_iterate(pblock->kslist,
5310Sstevel@tonic-gate 					   pblock->nkslist,
5320Sstevel@tonic-gate 					   1,
5330Sstevel@tonic-gate 					   tgt_keysalt_iterate,
5340Sstevel@tonic-gate 					   (krb5_pointer) &iargs)))
5350Sstevel@tonic-gate 		return (retval);
5360Sstevel@tonic-gate 	break;
5370Sstevel@tonic-gate     case NULL_KEY:
5380Sstevel@tonic-gate 	return (EOPNOTSUPP);
5390Sstevel@tonic-gate     default:
5400Sstevel@tonic-gate 	break;
5410Sstevel@tonic-gate     }
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate     retval = krb5_db_put_principal(context, &entry, &nentries);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate error_out:;
5460Sstevel@tonic-gate 	krb5_dbe_free_contents(context, &entry);
5470Sstevel@tonic-gate 	return (retval);
5480Sstevel@tonic-gate }
549