2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
9 * Openvision retains the copyright to derivative works of
10 * this source code. Do *NOT* create a derivative of this
11 * source code before consulting with your legal department.
12 * Do *NOT* integrate *ANY* of this source code into another
13 * product before consulting with your legal department.
15 * For further information, read the top-level Openvision
16 * copyright which is contained in the top-level MIT Kerberos
19 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
25 * admin/create/kdb5_create.c
27 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
28 * All Rights Reserved.
30 * Export of this software from the United States of America may
31 * require a specific license from the United States Government.
32 * It is the responsibility of any person or organization contemplating
33 * export to obtain such a license before exporting.
35 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
36 * distribute this software and its documentation for any purpose and
37 * without fee is hereby granted, provided that the above copyright
38 * notice appear in all copies and that both that copyright notice and
39 * this permission notice appear in supporting documentation, and that
40 * the name of M.I.T. not be used in advertising or publicity pertaining
41 * to distribution of the software without specific, written prior
42 * permission. Furthermore if you modify this software you must label
43 * your software as modified software and not distribute it in such a
44 * fashion that it might be confused with the original M.I.T. software.
45 * M.I.T. makes no representations about the suitability of
46 * this software for any purpose. It is provided "as is" without express
47 * or implied warranty.
50 * Generate (from scratch) a Kerberos KDC database.
54 * Yes, I know this is a hack, but we need admin.h without including the
55 * rpc.h header. Additionally, our rpc.h header brings in
56 * a des.h header which causes other problems.
63 #include <kadm5/server_internal.h>
64 #include <kadm5/admin.h>
65 #include <rpc/types.h>
68 #include "kdb5_util.h"
71 NULL_KEY
, /* setup null keys */
72 MASTER_KEY
, /* use master key as new key */
73 TGT_KEY
/* special handling for tgt key */
76 krb5_key_salt_tuple def_kslist
= { ENCTYPE_DES_CBC_CRC
, KRB5_KDB_SALTTYPE_NORMAL
};
80 krb5_deltat max_rlife
;
81 krb5_timestamp expiration
;
85 krb5_key_salt_tuple
*kslist
;
86 } rblock
= { /* XXX */
91 (krb5_keyblock
*) NULL
,
98 struct realm_info
*rblock
;
99 krb5_db_entry
*dbentp
;
102 static krb5_error_code add_principal
110 * Steps in creating a database:
112 * 1) use the db calls to open/create a new database
114 * 2) get a realm name for the new db
116 * 3) get a master password for the new db; convert to an encryption key.
118 * 4) create various required entries in the database
123 extern krb5_principal master_princ
;
125 krb5_data tgt_princ_entries
[] = {
126 {0, KRB5_TGS_NAME_SIZE
, KRB5_TGS_NAME
},
129 krb5_data db_creator_entries
[] = {
130 {0, sizeof("db_creation")-1, "db_creation"} };
132 /* XXX knows about contents of krb5_principal, and that tgt names
133 are of form TGT/REALM@REALM */
134 krb5_principal_data tgt_princ
= {
135 0, /* magic number */
136 {0, 0, 0}, /* krb5_data realm */
137 tgt_princ_entries
, /* krb5_data *data */
139 KRB5_NT_SRV_INST
/* int type */
142 krb5_principal_data db_create_princ
= {
143 0, /* magic number */
144 {0, 0, 0}, /* krb5_data realm */
145 db_creator_entries
, /* krb5_data *data */
147 KRB5_NT_SRV_INST
/* int type */
150 extern char *mkey_password
;
152 extern char *progname
;
153 extern int exit_status
;
154 extern kadm5_config_params global_params
;
155 extern krb5_context util_context
;
157 void kdb5_create(argc
, argv
)
163 krb5_error_code retval
;
166 unsigned int pw_size
= 0;
169 kdb_log_context
*log_ctx
;
171 krb5_data master_salt
= { 0, NULL
};
173 /* Solaris Kerberos */
174 (void) memset(&mkey
, 0, sizeof (mkey
));
176 /* Solaris Kerberos */
178 if (strrchr(argv
[0], '/'))
179 argv
[0] = strrchr(argv
[0], '/')+1;
181 while ((optchar
= getopt(argc
, argv
, "s")) != -1) {
187 if (!add_db_arg("hash=true")) {
188 com_err(progname
, ENOMEM
, "while parsing command arguments\n");
199 rblock
.max_life
= global_params
.max_life
;
200 rblock
.max_rlife
= global_params
.max_rlife
;
201 rblock
.expiration
= global_params
.expiration
;
202 rblock
.flags
= global_params
.flags
;
203 rblock
.nkslist
= global_params
.num_keysalts
;
204 rblock
.kslist
= global_params
.keysalts
;
206 log_ctx
= util_context
->kdblog_context
;
208 /* SUNW14resync XXX */
210 printf ("Loading random data\n");
211 retval
= krb5_c_random_os_entropy (util_context
, 1, NULL
);
213 /* Solaris Kerberos */
214 com_err (progname
, retval
, "Loading random data");
215 exit_status
++; return;
218 /* assemble & parse the master key name */
220 if ((retval
= krb5_db_setup_mkey_name(util_context
,
221 global_params
.mkey_name
,
223 &mkey_fullname
, &master_princ
))) {
224 /* Solaris Kerberos */
225 com_err(progname
, retval
,
226 gettext("while setting up master key name"));
227 exit_status
++; return;
230 krb5_princ_set_realm_data(util_context
, &db_create_princ
, global_params
.realm
);
231 krb5_princ_set_realm_length(util_context
, &db_create_princ
, strlen(global_params
.realm
));
232 krb5_princ_set_realm_data(util_context
, &tgt_princ
, global_params
.realm
);
233 krb5_princ_set_realm_length(util_context
, &tgt_princ
, strlen(global_params
.realm
));
234 krb5_princ_component(util_context
, &tgt_princ
,1)->data
= global_params
.realm
;
235 krb5_princ_component(util_context
, &tgt_princ
,1)->length
= strlen(global_params
.realm
);
237 printf(gettext("Initializing database '%s' for realm '%s',\n"
238 "master key name '%s'\n"),
239 global_params
.dbname
, global_params
.realm
, mkey_fullname
);
241 if (!mkey_password
) {
242 printf(gettext("You will be prompted for the "
243 "database Master Password.\n"));
244 printf(gettext("It is important that you NOT FORGET this password.\n"));
248 pw_str
= malloc(pw_size
);
250 retval
= krb5_read_password(util_context
,
251 gettext("Enter KDC database master key"),
252 gettext("Re-enter KDC database "
253 "master key to verify"),
256 /* Solaris Kerberos */
257 com_err(progname
, retval
,
258 gettext("while reading master key from keyboard"));
259 exit_status
++; return;
261 mkey_password
= pw_str
;
264 pwd
.data
= mkey_password
;
265 pwd
.length
= strlen(mkey_password
);
266 retval
= krb5_principal2salt(util_context
, master_princ
, &master_salt
);
268 /* Solaris Kerberos */
269 com_err(progname
, retval
,
270 gettext("while calculated master key salt"));
275 retval
= krb5_c_string_to_key(util_context
, global_params
.enctype
,
276 &pwd
, &master_salt
, &mkey
);
278 /* Solaris Kerberos */
279 com_err(progname
, retval
,
280 gettext("while transforming master key from password"));
285 retval
= krb5_copy_keyblock(util_context
, &mkey
, &rblock
.key
);
287 /* Solaris Kerberos */
288 com_err(progname
, retval
, gettext("while copying master key"));
293 seed
.length
= mkey
.length
;
294 seed
.data
= (char *)mkey
.contents
;
296 if ((retval
= krb5_c_random_seed(util_context
, &seed
))) {
297 /* Solaris Kerberos */
298 com_err(progname
, retval
,
299 gettext("while initializing random key generator"));
303 if ((retval
= krb5_db_create(util_context
, db5util_db_args
))) {
304 /* Solaris Kerberos */
305 com_err(progname
, retval
,
306 gettext("while creating database '%s'"),
307 global_params
.dbname
);
311 #if 0 /************** Begin IFDEF'ed OUT *******************************/
312 if (retval
= krb5_db_fini(util_context
)) {
313 /* Solaris Kerberos */
314 com_err(progname
, retval
,
315 gettext("while closing current database"));
319 if ((retval
= krb5_db_set_name(util_context
, global_params
.dbname
))) {
320 /* Solaris Kerberos */
321 com_err(progname
, retval
,
322 gettext("while setting active database to '%s'"),
323 global_params
.dbname
);
327 if ((retval
= krb5_db_init(util_context
))) {
328 com_err(progname
, retval
,
329 gettext("while initializing the database '%s'"),
330 global_params
.dbname
);
334 #endif /**************** END IFDEF'ed OUT *******************************/
336 /* Solaris Kerberos: for iprop */
337 if (log_ctx
&& log_ctx
->iproprole
) {
338 if (retval
= ulog_map(util_context
, &global_params
, FKCOMMAND
)) {
339 /* Solaris Kerberos */
340 com_err(progname
, retval
,
341 gettext("while creating update log"));
347 * We're reinitializing the update log in case one already
348 * existed, but this should never happen.
350 (void) memset(log_ctx
->ulog
, 0, sizeof (kdb_hlog_t
));
352 log_ctx
->ulog
->kdb_hmagic
= KDB_HMAGIC
;
353 log_ctx
->ulog
->db_version_num
= KDB_VERSION
;
354 log_ctx
->ulog
->kdb_state
= KDB_STABLE
;
355 log_ctx
->ulog
->kdb_block
= ULOG_BLOCK
;
358 * Since we're creating a new db we shouldn't worry about
359 * adding the initial principals since any slave might as well
360 * do full resyncs from this newly created db.
362 log_ctx
->iproprole
= IPROP_NULL
;
365 if ((retval
= add_principal(util_context
, master_princ
, MASTER_KEY
, &rblock
, &mkey
)) ||
366 (retval
= add_principal(util_context
, &tgt_princ
, TGT_KEY
, &rblock
, &mkey
))) {
367 (void) krb5_db_fini(util_context
);
368 /* Solaris Kerberos */
369 com_err(progname
, retval
, gettext("while adding entries to the database"));
374 * Always stash the master key so kadm5_create does not prompt for
375 * it; delete the file below if it was not requested. DO NOT EXIT
376 * BEFORE DELETING THE KEYFILE if do_stash is not set.
378 retval
= krb5_db_store_master_key(util_context
,
379 global_params
.stash_file
,
385 /* Solaris Kerberos */
386 com_err(progname
, errno
, gettext("while storing key"));
387 printf(gettext("Warning: couldn't stash master key.\n"));
391 memset(pw_str
, 0, pw_size
);
393 if (kadm5_create(&global_params
)) {
394 if (!do_stash
) unlink(global_params
.stash_file
);
398 if (!do_stash
) unlink(global_params
.stash_file
);
400 /* Solaris Kerberos: deal with master_keyblock in better way */
403 if (mkey_password
== pw_str
)
404 mkey_password
= NULL
;
407 if (master_salt
.data
)
408 free(master_salt
.data
);
409 krb5_free_keyblock(util_context
, rblock
.key
);
410 krb5_free_keyblock_contents(util_context
, &mkey
);
411 (void) krb5_db_fini(util_context
);
416 static krb5_error_code
417 tgt_keysalt_iterate(ksent
, ptr
)
418 krb5_key_salt_tuple
*ksent
;
421 krb5_context context
;
422 krb5_error_code kret
;
423 struct iterate_args
*iargs
;
428 iargs
= (struct iterate_args
*) ptr
;
431 context
= iargs
->ctx
;
434 * Convert the master key password into a key for this particular
437 pwd
.data
= mkey_password
;
438 pwd
.length
= strlen(mkey_password
);
439 kret
= krb5_c_random_seed(context
, &pwd
);
443 if (!(kret
= krb5_dbe_create_key_data(iargs
->ctx
, iargs
->dbentp
))) {
444 ind
= iargs
->dbentp
->n_key_data
-1;
445 if (!(kret
= krb5_c_make_random_key(context
, ksent
->ks_enctype
,
447 kret
= krb5_dbekd_encrypt_key_data(context
,
452 &iargs
->dbentp
->key_data
[ind
]);
453 krb5_free_keyblock_contents(context
, &key
);
460 static krb5_error_code
461 add_principal(context
, princ
, op
, pblock
, mkey
)
462 krb5_context context
;
463 krb5_principal princ
;
465 struct realm_info
*pblock
;
468 krb5_error_code retval
;
472 struct iterate_args iargs
;
476 memset((char *) &entry
, 0, sizeof(entry
));
478 entry
.len
= KRB5_KDB_V1_BASE_LENGTH
;
479 entry
.attributes
= pblock
->flags
;
480 entry
.max_life
= pblock
->max_life
;
481 entry
.max_renewable_life
= pblock
->max_rlife
;
482 entry
.expiration
= pblock
->expiration
;
484 if ((retval
= krb5_copy_principal(context
, princ
, &entry
.princ
)))
487 if ((retval
= krb5_timeofday(context
, &now
)))
490 if ((retval
= krb5_dbe_update_mod_princ_data(context
, &entry
,
491 now
, &db_create_princ
)))
496 if ((entry
.key_data
=(krb5_key_data
*)malloc(sizeof(krb5_key_data
)))
499 memset((char *) entry
.key_data
, 0, sizeof(krb5_key_data
));
500 entry
.n_key_data
= 1;
502 entry
.attributes
|= KRB5_KDB_DISALLOW_ALL_TIX
;
503 if ((retval
= krb5_dbekd_encrypt_key_data(context
, pblock
->key
,
510 iargs
.rblock
= pblock
;
511 iargs
.dbentp
= &entry
;
513 * Iterate through the key/salt list, ignoring salt types.
515 if ((retval
= krb5_keysalt_iterate(pblock
->kslist
,
519 (krb5_pointer
) &iargs
)))
528 entry
.mask
= (KADM5_KEY_DATA
| KADM5_PRINCIPAL
| KADM5_ATTRIBUTES
|
529 KADM5_MAX_LIFE
| KADM5_MAX_RLIFE
| KADM5_TL_DATA
|
530 KADM5_PRINC_EXPIRE_TIME
);
532 retval
= krb5_db_put_principal(context
, &entry
, &nentries
);
535 krb5_db_free_principal(context
, &entry
, 1);