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----