1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 | #pragma ident "@(#)kdb5_create.c 1.9 04/09/08 SMI" 6 | #pragma ident "@(#)kdb5_create.c 1.8 04/05/04 SMI" 7 8 /* 9 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 10 * 11 * Openvision retains the copyright to derivative works of 12 * this source code. Do *NOT* create a derivative of this 13 * source code before consulting with your legal department. 14 * Do *NOT* integrate *ANY* of this source code into another 15 * product before consulting with your legal department. 16 * 17 * For further information, read the top-level Openvision 18 * copyright which is contained in the top-level MIT Kerberos 19 * copyright. 20 * 21 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 22 * 23 */ 24 25 26 /* 27 * admin/create/kdb5_create.c 28 * 29 * Copyright 1990,1991 by the Massachusetts Institute of Technology. 30 * All Rights Reserved. 31 * 32 * Export of this software from the United States of America may 33 * require a specific license from the United States Government. 34 * It is the responsibility of any person or organization contemplating 35 * export to obtain such a license before exporting. 36 * 37 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 38 * distribute this software and its documentation for any purpose and 39 * without fee is hereby granted, provided that the above copyright 40 * notice appear in all copies and that both that copyright notice and 41 * this permission notice appear in supporting documentation, and that 42 * the name of M.I.T. not be used in advertising or publicity pertaining 43 * to distribution of the software without specific, written prior 44 * permission. Furthermore if you modify this software you must label 45 * your software as modified software and not distribute it in such a 46 * fashion that it might be confused with the original M.I.T. software. 47 * M.I.T. makes no representations about the suitability of 48 * this software for any purpose. It is provided "as is" without express 49 * or implied warranty. 50 * 51 * 52 * Generate (from scratch) a Kerberos KDC database. 53 */ 54 55 /* 56 * Yes, I know this is a hack, but we need admin.h without including the 57 * rpc.h header. Additionally, our rpc.h header brings in 58 * a des.h header which causes other problems. 59 */ 60 #define _RPC_RPC_H 61 62 #include <stdio.h> 63 #define KDB5_DISPATCH 64 #define KRB5_KDB5_DBM__ 65 #include <k5-int.h> 66 /* #define these to avoid an indirection function; for future implementations, 67 these may be redirected from a dispatch table/routine */ 68 #define krb5_dbm_db_set_name krb5_db_set_name 69 #define krb5_dbm_db_set_nonblocking krb5_db_set_nonblocking 70 #define krb5_dbm_db_init krb5_db_init 71 #define krb5_dbm_db_get_age krb5_db_get_age 72 #define krb5_dbm_db_create krb5_db_create 73 #define krb5_dbm_db_rename krb5_db_rename 74 #define krb5_dbm_db_get_principal krb5_db_get_principal 75 #define krb5_dbm_db_free_principal krb5_db_free_principal 76 #define krb5_dbm_db_put_principal krb5_db_put_principal 77 #define krb5_dbm_db_delete_principal krb5_db_delete_principal 78 #define krb5_dbm_db_lock krb5_db_lock 79 #define krb5_dbm_db_unlock krb5_db_unlock 80 #define krb5_dbm_db_set_lockmode krb5_db_set_lockmode 81 #define krb5_dbm_db_close_database krb5_db_close_database 82 #define krb5_dbm_db_open_database krb5_db_open_database 83 84 #include <kadm5/admin.h> 85 #include <rpc/types.h> 86 #include <rpc/xdr.h> 87 #include <kadm5/adb.h> 88 #include <libintl.h> 89 + #include "kdb5_util.h" 90 91 enum ap_op { 92 NULL_KEY, /* setup null keys */ 93 MASTER_KEY, /* use master key as new key */ 94 TGT_KEY /* special handling for tgt key */ 95 }; ----Unchanged portion omitted---- 173 174 extern char *mkey_password; 175 176 extern char *progname; 177 extern int exit_status; 178 extern osa_adb_policy_t policy_db; 179 extern kadm5_config_params global_params; 180 extern krb5_context util_context; 181 182 void 183 kdb5_create(argc, argv) 184 int argc; 185 char *argv[]; 186 { 187 int optchar; 188 189 krb5_error_code retval; 190 char *mkey_fullname; 191 char *pw_str = 0; 192 unsigned int pw_size = 0; 193 int do_stash = 0; 194 krb5_int32 crflags = KRB5_KDB_CREATE_BTREE; 195 krb5_data pwd, seed; 196 + kdb_log_context *log_ctx; 197 krb5_keyblock mkey; 198 krb5_data master_salt = { 0, NULL }; 199 200 if (strrchr(argv[0], '/')) 201 argv[0] = strrchr(argv[0], '/')+1; 202 203 while ((optchar = getopt(argc, argv, "s")) != -1) { 204 switch(optchar) { 205 case 's': 206 do_stash++; 207 break; 208 case 'h': 209 crflags = KRB5_KDB_CREATE_HASH; 210 case '?': 211 default: 212 usage(); 213 return; 214 } 215 } 216 217 rblock.max_life = global_params.max_life; 218 rblock.max_rlife = global_params.max_rlife; 219 rblock.expiration = global_params.expiration; 220 rblock.flags = global_params.flags; 221 rblock.nkslist = global_params.num_keysalts; 222 rblock.kslist = global_params.keysalts; 223 224 + log_ctx = util_context->kdblog_context; 225 + 226 retval = krb5_db_set_name(util_context, global_params.dbname); 227 if (!retval) 228 retval = EEXIST; 229 230 if (retval == EEXIST || retval == EACCES || retval == EPERM) { 231 /* it exists ! */ 232 com_err(argv[0], 0, 233 gettext("The database '%s' appears to already exist"), 234 global_params.dbname); 235 exit_status++; 236 return; 237 } 238 /* assemble & parse the master key name */ 239 240 if ((retval = krb5_db_setup_mkey_name(util_context, 241 global_params.mkey_name, 242 global_params.realm, 243 &mkey_fullname, &master_princ))) { 244 com_err(argv[0], retval, 245 gettext("while setting up master key name")); 246 exit_status++; 247 return; 248 } 249 krb5_princ_set_realm_data(util_context, 250 &db_create_princ, global_params.realm); 251 krb5_princ_set_realm_length(util_context, 252 &db_create_princ, 253 strlen(global_params.realm)); 254 krb5_princ_set_realm_data(util_context, 255 &tgt_princ, global_params.realm); 256 krb5_princ_set_realm_length(util_context, 257 &tgt_princ, strlen(global_params.realm)); 258 krb5_princ_component(util_context, &tgt_princ, 1)->data = 259 global_params.realm; 260 krb5_princ_component(util_context, &tgt_princ, 1)->length = 261 strlen(global_params.realm); 262 263 printf(gettext("Initializing database '%s' for realm '%s',\n" 264 "master key name '%s'\n"), 265 global_params.dbname, global_params.realm, mkey_fullname); 266 267 if (!mkey_password) { 268 printf(gettext("You will be prompted for the " 269 "database Master Password.\n")); 270 printf(gettext("It is important that you NOT FORGET this password.\n")); 271 fflush(stdout); 272 273 pw_size = 1024; 274 pw_str = malloc(pw_size); 275 276 retval = krb5_read_password(util_context, 277 gettext("Enter KDC database master key:"), 278 gettext("Re-enter KDC database " 279 "master key to verify:"), 280 pw_str, &pw_size); 281 if (retval) { 282 com_err(argv[0], retval, 283 gettext("while reading master key from keyboard")); 284 exit_status++; 285 return; 286 } 287 mkey_password = pw_str; 288 } 289 290 pwd.data = mkey_password; 291 pwd.length = strlen(mkey_password); 292 293 retval = krb5_principal2salt(util_context, master_princ, &master_salt); 294 if (retval) { 295 com_err(argv[0], retval, 296 gettext("while calculated master key salt")); 297 exit_status++; 298 goto cleanup; 299 } 300 301 if (retval = krb5_c_string_to_key(util_context, global_params.enctype, 302 &pwd, &master_salt, &mkey)) { 303 com_err(argv[0], retval, 304 gettext("while transforming master key from password")); 305 exit_status++; 306 goto cleanup; 307 } 308 309 retval = krb5_copy_keyblock(util_context, &mkey, &rblock.key); 310 if (retval) { 311 com_err(argv[0], retval, gettext("while copying master key")); 312 exit_status++; 313 goto cleanup; 314 } 315 316 seed.length = mkey.length; 317 seed.data = (char *)mkey.contents; 318 319 if ((retval = krb5_c_random_seed(util_context, &seed))) { 320 com_err(argv[0], retval, 321 gettext("while initializing random key generator")); 322 exit_status++; 323 goto cleanup; 324 } 325 if ((retval = krb5_db_create(util_context, 326 global_params.dbname, crflags))) { 327 com_err(argv[0], retval, 328 gettext("while creating database '%s'"), 329 global_params.dbname); 330 exit_status++; 331 goto cleanup; 332 } 333 if (retval = krb5_db_fini(util_context)) { 334 com_err(argv[0], retval, 335 gettext("while closing current database")); 336 exit_status++; 337 goto cleanup; 338 } 339 if ((retval = krb5_db_set_name(util_context, global_params.dbname))) { 340 com_err(argv[0], retval, 341 gettext("while setting active database to '%s'"), 342 global_params.dbname); 343 exit_status++; 344 goto cleanup; 345 } 346 if ((retval = krb5_db_init(util_context))) { 347 com_err(argv[0], retval, 348 gettext("while initializing the database '%s'"), 349 global_params.dbname); 350 exit_status++; 351 goto cleanup; 352 } 353 354 + if (log_ctx && log_ctx->iproprole) { 355 + if (retval = ulog_map(util_context, &global_params, FKCOMMAND)) { 356 + com_err(argv[0], retval, 357 + gettext("while creating update log")); 358 + exit_status++; 359 + goto cleanup; 360 + } 361 + 362 + /* 363 + * We're reinitializing the update log in case one already 364 + * existed, but this should never happen. 365 + */ 366 + (void) memset(log_ctx->ulog, 0, sizeof (kdb_hlog_t)); 367 + 368 + log_ctx->ulog->kdb_hmagic = KDB_HMAGIC; 369 + log_ctx->ulog->db_version_num = KDB_VERSION; 370 + log_ctx->ulog->kdb_state = KDB_STABLE; 371 + log_ctx->ulog->kdb_block = ULOG_BLOCK; 372 + 373 + /* 374 + * Since we're creating a new db we shouldn't worry about 375 + * adding the initial principals since any slave might as well 376 + * do full resyncs from this newly created db. 377 + */ 378 + log_ctx->iproprole = IPROP_NULL; 379 + } 380 + 381 if ((retval = add_principal(util_context, 382 master_princ, MASTER_KEY, &rblock, &mkey)) || 383 (retval = add_principal(util_context, 384 &tgt_princ, TGT_KEY, &rblock, &mkey))) { 385 (void) krb5_db_fini(util_context); 386 com_err(argv[0], retval, 387 gettext("while adding entries to the database")); 388 exit_status++; 389 goto cleanup; 390 } 391 /* 392 * Always stash the master key so kadm5_create does not prompt for 393 * it; delete the file below if it was not requested. DO NOT EXIT 394 * BEFORE DELETING THE KEYFILE if do_stash is not set. 395 */ 396 if (retval = krb5_db_store_mkey(util_context, 397 global_params.stash_file, 398 master_princ, 399 &mkey)) { 400 com_err(argv[0], errno, gettext("while storing key")); 401 printf(gettext("Warning: couldn't stash master key.\n")); 402 } 403 404 if (pw_str) 405 memset(pw_str, 0, pw_size); 406 407 if (kadm5_create(&global_params)) { 408 if (!do_stash) 409 unlink(global_params.stash_file); 410 exit_status++; 411 goto cleanup; 412 } 413 if (!do_stash) 414 unlink(global_params.stash_file); 415 416 cleanup: 417 if (pw_str) { 418 if (mkey_password == pw_str) 419 mkey_password = NULL; 420 free(pw_str); 421 } 422 if (master_salt.data) 423 free(master_salt.data); 424 krb5_free_keyblock_contents(util_context, rblock.key); 425 krb5_free_keyblock_contents(util_context, &mkey); 426 (void) krb5_db_fini(util_context); 427 428 return; 429 430 } ----Unchanged portion omitted----