summaryrefslogtreecommitdiffstats
path: root/src/kadmin/dbutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/kadmin/dbutil')
-rw-r--r--src/kadmin/dbutil/ChangeLog440
-rw-r--r--src/kadmin/dbutil/Makefile.in18
-rw-r--r--src/kadmin/dbutil/Makefile.ov19
-rw-r--r--src/kadmin/dbutil/configure.in13
-rw-r--r--src/kadmin/dbutil/dump.c1957
-rw-r--r--src/kadmin/dbutil/dumpv4.c411
-rw-r--r--src/kadmin/dbutil/kadm5_create.c241
-rw-r--r--src/kadmin/dbutil/kdb5_create.c449
-rw-r--r--src/kadmin/dbutil/kdb5_destroy.c117
-rw-r--r--src/kadmin/dbutil/kdb5_edit.M179
-rw-r--r--src/kadmin/dbutil/kdb5_stash.c153
-rw-r--r--src/kadmin/dbutil/kdb5_util.M122
-rw-r--r--src/kadmin/dbutil/kdb5_util.c416
-rw-r--r--src/kadmin/dbutil/kdb5_util.h49
-rw-r--r--src/kadmin/dbutil/kdb5_util_ct.ct56
-rw-r--r--src/kadmin/dbutil/loadv4.c881
-rw-r--r--src/kadmin/dbutil/ss_wrapper.c85
-rw-r--r--src/kadmin/dbutil/string_table.c91
-rw-r--r--src/kadmin/dbutil/string_table.h40
-rw-r--r--src/kadmin/dbutil/tcl_wrapper.c235
-rw-r--r--src/kadmin/dbutil/util.c155
21 files changed, 6127 insertions, 0 deletions
diff --git a/src/kadmin/dbutil/ChangeLog b/src/kadmin/dbutil/ChangeLog
new file mode 100644
index 000000000..7719cc749
--- /dev/null
+++ b/src/kadmin/dbutil/ChangeLog
@@ -0,0 +1,440 @@
+Thu Jul 18 19:22:04 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in: removed SS_RULES
+
+Wed Jul 10 19:43:22 1996 Marc Horowitz <marc@mit.edu>
+
+ * dumpv4.c (configure.in, Makefile.in): make autoconf work after
+ barry's carnage
+
+Sun May 12 00:27:44 1996 Marc Horowitz <marc@mit.edu>
+
+ * loadv4.c (enter_in_v5_db, add_principal), kdb5_edit.c
+ (create_db_entry, modent), dumpv4.c (dump_v4_iterator), dump.c
+ (dump_k5beta_iterator, process_k5beta_record): convert to use new
+ krb5_dbe_* tl_data functions.
+
+ * cpw.c (enter_pwd_key): krb5_dbe_cpw() takes a kvno now.
+
+Tue May 7 23:16:57 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in: USE_KADM_LIBRARY replaced by USE_KADMSRV_LIBRARY
+
+Thu Apr 11 19:32:36 1996 Richard Basch <basch@lehman.com>
+
+ * kdb5_edit.c (extract_v4_srvtab): Use the matching key_data's kvno;
+ don't assume that key_data[0]'s kvno is necessarily the matching
+ key_data's kvno.
+
+Wed Apr 10 19:17:58 1996 Richard Basch <basch@lehman.com>
+
+ * kdb5_edit.c (extract_v4_srvtab): Translate the principal name to
+ the common V4 name.
+
+Tue Mar 19 18:00:58 1996 Richard Basch <basch@lehman.com>
+
+ * kdb5_edit.c (extract_v4_srvtab): do not test to make sure we
+ fetched a key of enctype 1 (des-cbc-crc), since we may have gotten
+ another des key from the database, which is just as useful in a
+ v4 srvtab
+
+ * dumpv4.c (dump_v4_iterator): use krb5_524_conv_principal to do the
+ v5 to v4 principal translation, instead of having yet another
+ hard-coded table.
+
+Wed Mar 6 16:17:20 1996 Richard Basch <basch@lehman.com>
+
+ * dumpv4.c: The V4 master key & schedule was never initialized,
+ so the dump created by dump_v4db was garbage. Read the V4
+ master key from /.k or prompt for the V4 master key password.
+ If there is no V4-salt key in the database, but there is a DES
+ key, include it in the V4 dump, in case it is merely a random
+ service key for which there is no associated password.
+ Skip over K/M in the V5 database (use the entered V4 master key).
+ Both krbtgt and afs keys often have domain-qualifed instances.
+
+Tue Mar 5 12:18:22 1996 Richard Basch <basch@lehman.com>
+
+ * dump.c: POSIX locking requires that the file be opened read-write.
+
+Mon Feb 26 22:42:09 1996 Mark Eichin <eichin@cygnus.com>
+
+ * kdb5_edit.c: new command line option -f stashfile.
+ * kdb5_edit.M: document stashfile option.
+
+Mon Feb 26 22:13:45 1996 Mark Eichin <eichin@cygnus.com>
+
+ * dump.c (process_k5beta_record): since V4 salt type has no data
+ either, only set key_data_ver to 1 for data_type 0 with 0-length
+ salt. Also, don't include alternate key if akey has all-zero type
+ and length in both fields.
+
+Sat Feb 24 04:02:18 1996 Mark W. Eichin <eichin@cygnus.com>
+
+ * dump.c (process_k5beta_record): encrypted keys used to have 4
+ byte lengths in MSB order, need to convert to 2 byte LSB order
+ lengths before storing. Handle primary key and alternate key.
+
+Fri Feb 23 18:44:10 1996 Mark Eichin <eichin@cygnus.com>
+
+ * kdb5_edit.c (kdb5_edit_Init): set manual_mkey for testing with -P
+
+Wed Feb 14 09:52:18 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * kdb5_edit.c (enter_master_key, set_dbname_help): If master key
+ enctype is unknown, set to DEFAULT_KDC_ENCTYPE.
+
+Tue Feb 13 16:08:07 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * kdb5_edit.c (extract_v4_srvtab): krb5_dbekd_decrypt_key_data
+ takes krb5_key_data *, not **.
+
+Tue Jan 30 18:28:57 1996 Mark Eichin <eichin@cygnus.com>
+
+ * dump.c (load_db): dbrenerr_fmt prints "from" first, so pass it
+ to fprintf correctly.
+
+Sun Jan 28 14:31:47 1996 Mark Eichin <eichin@cygnus.com>
+
+ * dump.c (process_k5_record): t2..t9 is only 8 vars, not 9.
+
+Thu Jan 25 16:07:42 1996 Sam Hartman <hartmans@tertius.mit.edu>
+
+ * kdb5_edit.c (extract_srvtab): Extract *all* the keys in a
+ dbentry, not the first one.
+ (extract_v4_srvtab): Attempt to find the right v4 keys.
+
+Wed Jan 24 18:48:38 1996 Tom Yu <tlyu@dragons-lair.MIT.EDU>
+
+ * Makefile.in: Remove spurious @DEFS@
+
+
+Wed Dec 13 03:44:58 1995 Chris Provenzano (proven@mit.edu)
+
+ * dump.c, dumpv4.c, kdb5_edit.c, loadv4.c :
+ Remove mkvno from krb5_db_entry.
+
+Sun Dec 10 11:07:51 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * kdb5_edit.M: Document that modent exists
+
+ * kdb5_edit.c (modent): Add usage as suggested by jhawk@mit.edu.
+
+Thu Nov 09 17:05:57 1995 Chris Provenzano (proven@mit.edu)
+
+ * kdb5_edit.c : Remove krb5_enctype from krb5_string_to_key() args.
+
+Fri Oct 27 13:37:04 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * dump.c (process_k5_record): Fix off by one in malloc.
+
+Mon Oct 9 16:35:19 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * kdb5_edit.c (extract_v4_srvtab): Extract a one byte version
+ number for v4 srvtabs (from warlord).
+
+Thu Oct 5 10:35:35 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * cpw.c: Declare std_ks_tuple as extern.
+ * kdb5_edit.h: Remove std_ks_tuple declaration as not all sources
+ include adm.h for structures
+
+Tue Oct 3 23:10:57 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * cpw.c (enter_rnd_key, enter_pwd_key):
+ * kdb5_edit.c (kdb5_edit_Init): Use the kdc.conf file to determine
+ the default list of keysalt tuples to be used. This is
+ stored in std_ks_tuple, and is used by cpw.c for random
+ keys and when a list of keysalts is not specified.
+
+Mon Sep 18 03:59:47 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * kdb5_edit.c (show_principal): Show key version and last password
+ change.
+
+ * cpw.c: Fix typo in below change in which list was terminated
+ after third entry. (extra } removed)
+
+Fri Sep 15 14:21:25 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * cpw.c: Add DES_CBC_MD5 and DES_CBC_CRC with the V4 salt as
+ default key/salt tuples to be added. (Once proven's DES_*
+ folding code is implemented, we can shorten this list.)
+ Eventually, this list should be read in from kdc.conf.
+
+Thu Sep 7 20:41:24 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * loadv4.c (load_v4db): Provide a dummy routine if krb4
+ compatibility is not compiled in.
+
+Wed Sep 06 14:20:57 1995 Chris Provenzano (proven@mit.edu)
+
+ * cpw.c, dump.c, dumpv4.c, kdb5_edit.c, loadv4.c :
+ s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995 Chris Provenzano (proven@mit.edu)
+
+ * cpw.c, dump.c, dumpv4.c, kdb5_edit.c, loadv4.c : Remove krb5_enctype
+ references, and replace with krb5_keytype where appropriate.
+
+Fri Aug 25 17:37:33 EDT 1995 Paul Park (pjpark@mit.edu)
+ * dumpv4.c - Fix handle_keys(). It was trying to recreate work that
+ has already been done.
+ * Makefile.in, .Sanitize, loadv4.c, kdb5_ed_ct.ct - Add lddb4, the
+ command to load a v4 dump file. This is basically, kdb5_
+ convert reconstituted to fit within the framework of kdb5_edit.
+
+Thu Aug 24 19:28:39 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * .Sanitize: Update file list
+
+Mon Aug 21 16:45:39 EDT 1995 Paul Park (pjpark@mit.edu)
+ * dump.c - Completely rework this logic to support old (e.g. Beta 5
+ and previous) dump format and new dump format using the same
+ commands. This is differentiated by using the "-old" command
+ qualifier.
+
+ * kdb5_edit.M - Add description of -R and -s. Remove "ascii represen-
+ tation of a decimal number". Remove "Bugs".
+
+Fri Aug 18 17:06:06 EDT 1995 Paul Park (pjpark@mit.edu)
+
+ * ss_wrapper.c - Change sense of fgets() check so scripts work.
+
+
+Tue Aug 15 14:22:50 EDT 1995 Paul Park (pjpark@mit.edu)
+
+ * kdb5_edit.c, ss_wrapper.c, cpw.c, kdb5_edit.h - Add support for
+ -s scriptfile and fix up assorted gcc -Wall complaints.
+
+
+Mon Aug 7 17:32:31 EDT 1995 Paul Park (pjpark@mit.edu)
+ * cpw.c - Use krb5_string_to_keysalts() to generate a list of unique
+ key/salt pairs supplied in argv.
+
+
+Mon Aug 07 11:16:03 1995 Chris Provenzano (proven@mit.edu)
+
+ * cpw.c : Uses new kdb change password routines for ank, ark, cpw,
+ and crk. Also remove v4 variants of ank and cpw.
+ * krb5_edit.c : Deleted old variants of rotuines now in cpw.c
+ * kdb5_ed_ct.ct, kdb5_edit.M, tcl_wrapper.c:
+ Removed references to v4 variants of ank and cpw.
+ * kdb5_edit.h (enter_pwd_key()) : Removed proto, it's nolonger
+ necessary as it's a static routine in cpw.c
+
+Thu Aug 03 12:13:50 1995 Chris Provenzano (proven@mit.edu)
+
+ * cpw.c : New change password code for kdb5_edit.
+ * dumpv4.c : Get it to compile with new kdb format.
+
+Mon Jul 31 15:47:30 EDT 1995 Paul Park (pjpark@mit.edu)
+ * kdb5_edit.c - Use libkadm string conversion routines. These are
+ shared by all utilities.
+ * Makefile.in - Remove getdate.y.
+ * configure.in - Remove getdate.y dependency checks.
+ * getdate.y - Sayonara.
+
+
+Thu Jul 27 15:01:01 EDT 1995 Paul Park (pjpark@mit.edu)
+ * configure.in - Add --with-dbm and check for already checking for dbm.
+
+
+Thu Jul 27 02:59:05 1995 Chris Provenzano (proven@mit.edu)
+
+ * dump.c kdb5_edit.c kdb5_edit.h util.c : Use new kdb format.
+
+Mon Jul 17 15:00:08 EDT 1995 Paul Park (pjpark@mit.edu)
+ * configure.in - Add KADM library.
+ * dumpv4.c - Change calling sequence to krb5_db_fetch_mkey().
+ * kdb5_edit.c - Change calling sequence to krb5_db_fetch_mkey() which
+ uses the stash file. Add KDC profile reading/handling as a
+ supplement to command line supplied arguments.
+
+
+Wed Jul 12 12:01:04 EDT 1995 Paul Park (pjpark@mit.edu)
+ * configure.in - Temporarily add --with-kdb4 option. Default is without
+ kdb4. Without kdb4 enables a define. With kdb4 uses -lkdb4 and
+ -l[n]dbm libraries.
+ * dumpv4.c - Conditionalize references to kdb4 routines with
+ KDB4_DISABLE. Replace two required routines:
+ kdb_encrypt_key -> pcbc_encrypt
+ kdb_get_master_key -> des_read_password/printf/key_sched
+
+
+Fri Jul 7 15:38:00 EDT 1995 Paul Park (pjpark@mit.edu)
+ * Makefile.in - Remove all explicit library handling and LDFLAGS.
+ * configure.in - Add USE_<mumble> and KRB5_LIBRARIES.
+
+
+Thu Jun 15 15:34:59 EDT 1995 Paul Park (pjpark@mit.edu)
+ * Makefile.in - Change explicit library names to -l<lib> form, and
+ change target link line to use $(LD) and associated flags.
+ Also, for K4, use KRB4_LIB and KRB4_CRYPTO_LIB, these wer
+ split out.
+ * configure.in - Add shared library usage check.
+
+Fri Jun 9 18:14:43 1995 <tytso@rsx-11.mit.edu>
+
+ * configure.in: Remove standardized set of autoconf macros, which
+ are now handled by CONFIG_RULES.
+
+ * dumpv4.c: Change name of controlling #ifdef to be
+ KRB5_KRB4_COMPAT instead of KRB4.
+
+Sun May 21 14:20:32 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * dumpv4.c: Include k5-int.h before krb.h so that PROTOTYPE is not
+ redefined.
+
+Sun May 7 13:46:30 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * configure.in: Add AC_HEADER_STDC to define STDC_HEADERS for
+ getdate.y.
+
+Mon May 1 13:36:41 1995 Theodore Y. Ts'o (tytso@dcl)
+
+ * kdb5_edit.c (kdb5_edit_Init): Check the return code from
+ kdb5_init_context().
+
+Fri Apr 28 18:04:26 1995 Mark Eichin <eichin@cygnus.com>
+
+ * Makefile.in (LOCAL_LIBRARIES): put KRB4_LIB inside KLIB, and put
+ KDB4_LIB ahead of them both.
+
+Thu Apr 27 13:47:23 1995 Mark Eichin <eichin@cygnus.com>
+
+ * Makefile.in (LOCAL_LIBRARIES): use KRB4_LIB and KDB4_LIB
+ directly.
+ * configure.in: just use WITH_KRB4.
+
+Wed Apr 19 13:59:47 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * kdb5_edit.c (kdb5_edit_Init): If a default realm is specified
+ (with -r), use krb5_set_default_realm so that created keys
+ will have the correct realm.
+
+Thu Mar 23 23:28:26 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * kdb5_edit.c (show_principal, parse_princ_args): Add
+ "support_desmd5" flag.
+
+Tue Mar 14 16:29:05 1995 <tytso@rsx-11.mit.edu>
+
+ * ss_wrapper.c (main): Set the return code from ss_execute_line(),
+ so that appropriate error checking is done.
+
+Thu Mar 2 12:18:57 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar 1 11:53:02 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+ and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 02:06:26 1995 John Gilmore (gnu at toad.com)
+
+ * dump.c, dumpv4.c, kdb5_edit.c, ss_wrapper.c, tcl_wrapper.c,
+ util.c: Avoid <krb5/...> includes.
+
+Thu Feb 23 19:52:35 1995 Mark Eichin (eichin@cygnus.com)
+
+ * kdb5_edit.c: add struct timeb and sys/timeb includes from
+ getdate.y.
+ (ftime): new function, in case we don't HAVE_FTIME.
+
+Tue Feb 14 17:55:47 1995 Tom Yu (tlyu@dragons-lair)
+
+ * kdb5_edit.c: add modent
+ * getdate.y: import get_date
+ * kdbt_ed_ct.ct: add modent
+ * configure.in:
+ * Makefile.in: support for getdate.y
+
+Wed Feb 8 20:08:36 1995 Tom Yu (tlyu@dragons-lair)
+
+ * kdb5_edit.c (show_principal): make sane and print all useful
+ fields
+
+Wed Jan 25 16:54:40 1995 Chris Provenzano (proven@mit.edu)
+
+ * Removed all narrow types and references to wide.h and narrow.h
+
+Fri Jan 13 15:23:47 1995 Chris Provenzano (proven@mit.edu)
+
+ * Added krb5_context to all krb5_routines
+
+Mon Dec 19 18:04:11 1994 Theodore Y. Ts'o (tytso@dcl)
+
+ * configure.in:
+ * Makefile.in:
+ * dumpv4.c (dump_v4db): Do the right thing if we are compiling
+ without V4 support. (The dump_v4db command is disabled.)
+
+Wed Dec 7 00:07:46 1994 <tytso@rsx-11.mit.edu>
+
+ * dumpv4.c (v4_print_time): gmtime expects a pointer to a time_t,
+ not a long. On most systems these are the same, on
+ others....
+
+Wed Nov 16 01:03:42 1994 Mark Eichin (eichin@cygnus.com)
+
+ * dumpv4.c: new file. New command dump_v4db which creates a v4
+ slave dump out of a v5 database, leaving out any keys which aren't
+ using v4 salt, and any keys that aren't for the current
+ realm. Reencrypts using v4 master key, synthesizes arbitrary
+ master key version number.
+ * configure.in: use WITH_KRB4 for dump support.
+ * kdb5_ed_ct.ct: add new dump_v4 command.
+ * Makefile.in: link in dumpv4.
+
+Fri Oct 14 23:31:49 1994 Theodore Y. Ts'o (tytso@dcl)
+
+ * dump.c (load_db): When scanning a database entry, read
+ fail_auth_count into a temporary integer variable, and
+ then copy that into entry.fail_auth_count, which is a
+ char.
+
+Fri Oct 7 00:01:40 1994 Theodore Y. Ts'o (tytso@dcl)
+
+ * kdb5_edit.c (kdb5_edit_Init): Don't let errors in
+ set_dbname_help initially cause the exit status to be set.
+ Commands like load_db don't need a valid database to be
+ opened.
+
+ * ss_wrapper.c (main): Clear code before ss_execute_line, since
+ ss_execute_line doesn't set code to 0 if there are no
+ problems.
+
+ * kdb5_edit.c (kdb5_edit_Init): Add a new option so that the
+ master key password can be entered on the command line ---
+ for testing only; not documented!!
+
+Mon Oct 3 19:10:47 1994 Theodore Y. Ts'o (tytso@dcl)
+
+ * Makefile.in: Use $(srcdir) to find manual page for make install.
+
+Thu Sep 29 15:52:22 1994 Theodore Y. Ts'o (tytso@dcl)
+
+ * dump.c (update_ok_file): Make sure mod time on the dump_ok file
+ is updated. (Some systems don't update the mod-time when
+ a file is opened for writing.)
+
+ * Makefile.in: Relink executable when libraries change.
+
+ * kdb5_edit.c (show_principal): Pass variable with correct type to
+ ctime().
+
+ * tcl_wrapper.c (doquit):
+ ss_wrapper.c (main):
+ kdb5_edit.c:
+ dump.c: Exit with a non-zero exit status if there was an error
+ in a executed command.
+
+Thu Sep 15 11:00:30 1994 Theodore Y. Ts'o (tytso@dcl)
+
+ * dump.c (load_db): Fix error string on failed fopen. ("for
+ writing" -> "for reading")
+
+
diff --git a/src/kadmin/dbutil/Makefile.in b/src/kadmin/dbutil/Makefile.in
new file mode 100644
index 000000000..b5bba09d9
--- /dev/null
+++ b/src/kadmin/dbutil/Makefile.in
@@ -0,0 +1,18 @@
+CFLAGS = $(CCOPTS) $(DEFS) -DKDB4_DISABLE $(LOCALINCLUDE) @KRB4_INCLUDES@
+
+PROG = kdb5_util
+OBJS = kdb5_create.o kadm5_create.o string_table.o
+OBJS = kdb5_util.o kdb5_util_ct.o dump.o dumpv4.o loadv4.o ss_wrapper.o \
+ kdb5_create.o kadm5_create.o string_table.o kdb5_stash.o \
+ kdb5_destroy.o
+
+all:: $(PROG)
+
+$(PROG): $(OBJS) $(DEPLIBS)
+ $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG) $(OBJS) $(LIBS)
+
+install::
+ $(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+
+clean::
+ $(RM) $(PROG) $(OBJS)
diff --git a/src/kadmin/dbutil/Makefile.ov b/src/kadmin/dbutil/Makefile.ov
new file mode 100644
index 000000000..f762282f2
--- /dev/null
+++ b/src/kadmin/dbutil/Makefile.ov
@@ -0,0 +1,19 @@
+TOP = ..
+include $(TOP)/config.mk/template
+
+CFLAGS += -I$(TOP)/../include/kerberosIV
+
+PROG = kdb5_util
+SRCS = kdb5_util.c kdb5_util_ct.c dump.c ss_wrapper.c dumpv4.c loadv4.c \
+ kdb5_create.c kadm5_create.c string_table.c kdb5_stash.c \
+ kdb5_destroy.c
+OBJS = kdb5_util.o kdb5_util_ct.o dump.o dumpv4.o loadv4.o ss_wrapper.o \
+ kdb5_create.o kadm5_create.o string_table.o kdb5_stash.o \
+ kdb5_destroy.o
+ETABLES = kdb5_util_ct.ct
+
+LIBS = $(LIBADMSRV) $(LIBKDB5) $(LIBKRB5_ALL) $(LIBRPCLIB) $(LIBDYN) \
+ $(LIBSS) $(LIBDB)
+
+expand NormalProgram
+expand ErrorTables
diff --git a/src/kadmin/dbutil/configure.in b/src/kadmin/dbutil/configure.in
new file mode 100644
index 000000000..c9234524e
--- /dev/null
+++ b/src/kadmin/dbutil/configure.in
@@ -0,0 +1,13 @@
+AC_INIT(kdb5_create.c)
+CONFIG_RULES
+WITH_KRB4
+AC_PROG_INSTALL
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_KDB5_LIBRARY
+USE_DYN_LIBRARY
+USE_SS_LIBRARY
+USE_KRB4_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
new file mode 100644
index 000000000..8bd54ca4d
--- /dev/null
+++ b/src/kadmin/dbutil/dump.c
@@ -0,0 +1,1957 @@
+/*
+ * admin/edit/dump.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Dump a KDC database
+ */
+
+#include <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <kadm5/adb.h>
+#include <com_err.h>
+#include "kdb5_util.h"
+#if HAVE_REGEX_H
+#include <regex.h>
+#endif /* HAVE_REGEX_H */
+
+/*
+ * Use compile(3) if no regcomp present.
+ */
+#if !defined(HAVE_REGCOMP) && defined(HAVE_REGEXP_H)
+#define INIT char *sp = instring;
+#define GETC() (*sp++)
+#define PEEKC() (*sp)
+#define UNGETC(c) (--sp)
+#define RETURN(c) return(c)
+#define ERROR(c)
+#define RE_BUF_SIZE 1024
+#include <regexp.h>
+#endif /* !HAVE_REGCOMP && HAVE_REGEXP_H */
+
+struct dump_args {
+ char *programname;
+ FILE *ofile;
+ krb5_context kcontext;
+ char **names;
+ int nnames;
+ int verbose;
+};
+
+static krb5_error_code dump_k5beta_iterator PROTOTYPE((krb5_pointer,
+ krb5_db_entry *));
+static krb5_error_code dump_k5beta6_iterator PROTOTYPE((krb5_pointer,
+ krb5_db_entry *));
+static krb5_error_code dump_k5beta7_princ PROTOTYPE((krb5_pointer,
+ krb5_db_entry *));
+static void dump_k5beta7_policy PROTOTYPE((void *, osa_policy_ent_t));
+
+typedef krb5_error_code (*dump_func)PROTOTYPE((krb5_pointer,
+ krb5_db_entry *));
+
+static int process_k5beta_record PROTOTYPE((char *, krb5_context,
+ FILE *, int, int *, void *));
+static int process_k5beta6_record PROTOTYPE((char *, krb5_context,
+ FILE *, int, int *, void *));
+static int process_k5beta7_record PROTOTYPE((char *, krb5_context,
+ FILE *, int, int *, void *));
+typedef krb5_error_code (*load_func)PROTOTYPE((char *, krb5_context,
+ FILE *, int, int *, void *));
+
+typedef struct _dump_version {
+ char *name;
+ char *header;
+ dump_func dump_princ;
+ osa_adb_iter_policy_func dump_policy;
+ load_func load_record;
+} dump_version;
+
+dump_version old_version = {
+ "Kerberos version 5 old format",
+ "kdb5_edit load_dump version 2.0\n",
+ dump_k5beta_iterator,
+ NULL,
+ process_k5beta_record,
+};
+dump_version beta6_version = {
+ "Kerberos version 5 beta 6 format",
+ "kdb5_edit load_dump version 3.0\n",
+ dump_k5beta6_iterator,
+ NULL,
+ process_k5beta6_record,
+};
+dump_version beta7_version = {
+ "Kerberos version 5",
+ "kdb5_util load_dump version 4\n",
+ dump_k5beta7_princ,
+ dump_k5beta7_policy,
+ process_k5beta7_record,
+};
+
+/* External data */
+extern char *current_dbname;
+extern krb5_boolean dbactive;
+extern int exit_status;
+extern krb5_context util_context;
+extern kadm5_config_params global_params;
+
+/* Strings */
+
+static const char k5beta_dump_header[] = "kdb5_edit load_dump version 2.0\n";
+static const char k5beta6_dump_header[] = "kdb5_edit load_dump version 3.0\n";
+static const char k5beta7_dump_header[] = "kdb5_edit load_dump version 4\n";
+
+static const char null_mprinc_name[] = "kdb5_dump@MISSING";
+
+/* Message strings */
+static const char regex_err[] = "%s: regular expression error - %s\n";
+static const char regex_merr[] = "%s: regular expression match error - %s\n";
+static const char pname_unp_err[] = "%s: cannot unparse principal name (%s)\n";
+static const char mname_unp_err[] = "%s: cannot unparse modifier name (%s)\n";
+static const char nokeys_err[] = "%s: cannot find any standard key for %s\n";
+static const char sdump_tl_inc_err[] = "%s: tagged data list inconsistency for %s (counted %d, stored %d)\n";
+static const char stand_fmt_name[] = "Kerberos version 5";
+static const char old_fmt_name[] = "Kerberos version 5 old format";
+static const char b6_fmt_name[] = "Kerberos version 5 beta 6 format";
+static const char ofopen_error[] = "%s: cannot open %s for writing (%s)\n";
+static const char oflock_error[] = "%s: cannot lock %s (%s)\n";
+static const char dumprec_err[] = "%s: error performing %s dump (%s)\n";
+static const char dumphdr_err[] = "%s: error dumping %s header (%s)\n";
+static const char trash_end_fmt[] = "%s(%d): ignoring trash at end of line: ";
+static const char read_name_string[] = "name string";
+static const char read_key_type[] = "key type";
+static const char read_key_data[] = "key data";
+static const char read_pr_data1[] = "first set of principal attributes";
+static const char read_mod_name[] = "modifier name";
+static const char read_pr_data2[] = "second set of principal attributes";
+static const char read_salt_data[] = "salt data";
+static const char read_akey_type[] = "alternate key type";
+static const char read_akey_data[] = "alternate key data";
+static const char read_asalt_type[] = "alternate salt type";
+static const char read_asalt_data[] = "alternate salt data";
+static const char read_exp_data[] = "expansion data";
+static const char store_err_fmt[] = "%s(%d): cannot store %s(%s)\n";
+static const char add_princ_fmt[] = "%s\n";
+static const char parse_err_fmt[] = "%s(%d): cannot parse %s (%s)\n";
+static const char read_err_fmt[] = "%s(%d): cannot read %s\n";
+static const char no_mem_fmt[] = "%s(%d): no memory for buffers\n";
+static const char rhead_err_fmt[] = "%s(%d): cannot match size tokens\n";
+static const char err_line_fmt[] = "%s: error processing line %d of %s\n";
+static const char head_bad_fmt[] = "%s: dump header bad in %s\n";
+static const char read_bytecnt[] = "record byte count";
+static const char read_encdata[] = "encoded data";
+static const char n_name_unp_fmt[] = "%s(%s): cannot unparse name\n";
+static const char n_dec_cont_fmt[] = "%s(%s): cannot decode contents\n";
+static const char read_nint_data[] = "principal static attributes";
+static const char read_tcontents[] = "tagged data contents";
+static const char read_ttypelen[] = "tagged data type and length";
+static const char read_kcontents[] = "key data contents";
+static const char read_ktypelen[] = "key data type and length";
+static const char read_econtents[] = "extra data contents";
+static const char k5beta_fmt_name[] = "Kerberos version 5 old format";
+static const char standard_fmt_name[] = "Kerberos version 5 format";
+static const char lusage_err_fmt[] = "%s: usage is %s [%s] [%s] [%s] filename dbname [admin_dbname]\n";
+static const char no_name_mem_fmt[] = "%s: cannot get memory for temporary name\n";
+static const char ctx_err_fmt[] = "%s: cannot initialize Kerberos context\n";
+static const char stdin_name[] = "standard input";
+static const char restfail_fmt[] = "%s: %s restore failed\n";
+static const char close_err_fmt[] = "%s: cannot close database (%s)\n";
+static const char dbinit_err_fmt[] = "%s: cannot initialize database (%s)\n";
+static const char dbname_err_fmt[] = "%s: cannot set database name to %s (%s)\n";
+static const char dbdelerr_fmt[] = "%s: cannot delete bad database %s (%s)\n";
+static const char dbrenerr_fmt[] = "%s: cannot rename database %s to %s (%s)\n";
+static const char dbcreaterr_fmt[] = "%s: cannot create database %s (%s)\n";
+static const char dfile_err_fmt[] = "%s: cannot open %s (%s)\n";
+
+static const char oldoption[] = "-old";
+static const char b6option[] = "-b6";
+static const char verboseoption[] = "-verbose";
+static const char updateoption[] = "-update";
+static const char dump_tmptrail[] = "~";
+
+/*
+ * Update the "ok" file.
+ */
+void update_ok_file (file_name)
+ char *file_name;
+{
+ /* handle slave locking/failure stuff */
+ char *file_ok;
+ int fd;
+ static char ok[]=".dump_ok";
+
+ if ((file_ok = (char *)malloc(strlen(file_name) + strlen(ok) + 1))
+ == NULL) {
+ com_err(progname, ENOMEM,
+ "while allocating filename for update_ok_file");
+ exit_status++;
+ return;
+ }
+ strcpy(file_ok, file_name);
+ strcat(file_ok, ok);
+ if ((fd = open(file_ok, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
+ com_err(progname, errno, "while creating 'ok' file, '%s'",
+ file_ok);
+ exit_status++;
+ free(file_ok);
+ return;
+ }
+ if (write(fd, "", 1) != 1) {
+ com_err(progname, errno, "while writing to 'ok' file, '%s'",
+ file_ok);
+ exit_status++;
+ free(file_ok);
+ return;
+ }
+
+ free(file_ok);
+ close(fd);
+ return;
+}
+
+/*
+ * name_matches() - See if a principal name matches a regular expression
+ * or string.
+ */
+static int
+name_matches(name, arglist)
+ char *name;
+ struct dump_args *arglist;
+{
+#if HAVE_REGCOMP
+ regex_t match_exp;
+ regmatch_t match_match;
+ int match_error;
+ char match_errmsg[BUFSIZ];
+ size_t errmsg_size;
+#elif HAVE_REGEXP_H
+ char regexp_buffer[RE_BUF_SIZE];
+#elif HAVE_RE_COMP
+ extern char *re_comp();
+ char *re_result;
+#endif /* HAVE_RE_COMP */
+ int i, match;
+
+ /*
+ * Plow, brute force, through the list of names/regular expressions.
+ */
+ match = (arglist->nnames) ? 0 : 1;
+ for (i=0; i<arglist->nnames; i++) {
+#if HAVE_REGCOMP
+ /*
+ * Compile the regular expression.
+ */
+ if (match_error = regcomp(&match_exp,
+ arglist->names[i],
+ REG_EXTENDED)) {
+ errmsg_size = regerror(match_error,
+ &match_exp,
+ match_errmsg,
+ sizeof(match_errmsg));
+ fprintf(stderr, regex_err, arglist->programname, match_errmsg);
+ break;
+ }
+ /*
+ * See if we have a match.
+ */
+ if (match_error = regexec(&match_exp, name, 1, &match_match, 0)) {
+ if (match_error != REG_NOMATCH) {
+ errmsg_size = regerror(match_error,
+ &match_exp,
+ match_errmsg,
+ sizeof(match_errmsg));
+ fprintf(stderr, regex_merr,
+ arglist->programname, match_errmsg);
+ break;
+ }
+ }
+ else {
+ /*
+ * We have a match. See if it matches the whole
+ * name.
+ */
+ if ((match_match.rm_so == 0) &&
+ (match_match.rm_eo == strlen(name)))
+ match = 1;
+ }
+ regfree(&match_exp);
+#elif HAVE_REGEXP_H
+ /*
+ * Compile the regular expression.
+ */
+ compile(arglist->names[i],
+ regexp_buffer,
+ &regexp_buffer[RE_BUF_SIZE],
+ '\0');
+ if (step(name, regexp_buffer)) {
+ if ((loc1 == name) &&
+ (loc2 == &name[strlen(name)]))
+ match = 1;
+ }
+#elif HAVE_RE_COMP
+ /*
+ * Compile the regular expression.
+ */
+ if (re_result = re_comp(arglist->names[i])) {
+ fprintf(stderr, regex_err, arglist->programname, re_result);
+ break;
+ }
+ if (re_exec(name))
+ match = 1;
+#else /* HAVE_RE_COMP */
+ /*
+ * If no regular expression support, then just compare the strings.
+ */
+ if (!strcmp(arglist->names[i], name))
+ match = 1;
+#endif /* HAVE_REGCOMP */
+ if (match)
+ break;
+ }
+ return(match);
+}
+
+static krb5_error_code
+find_enctype(dbentp, enctype, salttype, kentp)
+ krb5_db_entry *dbentp;
+ krb5_enctype enctype;
+ krb5_int32 salttype;
+ krb5_key_data **kentp;
+{
+ int i;
+ int maxkvno;
+ krb5_key_data *datap;
+
+ maxkvno = -1;
+ datap = (krb5_key_data *) NULL;
+ for (i=0; i<dbentp->n_key_data; i++) {
+ if ((dbentp->key_data[i].key_data_type[0] == enctype) &&
+ ((dbentp->key_data[i].key_data_type[1] == salttype) ||
+ (salttype < 0))) {
+ maxkvno = dbentp->key_data[i].key_data_kvno;
+ datap = &dbentp->key_data[i];
+ }
+ }
+ if (maxkvno >= 0) {
+ *kentp = datap;
+ return(0);
+ }
+ return(ENOENT);
+}
+
+/*
+ * dump_k5beta_header() - Make a dump header that is recognizable by Kerberos
+ * Version 5 Beta 5 and previous releases.
+ */
+static krb5_error_code
+dump_k5beta_header(arglist)
+ struct dump_args *arglist;
+{
+ /* The old header consists of the leading string */
+ fprintf(arglist->ofile, k5beta_dump_header);
+ return(0);
+}
+
+/*
+ * dump_k5beta_iterator() - Dump an entry in a format that is usable
+ * by Kerberos Version 5 Beta 5 and previous
+ * releases.
+ */
+static krb5_error_code
+dump_k5beta_iterator(ptr, entry)
+ krb5_pointer ptr;
+ krb5_db_entry *entry;
+{
+ krb5_error_code retval;
+ struct dump_args *arg;
+ char *name, *mod_name;
+ krb5_principal mod_princ;
+ krb5_tl_data *pwchg;
+ krb5_key_data *pkey, *akey, nullkey;
+ krb5_timestamp mod_date, last_pwd_change;
+ int i;
+
+ /* Initialize */
+ arg = (struct dump_args *) ptr;
+ name = (char *) NULL;
+ mod_name = (char *) NULL;
+ memset(&nullkey, 0, sizeof(nullkey));
+
+ /*
+ * Flatten the principal name.
+ */
+ if ((retval = krb5_unparse_name(arg->kcontext,
+ entry->princ,
+ &name))) {
+ fprintf(stderr, pname_unp_err,
+ arg->programname, error_message(retval));
+ return(retval);
+ }
+ /*
+ * If we don't have any match strings, or if our name matches, then
+ * proceed with the dump, otherwise, just forget about it.
+ */
+ if (!arg->nnames || name_matches(name, arg)) {
+ /*
+ * Deserialize the modifier record.
+ */
+ mod_name = (char *) NULL;
+ mod_princ = NULL;
+ last_pwd_change = mod_date = 0;
+ pkey = akey = (krb5_key_data *) NULL;
+ if (!(retval = krb5_dbe_lookup_mod_princ_data(arg->kcontext,
+ entry,
+ &mod_date,
+ &mod_princ))) {
+ if (mod_princ) {
+ /*
+ * Flatten the modifier name.
+ */
+ if ((retval = krb5_unparse_name(arg->kcontext,
+ mod_princ,
+ &mod_name)))
+ fprintf(stderr, mname_unp_err, arg->programname,
+ error_message(retval));
+ krb5_free_principal(arg->kcontext, mod_princ);
+ }
+ }
+ if (!mod_name)
+ mod_name = strdup(null_mprinc_name);
+
+ /*
+ * Find the last password change record and set it straight.
+ */
+ if (retval =
+ krb5_dbe_lookup_last_pwd_change(arg->kcontext, entry,
+ &last_pwd_change)) {
+ fprintf(stderr, nokeys_err, arg->programname, name);
+ krb5_xfree(mod_name);
+ krb5_xfree(name);
+ return(retval);
+ }
+
+ /*
+ * Find the 'primary' key and the 'alternate' key.
+ */
+ if ((retval = find_enctype(entry,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_NORMAL,
+ &pkey)) &&
+ (retval = find_enctype(entry,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4,
+ &akey))) {
+ fprintf(stderr, nokeys_err, arg->programname, name);
+ krb5_xfree(mod_name);
+ krb5_xfree(name);
+ return(retval);
+ }
+
+ /* If we only have one type, then ship it out as the primary. */
+ if (!pkey && akey) {
+ pkey = akey;
+ akey = &nullkey;
+ }
+ else {
+ if (!akey)
+ akey = &nullkey;
+ }
+
+ /*
+ * First put out strings representing the length of the variable
+ * length data in this record, then the name and the primary key type.
+ */
+ fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%s\t%d\t", strlen(name),
+ strlen(mod_name),
+ (krb5_int32) pkey->key_data_length[0],
+ (krb5_int32) akey->key_data_length[0],
+ (krb5_int32) pkey->key_data_length[1],
+ (krb5_int32) akey->key_data_length[1],
+ name,
+ (krb5_int32) pkey->key_data_type[0]);
+ for (i=0; i<pkey->key_data_length[0]; i++) {
+ fprintf(arg->ofile, "%02x", pkey->key_data_contents[0][i]);
+ }
+ /*
+ * Second, print out strings representing the standard integer
+ * data in this record.
+ */
+ fprintf(arg->ofile,
+ "\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%s\t%u\t%u\t%u\t",
+ (krb5_int32) pkey->key_data_kvno,
+ entry->max_life, entry->max_renewable_life,
+ 1 /* Fake mkvno */, entry->expiration, entry->pw_expiration,
+ last_pwd_change, entry->last_success, entry->last_failed,
+ entry->fail_auth_count, mod_name, mod_date,
+ entry->attributes, pkey->key_data_type[1]);
+
+ /* Pound out the salt data, if present. */
+ for (i=0; i<pkey->key_data_length[1]; i++) {
+ fprintf(arg->ofile, "%02x", pkey->key_data_contents[1][i]);
+ }
+ /* Pound out the alternate key type and contents */
+ fprintf(arg->ofile, "\t%u\t", akey->key_data_type[0]);
+ for (i=0; i<akey->key_data_length[0]; i++) {
+ fprintf(arg->ofile, "%02x", akey->key_data_contents[0][i]);
+ }
+ /* Pound out the alternate salt type and contents */
+ fprintf(arg->ofile, "\t%u\t", akey->key_data_type[1]);
+ for (i=0; i<akey->key_data_length[1]; i++) {
+ fprintf(arg->ofile, "%02x", akey->key_data_contents[1][i]);
+ }
+ /* Pound out the expansion data. (is null) */
+ for (i=0; i < 8; i++) {
+ fprintf(arg->ofile, "\t%u", 0);
+ }
+ fprintf(arg->ofile, ";\n");
+ /* If we're blabbing, do it */
+ if (arg->verbose)
+ fprintf(stderr, "%s\n", name);
+ krb5_xfree(mod_name);
+ }
+ krb5_xfree(name);
+ return(0);
+}
+
+/*
+ * dump_k5beta6_iterator() - Output a dump record in krb5b6 format.
+ */
+static krb5_error_code
+dump_k5beta6_iterator(ptr, entry)
+ krb5_pointer ptr;
+ krb5_db_entry *entry;
+{
+ krb5_error_code retval;
+ struct dump_args *arg;
+ char *name;
+ krb5_tl_data *tlp;
+ krb5_key_data *kdata;
+ int counter, i, j;
+
+ /* Initialize */
+ arg = (struct dump_args *) ptr;
+ name = (char *) NULL;
+
+ /*
+ * Flatten the principal name.
+ */
+ if ((retval = krb5_unparse_name(arg->kcontext,
+ entry->princ,
+ &name))) {
+ fprintf(stderr, pname_unp_err,
+ arg->programname, error_message(retval));
+ return(retval);
+ }
+ /*
+ * If we don't have any match strings, or if our name matches, then
+ * proceed with the dump, otherwise, just forget about it.
+ */
+ if (!arg->nnames || name_matches(name, arg)) {
+ /*
+ * We'd like to just blast out the contents as they would appear in
+ * the database so that we can just suck it back in, but it doesn't
+ * lend itself to easy editing.
+ */
+
+ /*
+ * The dump format is as follows:
+ * len strlen(name) n_tl_data n_key_data e_length
+ * name
+ * attributes max_life max_renewable_life expiration
+ * pw_expiration last_success last_failed fail_auth_count
+ * n_tl_data*[type length <contents>]
+ * n_key_data*[ver kvno ver*(type length <contents>)]
+ * <e_data>
+ * Fields which are not encapsulated by angle-brackets are to appear
+ * verbatim. Bracketed fields absence is indicated by a -1 in its
+ * place
+ */
+
+ /*
+ * Make sure that the tagged list is reasonably correct.
+ */
+ counter = 0;
+ for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next)
+ counter++;
+ if (counter == entry->n_tl_data) {
+ /* Pound out header */
+ fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
+ (int) entry->len,
+ strlen(name),
+ (int) entry->n_tl_data,
+ (int) entry->n_key_data,
+ (int) entry->e_length,
+ name);
+ fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
+ entry->attributes,
+ entry->max_life,
+ entry->max_renewable_life,
+ entry->expiration,
+ entry->pw_expiration,
+ entry->last_success,
+ entry->last_failed,
+ entry->fail_auth_count);
+ /* Pound out tagged data. */
+ for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
+ fprintf(arg->ofile, "%d\t%d\t",
+ (int) tlp->tl_data_type,
+ (int) tlp->tl_data_length);
+ if (tlp->tl_data_length)
+ for (i=0; i<tlp->tl_data_length; i++)
+ fprintf(arg->ofile, "%02x", tlp->tl_data_contents[i]);
+ else
+ fprintf(arg->ofile, "%d", -1);
+ fprintf(arg->ofile, "\t");
+ }
+
+ /* Pound out key data */
+ for (counter=0; counter<entry->n_key_data; counter++) {
+ kdata = &entry->key_data[counter];
+ fprintf(arg->ofile, "%d\t%d\t",
+ (int) kdata->key_data_ver,
+ (int) kdata->key_data_kvno);
+ for (i=0; i<kdata->key_data_ver; i++) {
+ fprintf(arg->ofile, "%d\t%d\t",
+ kdata->key_data_type[i],
+ kdata->key_data_length[i]);
+ if (kdata->key_data_length[i])
+ for (j=0; j<kdata->key_data_length[i]; j++)
+ fprintf(arg->ofile, "%02x",
+ kdata->key_data_contents[i][j]);
+ else
+ fprintf(arg->ofile, "%d", -1);
+ fprintf(arg->ofile, "\t");
+ }
+ }
+
+ /* Pound out extra data */
+ if (entry->e_length)
+ for (i=0; i<entry->e_length; i++)
+ fprintf(arg->ofile, "%02x", entry->e_data[i]);
+ else
+ fprintf(arg->ofile, "%d", -1);
+
+ /* Print trailer */
+ fprintf(arg->ofile, ";\n");
+
+ if (arg->verbose)
+ fprintf(stderr, "%s\n", name);
+ }
+ else {
+ fprintf(stderr, sdump_tl_inc_err,
+ arg->programname, name, counter, (int) entry->n_tl_data);
+ retval = EINVAL;
+ }
+ }
+ krb5_xfree(name);
+ return(retval);
+}
+
+/*
+ * dump_k5beta7_iterator() - Output a dump record in krb5b7 format.
+ */
+static krb5_error_code
+dump_k5beta7_princ(ptr, entry)
+ krb5_pointer ptr;
+ krb5_db_entry *entry;
+{
+ krb5_error_code retval;
+ struct dump_args *arg;
+ char *name;
+ int tmp_nnames;
+
+ /* Initialize */
+ arg = (struct dump_args *) ptr;
+ name = (char *) NULL;
+
+ /*
+ * Flatten the principal name.
+ */
+ if ((retval = krb5_unparse_name(arg->kcontext,
+ entry->princ,
+ &name))) {
+ fprintf(stderr, pname_unp_err,
+ arg->programname, error_message(retval));
+ return(retval);
+ }
+ /*
+ * If we don't have any match strings, or if our name matches, then
+ * proceed with the dump, otherwise, just forget about it.
+ */
+ if (!arg->nnames || name_matches(name, arg)) {
+ fprintf(arg->ofile, "princ\t");
+
+ /* save the callee from matching the name again */
+ tmp_nnames = arg->nnames;
+ arg->nnames = 0;
+ retval = dump_k5beta6_iterator(ptr, entry);
+ arg->nnames = tmp_nnames;
+ }
+
+ free(name);
+ return retval;
+}
+
+void dump_k5beta7_policy(void *data, osa_policy_ent_t entry)
+{
+ struct dump_args *arg;
+
+ arg = (struct dump_args *) data;
+ fprintf(arg->ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n", entry->name,
+ entry->pw_min_life, entry->pw_max_life, entry->pw_min_length,
+ entry->pw_min_classes, entry->pw_history_num,
+ entry->policy_refcnt);
+}
+
+/*
+ * usage is:
+ * dump_db [-old] [-b6] [-verbose] [filename [principals...]]
+ */
+void
+dump_db(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *f;
+ struct dump_args arglist;
+ int error;
+ char *programname;
+ char *ofile;
+ krb5_error_code kret;
+ dump_version *dump;
+ int aindex;
+ krb5_boolean locked;
+ extern osa_adb_policy_t policy_db;
+
+ /*
+ * Parse the arguments.
+ */
+ programname = argv[0];
+ if (strrchr(programname, (int) '/'))
+ programname = strrchr(argv[0], (int) '/') + 1;
+ ofile = (char *) NULL;
+ error = 0;
+ dump = &beta7_version;
+ arglist.verbose = 0;
+
+ /*
+ * Parse the qualifiers.
+ */
+ for (aindex = 1; aindex < argc; aindex++) {
+ if (!strcmp(argv[aindex], oldoption))
+ dump = &old_version;
+ else if (!strcmp(argv[aindex], b6option))
+ dump = &beta6_version;
+ else if (!strcmp(argv[aindex], verboseoption))
+ arglist.verbose++;
+ else
+ break;
+ }
+
+ arglist.names = (char **) NULL;
+ arglist.nnames = 0;
+ if (aindex < argc) {
+ ofile = argv[aindex];
+ aindex++;
+ if (aindex < argc) {
+ arglist.names = &argv[aindex];
+ arglist.nnames = argc - aindex;
+ }
+ }
+
+ /*
+ * Attempt to open the database. The policy database only has to
+ * be opened if we try a dump that uses it.
+ */
+ if (!dbactive || (dump->dump_policy != NULL && policy_db == NULL)) {
+ com_err(argv[0], 0, Err_no_database);
+ exit_status++;
+ return;
+ }
+
+ kret = 0;
+ locked = 0;
+ if (ofile && strcmp(ofile, "-")) {
+ /*
+ * Make sure that we don't open and truncate on the fopen,
+ * since that may hose an on-going kprop process.
+ *
+ * We could also control this by opening for read and
+ * write, doing an flock with LOCK_EX, and then
+ * truncating the file once we have gotten the lock,
+ * but that would involve more OS dependencies than I
+ * want to get into.
+ */
+ unlink(ofile);
+ if (!(f = fopen(ofile, "w"))) {
+ fprintf(stderr, ofopen_error,
+ programname, ofile, error_message(errno));
+ exit_status++;
+ }
+ if ((kret = krb5_lock_file(util_context,
+ fileno(f),
+ KRB5_LOCKMODE_EXCLUSIVE))) {
+ fprintf(stderr, oflock_error,
+ programname, ofile, error_message(kret));
+ exit_status++;
+ }
+ else
+ locked = 1;
+ } else {
+ f = stdout;
+ }
+ if (f && !(kret)) {
+ arglist.programname = programname;
+ arglist.ofile = f;
+ arglist.kcontext = util_context;
+ fprintf(arglist.ofile, "%s", dump->header);
+ if ((kret = krb5_db_iterate(util_context,
+ dump->dump_princ,
+ (krb5_pointer) &arglist))) {
+ fprintf(stderr, dumprec_err,
+ programname, dump->name, error_message(kret));
+ exit_status++;
+ }
+ if (dump->dump_policy &&
+ (kret = osa_adb_iter_policy(policy_db, dump->dump_policy,
+ &arglist))) {
+ fprintf(stderr, dumprec_err, programname, dump->name,
+ error_message(kret));
+ exit_status++;
+ }
+ if (ofile && !exit_status) {
+ fclose(f);
+ update_ok_file(ofile);
+ }
+ }
+ if (locked)
+ (void) krb5_lock_file(util_context, fileno(f), KRB5_LOCKMODE_UNLOCK);
+}
+
+/*
+ * Read a string of bytes while counting the number of lines passed.
+ */
+static int
+read_string(f, buf, len, lp)
+ FILE *f;
+ char *buf;
+ int len;
+ int *lp;
+{
+ int c;
+ int i, retval;
+
+ retval = 0;
+ for (i=0; i<len; i++) {
+ c = (char) fgetc(f);
+ if (c < 0) {
+ retval = 1;
+ break;
+ }
+ if (c == '\n')
+ (*lp)++;
+ buf[i] = (char) c;
+ }
+ buf[len] = '\0';
+ return(retval);
+}
+
+/*
+ * Read a string of two character representations of bytes.
+ */
+static int
+read_octet_string(f, buf, len)
+ FILE *f;
+ krb5_octet *buf;
+ int len;
+{
+ int c;
+ int i, retval;
+
+ retval = 0;
+ for (i=0; i<len; i++) {
+ if (fscanf(f, "%02x", &c) != 1) {
+ retval = 1;
+ break;
+ }
+ buf[i] = (krb5_octet) c;
+ }
+ return(retval);
+}
+
+/*
+ * Find the end of an old format record.
+ */
+static void
+find_record_end(f, fn, lineno)
+ FILE *f;
+ char *fn;
+ int lineno;
+{
+ int ch;
+
+ if (((ch = fgetc(f)) != ';') || ((ch = fgetc(f)) != '\n')) {
+ fprintf(stderr, trash_end_fmt, fn, lineno);
+ while (ch != '\n') {
+ putc(ch, stderr);
+ ch = fgetc(f);
+ }
+ putc(ch, stderr);
+ }
+}
+
+#if 0
+/*
+ * update_tl_data() - Generate the tl_data entries.
+ */
+static krb5_error_code
+update_tl_data(kcontext, dbentp, mod_name, mod_date, last_pwd_change)
+ krb5_context kcontext;
+ krb5_db_entry *dbentp;
+ krb5_principal mod_name;
+ krb5_timestamp mod_date;
+ krb5_timestamp last_pwd_change;
+{
+ krb5_error_code kret;
+
+ kret = 0 ;
+
+ /*
+ * Handle modification principal.
+ */
+ if (mod_name) {
+ krb5_tl_mod_princ mprinc;
+
+ memset(&mprinc, 0, sizeof(mprinc));
+ if (!(kret = krb5_copy_principal(kcontext,
+ mod_name,
+ &mprinc.mod_princ))) {
+ mprinc.mod_date = mod_date;
+ kret = krb5_dbe_encode_mod_princ_data(kcontext,
+ &mprinc,
+ dbentp);
+ }
+ if (mprinc.mod_princ)
+ krb5_free_principal(kcontext, mprinc.mod_princ);
+ }
+
+ /*
+ * Handle last password change.
+ */
+ if (!kret) {
+ krb5_tl_data *pwchg;
+ krb5_boolean linked;
+
+ /* Find a previously existing entry */
+ for (pwchg = dbentp->tl_data;
+ (pwchg) && (pwchg->tl_data_type != KRB5_TL_LAST_PWD_CHANGE);
+ pwchg = pwchg->tl_data_next);
+
+ /* Check to see if we found one. */
+ linked = 0;
+ if (!pwchg) {
+ /* No, allocate a new one */
+ if ((pwchg = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
+ memset(pwchg, 0, sizeof(krb5_tl_data));
+ if (!(pwchg->tl_data_contents =
+ (krb5_octet *) malloc(sizeof(krb5_timestamp)))) {
+ free(pwchg);
+ pwchg = (krb5_tl_data *) NULL;
+ }
+ else {
+ pwchg->tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
+ pwchg->tl_data_length =
+ (krb5_int16) sizeof(krb5_timestamp);
+ }
+ }
+ }
+ else
+ linked = 1;
+
+ /* Do we have an entry? */
+ if (pwchg && pwchg->tl_data_contents) {
+ /* Encode it */
+ krb5_kdb_encode_int32(last_pwd_change, pwchg->tl_data_contents);
+ /* Link it in if necessary */
+ if (!linked) {
+ pwchg->tl_data_next = dbentp->tl_data;
+ dbentp->tl_data = pwchg;
+ dbentp->n_tl_data++;
+ }
+ }
+ else
+ kret = ENOMEM;
+ }
+
+ return(kret);
+}
+#endif
+
+/*
+ * process_k5beta_record() - Handle a dump record in old format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5beta_record(fname, kcontext, filep, verbose, linenop, pol_db)
+ char *fname;
+ krb5_context kcontext;
+ FILE *filep;
+ int verbose;
+ int *linenop;
+ void *pol_db;
+{
+ int nmatched;
+ int retval;
+ krb5_db_entry dbent;
+ int name_len, mod_name_len, key_len;
+ int alt_key_len, salt_len, alt_salt_len;
+ char *name;
+ char *mod_name;
+ int tmpint1, tmpint2, tmpint3;
+ int error;
+ const char *try2read;
+ int i;
+ krb5_key_data *pkey, *akey;
+ krb5_timestamp last_pwd_change, mod_date;
+ krb5_principal mod_princ;
+ krb5_error_code kret;
+
+ try2read = (char *) NULL;
+ (*linenop)++;
+ retval = 1;
+ memset((char *)&dbent, 0, sizeof(dbent));
+
+ /* Make sure we've got key_data entries */
+ if (krb5_dbe_create_key_data(kcontext, &dbent) ||
+ krb5_dbe_create_key_data(kcontext, &dbent)) {
+ krb5_db_free_principal(kcontext, &dbent, 1);
+ return(1);
+ }
+ pkey = &dbent.key_data[0];
+ akey = &dbent.key_data[1];
+
+ /*
+ * Match the sizes. 6 tokens to match.
+ */
+ nmatched = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t",
+ &name_len, &mod_name_len, &key_len,
+ &alt_key_len, &salt_len, &alt_salt_len);
+ if (nmatched == 6) {
+ pkey->key_data_length[0] = key_len;
+ akey->key_data_length[0] = alt_key_len;
+ pkey->key_data_length[1] = salt_len;
+ akey->key_data_length[1] = alt_salt_len;
+ name = (char *) NULL;
+ mod_name = (char *) NULL;
+ /*
+ * Get the memory for the variable length fields.
+ */
+ if ((name = (char *) malloc((size_t) (name_len + 1))) &&
+ (mod_name = (char *) malloc((size_t) (mod_name_len + 1))) &&
+ (!key_len ||
+ (pkey->key_data_contents[0] =
+ (krb5_octet *) malloc((size_t) (key_len + 1)))) &&
+ (!alt_key_len ||
+ (akey->key_data_contents[0] =
+ (krb5_octet *) malloc((size_t) (alt_key_len + 1)))) &&
+ (!salt_len ||
+ (pkey->key_data_contents[1] =
+ (krb5_octet *) malloc((size_t) (salt_len + 1)))) &&
+ (!alt_salt_len ||
+ (akey->key_data_contents[1] =
+ (krb5_octet *) malloc((size_t) (alt_salt_len + 1))))
+ ) {
+ error = 0;
+
+ /* Read the principal name */
+ if (read_string(filep, name, name_len, linenop)) {
+ try2read = read_name_string;
+ error++;
+ }
+ /* Read the key type */
+ if (!error && (fscanf(filep, "\t%d\t", &tmpint1) != 1)) {
+ try2read = read_key_type;
+ error++;
+ }
+ pkey->key_data_type[0] = tmpint1;
+ /* Read the old format key */
+ if (!error && read_octet_string(filep,
+ pkey->key_data_contents[0],
+ pkey->key_data_length[0])) {
+ try2read = read_key_data;
+ error++;
+ }
+ /* convert to a new format key */
+ /* the encrypted version is stored as the unencrypted key length
+ (4 bytes, MSB first) followed by the encrypted key. */
+ if ((pkey->key_data_length[0] > 4)
+ && (pkey->key_data_contents[0][0] == 0)
+ && (pkey->key_data_contents[0][1] == 0)) {
+ /* this really does look like an old key, so drop and swap */
+ /* the *new* length is 2 bytes, LSB first, sigh. */
+ size_t shortlen = pkey->key_data_length[0]-4+2;
+ char *shortcopy = (krb5_octet *) malloc(shortlen);
+ char *origdata = pkey->key_data_contents[0];
+ shortcopy[0] = origdata[3];
+ shortcopy[1] = origdata[2];
+ memcpy(shortcopy+2,origdata+4,shortlen-2);
+ free(origdata);
+ pkey->key_data_length[0] = shortlen;
+ pkey->key_data_contents[0] = shortcopy;
+ }
+
+ /* Read principal attributes */
+ if (!error && (fscanf(filep,
+ "\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t",
+ &tmpint1, &dbent.max_life,
+ &dbent.max_renewable_life,
+ &tmpint2, &dbent.expiration,
+ &dbent.pw_expiration, &last_pwd_change,
+ &dbent.last_success, &dbent.last_failed,
+ &tmpint3) != 10)) {
+ try2read = read_pr_data1;
+ error++;
+ }
+ pkey->key_data_kvno = tmpint1;
+ dbent.fail_auth_count = tmpint3;
+ /* Read modifier name */
+ if (!error && read_string(filep,
+ mod_name,
+ mod_name_len,
+ linenop)) {
+ try2read = read_mod_name;
+ error++;
+ }
+ /* Read second set of attributes */
+ if (!error && (fscanf(filep, "\t%u\t%u\t%u\t",
+ &mod_date, &dbent.attributes,
+ &tmpint1) != 3)) {
+ try2read = read_pr_data2;
+ error++;
+ }
+ pkey->key_data_type[1] = tmpint1;
+ /* Read salt data */
+ if (!error && read_octet_string(filep,
+ pkey->key_data_contents[1],
+ pkey->key_data_length[1])) {
+ try2read = read_salt_data;
+ error++;
+ }
+ /* Read alternate key type */
+ if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
+ try2read = read_akey_type;
+ error++;
+ }
+ akey->key_data_type[0] = tmpint1;
+ /* Read alternate key */
+ if (!error && read_octet_string(filep,
+ akey->key_data_contents[0],
+ akey->key_data_length[0])) {
+ try2read = read_akey_data;
+ error++;
+ }
+
+ /* convert to a new format key */
+ /* the encrypted version is stored as the unencrypted key length
+ (4 bytes, MSB first) followed by the encrypted key. */
+ if ((akey->key_data_length[0] > 4)
+ && (akey->key_data_contents[0][0] == 0)
+ && (akey->key_data_contents[0][1] == 0)) {
+ /* this really does look like an old key, so drop and swap */
+ /* the *new* length is 2 bytes, LSB first, sigh. */
+ size_t shortlen = akey->key_data_length[0]-4+2;
+ char *shortcopy = (krb5_octet *) malloc(shortlen);
+ char *origdata = akey->key_data_contents[0];
+ shortcopy[0] = origdata[3];
+ shortcopy[1] = origdata[2];
+ memcpy(shortcopy+2,origdata+4,shortlen-2);
+ free(origdata);
+ akey->key_data_length[0] = shortlen;
+ akey->key_data_contents[0] = shortcopy;
+ }
+
+ /* Read alternate salt type */
+ if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
+ try2read = read_asalt_type;
+ error++;
+ }
+ akey->key_data_type[1] = tmpint1;
+ /* Read alternate salt data */
+ if (!error && read_octet_string(filep,
+ akey->key_data_contents[1],
+ akey->key_data_length[1])) {
+ try2read = read_asalt_data;
+ error++;
+ }
+ /* Read expansion data - discard it */
+ if (!error) {
+ for (i=0; i<8; i++) {
+ if (fscanf(filep, "\t%u", &tmpint1) != 1) {
+ try2read = read_exp_data;
+ error++;
+ break;
+ }
+ }
+ if (!error)
+ find_record_end(filep, fname, *linenop);
+ }
+
+ /*
+ * If no error, then we're done reading. Now parse the names
+ * and store the database dbent.
+ */
+ if (!error) {
+ if (!(kret = krb5_parse_name(kcontext,
+ name,
+ &dbent.princ))) {
+ if (!(kret = krb5_parse_name(kcontext,
+ mod_name,
+ &mod_princ))) {
+ if (!(kret =
+ krb5_dbe_update_mod_princ_data(kcontext,
+ &dbent,
+ mod_date,
+ mod_princ)) &&
+ !(kret =
+ krb5_dbe_update_last_pwd_change(kcontext,
+ &dbent,
+ last_pwd_change))) {
+ int one = 1;
+
+ dbent.len = KRB5_KDB_V1_BASE_LENGTH;
+ pkey->key_data_ver = (pkey->key_data_type[1] || pkey->key_data_length[1]) ?
+ 2 : 1;
+ akey->key_data_ver = (akey->key_data_type[1] || akey->key_data_length[1]) ?
+ 2 : 1;
+ if ((pkey->key_data_type[0] ==
+ akey->key_data_type[0]) &&
+ (pkey->key_data_type[1] ==
+ akey->key_data_type[1]))
+ dbent.n_key_data--;
+ else if ((akey->key_data_type[0] == 0)
+ && (akey->key_data_length[0] == 0)
+ && (akey->key_data_type[1] == 0)
+ && (akey->key_data_length[1] == 0))
+ dbent.n_key_data--;
+ if ((kret = krb5_db_put_principal(kcontext,
+ &dbent,
+ &one)) ||
+ (one != 1)) {
+ fprintf(stderr, store_err_fmt,
+ fname, *linenop, name,
+ error_message(kret));
+ error++;
+ }
+ else {
+ if (verbose)
+ fprintf(stderr, add_princ_fmt, name);
+ retval = 0;
+ }
+ dbent.n_key_data = 2;
+ }
+ krb5_free_principal(kcontext, mod_princ);
+ }
+ else {
+ fprintf(stderr, parse_err_fmt,
+ fname, *linenop, mod_name,
+ error_message(kret));
+ error++;
+ }
+ }
+ else {
+ fprintf(stderr, parse_err_fmt,
+ fname, *linenop, name, error_message(kret));
+ error++;
+ }
+ }
+ else {
+ fprintf(stderr, read_err_fmt, fname, *linenop, try2read);
+ }
+ }
+ else {
+ fprintf(stderr, no_mem_fmt, fname, *linenop);
+ }
+
+ krb5_db_free_principal(kcontext, &dbent, 1);
+ if (mod_name)
+ free(mod_name);
+ if (name)
+ free(name);
+ }
+ else {
+ if (nmatched != EOF)
+ fprintf(stderr, rhead_err_fmt, fname, *linenop);
+ else
+ retval = -1;
+ }
+ return(retval);
+}
+
+/*
+ * process_k5beta6_record() - Handle a dump record in krb5b6 format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5beta6_record(fname, kcontext, filep, verbose, linenop, pol_db)
+ char *fname;
+ krb5_context kcontext;
+ FILE *filep;
+ int verbose;
+ int *linenop;
+ void *pol_db;
+{
+ int retval;
+ krb5_db_entry dbentry;
+ krb5_int32 t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ int nread;
+ int error;
+ int i, j, one;
+ char *name;
+ krb5_key_data *kp, *kdatap;
+ krb5_tl_data **tlp, *tl;
+ krb5_octet *op;
+ krb5_error_code kret;
+ const char *try2read;
+
+ try2read = (char *) NULL;
+ memset((char *) &dbentry, 0, sizeof(dbentry));
+ (*linenop)++;
+ retval = 1;
+ name = (char *) NULL;
+ kp = (krb5_key_data *) NULL;
+ op = (krb5_octet *) NULL;
+ error = 0;
+ kret = 0;
+ nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t", &t1, &t2, &t3, &t4, &t5);
+ if (nread == 5) {
+ /* Get memory for flattened principal name */
+ if (!(name = (char *) malloc((size_t) t2 + 1)))
+ error++;
+
+ /* Get memory for and form tagged data linked list */
+ tlp = &dbentry.tl_data;
+ for (i=0; i<t3; i++) {
+ if ((*tlp = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
+ memset(*tlp, 0, sizeof(krb5_tl_data));
+ tlp = &((*tlp)->tl_data_next);
+ dbentry.n_tl_data++;
+ }
+ else {
+ error++;
+ break;
+ }
+ }
+
+ /* Get memory for key list */
+ if (t4 && !(kp = (krb5_key_data *) malloc((size_t)
+ (t4*sizeof(krb5_key_data)))))
+ error++;
+
+ /* Get memory for extra data */
+ if (t5 && !(op = (krb5_octet *) malloc((size_t) t5)))
+ error++;
+
+ if (!error) {
+ dbentry.len = t1;
+ dbentry.n_key_data = t4;
+ dbentry.e_length = t5;
+ if (kp) {
+ memset(kp, 0, (size_t) (t4*sizeof(krb5_key_data)));
+ dbentry.key_data = kp;
+ kp = (krb5_key_data *) NULL;
+ }
+ if (op) {
+ memset(op, 0, (size_t) t5);
+ dbentry.e_data = op;
+ op = (krb5_octet *) NULL;
+ }
+
+ /* Read in and parse the principal name */
+ if (!read_string(filep, name, t2, linenop) &&
+ !(kret = krb5_parse_name(kcontext, name, &dbentry.princ))) {
+
+ /* Get the fixed principal attributes */
+ nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
+ &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9);
+ if (nread == 8) {
+ dbentry.attributes = (krb5_flags) t2;
+ dbentry.max_life = (krb5_deltat) t3;
+ dbentry.max_renewable_life = (krb5_deltat) t4;
+ dbentry.expiration = (krb5_timestamp) t5;
+ dbentry.pw_expiration = (krb5_timestamp) t6;
+ dbentry.last_success = (krb5_timestamp) t7;
+ dbentry.last_failed = (krb5_timestamp) t8;
+ dbentry.fail_auth_count = (krb5_kvno) t9;
+ } else {
+ try2read = read_nint_data;
+ error++;
+ }
+
+ /* Get the tagged data */
+ if (!error && dbentry.n_tl_data) {
+ for (tl = dbentry.tl_data; tl; tl = tl->tl_data_next) {
+ nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
+ if (nread == 2) {
+ tl->tl_data_type = (krb5_int16) t1;
+ tl->tl_data_length = (krb5_int16) t2;
+ if (tl->tl_data_length) {
+ if (!(tl->tl_data_contents =
+ (krb5_octet *) malloc((size_t) t2+1)) ||
+ read_octet_string(filep,
+ tl->tl_data_contents,
+ t2)) {
+ try2read = read_tcontents;
+ error++;
+ break;
+ }
+ }
+ else {
+ /* Should be a null field */
+ nread = fscanf(filep, "%d", &t9);
+ if ((nread != 1) || (t9 != -1)) {
+ error++;
+ try2read = read_tcontents;
+ break;
+ }
+ }
+ }
+ else {
+ try2read = read_ttypelen;
+ error++;
+ break;
+ }
+ }
+ }
+
+ /* Get the key data */
+ if (!error && dbentry.n_key_data) {
+ for (i=0; !error && (i<dbentry.n_key_data); i++) {
+ kdatap = &dbentry.key_data[i];
+ nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
+ if (nread == 2) {
+ kdatap->key_data_ver = (krb5_int16) t1;
+ kdatap->key_data_kvno = (krb5_int16) t2;
+
+ for (j=0; j<t1; j++) {
+ nread = fscanf(filep, "%d\t%d\t", &t3, &t4);
+ if (nread == 2) {
+ kdatap->key_data_type[j] = t3;
+ kdatap->key_data_length[j] = t4;
+ if (t4) {
+ if (!(kdatap->key_data_contents[j] =
+ (krb5_octet *)
+ malloc((size_t) t4+1)) ||
+ read_octet_string(filep,
+ kdatap->key_data_contents[j],
+ t4)) {
+ try2read = read_kcontents;
+ error++;
+ break;
+ }
+ }
+ else {
+ /* Should be a null field */
+ nread = fscanf(filep, "%d", &t9);
+ if ((nread != 1) || (t9 != -1)) {
+ error++;
+ try2read = read_kcontents;
+ break;
+ }
+ }
+ }
+ else {
+ try2read = read_ktypelen;
+ error++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Get the extra data */
+ if (!error && dbentry.e_length) {
+ if (read_octet_string(filep,
+ dbentry.e_data,
+ (int) dbentry.e_length)) {
+ try2read = read_econtents;
+ error++;
+ }
+ }
+ else {
+ nread = fscanf(filep, "%d", &t9);
+ if ((nread != 1) || (t9 != -1)) {
+ error++;
+ try2read = read_econtents;
+ }
+ }
+
+ /* Finally, find the end of the record. */
+ if (!error)
+ find_record_end(filep, fname, *linenop);
+
+ /*
+ * We have either read in all the data or choked.
+ */
+ if (!error) {
+ one = 1;
+ if ((kret = krb5_db_put_principal(kcontext,
+ &dbentry,
+ &one))) {
+ fprintf(stderr, store_err_fmt,
+ fname, *linenop,
+ name, error_message(kret));
+ }
+ else {
+ if (verbose)
+ fprintf(stderr, add_princ_fmt, name);
+ retval = 0;
+ }
+ }
+ else {
+ fprintf(stderr, read_err_fmt, fname, *linenop, try2read);
+ }
+ }
+ else {
+ if (kret)
+ fprintf(stderr, parse_err_fmt,
+ fname, *linenop, name, error_message(kret));
+ else
+ fprintf(stderr, no_mem_fmt, fname, *linenop);
+ }
+ }
+ else {
+ fprintf(stderr, rhead_err_fmt, fname, *linenop);
+ }
+
+ if (op)
+ free(op);
+ if (kp)
+ free(kp);
+ if (name)
+ free(name);
+ krb5_db_free_principal(kcontext, &dbentry, 1);
+ }
+ else {
+ if (nread == EOF)
+ retval = -1;
+ }
+ return(retval);
+}
+
+int process_k5beta7_policy(fname, kcontext, filep, verbose, linenop, pol_db)
+ char *fname;
+ krb5_context kcontext;
+ FILE *filep;
+ int verbose;
+ int *linenop;
+ void *pol_db;
+{
+ osa_policy_ent_rec rec;
+ char namebuf[1024];
+ int nread, ret;
+
+ (*linenop)++;
+ rec.name = namebuf;
+
+ nread = fscanf(filep, "%1024s\t%d\t%d\t%d\t%d\t%d\t%d", rec.name,
+ &rec.pw_min_life, &rec.pw_max_life,
+ &rec.pw_min_length, &rec.pw_min_classes,
+ &rec.pw_history_num, &rec.policy_refcnt);
+ if (nread == EOF)
+ return -1;
+ else if (nread != 7) {
+ fprintf(stderr, "cannot parse policy on line %d (%d read)\n",
+ *linenop, nread);
+ return 1;
+ }
+
+ if (ret = osa_adb_create_policy(pol_db, &rec)) {
+ fprintf(stderr, "cannot create policy on line %d: %s\n",
+ *linenop, error_message(ret));
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "created policy %s\n", rec.name);
+
+ return 0;
+}
+
+
+/*
+ * process_k5beta7_record() - Handle a dump record in krb5b6 format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5beta7_record(fname, kcontext, filep, verbose, linenop, pol_db)
+ char *fname;
+ krb5_context kcontext;
+ FILE *filep;
+ int verbose;
+ int *linenop;
+ void *pol_db;
+{
+ int nread;
+ char rectype[100];
+
+ nread = fscanf(filep, "%100s\t", rectype);
+ if (nread == EOF)
+ return -1;
+ else if (nread != 1)
+ return 1;
+ if (strcmp(rectype, "princ") == 0)
+ process_k5beta6_record(fname, kcontext, filep, verbose,
+ linenop, pol_db);
+ else if (strcmp(rectype, "policy") == 0)
+ process_k5beta7_policy(fname, kcontext, filep, verbose,
+ linenop, pol_db);
+ else {
+ fprintf(stderr, "unknown record type \"%s\" on line %d\n",
+ rectype, *linenop);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * restore_dump() - Restore the database from any version dump file.
+ */
+static int
+restore_dump(programname, kcontext, dumpfile, f, verbose, dump, pol_db)
+ char *programname;
+ krb5_context kcontext;
+ char *dumpfile;
+ FILE *f;
+ int verbose;
+ dump_version *dump;
+ osa_adb_policy_t pol_db;
+{
+ int error;
+ int lineno;
+
+ error = 0;
+ lineno = 1;
+
+ /*
+ * Process the records.
+ */
+ while (!(error = (*dump->load_record)(dumpfile,
+ kcontext,
+ f,
+ verbose,
+ &lineno,
+ pol_db)))
+ ;
+ if (error != -1)
+ fprintf(stderr, err_line_fmt, programname, lineno, dumpfile);
+ else
+ error = 0;
+
+ return(error);
+}
+
+/*
+ * Usage is
+ * load_db [-old] [-verbose] [-update] filename dbname
+ */
+void
+load_db(argc, argv)
+ int argc;
+ char **argv;
+{
+ kadm5_config_params newparams;
+ osa_adb_policy_t pol_db;
+ krb5_error_code kret;
+ krb5_context kcontext;
+ FILE *f;
+ extern char *optarg;
+ extern int optind;
+ char *programname;
+ char *dumpfile;
+ char *dbname, *adbname;
+ char *dbname_tmp, *adbname_real;
+ char buf[BUFSIZ];
+ dump_version *load;
+ int update, verbose;
+ int aindex;
+
+ /*
+ * Parse the arguments.
+ */
+ programname = argv[0];
+ if (strrchr(programname, (int) '/'))
+ programname = strrchr(argv[0], (int) '/') + 1;
+ dumpfile = (char *) NULL;
+ dbname = (char *) NULL;
+ load = NULL;
+ update = 0;
+ verbose = 0;
+ exit_status = 0;
+ dbname_tmp = (char *) NULL;
+ for (aindex = 1; aindex < argc; aindex++) {
+ if (!strcmp(argv[aindex], oldoption))
+ load = &old_version;
+ else if (!strcmp(argv[aindex], b6option))
+ load = &beta6_version;
+ else if (!strcmp(argv[aindex], verboseoption))
+ verbose = 1;
+ else if (!strcmp(argv[aindex], updateoption))
+ update = 1;
+ else
+ break;
+ }
+ if ((argc - aindex) != 2 && (argc - aindex) != 3) {
+ fprintf(stderr, lusage_err_fmt, argv[0], argv[0],
+ oldoption, verboseoption, updateoption);
+ exit_status++;
+ return;
+ }
+
+ dumpfile = argv[aindex];
+ dbname = argv[aindex+1];
+ adbname = argv[aindex+2];
+ if (!(dbname_tmp = (char *) malloc(strlen(dbname)+
+ strlen(dump_tmptrail)+1))) {
+ fprintf(stderr, no_name_mem_fmt, argv[0]);
+ exit_status++;
+ return;
+ }
+ strcpy(dbname_tmp, dbname);
+ strcat(dbname_tmp, dump_tmptrail);
+
+ /*
+ * Initialize the Kerberos context and error tables.
+ */
+ if ((kret = krb5_init_context(&kcontext))) {
+ fprintf(stderr, ctx_err_fmt, programname);
+ free(dbname_tmp);
+ exit_status++;
+ return;
+ }
+ krb5_init_ets(kcontext);
+
+ /*
+ * Open the dumpfile
+ */
+ if (dumpfile) {
+ if ((f = fopen(dumpfile, "r+")) == NULL) {
+ fprintf(stderr, dfile_err_fmt, programname, dumpfile,
+ error_message(errno));
+ exit_status++;
+ return;
+ }
+ if (kret = krb5_lock_file(kcontext, fileno(f), KRB5_LOCKMODE_SHARED)) {
+ fprintf(stderr, "%s: Cannot lock %s: %s\n", programname,
+ dumpfile, error_message(errno));
+ exit_status++;
+ return;
+ }
+ } else
+ f = stdin;
+
+ /*
+ * Auto-detect dump version if we weren't told, verify if we
+ * were told.
+ */
+ fgets(buf, sizeof(buf), f);
+ if (load) {
+ if (strcmp(buf, load->header) != 0) {
+ fprintf(stderr, head_bad_fmt, programname, dumpfile);
+ exit_status++;
+ if (dumpfile) fclose(f);
+ return;
+ }
+ } else {
+ /* perhaps this should be in an array, but so what? */
+ if (strcmp(buf, old_version.header) == 0)
+ load = &old_version;
+ else if (strcmp(buf, beta6_version.header) == 0)
+ load = &beta6_version;
+ else if (strcmp(buf, beta7_version.header) == 0)
+ load = &beta7_version;
+ else {
+ fprintf(stderr, head_bad_fmt, programname, dumpfile);
+ exit_status++;
+ if (dumpfile) fclose(f);
+ return;
+ }
+
+ if (load != &beta7_version && adbname != NULL) {
+ fprintf(stderr, lusage_err_fmt, argv[0], argv[0],
+ oldoption, verboseoption, updateoption);
+ exit_status++;
+ return;
+ }
+ }
+
+ /*
+ * Cons up config params for new policy database. Use adbname is
+ * specified, otherwise let the policy dbname key off the dbname.
+ * However, after the name is retrieved, change the actual file
+ * name to a temp name that we'll rename later (but use the
+ * correct lock file).
+ */
+ newparams = global_params;
+ newparams.mask &= ~(KADM5_CONFIG_ADBNAME | KADM5_CONFIG_ADB_LOCKFILE);
+ newparams.dbname = dbname;
+ newparams.mask |= KADM5_CONFIG_DBNAME;
+ if (adbname) {
+ newparams.admin_dbname = adbname;
+ newparams.mask |= KADM5_CONFIG_ADBNAME;
+ }
+ if (kret = kadm5_get_config_params(kcontext, NULL, NULL, &newparams,
+ &newparams)) {
+ fprintf(stderr, "%s while retrieiving configuration "
+ "parameters.\n", error_message(kret));
+ if (dumpfile) fclose(f);
+ exit_status++;
+ return;
+ }
+ adbname_real = newparams.admin_dbname;
+ newparams.admin_dbname = (char *) malloc(strlen(adbname_real) +
+ strlen(dump_tmptrail) + 1);
+ strcpy(newparams.admin_dbname, adbname_real);
+ strcat(newparams.admin_dbname, dump_tmptrail);
+
+ /*
+ * Create the new database if not an update restoration. Always
+ * create the policy db, even if we are not loading a dump file
+ * with policy info, because they may be loading an old dump
+ * intending to use it with the new kadm5 system (ie: using load
+ * as create).
+ */
+ if (!update && (kret = krb5_db_create(kcontext, dbname_tmp))) {
+ fprintf(stderr, dbcreaterr_fmt,
+ programname, dbname, error_message(kret));
+ exit_status++;
+ kadm5_free_config_params(kcontext, &newparams);
+ if (dumpfile) fclose(f);
+ return;
+ }
+ if (!update && (kret = osa_adb_create_policy_db(&newparams))) {
+ fprintf(stderr, "%s: %s while creating policy database\n",
+ programname, error_message(kret));
+ kadm5_free_config_params(kcontext, &newparams);
+ if (dumpfile) fclose(f);
+ return;
+ }
+
+ /*
+ * Point ourselves at the new databases.
+ */
+ if (kret = krb5_db_set_name(kcontext,
+ (update) ? dbname : dbname_tmp)) {
+ fprintf(stderr, dbname_err_fmt,
+ programname,
+ (update) ? dbname : dbname_tmp, error_message(kret));
+ exit_status++;
+ goto error;
+ }
+ if (kret = osa_adb_open_policy(&pol_db, &newparams)) {
+ fprintf(stderr, "%s: %s while opening policy database\n",
+ programname, error_message(kret));
+ exit_status++;
+ goto error;
+ }
+
+ /*
+ * Initialize the database.
+ */
+ if (kret = krb5_db_init(kcontext)) {
+ fprintf(stderr, dbinit_err_fmt,
+ programname, error_message(kret));
+ exit_status++;
+ goto error;
+ }
+
+ if (restore_dump(programname, kcontext, (dumpfile) ? dumpfile : stdin_name,
+ f, verbose, load, pol_db)) {
+ fprintf(stderr, restfail_fmt,
+ programname, load->name);
+ exit_status++;
+ }
+
+ if ((kret = krb5_db_fini(kcontext)) ||
+ (kret = osa_adb_close_policy(pol_db))) {
+ fprintf(stderr, close_err_fmt,
+ programname, error_message(kret));
+ exit_status++;
+ }
+
+error:
+ /*
+ * If there was an error and this is not an update, then
+ * destroy the database.
+ */
+ if (!update) {
+ if (exit_status) {
+ if ((kret = kdb5_db_destroy(kcontext, dbname))) {
+ fprintf(stderr, dbdelerr_fmt,
+ programname, dbname_tmp, error_message(kret));
+ exit_status++;
+ }
+ }
+ else {
+ if ((kret = krb5_db_rename(kcontext,
+ dbname_tmp,
+ dbname))) {
+ fprintf(stderr, dbrenerr_fmt,
+ programname, dbname_tmp, dbname,
+ error_message(kret));
+ exit_status++;
+ }
+
+ if (kret = osa_adb_get_lock(pol_db, OSA_ADB_PERMANENT)) {
+ fprintf(stderr,
+ "%s: %s while getting permanent lock\n",
+ programname, error_message(kret));
+ exit_status++;
+ } else if (rename(newparams.admin_dbname,
+ adbname_real) < 0) {
+ fprintf(stderr, "%s: %s while renaming %s to %s\n",
+ programname, error_message(kret),
+ newparams.admin_dbname, adbname_real);
+ exit_status++;
+ } else if (kret = osa_adb_release_lock(pol_db)) {
+ fprintf(stderr, "%s: %s while unlocking %s\n",
+ programname, error_message(kret),
+ adbname_real);
+ exit_status++;
+ }
+ }
+ }
+
+ if (dumpfile) {
+ (void) krb5_lock_file(kcontext, fileno(f), KRB5_LOCKMODE_UNLOCK);
+ fclose(f);
+ }
+
+ free(newparams.admin_dbname);
+ newparams.admin_dbname = adbname_real;
+ kadm5_free_config_params(kcontext, &newparams);
+ free(dbname_tmp);
+ krb5_free_context(kcontext);
+}
diff --git a/src/kadmin/dbutil/dumpv4.c b/src/kadmin/dbutil/dumpv4.c
new file mode 100644
index 000000000..a51626db3
--- /dev/null
+++ b/src/kadmin/dbutil/dumpv4.c
@@ -0,0 +1,411 @@
+/*
+ * admin/edit/dumpv4.c
+ *
+ * Copyright 1990,1991, 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Dump a KDC database into a V4 slave dump.
+ */
+
+#ifdef KRB5_KRB4_COMPAT
+
+#include "k5-int.h"
+#include "com_err.h"
+
+#include <des.h>
+#include <krb.h>
+#include <krb_db.h>
+/* MKEYFILE is now defined in kdc.h */
+#include <kdc.h>
+
+#include <stdio.h>
+#include "kdb5_util.h"
+
+struct dump_record {
+ char *comerr_name;
+ FILE *f;
+ krb5_encrypt_block *v5master;
+ C_Block v4_master_key;
+ Key_schedule v4_master_key_schedule;
+ long master_key_version;
+ char *realm;
+};
+
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+extern krb5_principal master_princ;
+extern krb5_boolean dbactive;
+extern int exit_status;
+extern krb5_context util_context;
+
+void update_ok_file();
+
+#define ANAME_SZ 40
+#define INST_SZ 40
+
+static char *v4_mkeyfile = "/.k";
+
+static int
+v4init(arg, manual)
+ struct dump_record *arg;
+ int manual;
+{
+ int fd;
+ int ok = 0;
+
+ if (!manual) {
+ fd = open(v4_mkeyfile, O_RDONLY, 0600);
+ if (fd >= 0) {
+ if (read(fd,arg->v4_master_key,sizeof(C_Block)) == sizeof(C_Block))
+ ok = 1;
+ close(fd);
+ }
+ }
+ if (!ok) {
+ des_read_password(arg->v4_master_key, "V4 Kerberos master key: ", 1);
+ printf("\n");
+ }
+ arg->master_key_version = 1;
+ key_sched(arg->v4_master_key, arg->v4_master_key_schedule);
+
+ return 0;
+}
+
+v4_print_time(file, timeval)
+ FILE *file;
+ unsigned long timeval;
+{
+ struct tm *tm;
+ struct tm *gmtime();
+ tm = gmtime((time_t *)&timeval);
+ fprintf(file, " %04d%02d%02d%02d%02d",
+ tm->tm_year < 1900 ? tm->tm_year + 1900: tm->tm_year,
+ tm->tm_mon + 1,
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min);
+}
+
+
+
+krb5_error_code
+dump_v4_iterator(ptr, entry)
+ krb5_pointer ptr;
+ krb5_db_entry *entry;
+{
+ struct dump_record *arg = (struct dump_record *) ptr;
+ krb5_principal mod_princ;
+ krb5_timestamp mod_time;
+ krb5_error_code retval;
+ int i, max_kvno, ok_key;
+
+ struct v4princ {
+ char name[ANAME_SZ+1];
+ char instance[INST_SZ+1];
+ char realm[REALM_SZ+1];
+ int max_life;
+ int kdc_key_ver, key_version, attributes;
+ char mod_name[ANAME_SZ+1];
+ char mod_instance[INST_SZ+1];
+ char mod_realm[REALM_SZ+1];
+ } v4princ, *principal;
+ des_cblock v4key;
+
+ principal = &v4princ;
+
+ if (strcmp(krb5_princ_realm(util_context, entry->princ)->data, arg->realm))
+ /* skip this because it's a key for a different realm, probably
+ * a paired krbtgt key */
+ return 0;
+
+ retval = krb5_524_conv_principal(util_context, entry->princ,
+ principal->name, principal->instance,
+ principal->realm);
+ if (retval)
+ /* Skip invalid V4 principals */
+ return 0;
+
+ if (!strcmp(principal->name, "K") && !strcmp(principal->instance, "M"))
+ /* The V4 master key is handled specially */
+ return 0;
+
+ if (! principal->name[0])
+ return 0;
+ if (! principal->instance[0])
+ strcpy(principal->instance, "*");
+
+ /* Now move to mod princ */
+ if (retval = krb5_dbe_lookup_mod_princ_data(util_context,entry,
+ &mod_time, &mod_princ)){
+ com_err(arg->comerr_name, retval, "while unparsing db entry");
+ exit_status++;
+ return retval;
+ }
+ retval = krb5_524_conv_principal(util_context, mod_princ,
+ principal->mod_name, principal->mod_instance,
+ principal->mod_realm);
+ if (retval) {
+ /* Invalid V4 mod principal */
+ principal->mod_name[0] = '\0';
+ principal->mod_instance[0] = '\0';
+ }
+
+ if (! principal->mod_name[0])
+ strcpy(principal->mod_name, "*");
+ if (! principal->mod_instance[0])
+ strcpy(principal->mod_instance, "*");
+
+ /* OK deal with the key now. */
+ for (max_kvno = i = 0; i < entry->n_key_data; i++) {
+ if (max_kvno < entry->key_data[i].key_data_kvno) {
+ max_kvno = entry->key_data[i].key_data_kvno;
+ ok_key = i;
+ }
+ }
+
+ i = ok_key;
+ while (ok_key < entry->n_key_data) {
+ if (max_kvno == entry->key_data[ok_key].key_data_kvno) {
+ if (entry->key_data[ok_key].key_data_type[1]
+ == KRB5_KDB_SALTTYPE_V4) {
+ goto found_one;
+ }
+ }
+ ok_key++;
+ }
+
+ /* See if there are any DES keys that may be suitable */
+ ok_key = i;
+ while (ok_key < entry->n_key_data) {
+ if (max_kvno == entry->key_data[ok_key].key_data_kvno) {
+ krb5_enctype enctype = entry->key_data[ok_key].key_data_type[0];
+ if ((enctype == ENCTYPE_DES_CBC_CRC) ||
+ (enctype == ENCTYPE_DES_CBC_MD5) ||
+ (enctype == ENCTYPE_DES_CBC_RAW))
+ goto found_one;
+ }
+ ok_key++;
+ }
+ /* skip this because it's a new style key and we can't help it */
+ return 0;
+
+found_one:;
+ principal->key_version = max_kvno;
+ if ((principal->max_life = entry->max_life / (60 * 5)) > 255)
+ principal->max_life = 255;
+ principal->kdc_key_ver = arg->master_key_version;
+ principal->attributes = 0; /* ??? not preserved either */
+
+ fprintf(arg->f, "%s %s %d %d %d %d ",
+ principal->name,
+ principal->instance,
+ principal->max_life,
+ principal->kdc_key_ver,
+ principal->key_version,
+ principal->attributes);
+
+ handle_one_key(arg, arg->v5master, &entry->key_data[ok_key], v4key);
+
+ for (i = 0; i < 8; i++) {
+ fprintf(arg->f, "%02x", ((unsigned char*)v4key)[i]);
+ if (i == 3) fputc(' ', arg->f);
+ }
+
+ v4_print_time(arg->f, entry->expiration);
+ v4_print_time(arg->f, mod_time);
+
+ fprintf(arg->f, " %s %s\n", principal->mod_name, principal->mod_instance);
+ return 0;
+}
+
+/*ARGSUSED*/
+void dump_v4db(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *f;
+ struct dump_record arg;
+
+ if (argc > 2) {
+ com_err(argv[0], 0, "Usage: %s filename", argv[0]);
+ exit_status++;
+ return;
+ }
+ if (!dbactive) {
+ com_err(argv[0], 0, Err_no_database);
+ exit_status++;
+ return;
+ }
+ if (argc == 2) {
+ /*
+ * Make sure that we don't open and truncate on the fopen,
+ * since that may hose an on-going kprop process.
+ *
+ * We could also control this by opening for read and
+ * write, doing an flock with LOCK_EX, and then
+ * truncating the file once we have gotten the lock,
+ * but that would involve more OS dependancies than I
+ * want to get into.
+ */
+ unlink(argv[1]);
+ if (!(f = fopen(argv[1], "w"))) {
+ com_err(argv[0], errno,
+ "While opening file %s for writing", argv[1]);
+ exit_status++;
+ return;
+ }
+ } else {
+ f = stdout;
+ }
+
+ arg.comerr_name = argv[0];
+ arg.f = f;
+ v4init(&arg, 0);
+ handle_keys(&arg);
+
+ /* special handling for K.M since it isn't preserved */
+ {
+ des_cblock v4key;
+ int i;
+
+ /* assume:
+ max lifetime (255)
+ key version == 1 (actually, should be whatever the v5 one is)
+ master key version == key version
+ args == 0 (none are preserved)
+ expiration date is the default 2000
+ last mod time is near zero (arbitrarily.)
+ creator is db_creation *
+ */
+
+ fprintf(f,"K M 255 1 1 0 ");
+
+#ifndef KDB4_DISABLE
+ kdb_encrypt_key (arg.v4_master_key, v4key,
+ arg.v4_master_key, arg.v4_master_key_schedule,
+ ENCRYPT);
+#else /* KDB4_DISABLE */
+ pcbc_encrypt((C_Block *) arg.v4_master_key,
+ (C_Block *) v4key,
+ (long) sizeof(C_Block),
+ arg.v4_master_key_schedule,
+ (C_Block *) arg.v4_master_key,
+ ENCRYPT);
+#endif /* KDB4_DISABLE */
+
+ for (i=0; i<8; i++) {
+ fprintf(f, "%02x", ((unsigned char*)v4key)[i]);
+ if (i == 3) fputc(' ', f);
+ }
+ fprintf(f," 200001010459 197001020000 db_creation *\n");
+ }
+
+ (void) krb5_db_iterate(util_context, dump_v4_iterator,
+ (krb5_pointer) &arg);
+ if (argc == 2)
+ fclose(f);
+ if (argv[1])
+ update_ok_file(argv[1]);
+}
+
+int handle_keys(arg)
+ struct dump_record *arg;
+{
+ krb5_error_code retval;
+ char *defrealm;
+ char *mkey_name = 0;
+ char *mkey_fullname;
+ krb5_principal master_princ;
+
+ if (retval = krb5_get_default_realm(util_context, &defrealm)) {
+ com_err(arg->comerr_name, retval,
+ "while retrieving default realm name");
+ exit(1);
+ }
+ arg->realm = defrealm;
+
+ /* assemble & parse the master key name */
+
+ if (retval = krb5_db_setup_mkey_name(util_context, mkey_name, arg->realm,
+ &mkey_fullname, &master_princ)) {
+ com_err(arg->comerr_name, retval, "while setting up master key name");
+ exit(1);
+ }
+
+ krb5_use_enctype(util_context, &master_encblock, DEFAULT_KDC_ENCTYPE);
+ if (retval = krb5_db_fetch_mkey(util_context, master_princ,
+ &master_encblock, 0,
+ 0, (char *) NULL, 0, &master_keyblock)) {
+ com_err(arg->comerr_name, retval, "while reading master key");
+ exit(1);
+ }
+ if (retval = krb5_process_key(util_context, &master_encblock,
+ &master_keyblock)) {
+ com_err(arg->comerr_name, retval, "while processing master key");
+ exit(1);
+ }
+ arg->v5master = &master_encblock;
+ return(0);
+}
+
+handle_one_key(arg, v5master, v5key, v4key)
+ struct dump_record *arg;
+ krb5_encrypt_block *v5master;
+ krb5_key_data *v5key;
+ des_cblock v4key;
+{
+ krb5_error_code retval;
+
+ krb5_keyblock v4v5key;
+ krb5_keyblock v5plainkey;
+ /* v4key is the actual v4 key from the file. */
+
+ if (retval = krb5_dbekd_decrypt_key_data(util_context, v5master, v5key,
+ &v5plainkey, NULL))
+ return retval;
+
+ /* v4v5key.contents = (krb5_octet *)v4key; */
+ /* v4v5key.enctype = ENCTYPE_DES; */
+ /* v4v5key.length = sizeof(v4key); */
+
+ memcpy(v4key, v5plainkey.contents, sizeof(des_cblock));
+#ifndef KDB4_DISABLE
+ kdb_encrypt_key (v4key, v4key,
+ arg->v4_master_key, arg->v4_master_key_schedule,
+ ENCRYPT);
+#else /* KDB4_DISABLE */
+ pcbc_encrypt((C_Block *) v4key,
+ (C_Block *) v4key,
+ (long) sizeof(C_Block),
+ arg->v4_master_key_schedule,
+ (C_Block *) arg->v4_master_key,
+ ENCRYPT);
+#endif /* KDB4_DISABLE */
+ return 0;
+}
+
+#else /* KRB5_KRB4_COMPAT */
+void dump_v4db(argc, argv)
+ int argc;
+ char **argv;
+{
+ printf("This version of krb5_edit does not support the V4 dump command.\n");
+}
+#endif /* KRB5_KRB4_COMPAT */
diff --git a/src/kadmin/dbutil/kadm5_create.c b/src/kadmin/dbutil/kadm5_create.c
new file mode 100644
index 000000000..d31ce3319
--- /dev/null
+++ b/src/kadmin/dbutil/kadm5_create.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include "string_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <kadm5/adb.h>
+#include <kadm5/admin.h>
+
+#include <krb5.h>
+#include <krb5/kdb.h>
+
+int add_admin_princ(void *handle, krb5_context context,
+ char *name, char *realm, int attrs, int lifetime);
+
+#define ERR 1
+#define OK 0
+
+#define ADMIN_LIFETIME 60*60*3 /* 3 hours */
+#define CHANGEPW_LIFETIME 60*5 /* 5 minutes */
+
+extern char *whoami;
+
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+extern krb5_db_entry master_db;
+
+/*
+ * Function: kadm5_create
+ *
+ * Purpose: create admin principals in KDC database
+ *
+ * Arguments: params (r) configuration parameters to use
+ *
+ * Effects: Creates KADM5_ADMIN_SERVICE and KADM5_CHANGEPW_SERVICE
+ * principals in the KDC database and sets their attributes
+ * appropriately.
+ */
+int kadm5_create(kadm5_config_params *params)
+{
+ int retval;
+ void *handle;
+ krb5_context context;
+ FILE *f;
+
+
+ if (retval = krb5_init_context(&context))
+ exit(ERR);
+
+ /*
+ * The lock file has to exist before calling kadm5_init, but
+ * params->admin_lockfile may not be set yet...
+ */
+ if (retval = kadm5_get_config_params(context, NULL, NULL,
+ params, params)) {
+ com_err(whoami, retval, str_INITING_KCONTEXT);
+ return 1;
+ }
+
+ if (retval = osa_adb_create_policy_db(params)) {
+ com_err(whoami, retval, str_CREATING_POLICY_DB);
+ return 1;
+ }
+
+ if ((retval = kadm5_init(whoami, NULL, NULL, params,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &handle))) {
+ com_err(whoami, retval, str_INITING_KCONTEXT);
+
+ krb5_free_context(context);
+ exit(ERR);
+ }
+
+ retval = add_admin_princs(handle, context, params->realm);
+
+ kadm5_destroy(handle);
+ krb5_free_context(context);
+
+ if (retval)
+ exit(retval);
+
+ return 0;
+}
+
+/*
+ * Function: build_name_with_realm
+ *
+ * Purpose: concatenate a name and a realm to form a krb5 name
+ *
+ * Arguments:
+ *
+ * name (input) the name
+ * realm (input) the realm
+ *
+ * Returns:
+ *
+ * pointer to name@realm, in allocated memory, or NULL if it
+ * cannot be allocated
+ *
+ * Requires: both strings are null-terminated
+ */
+char *build_name_with_realm(char *name, char *realm)
+{
+ char *n;
+
+ n = (char *) malloc(strlen(name) + strlen(realm) + 2);
+ sprintf(n, "%s@%s", name, realm);
+ return n;
+}
+
+/*
+ * Function: add_admin_princs
+ *
+ * Purpose: create admin principals
+ *
+ * Arguments:
+ *
+ * rseed (input) random seed
+ * realm (input) realm, or NULL for default realm
+ * <return value> (output) status, 0 for success, 1 for serious error
+ *
+ * Requires:
+ *
+ * Effects:
+ *
+ * add_admin_princs creates KADM5_ADMIN_SERVICE,
+ * KADM5_CHANGEPW_SERVICE. If any of these exist a message is
+ * printed. If any of these existing principal do not have the proper
+ * attributes, a warning message is printed.
+ */
+int add_admin_princs(void *handle, krb5_context context, char *realm)
+{
+ krb5_error_code ret = 0;
+
+ if ((ret = add_admin_princ(handle, context,
+ KADM5_ADMIN_SERVICE, realm,
+ KRB5_KDB_DISALLOW_TGT_BASED,
+ ADMIN_LIFETIME)))
+ goto clean_and_exit;
+
+ if ((ret = add_admin_princ(handle, context,
+ KADM5_CHANGEPW_SERVICE, realm,
+ KRB5_KDB_DISALLOW_TGT_BASED |
+ KRB5_KDB_PWCHANGE_SERVICE,
+ CHANGEPW_LIFETIME)))
+ goto clean_and_exit;
+
+clean_and_exit:
+
+ return ret;
+}
+
+/*
+ * Function: add_admin_princ
+ *
+ * Arguments:
+ *
+ * creator (r) principal to use as "mod_by"
+ * rseed (r) seed for random key generator
+ * name (r) principal name
+ * realm (r) realm name for principal
+ * attrs (r) principal's attributes
+ * lifetime (r) principal's max life, or 0
+ * not_unique (r) error message for multiple entries, never used
+ * exists (r) warning message for principal exists
+ * wrong_attrs (r) warning message for wrong attributes
+ *
+ * Returns:
+ *
+ * OK on success
+ * ERR on serious errors
+ *
+ * Effects:
+ *
+ * If the principal is not unique, not_unique is printed (but this
+ * never happens). If the principal exists, then exists is printed
+ * and if the principals attributes != attrs, wrong_attrs is printed.
+ * Otherwise, the principal is created with mod_by creator and
+ * attributes attrs and max life of lifetime (if not zero).
+ */
+
+int add_admin_princ(void *handle, krb5_context context,
+ char *name, char *realm, int attrs, int lifetime)
+{
+ char *fullname;
+ int nprincs;
+ krb5_error_code ret;
+ kadm5_principal_ent_rec ent;
+
+ memset(&ent, 0, sizeof(ent));
+
+ fullname = build_name_with_realm(name, realm);
+ if (ret = krb5_parse_name(context, fullname, &ent.principal)) {
+ com_err(whoami, ret, str_PARSE_NAME);
+ return(ERR);
+ }
+ ent.max_life = lifetime;
+ ent.attributes = attrs;
+
+ if (ret = kadm5_create_principal(handle, &ent,
+ (KADM5_PRINCIPAL |
+ KADM5_MAX_LIFE |
+ KADM5_ATTRIBUTES),
+ "to-be-random")) {
+ if (ret == KADM5_DUP)
+ ret = kadm5_modify_principal(handle, &ent,
+ (KADM5_PRINCIPAL |
+ KADM5_MAX_LIFE |
+ KADM5_ATTRIBUTES));
+
+ if (ret) {
+ com_err(whoami, ret, str_PUT_PRINC, fullname);
+ krb5_free_principal(context, ent.principal);
+ free(fullname);
+ return ERR;
+ }
+ }
+
+ ret = kadm5_randkey_principal(handle, ent.principal, NULL, NULL);
+
+ krb5_free_principal(context, ent.principal);
+ free(fullname);
+
+ if (ret) {
+ com_err(whoami, ret, str_RANDOM_KEY, fullname);
+ return ERR;
+ }
+
+ return OK;
+}
diff --git a/src/kadmin/dbutil/kdb5_create.c b/src/kadmin/dbutil/kdb5_create.c
new file mode 100644
index 000000000..b7520d98d
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_create.c
@@ -0,0 +1,449 @@
+/*
+ * admin/create/kdb5_create.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Generate (from scratch) a Kerberos KDC database.
+ */
+
+#include <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <kadm5/adb.h>
+
+enum ap_op {
+ NULL_KEY, /* setup null keys */
+ MASTER_KEY, /* use master key as new key */
+ TGT_KEY /* special handling for tgt key */
+};
+
+krb5_key_salt_tuple def_kslist = { ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_NORMAL };
+
+struct realm_info {
+ krb5_deltat max_life;
+ krb5_deltat max_rlife;
+ krb5_timestamp expiration;
+ krb5_flags flags;
+ krb5_encrypt_block *eblock;
+ krb5_pointer rseed;
+ krb5_int32 nkslist;
+ krb5_key_salt_tuple *kslist;
+} rblock = { /* XXX */
+ KRB5_KDB_MAX_LIFE,
+ KRB5_KDB_MAX_RLIFE,
+ KRB5_KDB_EXPIRATION,
+ KRB5_KDB_DEF_FLAGS,
+ (krb5_encrypt_block *) NULL,
+ (krb5_pointer) NULL,
+ 1,
+ &def_kslist
+};
+
+struct iterate_args {
+ krb5_context ctx;
+ struct realm_info *rblock;
+ krb5_db_entry *dbentp;
+};
+
+static krb5_error_code add_principal
+ PROTOTYPE((krb5_context,
+ krb5_principal,
+ enum ap_op,
+ struct realm_info *));
+
+/*
+ * Steps in creating a database:
+ *
+ * 1) use the db calls to open/create a new database
+ *
+ * 2) get a realm name for the new db
+ *
+ * 3) get a master password for the new db; convert to an encryption key.
+ *
+ * 4) create various required entries in the database
+ *
+ * 5) close & exit
+ */
+
+extern krb5_keyblock master_keyblock;
+extern krb5_principal master_princ;
+extern krb5_encrypt_block master_encblock;
+krb5_data master_salt;
+
+krb5_data tgt_princ_entries[] = {
+ {0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME},
+ {0, 0, 0} };
+
+krb5_data db_creator_entries[] = {
+ {0, sizeof("db_creation")-1, "db_creation"} };
+
+/* XXX knows about contents of krb5_principal, and that tgt names
+ are of form TGT/REALM@REALM */
+krb5_principal_data tgt_princ = {
+ 0, /* magic number */
+ {0, 0, 0}, /* krb5_data realm */
+ tgt_princ_entries, /* krb5_data *data */
+ 2, /* int length */
+ KRB5_NT_SRV_INST /* int type */
+};
+
+krb5_principal_data db_create_princ = {
+ 0, /* magic number */
+ {0, 0, 0}, /* krb5_data realm */
+ db_creator_entries, /* krb5_data *data */
+ 1, /* int length */
+ KRB5_NT_SRV_INST /* int type */
+};
+
+static char *mkey_password = 0;
+char *whoami;
+
+extern int exit_status;
+extern osa_adb_policy_t policy_db;
+extern kadm5_config_params global_params;
+extern krb5_context util_context;
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-s]\n", whoami);
+ exit_status++;
+}
+
+void kdb5_create(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int optchar;
+
+ krb5_error_code retval;
+ char *mkey_fullname;
+ char *pw_str = 0;
+ int pw_size = 0;
+ int do_stash = 0;
+ krb5_data pwd;
+
+ if (strrchr(argv[0], '/'))
+ argv[0] = strrchr(argv[0], '/')+1;
+ whoami = argv[0];
+
+ mkey_password = NULL;
+ optind = 1;
+ while ((optchar = getopt(argc, argv, "P:s")) != EOF) {
+ switch(optchar) {
+ case 's':
+ do_stash++;
+ break;
+ case 'P': /* Only used for testing!!! */
+ mkey_password = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ return;
+ }
+ }
+
+ rblock.max_life = global_params.max_life;
+ rblock.max_rlife = global_params.max_rlife;
+ rblock.expiration = global_params.expiration;
+ rblock.flags = global_params.flags;
+ rblock.nkslist = global_params.num_keysalts;
+ rblock.kslist = global_params.keysalts;
+
+ krb5_use_enctype(util_context, &master_encblock, master_keyblock.enctype);
+
+ retval = krb5_db_set_name(util_context, global_params.dbname);
+ if (!retval) retval = EEXIST;
+
+ if (retval == EEXIST || retval == EACCES || retval == EPERM) {
+ /* it exists ! */
+ com_err(argv[0], 0, "The database '%s' appears to already exist",
+ global_params.dbname);
+ exit_status++; return;
+ }
+
+ /* assemble & parse the master key name */
+
+ if ((retval = krb5_db_setup_mkey_name(util_context,
+ global_params.mkey_name,
+ global_params.realm,
+ &mkey_fullname, &master_princ))) {
+ com_err(argv[0], retval, "while setting up master key name");
+ exit_status++; return;
+ }
+
+ krb5_princ_set_realm_data(util_context, &db_create_princ, global_params.realm);
+ krb5_princ_set_realm_length(util_context, &db_create_princ, strlen(global_params.realm));
+ krb5_princ_set_realm_data(util_context, &tgt_princ, global_params.realm);
+ krb5_princ_set_realm_length(util_context, &tgt_princ, strlen(global_params.realm));
+ krb5_princ_component(util_context, &tgt_princ,1)->data = global_params.realm;
+ krb5_princ_component(util_context, &tgt_princ,1)->length = strlen(global_params.realm);
+
+ printf("Initializing database '%s' for realm '%s',\n\
+master key name '%s'\n",
+ global_params.dbname, global_params.realm, mkey_fullname);
+
+ if (!mkey_password) {
+ printf("You will be prompted for the database Master Password.\n");
+ printf("It is important that you NOT FORGET this password.\n");
+ fflush(stdout);
+
+ pw_size = 1024;
+ pw_str = malloc(pw_size);
+
+ retval = krb5_read_password(util_context, KRB5_KDC_MKEY_1, KRB5_KDC_MKEY_2,
+ pw_str, &pw_size);
+ if (retval) {
+ com_err(argv[0], retval, "while reading master key from keyboard");
+ exit_status++; return;
+ }
+ mkey_password = pw_str;
+ }
+
+ pwd.data = mkey_password;
+ pwd.length = strlen(mkey_password);
+ retval = krb5_principal2salt(util_context, master_princ, &master_salt);
+ if (retval) {
+ com_err(argv[0], retval, "while calculated master key salt");
+ exit_status++; return;
+ }
+ if (retval = krb5_string_to_key(util_context, &master_encblock,
+ &master_keyblock, &pwd, &master_salt)) {
+ com_err(argv[0], retval, "while transforming master key from password");
+ exit_status++; return;
+ }
+
+ if ((retval = krb5_process_key(util_context, &master_encblock,
+ &master_keyblock))) {
+ com_err(argv[0], retval, "while processing master key");
+ exit_status++; return;
+ }
+
+ rblock.eblock = &master_encblock;
+ if ((retval = krb5_init_random_key(util_context, &master_encblock,
+ &master_keyblock, &rblock.rseed))) {
+ com_err(argv[0], retval, "while initializing random key generator");
+ (void) krb5_finish_key(util_context, &master_encblock);
+ exit_status++; return;
+ }
+ if ((retval = krb5_db_create(util_context, global_params.dbname))) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
+ com_err(argv[0], retval, "while creating database '%s'",
+ global_params.dbname);
+ exit_status++; return;
+ }
+ if (retval = krb5_db_fini(util_context)) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock,
+ &rblock.rseed);
+ com_err(argv[0], retval, "while closing current database");
+ exit_status++; return;
+ }
+ if ((retval = krb5_db_set_name(util_context, global_params.dbname))) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
+ com_err(argv[0], retval, "while setting active database to '%s'",
+ global_params.dbname);
+ exit_status++; return;
+ }
+ if ((retval = krb5_db_init(util_context))) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
+ com_err(argv[0], retval, "while initializing the database '%s'",
+ global_params.dbname);
+ exit_status++; return;
+ }
+
+ if ((retval = add_principal(util_context, master_princ, MASTER_KEY, &rblock)) ||
+ (retval = add_principal(util_context, &tgt_princ, TGT_KEY, &rblock))) {
+ (void) krb5_db_fini(util_context);
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
+ com_err(argv[0], retval, "while adding entries to the database");
+ exit_status++; return;
+ }
+ /*
+ * Always stash the master key so kadm5_create does not prompt for
+ * it; delete the file below if it was not requested. DO NOT EXIT
+ * BEFORE DELETING THE KEYFILE if do_stash is not set.
+ */
+ if (retval = krb5_db_store_mkey(util_context,
+ global_params.stash_file,
+ master_princ,
+ &master_keyblock)) {
+ com_err(argv[0], errno, "while storing key");
+ printf("Warning: couldn't stash master key.\n");
+ }
+ /* clean up */
+ (void) krb5_db_fini(util_context);
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ free(master_keyblock.contents);
+ if (pw_str) {
+ memset(pw_str, 0, pw_size);
+ free(pw_str);
+ }
+ free(master_salt.data);
+
+ if (kadm5_create(&global_params)) {
+ if (!do_stash) unlink(global_params.stash_file);
+ exit_status++;
+ return;
+ }
+ if (!do_stash) unlink(global_params.stash_file);
+
+ /* now open the database */
+ open_db_and_mkey();
+
+ return;
+
+}
+
+static krb5_error_code
+tgt_keysalt_iterate(ksent, ptr)
+ krb5_key_salt_tuple *ksent;
+ krb5_pointer ptr;
+{
+ krb5_context context;
+ krb5_error_code kret;
+ struct iterate_args *iargs;
+ krb5_keyblock random_keyblock, *key;
+ krb5_int32 ind;
+ krb5_encrypt_block random_encblock;
+ krb5_pointer rseed;
+ krb5_data pwd;
+
+ iargs = (struct iterate_args *) ptr;
+ kret = 0;
+
+ context = iargs->ctx;
+
+ /*
+ * Convert the master key password into a key for this particular
+ * encryption system.
+ */
+ krb5_use_enctype(context, &random_encblock, ksent->ks_enctype);
+ pwd.data = mkey_password;
+ pwd.length = strlen(mkey_password);
+ if (kret = krb5_string_to_key(context, &random_encblock, &random_keyblock,
+ &pwd, &master_salt))
+ return kret;
+ if ((kret = krb5_init_random_key(context, &random_encblock,
+ &random_keyblock, &rseed)))
+ return kret;
+
+ if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) {
+ ind = iargs->dbentp->n_key_data-1;
+ if (!(kret = krb5_random_key(context,
+ &random_encblock, rseed,
+ &key))) {
+ kret = krb5_dbekd_encrypt_key_data(context,
+ iargs->rblock->eblock,
+ key,
+ NULL,
+ 1,
+ &iargs->dbentp->key_data[ind]);
+ krb5_free_keyblock(context, key);
+ }
+ }
+ memset((char *)random_keyblock.contents, 0, random_keyblock.length);
+ free(random_keyblock.contents);
+ (void) krb5_finish_random_key(context, &random_encblock, &rseed);
+ return(kret);
+}
+
+static krb5_error_code
+add_principal(context, princ, op, pblock)
+ krb5_context context;
+ krb5_principal princ;
+ enum ap_op op;
+ struct realm_info *pblock;
+{
+ krb5_error_code retval;
+ krb5_db_entry entry;
+
+ krb5_timestamp now;
+ struct iterate_args iargs;
+
+ int nentries = 1;
+
+ memset((char *) &entry, 0, sizeof(entry));
+
+ entry.len = KRB5_KDB_V1_BASE_LENGTH;
+ entry.attributes = pblock->flags;
+ entry.max_life = pblock->max_life;
+ entry.max_renewable_life = pblock->max_rlife;
+ entry.expiration = pblock->expiration;
+
+ if ((retval = krb5_copy_principal(context, princ, &entry.princ)))
+ goto error_out;
+
+ if ((retval = krb5_timeofday(context, &now)))
+ goto error_out;
+
+ if ((retval = krb5_dbe_update_mod_princ_data(context, &entry,
+ now, &db_create_princ)))
+ goto error_out;
+
+ switch (op) {
+ case MASTER_KEY:
+ if ((entry.key_data=(krb5_key_data*)malloc(sizeof(krb5_key_data)))
+ == NULL)
+ goto error_out;
+ memset((char *) entry.key_data, 0, sizeof(krb5_key_data));
+ entry.n_key_data = 1;
+
+ entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
+ if ((retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock,
+ &master_keyblock, NULL,
+ 1, entry.key_data)))
+ return retval;
+ break;
+ case TGT_KEY:
+ iargs.ctx = context;
+ iargs.rblock = pblock;
+ iargs.dbentp = &entry;
+ /*
+ * Iterate through the key/salt list, ignoring salt types.
+ */
+ if ((retval = krb5_keysalt_iterate(pblock->kslist,
+ pblock->nkslist,
+ 1,
+ tgt_keysalt_iterate,
+ (krb5_pointer) &iargs)))
+ return retval;
+ break;
+ case NULL_KEY:
+ return EOPNOTSUPP;
+ default:
+ break;
+ }
+
+ retval = krb5_db_put_principal(context, &entry, &nentries);
+
+error_out:;
+ krb5_dbe_free_contents(context, &entry);
+ return retval;
+}
diff --git a/src/kadmin/dbutil/kdb5_destroy.c b/src/kadmin/dbutil/kdb5_destroy.c
new file mode 100644
index 000000000..7c6873df7
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_destroy.c
@@ -0,0 +1,117 @@
+/*
+ * admin/destroy/kdb5_destroy.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * kdb_dest(roy): destroy the named database.
+ *
+ * This version knows about DBM format databases.
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+#include "com_err.h"
+#include <kadm5/admin.h>
+#include <kadm5/adb.h>
+
+extern int errno;
+extern int exit_status;
+extern krb5_boolean dbactive;
+extern kadm5_config_params global_params;
+
+char *yes = "yes\n"; /* \n to compare against result of
+ fgets */
+
+static void
+usage(who, status)
+ char *who;
+ int status;
+{
+ fprintf(stderr, "usage: %s [-f]\n", who);
+}
+
+void
+kdb5_destroy(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int optchar;
+ char *dbname;
+ char buf[5];
+ char dbfilename[MAXPATHLEN];
+ krb5_error_code retval, retval1, retval2;
+ krb5_context context;
+ int force = 0;
+
+ krb5_init_context(&context);
+ krb5_init_ets(context);
+
+ if (strrchr(argv[0], '/'))
+ argv[0] = strrchr(argv[0], '/')+1;
+
+ dbname = global_params.dbname;
+
+ optind = 1;
+ while ((optchar = getopt(argc, argv, "f")) != EOF) {
+ switch(optchar) {
+ case 'f':
+ force++;
+ break;
+ case '?':
+ default:
+ usage(argv[0], 1);
+ return;
+ /*NOTREACHED*/
+ }
+ }
+ if (!force) {
+ printf("Deleting KDC database stored in '%s', are you sure?\n", dbname);
+ printf("(type 'yes' to confirm)? ");
+ if (fgets(buf, sizeof(buf), stdin) == NULL) {
+ exit_status++; return;
+ }
+ if (strcmp(buf, yes)) {
+ exit_status++; return;
+ }
+ printf("OK, deleting database '%s'...\n", dbname);
+ }
+
+ if (retval = krb5_db_set_name(context, dbname)) {
+ com_err(argv[0], retval, "'%s'",dbname);
+ exit_status++; return;
+ }
+ retval1 = kdb5_db_destroy(context, dbname);
+ retval2 = osa_adb_destroy_policy_db(&global_params);
+ if (retval1) {
+ com_err(argv[0], retval1, "deleting database '%s'",dbname);
+ exit_status++; return;
+ }
+ if (retval2) {
+ com_err(argv[0], retval2, "destroying policy database");
+ exit_status++; return;
+ }
+
+ dbactive = FALSE;
+ printf("** Database '%s' destroyed.\n", dbname);
+ return;
+}
diff --git a/src/kadmin/dbutil/kdb5_edit.M b/src/kadmin/dbutil/kdb5_edit.M
new file mode 100644
index 000000000..8405c01cd
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_edit.M
@@ -0,0 +1,179 @@
+.\" admin/edit/kdb5_edit.M
+.\"
+.\" Copyright 1990 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\" require a specific license from the United States Government.
+.\" It is the responsibility of any person or organization contemplating
+.\" export to obtain such a license before exporting.
+.\"
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission. M.I.T. makes no representations about the suitability of
+.\" this software for any purpose. It is provided "as is" without express
+.\" or implied warranty.
+.\"
+.\"
+.TH KDB5_EDIT 8 "Kerberos Version 5.0" "MIT Project Athena"
+.SH NAME
+kdb5_edit \- edit a Kerberos V5 principal database
+.SH SYNOPSIS
+.B kdb5_edit
+[
+.B \-r
+.I realm
+] [
+.B \-d
+.I dbname
+] [
+.B \-k
+.I keytype
+] [
+.B \-M
+.I mkeyname
+] [
+.B \-e
+.I enctype
+] [
+.B \-m
+] [
+.B \-R
+.I command
+] [
+.B \-s
+.I script
+] [
+.B \-f
+.I stashfile
+]
+.br
+.SH DESCRIPTION
+.I kdb5_edit
+allows an administrator to add, delete, and edit entries in a Kerberos
+version 5 principal database.
+After themaster key is verified, commands are to
+.I kdb5_edit
+are issued using one of three mechanisms. If a single command is supplied
+using the
+.B \-R
+.I command
+argument, then that single command is processed and execution ceases. If a
+script file is provided using the
+.B \-s
+.I script
+argument, then commands are read from this file until either an error occurs
+or an end of file is detected. Finally, if neither a command or a script is
+specified, the invoker is placed into a shell-like command loop, from which
+[s]he may issue commands to modify the
+database.
+.PP
+The
+.B \-r
+.I realm
+option specifies the realm of the database;
+by default the realm returned by
+.IR krb5_default_local_realm (3)
+is used.
+.PP
+The
+.B \-d
+.I dbname
+option specifies the name under which the principal database is stored;
+by default the database is in DEFAULT_DBM_FILE (defined in <krb5/osconf.h>).
+.PP
+The
+.B \-k
+.I keytype
+option specifies the key type of the master key in the database; the default is
+the string representation of DEFAULT_KDC_KEYTYPE (defined in <krb5/osconf.h>).
+.PP
+The
+.B \-f
+.I stashfile
+option specifies the filename of the stashed V5 master key. The default is
+defined as DEFAULT_KEYFILE_STUB in <krb5/osconf.h> and is
+typically $(prefix)/lib/krb5kdc/.k5.REALMNAME. (In previous
+releases, this would have been /.k5.REALMNAME.)
+.PP
+The
+.B \-M
+.I mkeyname
+option specifies the principal name for the master key in the database;
+the default is KRB5_KDB_M_NAME (defined in <krb5/kdb.h>).
+.PP
+The
+.B \-e
+.I enctype
+option specifies the encryption type to be used when placing entries in
+the database; the default is the string representation of DEFAULT_KDC_ETYPE
+(defined in <krb5/osconf.h>).
+.PP
+The
+.B \-m
+option specifies that the master database password should be fetched
+from the keyboard rather than from a file on disk.
+.SH AVAILABLE COMMANDS
+
+The following is a list of commands and their aliases that the system
+administrator may use to manipulate the database:
+
+.IP add_new_key,ank
+Add new entry to Kerberos database (prompting for password)
+
+.IP change_pwd_key,cpw
+Change key of an entry in the Kerberos database (prompting for password)
+
+.IP add_rnd_key,ark
+Add new entry to Kerberos database, using a random key
+
+.IP change_rnd_key,crk
+Change key of an entry in the Kerberos database (select a new random key)
+
+.IP delete_entry,delent,del
+Delete an entry from the database
+
+.IP extract_srvtab,xst,ex_st
+Extract service key table
+
+.IP extract_v4_srvtab,xst4
+Extract service key table
+
+.IP modify_entry,modent
+Modify entry
+
+.IP list_db,ldb
+List database entries
+
+.IP dump_db,ddb
+Dump database entries to a file
+
+.IP load_db,lddb
+Load database entries from a file
+
+.IP set_dbname,sdbn
+Change database name
+
+.IP enter_master_key,emk
+Enter the master key for a database
+
+.IP change_working_directory,cwd,cd
+Change working directory
+
+.IP print_working_direcotry,pwd
+Print working directory
+
+.IP list_requests,lr,?
+List available requests.
+
+.IP quit,exit,q
+Exit program.
+
+.SH SEE ALSO
+krb5(3), krb5kdc(8), ss(3)
+.SH BUGS
+
diff --git a/src/kadmin/dbutil/kdb5_stash.c b/src/kadmin/dbutil/kdb5_stash.c
new file mode 100644
index 000000000..6952db7ec
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_stash.c
@@ -0,0 +1,153 @@
+/*
+ * admin/stash/kdb5_stash.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Store the master database key in a file.
+ */
+
+#include "k5-int.h"
+#include "com_err.h"
+#include <kadm5/admin.h>
+#include <stdio.h>
+
+extern int errno;
+
+extern krb5_keyblock master_keyblock;
+extern krb5_principal master_princ;
+extern krb5_encrypt_block master_encblock;
+extern kadm5_config_params global_params;
+
+extern int exit_status;
+
+static void
+usage(who, status)
+char *who;
+int status;
+{
+ fprintf(stderr, "usage: %s [-f keyfile]\n", who);
+ exit_status++; return;
+}
+
+
+void
+kdb5_stash(argc, argv)
+int argc;
+char *argv[];
+{
+ extern char *optarg;
+ int optchar;
+ krb5_error_code retval;
+ char *dbname = (char *) NULL;
+ char *realm = 0;
+ char *mkey_name = 0;
+ char *mkey_fullname;
+ char *keyfile = 0;
+ krb5_context context;
+ krb5_realm_params *rparams;
+
+ int enctypedone = 0;
+
+ if (strrchr(argv[0], '/'))
+ argv[0] = strrchr(argv[0], '/')+1;
+
+ krb5_init_context(&context);
+ krb5_init_ets(context);
+
+ dbname = global_params.dbname;
+ realm = global_params.realm;
+ mkey_name = global_params.mkey_name;
+ keyfile = global_params.stash_file;
+
+ optind = 1;
+ while ((optchar = getopt(argc, argv, "f:")) != EOF) {
+ switch(optchar) {
+ case 'f':
+ keyfile = optarg;
+ break;
+ case '?':
+ default:
+ usage(argv[0], 1);
+ return;
+ }
+ }
+
+ if (!valid_enctype(master_keyblock.enctype)) {
+ char tmp[32];
+ if (krb5_enctype_to_string(master_keyblock.enctype, tmp, sizeof(tmp)))
+ com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP,
+ "while setting up enctype %d", master_keyblock.enctype);
+ else
+ com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP, tmp);
+ exit_status++; return;
+ }
+
+ krb5_use_enctype(context, &master_encblock, master_keyblock.enctype);
+
+ if (retval = krb5_db_set_name(context, dbname)) {
+ com_err(argv[0], retval, "while setting active database to '%s'",
+ dbname);
+ exit_status++; return;
+ }
+
+ /* assemble & parse the master key name */
+
+ if (retval = krb5_db_setup_mkey_name(context, mkey_name, realm,
+ &mkey_fullname, &master_princ)) {
+ com_err(argv[0], retval, "while setting up master key name");
+ exit_status++; return;
+ }
+
+ if (retval = krb5_db_init(context)) {
+ com_err(argv[0], retval, "while initializing the database '%s'",
+ dbname);
+ exit_status++; return;
+ }
+
+ /* TRUE here means read the keyboard, but only once */
+ if (retval = krb5_db_fetch_mkey(context, master_princ, &master_encblock,
+ TRUE, FALSE, (char *) NULL,
+ 0, &master_keyblock)) {
+ com_err(argv[0], retval, "while reading master key");
+ (void) krb5_db_fini(context);
+ exit_status++; return;
+ }
+ if (retval = krb5_db_verify_master_key(context, master_princ,
+ &master_keyblock,&master_encblock)) {
+ com_err(argv[0], retval, "while verifying master key");
+ (void) krb5_db_fini(context);
+ exit_status++; return;
+ }
+ if (retval = krb5_db_store_mkey(context, keyfile, master_princ,
+ &master_keyblock)) {
+ com_err(argv[0], errno, "while storing key");
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ (void) krb5_db_fini(context);
+ exit_status++; return;
+ }
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ if (retval = krb5_db_fini(context)) {
+ com_err(argv[0], retval, "closing database '%s'", dbname);
+ exit_status++; return;
+ }
+
+ return;
+}
diff --git a/src/kadmin/dbutil/kdb5_util.M b/src/kadmin/dbutil/kdb5_util.M
new file mode 100644
index 000000000..746e018c0
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_util.M
@@ -0,0 +1,122 @@
+KDB5_UTIL(8)
+
+NAME
+ kdb5_util - Kerberos database maintainance utility
+
+SYNOPSIS
+ kdb5_util [-d dbpathname ] [-r realmname] [-R request ]
+ [-s scriptfile] [-k enctype] [-M mkeyname]
+ [-f stashfile]
+
+DESCRIPTION
+ kdb5_util allows an administrator to perform low-level
+ maintainance procedures on the Kerberos and KADM5 database.
+ Databases can be created, destroyed, and dumped to and loaded
+ from ASCII files. Additionally, kdb5_util can create a
+ Kerberos master key stash file. kdb5_util subsumes the
+ functionality of and makes obsolete the previous database
+ maintainance programs kdb5_create, kdb5_edit, kdb5_destroy,
+ and kdb5_stash.
+
+ When the program is first run, it attempts to acquire the
+ master key and open the database. Execution continues whether
+ or not it is successful, however, because the database may not
+ exist yet or the stash file may be corrupt. Commands can be
+ issued using one of three mechanisms. If a single command is
+ supplied using the request argument, then that single command
+ is processed and execution ceases. If a script file is
+ provided using the -s script argument, then commands are read
+ from this file until either an error occurs or an end of file
+ is detected. Finally, if neither a command or a script is
+ specified, the invoker is placed into a shell-like command
+ loop, from which commands may be executed.
+
+ The -r realm option specifies the realm of the database; by
+ default the realm returned by krb5_default_local_realm(3) is
+ used.
+
+ The -d dbname option specifies the name under which the
+ principal database is stored; by default the database is
+ controlled by kdc.conf. The KADM5 policy database and lock
+ file are also derived from this value.
+
+ The -k keytype option specifies the key type of the master key
+ in the database; the default is controlled by kdc.conf.
+
+ The -f stashfile option specifies the filename of the stashed
+ V5 master key. The default is controlled by kdc.conf and is
+ typically <krb5-prefix>/lib/krb5kdc/.k5.REALMNAME. (In
+ previous releases, this would have been /.k5.REALMNAME.)
+
+ The -M mkeyname option specifies the principal name for the
+ master key in the database; the default is controlled by
+ kdc.conf.
+
+ The -m option specifies that the master database password
+ should be fetched from the keyboard rather than from a file on
+ disk.
+
+AVAILABLE COMMANDS
+ create_db [-s]
+
+ Alias: create. Creates a new database. If the -s option is
+ specified, the stash file is also created. This command fails
+ if the database already exists. If the command is successful,
+ the database is opened just as if it had already existed when
+ the program was first run.
+
+ destroy_db [-f]
+
+ Alias: destroy. Destroys the database, first overwriting the
+ disk sectors and then unlinking the files, after prompting the
+ user for confirmation. With the -f argument, does not prompt
+ the user.
+
+ stash_mkey [-f keyfile]
+
+ Alias: stash. Stores the master principal's keys in a stash
+ file. The -f argument can be used to override the keyfile
+ specified at startup.
+
+ dump_db [-old] [-b6] [-verbose] [filename [principals...]]
+
+ Alias: ddb. Dumps the current Kerberos and KADM5 database
+ into an ASCII file. By default, the database is dumped in
+ current format, "kdb5_util load_dump version 4". The -b6
+ argument causes the dump to be in the Kerberos 5 Beta 6 format
+ ("kdb5_edit load_dump version 3.0"). The -old argument causes
+ the dump to be in the Kerberos 5 Beta 5 and earlier dump
+ format ("kdb5_edit load_dump version 2.0"). The -verbose
+ option causes the name of each principal and policy to be
+ printed as it is dumped.
+
+ load_db [-old] [-b6] [-verbose] [-update] filename dbname
+ [admin_dbname]
+
+ Alias: lddb. Loads a database dump from the named file into
+ the named database. The -old and -b6 options require the dump
+ to be in the specified format (see dump_db); otherwise, the
+ format of the dump file is detected automatically and handled
+ as appropriate. If the -update argument is specified, records
+ from the dump file are merely added to or updated in the
+ existing database; otherwise, a new database is created
+ containing only what is in the dump file and the old one
+ destroyed on a successful completion. The dbname argument is
+ required (XXX probably shouldn't be) and overrides the value
+ specified on the command line or the default. The
+ admin_dbname is optional and is derived from dbname if not
+ specified.
+
+ dump_v4db [filename]
+
+ Alias: d4db. Dumps the current database into the Kerberos 4
+ database dump format.
+
+ load_v4db [-d v5dbpathname] [-t] [-n] [-r realmname] [-K]
+ [-k enctype] [-M mkeyname] -f inputfile
+
+ Alias: lddb4. Loads a Kerberos 4 database dump file. XXX Not
+ sure what all the arguments mean.
+
+SEE ALSO
+ kadm5_export(8), kadm5_import(8)
diff --git a/src/kadmin/dbutil/kdb5_util.c b/src/kadmin/dbutil/kdb5_util.c
new file mode 100644
index 000000000..3f31fcb14
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_util.c
@@ -0,0 +1,416 @@
+/*
+ * admin/edit/kdb5_edit.c
+ *
+ * (C) Copyright 1990,1991, 1996 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Edit a KDC database.
+ */
+
+#include <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <kadm5/adb.h>
+#include <time.h>
+#include "kdb5_util.h"
+
+char *Err_no_master_msg = "Master key not entered!\n";
+char *Err_no_database = "Database not currently opened!\n";
+
+/*
+ * XXX Ick, ick, ick. These global variables shouldn't be global....
+ */
+static char *mkey_password = 0;
+
+/*
+ * I can't figure out any way for this not to be global, given how ss
+ * works.
+ */
+
+int exit_status = 0;
+krb5_context util_context;
+osa_adb_policy_t policy_db;
+kadm5_config_params global_params;
+
+/*
+ * Script input, specified by -s.
+ */
+FILE *scriptfile = (FILE *) NULL;
+
+static void
+usage(who, status)
+ char *who;
+ int status;
+{
+ fprintf(stderr,
+ "usage: %s [-d dbpathname ] [-r realmname] [-R request ]\n",
+ who);
+ fprintf(stderr, "\t [-k enctype] [-M mkeyname] [-f stashfile]\n");
+ exit(status);
+}
+
+krb5_keyblock master_keyblock;
+krb5_principal master_princ;
+krb5_db_entry master_entry;
+krb5_encrypt_block master_encblock;
+krb5_pointer master_random;
+int valid_master_key = 0;
+
+char *progname;
+krb5_boolean manual_mkey = FALSE;
+krb5_boolean dbactive = FALSE;
+
+char *kdb5_util_Init(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ int optchar;
+ krb5_error_code retval;
+ char *request = NULL;
+
+ retval = krb5_init_context(&util_context);
+ if (retval) {
+ fprintf(stderr, "krb5_init_context failed with error #%ld\n",
+ (long) retval);
+ exit(1);
+ }
+ krb5_init_ets(util_context);
+ initialize_adb_error_table();
+
+ if (strrchr(argv[0], '/'))
+ argv[0] = strrchr(argv[0], '/')+1;
+
+ progname = argv[0];
+
+ while ((optchar = getopt(argc, argv, "P:d:a:r:R:k:M:e:ms:f:")) != EOF) {
+ switch(optchar) {
+ case 'P': /* Only used for testing!!! */
+ mkey_password = optarg;
+ manual_mkey = TRUE;
+ break;
+ case 'd':
+ global_params.dbname = optarg;
+ global_params.mask |= KADM5_CONFIG_DBNAME;
+ break;
+ case 'a':
+ global_params.admin_dbname = optarg;
+ global_params.mask |= KADM5_CONFIG_ADBNAME;
+ break;
+ case 'r':
+ global_params.realm = optarg;
+ global_params.mask |= KADM5_CONFIG_REALM;
+ /* not sure this is really necessary */
+ if ((retval = krb5_set_default_realm(util_context,
+ global_params.realm))) {
+ com_err(progname, retval, "while setting default realm name");
+ exit(1);
+ }
+ break;
+ case 'R':
+ request = optarg;
+ break;
+ case 'k':
+ if (krb5_string_to_enctype(optarg, &global_params.enctype))
+ com_err(argv[0], 0, "%s is an invalid enctype", optarg);
+ global_params.mask |= KADM5_CONFIG_ENCTYPE;
+ break;
+ case 'M': /* master key name in DB */
+ global_params.mkey_name = optarg;
+ global_params.mask |= KADM5_CONFIG_MKEY_NAME;
+ break;
+ case 'm':
+ manual_mkey = TRUE;
+ global_params.mkey_from_kbd = 1;
+ global_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
+ break;
+ case 's':
+ /* Open the script file */
+ if (!(scriptfile = fopen(optarg, "r"))) {
+ com_err(argv[0], errno, "while opening script file %s",
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'f':
+ global_params.stash_file = optarg;
+ global_params.mask |= KADM5_CONFIG_STASH_FILE;
+ break;
+ case '?':
+ default:
+ usage(progname, 1);
+ /*NOTREACHED*/
+ }
+ }
+
+ if (retval = kadm5_get_config_params(util_context, NULL, NULL,
+ &global_params, &global_params)) {
+ com_err(argv[0], retval, "while retreiving configuration parameters");
+ exit(1);
+ }
+
+ /*
+ * Dump creates files which should not be world-readable. It is
+ * easiest to do a single umask call here; any shells run by the
+ * ss command interface will have umask = 77 but that is not a
+ * serious problem.
+ */
+ (void) umask(077);
+
+ master_keyblock.enctype = global_params.enctype;
+ if (master_keyblock.enctype != ENCTYPE_UNKNOWN) {
+ if (!valid_enctype(master_keyblock.enctype)) {
+ char tmp[32];
+ if (krb5_enctype_to_string(master_keyblock.enctype,
+ tmp, sizeof(tmp)))
+ com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP,
+ "while setting up enctype %d", master_keyblock.enctype);
+ else
+ com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP, tmp);
+ exit(1);
+ }
+ krb5_use_enctype(util_context, &master_encblock,
+ master_keyblock.enctype);
+ }
+
+
+ open_db_and_mkey();
+
+ exit_status = 0; /* It's OK if we get errors in open_db_and_mkey */
+ return request;
+}
+
+#if 0
+/*
+ * This function is no longer used in kdb5_util (and it would no
+ * longer work, anyway).
+ */
+void set_dbname(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+
+ if (argc < 3) {
+ com_err(argv[0], 0, "Too few arguments");
+ com_err(argv[0], 0, "Usage: %s dbpathname realmname", argv[0]);
+ exit_status++;
+ return;
+ }
+ if (dbactive) {
+ if ((retval = krb5_db_fini(util_context)) && retval!= KRB5_KDB_DBNOTINITED) {
+ com_err(argv[0], retval, "while closing previous database");
+ exit_status++;
+ return;
+ }
+ if (valid_master_key) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock,
+ &master_random);
+ memset((char *)master_keyblock.contents, 0,
+ master_keyblock.length);
+ krb5_xfree(master_keyblock.contents);
+ master_keyblock.contents = NULL;
+ valid_master_key = 0;
+ }
+ krb5_free_principal(util_context, master_princ);
+ dbactive = FALSE;
+ }
+
+ (void) set_dbname_help(argv[0], argv[1]);
+ return;
+}
+#endif
+
+/*
+ * open_db_and_mkey: Opens the KDC and policy database, and sets the
+ * global master_* variables. Sets dbactive to TRUE if the databases
+ * are opened, and valid_master_key to 1 if the global master
+ * variables are set properly. Returns 0 on success, and 1 on
+ * failure, but it is not considered a failure if the master key
+ * cannot be fetched (the master key stash file may not exist when the
+ * program is run).
+ */
+int open_db_and_mkey()
+{
+ krb5_error_code retval;
+ int nentries, i;
+ krb5_boolean more;
+ krb5_data scratch, pwd;
+
+ dbactive = FALSE;
+ valid_master_key = 0;
+
+ if ((retval = krb5_db_set_name(util_context, global_params.dbname))) {
+ com_err(progname, retval, "while setting active database to '%s'",
+ global_params.dbname);
+ exit_status++;
+ return(1);
+ }
+ if ((retval = krb5_db_init(util_context))) {
+ com_err(progname, retval, "while initializing database");
+ exit_status++;
+ return(1);
+ }
+ if (retval = osa_adb_open_policy(&policy_db, &global_params)) {
+ com_err(progname, retval, "opening policy database");
+ exit_status++;
+ return (1);
+ }
+
+ /* assemble & parse the master key name */
+
+ if ((retval = krb5_db_setup_mkey_name(util_context,
+ global_params.mkey_name,
+ global_params.realm,
+ 0, &master_princ))) {
+ com_err(progname, retval, "while setting up master key name");
+ exit_status++;
+ return(1);
+ }
+ nentries = 1;
+ if ((retval = krb5_db_get_principal(util_context, master_princ,
+ &master_entry, &nentries, &more))) {
+ com_err(progname, retval, "while retrieving master entry");
+ exit_status++;
+ (void) krb5_db_fini(util_context);
+ return(1);
+ } else if (more) {
+ com_err(progname, KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE,
+ "while retrieving master entry");
+ exit_status++;
+ (void) krb5_db_fini(util_context);
+ return(1);
+ } else if (!nentries) {
+ com_err(progname, KRB5_KDB_NOENTRY, "while retrieving master entry");
+ exit_status++;
+ (void) krb5_db_fini(util_context);
+ return(1);
+ }
+
+ krb5_db_free_principal(util_context, &master_entry, nentries);
+
+ /* the databases are now open, and the master principal exists */
+ dbactive = TRUE;
+
+ if (mkey_password) {
+ pwd.data = mkey_password;
+ pwd.length = strlen(mkey_password);
+ retval = krb5_principal2salt(util_context, master_princ, &scratch);
+ if (retval) {
+ com_err(progname, retval, "while calculated master key salt");
+ return(1);
+ }
+
+ /* If no encryption type is set, use the default */
+ if (master_keyblock.enctype == ENCTYPE_UNKNOWN) {
+ master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
+ if (!valid_enctype(master_keyblock.enctype)) {
+ char tmp[32];
+ if (krb5_enctype_to_string(master_keyblock.enctype,
+ tmp, sizeof(tmp)))
+ com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
+ "while setting up enctype %d", master_keyblock.enctype);
+ else
+ com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP, tmp);
+ exit(1);
+ }
+ krb5_use_enctype(util_context, &master_encblock,
+ master_keyblock.enctype);
+ }
+
+ retval = krb5_string_to_key(util_context, &master_encblock,
+ &master_keyblock, &pwd, &scratch);
+ if (retval) {
+ com_err(progname, retval,
+ "while transforming master key from password");
+ return(1);
+ }
+ free(scratch.data);
+ mkey_password = 0;
+ } else if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
+ &master_encblock, manual_mkey,
+ FALSE, global_params.stash_file,
+ 0, &master_keyblock))) {
+ com_err(progname, retval, "while reading master key");
+ com_err(progname, 0, "Warning: proceeding without master key");
+ exit_status++;
+ return(0);
+ }
+ if ((retval = krb5_db_verify_master_key(util_context, master_princ,
+ &master_keyblock,&master_encblock))
+ ) {
+ com_err(progname, retval, "while verifying master key");
+ exit_status++;
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ krb5_xfree(master_keyblock.contents);
+ return(1);
+ }
+ if ((retval = krb5_process_key(util_context, &master_encblock,
+ &master_keyblock))) {
+ com_err(progname, retval, "while processing master key");
+ exit_status++;
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ krb5_xfree(master_keyblock.contents);
+ return(1);
+ }
+ if ((retval = krb5_init_random_key(util_context, &master_encblock,
+ &master_keyblock,
+ &master_random))) {
+ com_err(progname, retval, "while initializing random key generator");
+ exit_status++;
+ (void) krb5_finish_key(util_context, &master_encblock);
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ krb5_xfree(master_keyblock.contents);
+ return(1);
+ }
+
+ valid_master_key = 1;
+ dbactive = TRUE;
+ return 0;
+}
+
+#ifdef HAVE_GETCWD
+#undef getwd
+#endif
+
+int
+quit()
+{
+ krb5_error_code retval;
+ static krb5_boolean finished = 0;
+
+ if (finished)
+ return 0;
+ if (valid_master_key) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock,
+ &master_random);
+ }
+ retval = krb5_db_fini(util_context);
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ finished = TRUE;
+ if (retval && retval != KRB5_KDB_DBNOTINITED) {
+ com_err(progname, retval, "while closing database");
+ exit_status++;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/kadmin/dbutil/kdb5_util.h b/src/kadmin/dbutil/kdb5_util.h
new file mode 100644
index 000000000..b580e2f6a
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_util.h
@@ -0,0 +1,49 @@
+/*
+ * admin/edit/kdb5_edit.h
+ *
+ * Copyright 1992 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#define REALM_SEP '@'
+#define REALM_SEP_STR "@"
+
+extern char *progname;
+extern char *Err_no_database;
+
+void add_key
+ PROTOTYPE((char const *, char const *,
+ krb5_const_principal, const krb5_keyblock *,
+ krb5_kvno, krb5_keysalt *));
+int set_dbname_help
+ PROTOTYPE((char *, char *));
+
+char *kdb5_util_Init PROTOTYPE((int, char **));
+
+int quit();
+
+int check_for_match
+ PROTOTYPE((char *, int, krb5_db_entry *, int, int));
+
+void parse_token
+ PROTOTYPE((char *, int *, int *, char *));
+
+int create_db_entry
+ PROTOTYPE((krb5_principal, krb5_db_entry *));
diff --git a/src/kadmin/dbutil/kdb5_util_ct.ct b/src/kadmin/dbutil/kdb5_util_ct.ct
new file mode 100644
index 000000000..bac1df125
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_util_ct.ct
@@ -0,0 +1,56 @@
+# admin/edit/kdb5_ed_ct.ct
+#
+# Copyright 1990 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+# require a specific license from the United States Government.
+# It is the responsibility of any person or organization contemplating
+# export to obtain such a license before exporting.
+#
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission. M.I.T. makes no representations about the suitability of
+# this software for any purpose. It is provided "as is" without express
+# or implied warranty.
+#
+#
+# Command table for Kerberos administration edit
+#
+
+command_table kdb5_edit_cmds;
+
+request kdb5_create, "Create a new Kerberos database",
+ create_db, create;
+
+request kdb5_destroy, "Destroy a Kerberos database",
+ destroy_db, destroy;
+
+request kdb5_stash, "Stash the Kerberos master key",
+ stash_mkey, stash;
+
+request dump_db, "Dump database entries to a file",
+ dump_db, ddb;
+
+request dump_v4db, "Dump database entries to a V4 slave dump file",
+ dump_v4db, d4db;
+
+request load_db, "Load database entries from a file",
+ load_db, lddb;
+
+request load_v4db, "Load database entries from a V4 slave dump file",
+ load_v4db, lddb4;
+
+# list_requests is generic -- unrelated to Kerberos
+request ss_list_requests, "List available requests.",
+ list_requests, lr, "?";
+
+request ss_quit, "Exit program.",
+ quit, exit, q;
+
+end;
diff --git a/src/kadmin/dbutil/loadv4.c b/src/kadmin/dbutil/loadv4.c
new file mode 100644
index 000000000..a1d37edc7
--- /dev/null
+++ b/src/kadmin/dbutil/loadv4.c
@@ -0,0 +1,881 @@
+/*
+ * admin/edit/loadv4.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Generate (from scratch) a Kerberos V5 KDC database, filling it in with the
+ * entries from a V4 database.
+ */
+
+#ifdef KRB5_KRB4_COMPAT
+
+#include <des.h>
+#include <krb.h>
+#include <krb_db.h>
+/* MKEYFILE is now defined in kdc.h */
+#include <kdc.h>
+
+static C_Block master_key;
+static Key_schedule master_key_schedule;
+static long master_key_version;
+
+static char *v4_mkeyfile = "/.k";
+
+#include "k5-int.h"
+#include "com_err.h"
+#include "adm.h"
+#include "adm_proto.h"
+#include <stdio.h>
+
+#include <netinet/in.h> /* ntohl */
+
+#define PROGNAME argv[0]
+
+enum ap_op {
+ NULL_KEY, /* setup null keys */
+ MASTER_KEY, /* use master key as new key */
+ RANDOM_KEY /* choose a random key */
+};
+
+struct realm_info {
+ krb5_deltat max_life;
+ krb5_deltat max_rlife;
+ krb5_timestamp expiration;
+ krb5_flags flags;
+ krb5_encrypt_block *eblock;
+ krb5_pointer rseed;
+};
+
+static struct realm_info rblock = { /* XXX */
+ KRB5_KDB_MAX_LIFE,
+ KRB5_KDB_MAX_RLIFE,
+ KRB5_KDB_EXPIRATION,
+ KRB5_KDB_DEF_FLAGS,
+ 0
+};
+
+static int verbose = 0;
+
+static krb5_error_code add_principal
+ PROTOTYPE((krb5_context,
+ krb5_principal,
+ enum ap_op,
+ struct realm_info *));
+
+static int v4init PROTOTYPE((char *, char *, int, char *));
+static krb5_error_code enter_in_v5_db PROTOTYPE((krb5_context,
+ char *, Principal *));
+static krb5_error_code process_v4_dump PROTOTYPE((krb5_context, char *,
+ char *));
+static krb5_error_code fixup_database PROTOTYPE((krb5_context, char *));
+
+static int create_local_tgt = 0;
+
+static void
+usage(who, status)
+char *who;
+int status;
+{
+ fprintf(stderr, "usage: %s [-d v5dbpathname] [-t] [-n] [-r realmname] [-K] [-k enctype]\n\
+\t[-M mkeyname] -f inputfile\n",
+ who);
+ return;
+}
+
+static krb5_keyblock master_keyblock;
+static krb5_principal master_princ;
+static krb5_encrypt_block master_encblock;
+
+static krb5_data tgt_princ_entries[] = {
+ {0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME},
+ {0, 0, 0} };
+
+static krb5_data db_creator_entries[] = {
+ {0, sizeof("db_creation")-1, "db_creation"} };
+
+/* XXX knows about contents of krb5_principal, and that tgt names
+ are of form TGT/REALM@REALM */
+static krb5_principal_data tgt_princ = {
+ 0, /* magic number */
+ {0, 0, 0}, /* krb5_data realm */
+ tgt_princ_entries, /* krb5_data *data */
+ 2, /* int length */
+ KRB5_NT_SRV_INST /* int type */
+};
+
+static krb5_principal_data db_create_princ = {
+ 0, /* magic number */
+ {0, 0, 0}, /* krb5_data realm */
+ db_creator_entries, /* krb5_data *data */
+ 1, /* int length */
+ KRB5_NT_SRV_INST /* int type */
+};
+
+
+void
+load_v4db(argc, argv)
+int argc;
+char *argv[];
+{
+ krb5_error_code retval;
+ /* The kdb library will default to this, but it is convenient to
+ make it explicit (error reporting and temporary filename generation
+ use it). */
+ char *dbname = DEFAULT_KDB_FILE;
+ char *v4dbname = 0;
+ char *v4dumpfile = 0;
+ char *realm = 0;
+ char *mkey_name = 0;
+ char *mkey_fullname;
+ char *defrealm;
+ int enctypedone = 0;
+ int v4manual = 0;
+ int read_mkey = 0;
+ int tempdb = 0;
+ char *tempdbname;
+ krb5_context context;
+ char *stash_file = (char *) NULL;
+ krb5_realm_params *rparams;
+ int persist, op_ind;
+
+ krb5_init_context(&context);
+
+ krb5_init_ets(context);
+
+ if (strrchr(argv[0], '/'))
+ argv[0] = strrchr(argv[0], '/')+1;
+
+ persist = 1;
+ op_ind = 1;
+ while (persist && (op_ind < argc)) {
+ if (!strcmp(argv[op_ind], "-d") && ((argc - op_ind) >= 2)) {
+ dbname = argv[op_ind+1];
+ op_ind++;
+ }
+ else if (!strcmp(argv[op_ind], "-T")) {
+ create_local_tgt = 1;
+ }
+ else if (!strcmp(argv[op_ind], "-t")) {
+ tempdb = 1;
+ }
+ else if (!strcmp(argv[op_ind], "-r") && ((argc - op_ind) >= 2)) {
+ realm = argv[op_ind+1];
+ op_ind++;
+ }
+ else if (!strcmp(argv[op_ind], "-K")) {
+ read_mkey = 1;
+ }
+ else if (!strcmp(argv[op_ind], "-v")) {
+ verbose = 1;
+ }
+ else if (!strcmp(argv[op_ind], "-k") && ((argc - op_ind) >= 2)) {
+ if (!krb5_string_to_enctype(argv[op_ind+1],
+ &master_keyblock.enctype))
+ enctypedone++;
+ else
+ com_err(argv[0], 0, "%s is an invalid enctype",
+ argv[op_ind+1]);
+ op_ind++;
+ }
+ else if (!strcmp(argv[op_ind], "-M") && ((argc - op_ind) >= 2)) {
+ mkey_name = argv[op_ind+1];
+ op_ind++;
+ }
+ else if (!strcmp(argv[op_ind], "-n")) {
+ v4manual++;
+ }
+ else if (!strcmp(argv[op_ind], "-f") && ((argc - op_ind) >= 2)) {
+ if (v4dbname) {
+ usage(PROGNAME, 1);
+ return;
+ }
+ v4dumpfile = argv[op_ind+1];
+ op_ind++;
+ }
+ else
+ persist = 0;
+ op_ind++;
+ }
+
+ /*
+ * Attempt to read the KDC profile. If we do, then read appropriate values
+ * from it and augment values supplied on the command line.
+ */
+ if (!(retval = krb5_read_realm_params(context,
+ realm,
+ (char *) NULL,
+ (char *) NULL,
+ &rparams))) {
+ /* Get the value for the database */
+ if (rparams->realm_dbname && !dbname)
+ dbname = strdup(rparams->realm_dbname);
+
+ /* Get the value for the master key name */
+ if (rparams->realm_mkey_name && !mkey_name)
+ mkey_name = strdup(rparams->realm_mkey_name);
+
+ /* Get the value for the master key type */
+ if (rparams->realm_enctype_valid && !enctypedone) {
+ master_keyblock.enctype = rparams->realm_enctype;
+ enctypedone++;
+ }
+
+ /* Get the value for the stashfile */
+ if (rparams->realm_stash_file)
+ stash_file = strdup(rparams->realm_stash_file);
+
+ /* Get the value for maximum ticket lifetime. */
+ if (rparams->realm_max_life_valid)
+ rblock.max_life = rparams->realm_max_life;
+
+ /* Get the value for maximum renewable ticket lifetime. */
+ if (rparams->realm_max_rlife_valid)
+ rblock.max_rlife = rparams->realm_max_rlife;
+
+ /* Get the value for the default principal expiration */
+ if (rparams->realm_expiration_valid)
+ rblock.expiration = rparams->realm_expiration;
+
+ /* Get the value for the default principal flags */
+ if (rparams->realm_flags_valid)
+ rblock.flags = rparams->realm_flags;
+
+ krb5_free_realm_params(context, rparams);
+ }
+
+ if (!v4dumpfile) {
+ usage(PROGNAME, 1);
+ return;
+ }
+
+ if (!enctypedone)
+ master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
+
+ if (!valid_enctype(master_keyblock.enctype)) {
+ com_err(PROGNAME, KRB5_PROG_KEYTYPE_NOSUPP,
+ "while setting up enctype %d", master_keyblock.enctype);
+ return;
+ }
+
+ krb5_use_enctype(context, &master_encblock, master_keyblock.enctype);
+
+ /* If the user has not requested locking, don't modify an existing database. */
+ if (! tempdb) {
+ retval = krb5_db_set_name(context, dbname);
+ if (retval != ENOENT) {
+ fprintf(stderr,
+ "%s: The v5 database appears to already exist.\n",
+ PROGNAME);
+ return;
+ }
+ tempdbname = dbname;
+ } else {
+ int dbnamelen = strlen(dbname);
+ tempdbname = malloc(dbnamelen + 2);
+ if (tempdbname == 0) {
+ com_err(PROGNAME, ENOMEM, "allocating temporary filename");
+ return;
+ }
+ strcpy(tempdbname, dbname);
+ tempdbname[dbnamelen] = '~';
+ tempdbname[dbnamelen+1] = 0;
+ (void) kdb5_db_destroy(context, tempdbname);
+ }
+
+
+ if (!realm) {
+ if (retval = krb5_get_default_realm(context, &defrealm)) {
+ com_err(PROGNAME, retval, "while retrieving default realm name");
+ return;
+ }
+ realm = defrealm;
+ }
+
+ /* assemble & parse the master key name */
+
+ if (retval = krb5_db_setup_mkey_name(context, mkey_name, realm,
+ &mkey_fullname, &master_princ)) {
+ com_err(PROGNAME, retval, "while setting up master key name");
+ return;
+ }
+
+ krb5_princ_set_realm_data(context, &db_create_princ, realm);
+ krb5_princ_set_realm_length(context, &db_create_princ, strlen(realm));
+ krb5_princ_set_realm_data(context, &tgt_princ, realm);
+ krb5_princ_set_realm_length(context, &tgt_princ, strlen(realm));
+ krb5_princ_component(context, &tgt_princ,1)->data = realm;
+ krb5_princ_component(context, &tgt_princ,1)->length = strlen(realm);
+
+ printf("Initializing database '%s' for realm '%s',\n\
+master key name '%s'\n",
+ dbname, realm, mkey_fullname);
+
+ if (read_mkey) {
+ puts("You will be prompted for the version 5 database Master Password.");
+ puts("It is important that you NOT FORGET this password.");
+ fflush(stdout);
+ }
+
+ if (retval = krb5_db_fetch_mkey(context, master_princ, &master_encblock,
+ read_mkey, read_mkey, stash_file, 0,
+ &master_keyblock)) {
+ com_err(PROGNAME, retval, "while reading master key");
+ return;
+ }
+ if (retval = krb5_process_key(context, &master_encblock, &master_keyblock)) {
+ com_err(PROGNAME, retval, "while processing master key");
+ return;
+ }
+
+ rblock.eblock = &master_encblock;
+ if (retval = krb5_init_random_key(context, &master_encblock,
+ &master_keyblock, &rblock.rseed)) {
+ com_err(PROGNAME, retval, "while initializing random key generator");
+ (void) krb5_finish_key(context, &master_encblock);
+ return;
+ }
+ if (retval = krb5_db_create(context, tempdbname)) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ com_err(PROGNAME, retval, "while creating %sdatabase '%s'",
+ tempdb ? "temporary " : "", tempdbname);
+ return;
+ }
+ if (retval = krb5_db_set_name(context, tempdbname)) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ com_err(PROGNAME, retval, "while setting active database to '%s'",
+ tempdbname);
+ return;
+ }
+ if (v4init(PROGNAME, v4dbname, v4manual, v4dumpfile)) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ return;
+ }
+ if ((retval = krb5_db_init(context)) ||
+ (retval = krb5_dbm_db_open_database(context))) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ com_err(PROGNAME, retval, "while initializing the database '%s'",
+ tempdbname);
+ return;
+ }
+
+ if (retval = add_principal(context, master_princ, MASTER_KEY, &rblock)) {
+ (void) krb5_db_fini(context);
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ com_err(PROGNAME, retval, "while adding K/M to the database");
+ return;
+ }
+
+ if (create_local_tgt &&
+ (retval = add_principal(context, &tgt_princ, RANDOM_KEY, &rblock))) {
+ (void) krb5_db_fini(context);
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ com_err(PROGNAME, retval, "while adding TGT service to the database");
+ return;
+ }
+
+ retval = process_v4_dump(context, v4dumpfile, realm);
+ putchar('\n');
+ if (retval)
+ com_err(PROGNAME, retval, "while translating entries to the database");
+ else {
+ retval = fixup_database(context, realm);
+ }
+
+ /* clean up; rename temporary database if there were no errors */
+ if (retval == 0) {
+ if (retval = krb5_db_fini (context))
+ com_err(PROGNAME, retval, "while shutting down database");
+ else if (tempdb && (retval = krb5_dbm_db_rename(context, tempdbname,
+ dbname)))
+ com_err(PROGNAME, retval, "while renaming temporary database");
+ } else {
+ (void) krb5_db_fini (context);
+ if (tempdb)
+ (void) krb5_dbm_db_destroy (context, tempdbname);
+ }
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ krb5_free_context(context);
+ return;
+}
+
+static int
+v4init(pname, name, manual, dumpfile)
+char *pname, *name;
+int manual;
+char *dumpfile;
+{
+ int fd;
+ int ok = 0;
+
+ if (!manual) {
+ fd = open(v4_mkeyfile, O_RDONLY, 0600);
+ if (fd >= 0) {
+ if (read(fd, master_key, sizeof(master_key)) == sizeof(master_key))
+ ok = 1;
+ close(fd);
+ }
+ }
+ if (!ok) {
+ des_read_password(master_key, "V4 Kerberos master key: ", 0);
+ printf("\n");
+ }
+ key_sched(master_key, master_key_schedule);
+ return 0;
+}
+
+static krb5_error_code
+enter_in_v5_db(context, realm, princ)
+krb5_context context;
+char *realm;
+Principal *princ;
+{
+ krb5_db_entry entry;
+ krb5_error_code retval;
+ krb5_keyblock v4v5key;
+ int nentries = 1;
+ des_cblock v4key;
+ char *name;
+ krb5_timestamp mod_time;
+ krb5_principal mod_princ;
+ krb5_keysalt keysalt;
+
+ /* don't convert local TGT if we created a TGT already.... */
+ if (create_local_tgt && !strcmp(princ->name, "krbtgt") &&
+ !strcmp(princ->instance, realm)) {
+ if (verbose)
+ printf("\nignoring local TGT: '%s.%s' ...",
+ princ->name, princ->instance);
+ return 0;
+ }
+ if (!strcmp(princ->name, KERB_M_NAME) &&
+ !strcmp(princ->instance, KERB_M_INST)) {
+ des_cblock key_from_db;
+ int val;
+
+ /* here's our chance to verify the master key */
+ /*
+ * use the master key to decrypt the key in the db, had better
+ * be the same!
+ */
+ memcpy(key_from_db, (char *)&princ->key_low, 4);
+ memcpy(((char *) key_from_db) + 4, (char *)&princ->key_high, 4);
+ pcbc_encrypt((C_Block *) &key_from_db,
+ (C_Block *) &key_from_db,
+ (long) sizeof(C_Block),
+ master_key_schedule,
+ (C_Block *) master_key,
+ DECRYPT);
+ val = memcmp((char *) master_key, (char *) key_from_db,
+ sizeof(master_key));
+ memset((char *)key_from_db, 0, sizeof(key_from_db));
+ if (val) {
+ return KRB5_KDB_BADMASTERKEY;
+ }
+ if (verbose)
+ printf("\nignoring '%s.%s' ...", princ->name, princ->instance);
+ return 0;
+ }
+ memset((char *) &entry, 0, sizeof(entry));
+ if (retval = krb5_425_conv_principal(context, princ->name, princ->instance,
+ realm, &entry.princ))
+ return retval;
+ if (verbose) {
+ if (retval = krb5_unparse_name(context, entry.princ, &name))
+ name = strdup("<not unparsable name!>");
+ if (verbose)
+ printf("\ntranslating %s...", name);
+ free(name);
+ }
+
+ if (retval = krb5_build_principal(context, &mod_princ,
+ strlen(realm),
+ realm, princ->mod_name,
+ princ->mod_instance[0] ? princ->mod_instance : 0,
+ 0)) {
+ krb5_free_principal(context, entry.princ);
+ return retval;
+ }
+ mod_time = princ->mod_date;
+
+ entry.max_life = princ->max_life * 60 * 5;
+ entry.max_renewable_life = rblock.max_rlife;
+ entry.len = KRB5_KDB_V1_BASE_LENGTH;
+ entry.expiration = princ->exp_date;
+ entry.attributes = rblock.flags; /* XXX is there a way to convert
+ the old attrs? */
+
+ memcpy((char *)v4key, (char *)&(princ->key_low), 4);
+ memcpy((char *) (((char *) v4key) + 4), (char *)&(princ->key_high), 4);
+ pcbc_encrypt((C_Block *) &v4key,
+ (C_Block *) &v4key,
+ (long) sizeof(C_Block),
+ master_key_schedule,
+ (C_Block *) master_key,
+ DECRYPT);
+
+ v4v5key.magic = KV5M_KEYBLOCK;
+ v4v5key.contents = (krb5_octet *)v4key;
+ v4v5key.enctype = ENCTYPE_DES_CBC_CRC;
+ v4v5key.length = sizeof(v4key);
+
+ retval = krb5_dbe_create_key_data(context, &entry);
+ if (retval) {
+ krb5_free_principal(context, entry.princ);
+ krb5_free_principal(context, mod_princ);
+ return retval;
+ }
+
+ keysalt.type = KRB5_KDB_SALTTYPE_V4;
+ keysalt.data.length = 0;
+ keysalt.data.data = (char *) NULL;
+ retval = krb5_dbekd_encrypt_key_data(context, rblock.eblock,
+ &v4v5key, &keysalt,
+ princ->key_version,
+ &entry.key_data[0]);
+ if (!retval)
+ retval = krb5_dbe_update_mod_princ_data(context, &entry,
+ mod_time, mod_princ);
+ if (retval) {
+ krb5_db_free_principal(context, &entry, 1);
+ krb5_free_principal(context, mod_princ);
+ return retval;
+ }
+ memset((char *)v4key, 0, sizeof(v4key));
+
+ retval = krb5_db_put_principal(context, &entry, &nentries);
+
+ if (!retval && !strcmp(princ->name, "krbtgt") &&
+ strcmp(princ->instance, realm) && princ->instance[0]) {
+ krb5_free_principal(context, entry.princ);
+ if (retval = krb5_build_principal(context, &entry.princ,
+ strlen(princ->instance),
+ princ->instance,
+ "krbtgt", realm, 0))
+ return retval;
+ retval = krb5_db_put_principal(context, &entry, &nentries);
+ }
+
+ krb5_db_free_principal(context, &entry, 1);
+ krb5_free_principal(context, mod_princ);
+
+ return retval;
+}
+
+static krb5_error_code
+add_principal(context, princ, op, pblock)
+krb5_context context;
+krb5_principal princ;
+enum ap_op op;
+struct realm_info *pblock;
+{
+ krb5_db_entry entry;
+ krb5_error_code retval;
+ krb5_keyblock *rkey;
+ int nentries = 1;
+ krb5_timestamp mod_time;
+ krb5_principal mod_princ;
+
+ memset((char *) &entry, 0, sizeof(entry));
+ if (retval = krb5_copy_principal(context, princ, &entry.princ))
+ return(retval);
+ entry.max_life = pblock->max_life;
+ entry.max_renewable_life = pblock->max_rlife;
+ entry.len = KRB5_KDB_V1_BASE_LENGTH;
+ entry.expiration = pblock->expiration;
+
+ if ((retval = krb5_timeofday(context, &mod_time))) {
+ krb5_db_free_principal(context, &entry, 1);
+ return retval;
+ }
+ entry.attributes = pblock->flags;
+
+ if (retval = krb5_dbe_create_key_data(context, &entry)) {
+ krb5_db_free_principal(context, &entry, 1);
+ return(retval);
+ }
+
+ switch (op) {
+ case MASTER_KEY:
+ entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
+ if (retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock,
+ &master_keyblock,
+ (krb5_keysalt *) NULL, 1,
+ &entry.key_data[0])) {
+ krb5_db_free_principal(context, &entry, 1);
+ return retval;
+ }
+ break;
+ case RANDOM_KEY:
+ if (retval = krb5_random_key(context, pblock->eblock, pblock->rseed,
+ &rkey)) {
+ krb5_db_free_principal(context, &entry, 1);
+ return retval;
+ }
+ if (retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock,
+ rkey,
+ (krb5_keysalt *) NULL, 1,
+ &entry.key_data[0])) {
+ krb5_db_free_principal(context, &entry, 1);
+ return(retval);
+ }
+ krb5_free_keyblock(context, rkey);
+ break;
+ case NULL_KEY:
+ return EOPNOTSUPP;
+ default:
+ break;
+ }
+
+ retval = krb5_dbe_update_mod_princ_data(context, &entry,
+ mod_time, &db_create_princ);
+ if (!retval)
+ retval = krb5_db_put_principal(context, &entry, &nentries);
+ krb5_db_free_principal(context, &entry, 1);
+ return retval;
+}
+
+/*
+ * Convert a struct tm * to a UNIX time.
+ */
+
+
+#define daysinyear(y) (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
+
+#define SECSPERDAY 24*60*60
+#define SECSPERHOUR 60*60
+#define SECSPERMIN 60
+
+static int cumdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
+ 365};
+
+static int leapyear[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static int nonleapyear[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static long
+maketime(tp, local)
+register struct tm *tp;
+int local;
+{
+ register long retval;
+ int foo;
+ int *marray;
+
+ if (tp->tm_mon < 0 || tp->tm_mon > 11 ||
+ tp->tm_hour < 0 || tp->tm_hour > 23 ||
+ tp->tm_min < 0 || tp->tm_min > 59 ||
+ tp->tm_sec < 0 || tp->tm_sec > 59) /* out of range */
+ return 0;
+
+ retval = 0;
+ if (tp->tm_year < 1900)
+ foo = tp->tm_year + 1900;
+ else
+ foo = tp->tm_year;
+
+ if (foo < 1901 || foo > 2038) /* year is too small/large */
+ return 0;
+
+ if (daysinyear(foo) == 366) {
+ if (tp->tm_mon > 1)
+ retval+= SECSPERDAY; /* add leap day */
+ marray = leapyear;
+ } else
+ marray = nonleapyear;
+
+ if (tp->tm_mday < 0 || tp->tm_mday > marray[tp->tm_mon])
+ return 0; /* out of range */
+
+ while (--foo >= 1970)
+ retval += daysinyear(foo) * SECSPERDAY;
+
+ retval += cumdays[tp->tm_mon] * SECSPERDAY;
+ retval += (tp->tm_mday-1) * SECSPERDAY;
+ retval += tp->tm_hour * SECSPERHOUR + tp->tm_min * SECSPERMIN + tp->tm_sec;
+
+ if (local) {
+ /* need to use local time, so we retrieve timezone info */
+ struct timezone tz;
+ struct timeval tv;
+ if (gettimeofday(&tv, &tz) < 0) {
+ /* some error--give up? */
+ return(retval);
+ }
+ retval += tz.tz_minuteswest * SECSPERMIN;
+ }
+ return(retval);
+}
+
+static long
+time_explode(cp)
+register char *cp;
+{
+ char wbuf[5];
+ struct tm tp;
+ int local;
+
+ memset((char *)&tp, 0, sizeof(tp));
+
+ if (strlen(cp) > 10) { /* new format */
+ (void) strncpy(wbuf, cp, 4);
+ wbuf[4] = 0;
+ tp.tm_year = atoi(wbuf);
+ cp += 4; /* step over the year */
+ local = 0; /* GMT */
+ } else { /* old format: local time,
+ year is 2 digits, assuming 19xx */
+ wbuf[0] = *cp++;
+ wbuf[1] = *cp++;
+ wbuf[2] = 0;
+ tp.tm_year = 1900 + atoi(wbuf);
+ local = 1; /* local */
+ }
+
+ wbuf[0] = *cp++;
+ wbuf[1] = *cp++;
+ wbuf[2] = 0;
+ tp.tm_mon = atoi(wbuf)-1;
+
+ wbuf[0] = *cp++;
+ wbuf[1] = *cp++;
+ tp.tm_mday = atoi(wbuf);
+
+ wbuf[0] = *cp++;
+ wbuf[1] = *cp++;
+ tp.tm_hour = atoi(wbuf);
+
+ wbuf[0] = *cp++;
+ wbuf[1] = *cp++;
+ tp.tm_min = atoi(wbuf);
+
+
+ return(maketime(&tp, local));
+}
+
+static krb5_error_code
+process_v4_dump(context, dumpfile, realm)
+krb5_context context;
+char *dumpfile;
+char *realm;
+{
+ krb5_error_code retval;
+ FILE *input_file;
+ Principal aprinc;
+ char exp_date_str[50];
+ char mod_date_str[50];
+ int temp1, temp2, temp3;
+ long time_explode();
+
+ input_file = fopen(dumpfile, "r");
+ if (!input_file)
+ return errno;
+
+ for (;;) { /* explicit break on eof from fscanf */
+ int nread;
+
+ memset((char *)&aprinc, 0, sizeof(aprinc));
+ nread = fscanf(input_file,
+ "%s %s %d %d %d %hd %x %x %s %s %s %s\n",
+ aprinc.name,
+ aprinc.instance,
+ &temp1,
+ &temp2,
+ &temp3,
+ &aprinc.attributes,
+ &aprinc.key_low,
+ &aprinc.key_high,
+ exp_date_str,
+ mod_date_str,
+ aprinc.mod_name,
+ aprinc.mod_instance);
+ if (nread != 12) {
+ retval = nread == EOF ? 0 : KRB5_KDB_DB_CORRUPT;
+ break;
+ }
+ aprinc.key_low = ntohl (aprinc.key_low);
+ aprinc.key_high = ntohl (aprinc.key_high);
+ aprinc.max_life = (unsigned char) temp1;
+ aprinc.kdc_key_ver = (unsigned char) temp2;
+ aprinc.key_version = (unsigned char) temp3;
+ aprinc.exp_date = time_explode(exp_date_str);
+ aprinc.mod_date = time_explode(mod_date_str);
+ if (aprinc.instance[0] == '*')
+ aprinc.instance[0] = '\0';
+ if (aprinc.mod_name[0] == '*')
+ aprinc.mod_name[0] = '\0';
+ if (aprinc.mod_instance[0] == '*')
+ aprinc.mod_instance[0] = '\0';
+ if (retval = enter_in_v5_db(context, realm, &aprinc))
+ break;
+ }
+ (void) fclose(input_file);
+ return retval;
+}
+
+static krb5_error_code fixup_database(context, realm)
+ krb5_context context;
+ char * realm;
+{
+ krb5_db_entry entry;
+ krb5_error_code retval;
+ int nprincs;
+ krb5_boolean more;
+
+ nprincs = 1;
+ if (retval = krb5_db_get_principal(context, &tgt_princ, &entry,
+ &nprincs, &more))
+ return retval;
+
+ if (nprincs == 0)
+ return 0;
+
+ entry.attributes |= KRB5_KDB_SUPPORT_DESMD5;
+
+ retval = krb5_db_put_principal(context, &entry, &nprincs);
+
+ if (nprincs)
+ krb5_db_free_principal(context, &entry, nprincs);
+
+ return retval;
+}
+
+#else /* KRB5_KRB4_COMPAT */
+void
+load_v4db(argc, argv)
+ int argc;
+ char *argv[];
+{
+ printf("This version of krb5_edit does not support the V4 load command.\n");
+}
+#endif /* KRB5_KRB4_COMPAT */
diff --git a/src/kadmin/dbutil/ss_wrapper.c b/src/kadmin/dbutil/ss_wrapper.c
new file mode 100644
index 000000000..ada85efc9
--- /dev/null
+++ b/src/kadmin/dbutil/ss_wrapper.c
@@ -0,0 +1,85 @@
+/*
+ * admin/edit/ss_wrapper.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * ss wrapper for kdb5_edit
+ */
+
+#include <k5-int.h>
+#include "kdb5_util.h"
+#include <ss/ss.h>
+#include <stdio.h>
+
+extern ss_request_table kdb5_edit_cmds;
+extern int exit_status;
+extern FILE *scriptfile;
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *request;
+ krb5_error_code retval;
+ int sci_idx, code = 0;
+
+ request = kdb5_util_Init(argc, argv);
+ sci_idx = ss_create_invocation("kdb5_util", "5.0", (char *) NULL,
+ &kdb5_edit_cmds, &retval);
+ if (retval) {
+ ss_perror(sci_idx, retval, "creating invocation");
+ exit(1);
+ }
+
+ if (request) {
+ code = ss_execute_line(sci_idx, request, &code);
+ if (code != 0) {
+ ss_perror(sci_idx, code, request);
+ exit_status++;
+ }
+ } else if (scriptfile) {
+ char *command;
+ int nread;
+
+ /* Get a buffer */
+ if ((command = (char *) malloc(BUFSIZ))) {
+ /* Process commands from the script until end-of-file or error */
+ while (!feof(scriptfile) &&
+ (fgets(command, BUFSIZ, scriptfile))) {
+
+ /* Strip trailing newline */
+ if (command[strlen(command)-1] == '\n')
+ command[strlen(command)-1] = '\0';
+
+ /* Execute the command */
+ code = ss_execute_line(sci_idx, command, &code);
+ if (code != 0) {
+ ss_perror(sci_idx, code, command);
+ exit_status++;
+ break;
+ }
+ }
+ free(command);
+ }
+ } else
+ ss_listen(sci_idx, &retval);
+ return quit() ? 1 : exit_status;
+}
diff --git a/src/kadmin/dbutil/string_table.c b/src/kadmin/dbutil/string_table.c
new file mode 100644
index 000000000..b9f86a363
--- /dev/null
+++ b/src/kadmin/dbutil/string_table.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+/* String table of messages for kadm5_create */
+
+char *str_INITING_KCONTEXT = "while initializing the kerberos context";
+
+char *str_PARSE_NAME = "while parsing admin principal name.";
+
+char *str_HISTORY_PARSE_NAME = "while parsing admin history principal name.";
+
+char *str_ADMIN_PRINC_EXISTS = "Warning! Admin principal already exists.";
+
+char *str_CHANGEPW_PRINC_EXISTS = "Warning! Changepw principal already exists.";
+
+char *str_HISTORY_PRINC_EXISTS = "Warning! Admin history principal already exists.";
+
+char *str_ADMIN_PRINC_WRONG_ATTRS =
+ "Warning! Admin principal has incorrect attributes.\n"
+ "\tDISALLOW_TGT should be set, and max_life should be three hours.\n"
+ "\tThis program will leave them as-is, but beware!.";
+
+char *str_CHANGEPW_PRINC_WRONG_ATTRS =
+ "Warning! Changepw principal has incorrect attributes.\n"
+ "\tDISALLOW_TGT and PW_CHANGE_SERVICE should both be set, and "
+ "max_life should be five minutes.\n"
+ "\tThis program will leave them as-is, but beware!.";
+
+char *str_HISTORY_PRINC_WRONG_ATTRS =
+ "Warning! Admin history principal has incorrect attributes.\n"
+ "\tDISALLOW_ALL_TIX should be set.\n"
+ "\tThis program will leave it as-is, but beware!.";
+
+char *str_CREATED_PRINC_DB =
+ "%s: Admin principal database created (or it already existed).\n"; /* whoami */
+
+char *str_CREATED_POLICY_DB =
+ "%s: Admin policy database created (or it already existed).\n"; /* whoami */
+
+char *str_RANDOM_KEY =
+ "while calling random key for %s."; /* principal name */
+
+char *str_ENCRYPT_KEY =
+ "while calling encrypt key for %s."; /* principal name */
+
+char *str_PUT_PRINC =
+ "while calling storing %s in Kerberos database."; /* principal name */
+
+char *str_CREATING_POLICY_DB = "while creating/opening admin policy database.";
+
+char *str_CLOSING_POLICY_DB = "while closing admin policy database.";
+
+char *str_CREATING_PRINC_DB = "while creating/opening admin principal database.";
+
+char *str_CLOSING_PRINC_DB = "while closing admin principal database.";
+
+char *str_CREATING_PRINC_ENTRY =
+ "while creating admin principal database entry for %s."; /* princ_name */
+
+char *str_A_PRINC = "a principal";
+
+char *str_UNPARSE_PRINC = "while unparsing principal.";
+
+char *str_CREATED_PRINC = "%s: Created %s principal.\n"; /* whoami, princ_name */
+
+char *str_INIT_KDB = "while initializing kdb.";
+
+char *str_NO_KDB =
+"while initializing kdb.\nThe Kerberos KDC database needs to exist in /krb5.\n\
+If you haven't run kdb5_create you need to do so before running this command.";
+
+
+char *str_INIT_RANDOM_KEY = "while initializing random key generator.";
+
+char *str_TOO_MANY_ADMIN_PRINC =
+ "while fetching admin princ. Can only have one admin principal.";
+
+char *str_TOO_MANY_CHANGEPW_PRINC =
+ "while fetching changepw princ. Can only have one changepw principal.";
+
+char *str_TOO_MANY_HIST_PRINC =
+ "while fetching history princ. Can only have one history principal.";
+
+char *str_WHILE_DESTROYING_ADMIN_SESSION = "while closing session with admin server and destroying tickets.";
diff --git a/src/kadmin/dbutil/string_table.h b/src/kadmin/dbutil/string_table.h
new file mode 100644
index 000000000..e8cb45367
--- /dev/null
+++ b/src/kadmin/dbutil/string_table.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef _OVSEC_ADM_STRINGS_
+
+extern char *str_INITING_KCONTEXT;
+extern char *str_PARSE_NAME;
+extern char *str_HISTORY_PARSE_NAME;
+extern char *str_ADMIN_PRINC_EXISTS;
+extern char *str_CHANGEPW_PRINC_EXISTS;
+extern char *str_HISTORY_PRINC_EXISTS;
+extern char *str_ADMIN_PRINC_WRONG_ATTRS;
+extern char *str_CHANGEPW_PRINC_WRONG_ATTRS;
+extern char *str_HISTORY_PRINC_WRONG_ATTRS;
+extern char *str_CREATED_PRINC_DB;
+extern char *str_CREATED_POLICY_DB;
+extern char *str_RANDOM_KEY;
+extern char *str_ENCRYPT_KEY;
+extern char *str_PUT_PRINC;
+extern char *str_CREATING_POLICY_DB;
+extern char *str_CLOSING_POLICY_DB;
+extern char *str_CREATING_PRINC_DB;
+extern char *str_CLOSING_PRINC_DB;
+extern char *str_CREATING_PRINC_ENTRY;
+extern char *str_A_PRINC;
+extern char *str_UNPARSE_PRINC;
+extern char *str_CREATED_PRINC;
+extern char *str_INIT_KDB;
+extern char *str_NO_KDB;
+extern char *str_INIT_RANDOM_KEY;
+extern char *str_TOO_MANY_ADMIN_PRINC;
+extern char *str_TOO_MANY_CHANGEPW_PRINC;
+extern char *str_TOO_MANY_HIST_PRINC;
+extern char *str_WHILE_DESTROYING_ADMIN_SESSION;
+
+#endif /* _OVSEC_ADM_STRINGS_ */
diff --git a/src/kadmin/dbutil/tcl_wrapper.c b/src/kadmin/dbutil/tcl_wrapper.c
new file mode 100644
index 000000000..d527fa0d1
--- /dev/null
+++ b/src/kadmin/dbutil/tcl_wrapper.c
@@ -0,0 +1,235 @@
+/*
+ * admin/edit/tcl_wrapper.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Tcl wrapper for kdb5_edit
+ */
+
+#include "k5-int.h"
+#include "kdb5_edit.h"
+#include <tcl.h>
+
+#define CMDDECL(x) int x(clientData, interp, argc, argv)\
+ ClientData clientData;\
+ Tcl_Interp * interp;\
+ int argc;\
+ char ** argv;
+#define CMDPROTO(x) int x PROTOTYPE((ClientData, Tcl_Interp,\
+ int, char **))
+#define MKCMD(name,cmd) Tcl_CreateCommand(interp, name, cmd,\
+ (ClientData)NULL,\
+ (Tcl_CmdDeleteProc *)NULL)
+
+extern int main();
+int *tclDummyMainPtr = (int *) main; /* force ld to suck in main()
+ from libtcl.a */
+extern Tcl_Interp *interp; /* XXX yes, this is gross,
+ but we do need it for some things */
+extern int exit_status;
+
+void show_principal PROTOTYPE((int, char **));
+void add_new_key PROTOTYPE((int, char **));
+void change_pwd_key PROTOTYPE((int, char **));
+void add_rnd_key PROTOTYPE((int, char **));
+void change_rnd_key PROTOTYPE((int, char **));
+void delete_entry PROTOTYPE((int, char **));
+void extract_srvtab PROTOTYPE((krb5_context, int, char **));
+void extract_v4_srvtab PROTOTYPE((int, char **));
+void list_db PROTOTYPE((int, char **));
+void dump_db PROTOTYPE((int, char **));
+void load_db PROTOTYPE((int, char **));
+void set_dbname PROTOTYPE((krb5_context, int, char **));
+void enter_master_key PROTOTYPE((krb5_context, int, char **));
+
+/*
+ * this is mostly stolen from tcl_ExitCmd()
+ * we need to do a few extra things, though...
+ */
+int doquit(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ int argc;
+ char *argv[];
+{
+ int value;
+
+ if ((argc != 1) && (argc != 2)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ?returnCode?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (argc == 1) {
+ exit(quit() ? 1 : exit_status);
+ }
+ if (Tcl_GetInt(interp, argv[1], &value) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ (void)quit();
+ exit(value);
+ /*NOTREACHED*/
+ return TCL_OK; /* Better not ever reach this! */
+}
+
+int list_requests(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ int argc;
+ char *argv[];
+{
+ Tcl_SetResult(interp, "show_principal, show: Show the Kerberos database entry for a principal\nadd_new_key, ank: Add new entry to the Kerberos database (prompting for password\nchange_pwd_key, cpw: Change key of an entry in the Kerberos database (prompting for password)\nadd_rnd_key, ark: Add new entry to Kerberos database, using a random key\nchange_rnd_key, crk: Change key of an entry in the Kerberos database (select a random key)\ndelete_entry, delent: Delete an entry from the database\nextract_srvtab, xst, ex_st: Extract service key table\nextract_v4_srvtab, xst4: Extract service key table\nlist_db, ldb: List database entries\nset_dbname, sdbn: Change database name\nenter_master_key, emk: Enter the master key for a database\nchange_working_directory, cwd, cd: Change working directory\nprint_working_directory, pwd: Print working directory\nlist_requests, lr: List available requests\nquit, exit: Exit program", TCL_STATIC);
+ return TCL_OK;
+}
+
+int wrapper(func, interp, argc, argv)
+ void (*func)();
+ Tcl_Interp *interp;
+ int argc;
+ char *argv[];
+{
+ (*func)(argc, argv);
+ return TCL_OK;
+}
+
+int Tcl_AppInit(interp)
+ Tcl_Interp *interp;
+{
+ int argc;
+ char **argv, **mostly_argv;
+ char *interp_argv, *interp_argv0, *request;
+ Tcl_CmdInfo cmdInfo;
+
+ if (Tcl_Init(interp) == TCL_ERROR)
+ return TCL_ERROR;
+ /*
+ * the following is, admittedly, sorta gross, but the only way
+ * to grab the original argc, argv once the interpreter is running
+ */
+ interp_argv = Tcl_GetVar(interp, "argv", 0);
+ if (interp_argv == NULL)
+ return TCL_ERROR;
+ else if (Tcl_SplitList(interp, interp_argv,
+ &argc, &mostly_argv) != TCL_OK)
+ return TCL_ERROR;
+ interp_argv0 = Tcl_GetVar(interp, "argv0", 0);
+ if (interp_argv0 == NULL)
+ return TCL_ERROR;
+ if ((argv = (char **)malloc((argc + 1) * sizeof (char *))) == NULL)
+ return TCL_ERROR;
+ argv[0] = interp_argv0;
+ memcpy(argv + 1, mostly_argv, argc++ * sizeof (char *));
+ /*
+ * set up a prompt
+ */
+ if (Tcl_SetVar(interp, "tcl_prompt1",
+ "puts -nonewline \"kdb5_edit: \"", 0) == NULL)
+ return TCL_ERROR;
+ /*
+ * we don't want arbitrary programs to get exec'd by accident
+ */
+ if (Tcl_SetVar(interp, "auto_noexec", "{}", 0) == NULL)
+ return TCL_ERROR;
+ request = kdb5_edit_Init(argc, argv);
+ Tcl_CallWhenDeleted(interp, doquit,
+ (ClientData)0);
+ Tcl_CreateCommand(interp, "quit", doquit,
+ (ClientData)0,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "exit", doquit,
+ (ClientData)0,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "list_requests", list_requests,
+ (ClientData)0,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "lr", list_requests,
+ (ClientData)0,
+ (Tcl_CmdDeleteProc *)0);
+ if (Tcl_GetCommandInfo(interp, "cd", &cmdInfo)) {
+ Tcl_CreateCommand(interp, "cwd", cmdInfo.proc,
+ (ClientData)0,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "change_working_directory", cmdInfo.proc,
+ (ClientData)0,
+ (Tcl_CmdDeleteProc *)0);
+ }
+ if (Tcl_GetCommandInfo(interp, "pwd", &cmdInfo)) {
+ Tcl_CreateCommand(interp, "print_working_directory", cmdInfo.proc,
+ (ClientData)0,
+ (Tcl_CmdDeleteProc *)0);
+ }
+ Tcl_CreateCommand(interp, "show_principal", wrapper, show_principal,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "show", wrapper, show_principal,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "add_new_key", wrapper, add_new_key,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "ank", wrapper, add_new_key,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "change_pwd_key", wrapper, change_pwd_key,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "cpw", wrapper, change_pwd_key,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "add_rnd_key", wrapper, add_rnd_key,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "ark", wrapper, add_rnd_key,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "change_rnd_key", wrapper, change_rnd_key,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "crk", wrapper, change_rnd_key,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "delete_entry", wrapper, delete_entry,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "delent", wrapper, delete_entry,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "extract_srvtab", wrapper, extract_srvtab,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "xst", wrapper, extract_srvtab,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "ex_st", wrapper, extract_srvtab,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "extract_v4_srvtab", wrapper, extract_v4_srvtab,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "xv4st", wrapper, extract_v4_srvtab,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "list_db", wrapper, list_db,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "ldb", wrapper, list_db,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "dump_db", wrapper, dump_db,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "ddb", wrapper, dump_db,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "load_db", wrapper, load_db,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "lddb", wrapper, load_db,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "set_dbname", wrapper, set_dbname,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "sdbn", wrapper, set_dbname,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "enter_master_key", wrapper, enter_master_key,
+ (Tcl_CmdDeleteProc *)0);
+ Tcl_CreateCommand(interp, "emk", wrapper, enter_master_key,
+ (Tcl_CmdDeleteProc *)0);
+ if (request && (Tcl_Eval(interp, request) == TCL_ERROR))
+ return TCL_ERROR;
+ return TCL_OK;
+}
diff --git a/src/kadmin/dbutil/util.c b/src/kadmin/dbutil/util.c
new file mode 100644
index 000000000..78de2cd6f
--- /dev/null
+++ b/src/kadmin/dbutil/util.c
@@ -0,0 +1,155 @@
+/*
+ * admin/edit/util.c
+ *
+ * Copyright 1992 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Utilities for kdb5_edit.
+ *
+ * Some routines derived from code contributed by the Sandia National
+ * Laboratories. Sandia National Laboratories also makes no
+ * representations about the suitability of the modifications, or
+ * additions to this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ */
+
+#include "k5-int.h"
+#include "./kdb5_edit.h"
+
+#if defined(sysvimp) || ( defined(mips) && defined(SYSTYPE_BSD43)) || (defined(vax) && !defined(ultrix))
+char *
+strstr(s1, s2)
+char *s1;
+char *s2;
+{
+ int s2len;
+ int i;
+ char *temp_ptr;
+
+ temp_ptr = s1;
+ for ( i = 0; i < strlen(s1); i++) {
+ if (memcmp(temp_ptr, s2, strlen(s2)) == 0) return(temp_ptr);
+ temp_ptr += 1;
+ }
+ return ((char *) 0);
+}
+#endif /* sysvimp */
+
+void
+parse_token(token_in, must_be_first_char, num_tokens, tokens_out)
+char *token_in;
+int *must_be_first_char;
+int *num_tokens;
+char *tokens_out;
+{
+ int i, j;
+ int token_count = 0;
+
+ i = 0;
+ j = 0;
+
+ /* Eliminate Up Front Asterisks */
+ *must_be_first_char = 1;
+ for (i = 0; token_in[i] == '*'; i++) {
+ *must_be_first_char = 0;
+ }
+
+ if (i == strlen(token_in)) {
+ *num_tokens = 0;
+ return;
+ }
+
+ /* Fill first token_out */
+ token_count++;
+ while ((token_in[i] != '*') && (token_in[i] != '\0')) {
+ tokens_out[j] = token_in[i];
+ j++;
+ i++;
+ }
+
+ if (i == strlen(token_in)) {
+ tokens_out[j] = '\0';
+ *num_tokens = token_count;
+ return;
+ }
+
+ /* Then All Subsequent Tokens */
+ while (i < strlen(token_in)) {
+ if (token_in[i] == '*') {
+ token_count++;
+ tokens_out[j] = '\t';
+ } else {
+ tokens_out[j] = token_in[i];
+ }
+ i++;
+ j++;
+ }
+ tokens_out[j] = '\0';
+
+ if (tokens_out[j - 1] == '\t') {
+ token_count--;
+ tokens_out[j - 1] = '\0';
+ }
+
+ *num_tokens = token_count;
+ return;
+}
+
+int
+check_for_match(search_field, must_be_first_character, chk_entry,
+ num_tokens, type)
+int must_be_first_character;
+char *search_field;
+krb5_db_entry *chk_entry;
+int num_tokens;
+int type;
+{
+ char token1[256];
+ char *found1;
+ char token2[256];
+ char *found2;
+ char token3[256];
+ char *found3;
+ char *local_entry;
+
+ local_entry = chk_entry->princ->data[type].data;
+
+ token1[0] = token2[0] = token3[0] = '\0';
+
+ (void) sscanf(search_field, "%s\t%s\t%s", token1, token2, token3);
+
+ found1 = strstr(local_entry, token1);
+
+ if (must_be_first_character && (found1 != local_entry)) return(0);
+
+ if (found1 && (num_tokens == 1)) return(1);
+
+ if (found1 && (num_tokens > 1)) {
+ found2 = strstr(local_entry, token2);
+ if (found2 && (found2 > found1) && (num_tokens == 2)) return(1);
+ }
+
+ if ((found2 > found1) && (num_tokens == 3)) {
+ found3 = strstr(local_entry, token3);
+ if (found3 && (found3 > found2) && (found2 > found1)) return(1);
+ }
+ return(0);
+}
+