xref: /onnv-gate/usr/src/cmd/krb5/kadmin/dbutil/kdb5_create.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate /*
9*0Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
10*0Sstevel@tonic-gate  *
11*0Sstevel@tonic-gate  *	Openvision retains the copyright to derivative works of
12*0Sstevel@tonic-gate  *	this source code.  Do *NOT* create a derivative of this
13*0Sstevel@tonic-gate  *	source code before consulting with your legal department.
14*0Sstevel@tonic-gate  *	Do *NOT* integrate *ANY* of this source code into another
15*0Sstevel@tonic-gate  *	product before consulting with your legal department.
16*0Sstevel@tonic-gate  *
17*0Sstevel@tonic-gate  *	For further information, read the top-level Openvision
18*0Sstevel@tonic-gate  *	copyright which is contained in the top-level MIT Kerberos
19*0Sstevel@tonic-gate  *	copyright.
20*0Sstevel@tonic-gate  *
21*0Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
22*0Sstevel@tonic-gate  *
23*0Sstevel@tonic-gate  */
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate 
26*0Sstevel@tonic-gate /*
27*0Sstevel@tonic-gate  * admin/create/kdb5_create.c
28*0Sstevel@tonic-gate  *
29*0Sstevel@tonic-gate  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
30*0Sstevel@tonic-gate  * All Rights Reserved.
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * Export of this software from the United States of America may
33*0Sstevel@tonic-gate  *   require a specific license from the United States Government.
34*0Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
35*0Sstevel@tonic-gate  *   export to obtain such a license before exporting.
36*0Sstevel@tonic-gate  *
37*0Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
38*0Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
39*0Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
40*0Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
41*0Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
42*0Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
43*0Sstevel@tonic-gate  * to distribution of the software without specific, written prior
44*0Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
45*0Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
46*0Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
47*0Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
48*0Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
49*0Sstevel@tonic-gate  * or implied warranty.
50*0Sstevel@tonic-gate  *
51*0Sstevel@tonic-gate  *
52*0Sstevel@tonic-gate  * Generate (from scratch) a Kerberos KDC database.
53*0Sstevel@tonic-gate  */
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate /*
56*0Sstevel@tonic-gate  *  Yes, I know this is a hack, but we need admin.h without including the
57*0Sstevel@tonic-gate  *  rpc.h header. Additionally, our rpc.h header brings in
58*0Sstevel@tonic-gate  *  a des.h header which causes other problems.
59*0Sstevel@tonic-gate  */
60*0Sstevel@tonic-gate #define	_RPC_RPC_H
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate #include <stdio.h>
63*0Sstevel@tonic-gate #define KDB5_DISPATCH
64*0Sstevel@tonic-gate #define KRB5_KDB5_DBM__
65*0Sstevel@tonic-gate #include <k5-int.h>
66*0Sstevel@tonic-gate /* #define these to avoid an indirection function; for future implementations,
67*0Sstevel@tonic-gate    these may be redirected from a dispatch table/routine */
68*0Sstevel@tonic-gate #define krb5_dbm_db_set_name krb5_db_set_name
69*0Sstevel@tonic-gate #define krb5_dbm_db_set_nonblocking krb5_db_set_nonblocking
70*0Sstevel@tonic-gate #define krb5_dbm_db_init krb5_db_init
71*0Sstevel@tonic-gate #define krb5_dbm_db_get_age krb5_db_get_age
72*0Sstevel@tonic-gate #define krb5_dbm_db_create krb5_db_create
73*0Sstevel@tonic-gate #define krb5_dbm_db_rename krb5_db_rename
74*0Sstevel@tonic-gate #define krb5_dbm_db_get_principal krb5_db_get_principal
75*0Sstevel@tonic-gate #define krb5_dbm_db_free_principal krb5_db_free_principal
76*0Sstevel@tonic-gate #define krb5_dbm_db_put_principal krb5_db_put_principal
77*0Sstevel@tonic-gate #define krb5_dbm_db_delete_principal krb5_db_delete_principal
78*0Sstevel@tonic-gate #define krb5_dbm_db_lock krb5_db_lock
79*0Sstevel@tonic-gate #define krb5_dbm_db_unlock krb5_db_unlock
80*0Sstevel@tonic-gate #define krb5_dbm_db_set_lockmode krb5_db_set_lockmode
81*0Sstevel@tonic-gate #define krb5_dbm_db_close_database krb5_db_close_database
82*0Sstevel@tonic-gate #define krb5_dbm_db_open_database krb5_db_open_database
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate #include <kadm5/admin.h>
85*0Sstevel@tonic-gate #include <rpc/types.h>
86*0Sstevel@tonic-gate #include <rpc/xdr.h>
87*0Sstevel@tonic-gate #include <kadm5/adb.h>
88*0Sstevel@tonic-gate #include <libintl.h>
89*0Sstevel@tonic-gate #include "kdb5_util.h"
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate enum ap_op {
92*0Sstevel@tonic-gate     NULL_KEY,				/* setup null keys */
93*0Sstevel@tonic-gate     MASTER_KEY,				/* use master key as new key */
94*0Sstevel@tonic-gate     TGT_KEY				/* special handling for tgt key */
95*0Sstevel@tonic-gate };
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate krb5_key_salt_tuple def_kslist =
98*0Sstevel@tonic-gate 	{ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_NORMAL};
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate struct realm_info {
101*0Sstevel@tonic-gate     krb5_deltat max_life;
102*0Sstevel@tonic-gate     krb5_deltat max_rlife;
103*0Sstevel@tonic-gate     krb5_timestamp expiration;
104*0Sstevel@tonic-gate     krb5_flags flags;
105*0Sstevel@tonic-gate     krb5_keyblock *key;
106*0Sstevel@tonic-gate     krb5_int32 nkslist;
107*0Sstevel@tonic-gate     krb5_key_salt_tuple *kslist;
108*0Sstevel@tonic-gate } rblock = { /* XXX */
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate     KRB5_KDB_MAX_LIFE,
111*0Sstevel@tonic-gate     KRB5_KDB_MAX_RLIFE,
112*0Sstevel@tonic-gate     KRB5_KDB_EXPIRATION,
113*0Sstevel@tonic-gate     KRB5_KDB_DEF_FLAGS,
114*0Sstevel@tonic-gate     (krb5_keyblock *) NULL,
115*0Sstevel@tonic-gate     1,
116*0Sstevel@tonic-gate     &def_kslist
117*0Sstevel@tonic-gate };
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate struct iterate_args {
120*0Sstevel@tonic-gate     krb5_context	ctx;
121*0Sstevel@tonic-gate     struct realm_info	*rblock;
122*0Sstevel@tonic-gate     krb5_db_entry	*dbentp;
123*0Sstevel@tonic-gate };
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate static krb5_error_code add_principal(krb5_context,
126*0Sstevel@tonic-gate 		krb5_principal,
127*0Sstevel@tonic-gate 		enum ap_op,
128*0Sstevel@tonic-gate 		struct realm_info *,
129*0Sstevel@tonic-gate 		krb5_keyblock *);
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate /*
132*0Sstevel@tonic-gate  * Steps in creating a database:
133*0Sstevel@tonic-gate  *
134*0Sstevel@tonic-gate  * 1) use the db calls to open/create a new database
135*0Sstevel@tonic-gate  *
136*0Sstevel@tonic-gate  * 2) get a realm name for the new db
137*0Sstevel@tonic-gate  *
138*0Sstevel@tonic-gate  * 3) get a master password for the new db; convert to an encryption key.
139*0Sstevel@tonic-gate  *
140*0Sstevel@tonic-gate  * 4) create various required entries in the database
141*0Sstevel@tonic-gate  *
142*0Sstevel@tonic-gate  * 5) close & exit
143*0Sstevel@tonic-gate  */
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate extern krb5_principal master_princ;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate krb5_data tgt_princ_entries[] = {
148*0Sstevel@tonic-gate 	{0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME},
149*0Sstevel@tonic-gate 	{0, 0, 0} };
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate krb5_data db_creator_entries[] = {
152*0Sstevel@tonic-gate 	{0, sizeof("db_creation")-1, "db_creation"} };
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate /*
155*0Sstevel@tonic-gate  * XXX knows about contents of krb5_principal, and that tgt names
156*0Sstevel@tonic-gate  * are of form TGT/REALM@REALM
157*0Sstevel@tonic-gate  */
158*0Sstevel@tonic-gate krb5_principal_data tgt_princ = {
159*0Sstevel@tonic-gate         0,					/* magic number */
160*0Sstevel@tonic-gate 	{0, 0, 0},				/* krb5_data realm */
161*0Sstevel@tonic-gate 	tgt_princ_entries,			/* krb5_data *data */
162*0Sstevel@tonic-gate 	2,					/* int length */
163*0Sstevel@tonic-gate 	KRB5_NT_SRV_INST			/* int type */
164*0Sstevel@tonic-gate };
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate krb5_principal_data db_create_princ = {
167*0Sstevel@tonic-gate         0,					/* magic number */
168*0Sstevel@tonic-gate 	{0, 0, 0},				/* krb5_data realm */
169*0Sstevel@tonic-gate 	db_creator_entries,			/* krb5_data *data */
170*0Sstevel@tonic-gate 	1,					/* int length */
171*0Sstevel@tonic-gate 	KRB5_NT_SRV_INST			/* int type */
172*0Sstevel@tonic-gate };
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate extern char *mkey_password;
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate extern char *progname;
177*0Sstevel@tonic-gate extern int exit_status;
178*0Sstevel@tonic-gate extern osa_adb_policy_t policy_db;
179*0Sstevel@tonic-gate extern kadm5_config_params global_params;
180*0Sstevel@tonic-gate extern krb5_context util_context;
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate void
183*0Sstevel@tonic-gate kdb5_create(argc, argv)
184*0Sstevel@tonic-gate    int argc;
185*0Sstevel@tonic-gate    char *argv[];
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate     int optchar;
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate     krb5_error_code retval;
190*0Sstevel@tonic-gate     char *mkey_fullname;
191*0Sstevel@tonic-gate     char *pw_str = 0;
192*0Sstevel@tonic-gate     unsigned int pw_size = 0;
193*0Sstevel@tonic-gate     int do_stash = 0;
194*0Sstevel@tonic-gate     krb5_int32 crflags = KRB5_KDB_CREATE_BTREE;
195*0Sstevel@tonic-gate     krb5_data pwd, seed;
196*0Sstevel@tonic-gate     kdb_log_context *log_ctx;
197*0Sstevel@tonic-gate     krb5_keyblock mkey;
198*0Sstevel@tonic-gate     krb5_data master_salt = { 0, NULL };
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate     if (strrchr(argv[0], '/'))
201*0Sstevel@tonic-gate 	argv[0] = strrchr(argv[0], '/')+1;
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate     while ((optchar = getopt(argc, argv, "s")) != -1) {
204*0Sstevel@tonic-gate 	switch(optchar) {
205*0Sstevel@tonic-gate 	case 's':
206*0Sstevel@tonic-gate 	    do_stash++;
207*0Sstevel@tonic-gate 	    break;
208*0Sstevel@tonic-gate 	case 'h':
209*0Sstevel@tonic-gate 	    crflags = KRB5_KDB_CREATE_HASH;
210*0Sstevel@tonic-gate 	case '?':
211*0Sstevel@tonic-gate 	default:
212*0Sstevel@tonic-gate 	    usage();
213*0Sstevel@tonic-gate 	    return;
214*0Sstevel@tonic-gate 	}
215*0Sstevel@tonic-gate     }
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate     rblock.max_life = global_params.max_life;
218*0Sstevel@tonic-gate     rblock.max_rlife = global_params.max_rlife;
219*0Sstevel@tonic-gate     rblock.expiration = global_params.expiration;
220*0Sstevel@tonic-gate     rblock.flags = global_params.flags;
221*0Sstevel@tonic-gate     rblock.nkslist = global_params.num_keysalts;
222*0Sstevel@tonic-gate     rblock.kslist = global_params.keysalts;
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate     log_ctx = util_context->kdblog_context;
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate     retval = krb5_db_set_name(util_context, global_params.dbname);
227*0Sstevel@tonic-gate 	if (!retval)
228*0Sstevel@tonic-gate 		retval = EEXIST;
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate     if (retval == EEXIST || retval == EACCES || retval == EPERM) {
231*0Sstevel@tonic-gate 	/* it exists ! */
232*0Sstevel@tonic-gate 		com_err(argv[0], 0,
233*0Sstevel@tonic-gate 			gettext("The database '%s' appears to already exist"),
234*0Sstevel@tonic-gate 		global_params.dbname);
235*0Sstevel@tonic-gate 		exit_status++;
236*0Sstevel@tonic-gate 		return;
237*0Sstevel@tonic-gate     }
238*0Sstevel@tonic-gate     /* assemble & parse the master key name */
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate     if ((retval = krb5_db_setup_mkey_name(util_context,
241*0Sstevel@tonic-gate 					  global_params.mkey_name,
242*0Sstevel@tonic-gate 					  global_params.realm,
243*0Sstevel@tonic-gate 					  &mkey_fullname, &master_princ))) {
244*0Sstevel@tonic-gate 		com_err(argv[0], retval,
245*0Sstevel@tonic-gate 			gettext("while setting up master key name"));
246*0Sstevel@tonic-gate 		exit_status++;
247*0Sstevel@tonic-gate 		return;
248*0Sstevel@tonic-gate     }
249*0Sstevel@tonic-gate 	krb5_princ_set_realm_data(util_context,
250*0Sstevel@tonic-gate 				&db_create_princ, global_params.realm);
251*0Sstevel@tonic-gate 	krb5_princ_set_realm_length(util_context,
252*0Sstevel@tonic-gate 				    &db_create_princ,
253*0Sstevel@tonic-gate 				    strlen(global_params.realm));
254*0Sstevel@tonic-gate 	krb5_princ_set_realm_data(util_context,
255*0Sstevel@tonic-gate 				&tgt_princ, global_params.realm);
256*0Sstevel@tonic-gate 	krb5_princ_set_realm_length(util_context,
257*0Sstevel@tonic-gate 				    &tgt_princ, strlen(global_params.realm));
258*0Sstevel@tonic-gate 	krb5_princ_component(util_context, &tgt_princ, 1)->data =
259*0Sstevel@tonic-gate 	    global_params.realm;
260*0Sstevel@tonic-gate 	krb5_princ_component(util_context, &tgt_princ, 1)->length =
261*0Sstevel@tonic-gate 	    strlen(global_params.realm);
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	printf(gettext("Initializing database '%s' for realm '%s',\n"
264*0Sstevel@tonic-gate 			"master key name '%s'\n"),
265*0Sstevel@tonic-gate 	   global_params.dbname, global_params.realm, mkey_fullname);
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate     if (!mkey_password) {
268*0Sstevel@tonic-gate 	printf(gettext("You will be prompted for the "
269*0Sstevel@tonic-gate 			"database Master Password.\n"));
270*0Sstevel@tonic-gate 	printf(gettext("It is important that you NOT FORGET this password.\n"));
271*0Sstevel@tonic-gate 	fflush(stdout);
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	pw_size = 1024;
274*0Sstevel@tonic-gate 	pw_str = malloc(pw_size);
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	retval = krb5_read_password(util_context,
277*0Sstevel@tonic-gate 			    gettext("Enter KDC database master key:"),
278*0Sstevel@tonic-gate 			    gettext("Re-enter KDC database "
279*0Sstevel@tonic-gate 				    "master key to verify:"),
280*0Sstevel@tonic-gate 			    pw_str, &pw_size);
281*0Sstevel@tonic-gate 	if (retval) {
282*0Sstevel@tonic-gate 		com_err(argv[0], retval,
283*0Sstevel@tonic-gate 		    gettext("while reading master key from keyboard"));
284*0Sstevel@tonic-gate 		exit_status++;
285*0Sstevel@tonic-gate 		return;
286*0Sstevel@tonic-gate 	}
287*0Sstevel@tonic-gate 	mkey_password = pw_str;
288*0Sstevel@tonic-gate     }
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate     pwd.data = mkey_password;
291*0Sstevel@tonic-gate     pwd.length = strlen(mkey_password);
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate     retval = krb5_principal2salt(util_context, master_princ, &master_salt);
294*0Sstevel@tonic-gate     if (retval) {
295*0Sstevel@tonic-gate 	com_err(argv[0], retval,
296*0Sstevel@tonic-gate 		gettext("while calculated master key salt"));
297*0Sstevel@tonic-gate 	exit_status++;
298*0Sstevel@tonic-gate 	goto cleanup;
299*0Sstevel@tonic-gate     }
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate     if (retval = krb5_c_string_to_key(util_context, global_params.enctype,
302*0Sstevel@tonic-gate 			      &pwd, &master_salt, &mkey)) {
303*0Sstevel@tonic-gate 	com_err(argv[0], retval,
304*0Sstevel@tonic-gate 	    gettext("while transforming master key from password"));
305*0Sstevel@tonic-gate 	exit_status++;
306*0Sstevel@tonic-gate 	goto cleanup;
307*0Sstevel@tonic-gate     }
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate     retval = krb5_copy_keyblock(util_context, &mkey, &rblock.key);
310*0Sstevel@tonic-gate     if (retval) {
311*0Sstevel@tonic-gate 	com_err(argv[0], retval, gettext("while copying master key"));
312*0Sstevel@tonic-gate 	exit_status++;
313*0Sstevel@tonic-gate 	goto cleanup;
314*0Sstevel@tonic-gate     }
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate     seed.length = mkey.length;
317*0Sstevel@tonic-gate     seed.data = (char *)mkey.contents;
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate     if ((retval = krb5_c_random_seed(util_context, &seed))) {
320*0Sstevel@tonic-gate 	com_err(argv[0], retval,
321*0Sstevel@tonic-gate 		gettext("while initializing random key generator"));
322*0Sstevel@tonic-gate 	exit_status++;
323*0Sstevel@tonic-gate 	goto cleanup;
324*0Sstevel@tonic-gate     }
325*0Sstevel@tonic-gate     if ((retval = krb5_db_create(util_context,
326*0Sstevel@tonic-gate 				 global_params.dbname, crflags))) {
327*0Sstevel@tonic-gate 	com_err(argv[0], retval,
328*0Sstevel@tonic-gate 		gettext("while creating database '%s'"),
329*0Sstevel@tonic-gate 		global_params.dbname);
330*0Sstevel@tonic-gate 	exit_status++;
331*0Sstevel@tonic-gate 	goto cleanup;
332*0Sstevel@tonic-gate     }
333*0Sstevel@tonic-gate     if (retval = krb5_db_fini(util_context)) {
334*0Sstevel@tonic-gate 	com_err(argv[0], retval,
335*0Sstevel@tonic-gate 		gettext("while closing current database"));
336*0Sstevel@tonic-gate 	exit_status++;
337*0Sstevel@tonic-gate 	goto cleanup;
338*0Sstevel@tonic-gate     }
339*0Sstevel@tonic-gate     if ((retval = krb5_db_set_name(util_context, global_params.dbname))) {
340*0Sstevel@tonic-gate 	com_err(argv[0], retval,
341*0Sstevel@tonic-gate 		gettext("while setting active database to '%s'"),
342*0Sstevel@tonic-gate                global_params.dbname);
343*0Sstevel@tonic-gate 	exit_status++;
344*0Sstevel@tonic-gate 	goto cleanup;
345*0Sstevel@tonic-gate     }
346*0Sstevel@tonic-gate     if ((retval = krb5_db_init(util_context))) {
347*0Sstevel@tonic-gate 	com_err(argv[0], retval,
348*0Sstevel@tonic-gate 		gettext("while initializing the database '%s'"),
349*0Sstevel@tonic-gate 	global_params.dbname);
350*0Sstevel@tonic-gate 	exit_status++;
351*0Sstevel@tonic-gate 	goto cleanup;
352*0Sstevel@tonic-gate     }
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate     if (log_ctx && log_ctx->iproprole) {
355*0Sstevel@tonic-gate 	if (retval = ulog_map(util_context, &global_params, FKCOMMAND)) {
356*0Sstevel@tonic-gate 		com_err(argv[0], retval,
357*0Sstevel@tonic-gate 			gettext("while creating update log"));
358*0Sstevel@tonic-gate 		exit_status++;
359*0Sstevel@tonic-gate 		goto cleanup;
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	/*
363*0Sstevel@tonic-gate 	 * We're reinitializing the update log in case one already
364*0Sstevel@tonic-gate 	 * existed, but this should never happen.
365*0Sstevel@tonic-gate 	 */
366*0Sstevel@tonic-gate 	(void) memset(log_ctx->ulog, 0, sizeof (kdb_hlog_t));
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	log_ctx->ulog->kdb_hmagic = KDB_HMAGIC;
369*0Sstevel@tonic-gate 	log_ctx->ulog->db_version_num = KDB_VERSION;
370*0Sstevel@tonic-gate 	log_ctx->ulog->kdb_state = KDB_STABLE;
371*0Sstevel@tonic-gate 	log_ctx->ulog->kdb_block = ULOG_BLOCK;
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	/*
374*0Sstevel@tonic-gate 	 * Since we're creating a new db we shouldn't worry about
375*0Sstevel@tonic-gate 	 * adding the initial principals since any slave might as well
376*0Sstevel@tonic-gate 	 * do full resyncs from this newly created db.
377*0Sstevel@tonic-gate 	 */
378*0Sstevel@tonic-gate 	log_ctx->iproprole = IPROP_NULL;
379*0Sstevel@tonic-gate     }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate     if ((retval = add_principal(util_context,
382*0Sstevel@tonic-gate 		    master_princ, MASTER_KEY, &rblock, &mkey)) ||
383*0Sstevel@tonic-gate 	(retval = add_principal(util_context,
384*0Sstevel@tonic-gate 			    &tgt_princ, TGT_KEY, &rblock, &mkey))) {
385*0Sstevel@tonic-gate 	(void) krb5_db_fini(util_context);
386*0Sstevel@tonic-gate 	com_err(argv[0], retval,
387*0Sstevel@tonic-gate 	    gettext("while adding entries to the database"));
388*0Sstevel@tonic-gate 	exit_status++;
389*0Sstevel@tonic-gate 	goto cleanup;
390*0Sstevel@tonic-gate     }
391*0Sstevel@tonic-gate     /*
392*0Sstevel@tonic-gate      * Always stash the master key so kadm5_create does not prompt for
393*0Sstevel@tonic-gate      * it; delete the file below if it was not requested.  DO NOT EXIT
394*0Sstevel@tonic-gate      * BEFORE DELETING THE KEYFILE if do_stash is not set.
395*0Sstevel@tonic-gate      */
396*0Sstevel@tonic-gate     if (retval = krb5_db_store_mkey(util_context,
397*0Sstevel@tonic-gate 				    global_params.stash_file,
398*0Sstevel@tonic-gate 				    master_princ,
399*0Sstevel@tonic-gate 				    &mkey)) {
400*0Sstevel@tonic-gate 	com_err(argv[0], errno, gettext("while storing key"));
401*0Sstevel@tonic-gate 	printf(gettext("Warning: couldn't stash master key.\n"));
402*0Sstevel@tonic-gate     }
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate     if (pw_str)
405*0Sstevel@tonic-gate 	memset(pw_str, 0, pw_size);
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate     if (kadm5_create(&global_params)) {
408*0Sstevel@tonic-gate 	if (!do_stash)
409*0Sstevel@tonic-gate 		unlink(global_params.stash_file);
410*0Sstevel@tonic-gate 	exit_status++;
411*0Sstevel@tonic-gate 	goto cleanup;
412*0Sstevel@tonic-gate     }
413*0Sstevel@tonic-gate     if (!do_stash)
414*0Sstevel@tonic-gate 	unlink(global_params.stash_file);
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate cleanup:
417*0Sstevel@tonic-gate     if (pw_str) {
418*0Sstevel@tonic-gate 	if (mkey_password == pw_str)
419*0Sstevel@tonic-gate 		mkey_password = NULL;
420*0Sstevel@tonic-gate 	free(pw_str);
421*0Sstevel@tonic-gate     }
422*0Sstevel@tonic-gate     if (master_salt.data)
423*0Sstevel@tonic-gate 	free(master_salt.data);
424*0Sstevel@tonic-gate     krb5_free_keyblock_contents(util_context, rblock.key);
425*0Sstevel@tonic-gate     krb5_free_keyblock_contents(util_context, &mkey);
426*0Sstevel@tonic-gate     (void) krb5_db_fini(util_context);
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate     return;
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate }
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate static krb5_error_code
433*0Sstevel@tonic-gate tgt_keysalt_iterate(ksent, ptr)
434*0Sstevel@tonic-gate     krb5_key_salt_tuple	*ksent;
435*0Sstevel@tonic-gate     krb5_pointer	ptr;
436*0Sstevel@tonic-gate {
437*0Sstevel@tonic-gate     krb5_context	context;
438*0Sstevel@tonic-gate     krb5_error_code	kret;
439*0Sstevel@tonic-gate     struct iterate_args	*iargs;
440*0Sstevel@tonic-gate     krb5_keyblock	key;
441*0Sstevel@tonic-gate     krb5_int32		ind;
442*0Sstevel@tonic-gate     krb5_pointer rseed;
443*0Sstevel@tonic-gate     krb5_data	pwd;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate     iargs = (struct iterate_args *) ptr;
446*0Sstevel@tonic-gate     kret = 0;
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate     context = iargs->ctx;
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate     /*
451*0Sstevel@tonic-gate      * Convert the master key password into a key for this particular
452*0Sstevel@tonic-gate      * encryption system.
453*0Sstevel@tonic-gate      */
454*0Sstevel@tonic-gate     pwd.data = mkey_password;
455*0Sstevel@tonic-gate     pwd.length = strlen(mkey_password);
456*0Sstevel@tonic-gate     if (kret = krb5_c_random_seed(context, &pwd))
457*0Sstevel@tonic-gate 	return kret;
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate     if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) {
460*0Sstevel@tonic-gate 	ind = iargs->dbentp->n_key_data-1;
461*0Sstevel@tonic-gate 	if (!(kret = krb5_c_make_random_key(context, ksent->ks_enctype,
462*0Sstevel@tonic-gate 					    &key))) {
463*0Sstevel@tonic-gate 	    kret = krb5_dbekd_encrypt_key_data(context,
464*0Sstevel@tonic-gate 					       iargs->rblock->key,
465*0Sstevel@tonic-gate 					       &key,
466*0Sstevel@tonic-gate 					       NULL,
467*0Sstevel@tonic-gate 					       1,
468*0Sstevel@tonic-gate 					       &iargs->dbentp->key_data[ind]);
469*0Sstevel@tonic-gate 	    krb5_free_keyblock_contents(context, &key);
470*0Sstevel@tonic-gate 	}
471*0Sstevel@tonic-gate     }
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate     return(kret);
474*0Sstevel@tonic-gate }
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate static krb5_error_code
477*0Sstevel@tonic-gate add_principal(krb5_context context,
478*0Sstevel@tonic-gate     krb5_principal princ,
479*0Sstevel@tonic-gate     enum ap_op op,
480*0Sstevel@tonic-gate     struct realm_info *pblock,
481*0Sstevel@tonic-gate     krb5_keyblock *mkey)
482*0Sstevel@tonic-gate {
483*0Sstevel@tonic-gate     krb5_error_code 	  retval;
484*0Sstevel@tonic-gate     krb5_db_entry 	  entry;
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate     krb5_timestamp	  now;
487*0Sstevel@tonic-gate     struct iterate_args	  iargs;
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate     int			  nentries = 1;
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate     memset((char *) &entry, 0, sizeof(entry));
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate     entry.len = KRB5_KDB_V1_BASE_LENGTH;
494*0Sstevel@tonic-gate     entry.attributes = pblock->flags;
495*0Sstevel@tonic-gate     entry.max_life = pblock->max_life;
496*0Sstevel@tonic-gate     entry.max_renewable_life = pblock->max_rlife;
497*0Sstevel@tonic-gate     entry.expiration = pblock->expiration;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate     if ((retval = krb5_copy_principal(context, princ, &entry.princ)))
500*0Sstevel@tonic-gate 	goto error_out;
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate     if ((retval = krb5_timeofday(context, &now)))
503*0Sstevel@tonic-gate 	goto error_out;
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate     if ((retval = krb5_dbe_update_mod_princ_data(context, &entry,
506*0Sstevel@tonic-gate 						 now, &db_create_princ)))
507*0Sstevel@tonic-gate 	goto error_out;
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate     switch (op) {
510*0Sstevel@tonic-gate     case MASTER_KEY:
511*0Sstevel@tonic-gate 	entry.key_data = (krb5_key_data *) malloc(sizeof (krb5_key_data));
512*0Sstevel@tonic-gate 	if (entry.key_data == NULL)
513*0Sstevel@tonic-gate 	    goto error_out;
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	memset((char *) entry.key_data, 0, sizeof(krb5_key_data));
516*0Sstevel@tonic-gate 	entry.n_key_data = 1;
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
519*0Sstevel@tonic-gate 	if ((retval = krb5_dbekd_encrypt_key_data(context, pblock->key,
520*0Sstevel@tonic-gate 				  mkey, NULL, 1, entry.key_data)))
521*0Sstevel@tonic-gate 		goto error_out;
522*0Sstevel@tonic-gate 	break;
523*0Sstevel@tonic-gate     case TGT_KEY:
524*0Sstevel@tonic-gate 	iargs.ctx = context;
525*0Sstevel@tonic-gate 	iargs.rblock = pblock;
526*0Sstevel@tonic-gate 	iargs.dbentp = &entry;
527*0Sstevel@tonic-gate 	/*
528*0Sstevel@tonic-gate 	 * Iterate through the key/salt list, ignoring salt types.
529*0Sstevel@tonic-gate 	 */
530*0Sstevel@tonic-gate 	if ((retval = krb5_keysalt_iterate(pblock->kslist,
531*0Sstevel@tonic-gate 					   pblock->nkslist,
532*0Sstevel@tonic-gate 					   1,
533*0Sstevel@tonic-gate 					   tgt_keysalt_iterate,
534*0Sstevel@tonic-gate 					   (krb5_pointer) &iargs)))
535*0Sstevel@tonic-gate 		return (retval);
536*0Sstevel@tonic-gate 	break;
537*0Sstevel@tonic-gate     case NULL_KEY:
538*0Sstevel@tonic-gate 	return (EOPNOTSUPP);
539*0Sstevel@tonic-gate     default:
540*0Sstevel@tonic-gate 	break;
541*0Sstevel@tonic-gate     }
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate     retval = krb5_db_put_principal(context, &entry, &nentries);
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate error_out:;
546*0Sstevel@tonic-gate 	krb5_dbe_free_contents(context, &entry);
547*0Sstevel@tonic-gate 	return (retval);
548*0Sstevel@tonic-gate }
549