diff options
| author | Marc Horowitz <marc@mit.edu> | 1996-07-22 20:49:46 +0000 |
|---|---|---|
| committer | Marc Horowitz <marc@mit.edu> | 1996-07-22 20:49:46 +0000 |
| commit | edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1 (patch) | |
| tree | 6c2974a97b448c040fa4a31708ec5e02f187526c /src/kadmin/dbutil | |
| parent | 013bb1391582ed9e653ae706e398ddb8d08cfcc9 (diff) | |
this commit includes all the changes on the OV_9510_INTEGRATION and
OV_MERGE branches. This includes, but is not limited to, the new openvision
admin system, and major changes to gssapi to add functionality, and bring
the implementation in line with rfc1964. before committing, the
code was built and tested for netbsd and solaris.
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@8774 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/kadmin/dbutil')
| -rw-r--r-- | src/kadmin/dbutil/ChangeLog | 440 | ||||
| -rw-r--r-- | src/kadmin/dbutil/Makefile.in | 18 | ||||
| -rw-r--r-- | src/kadmin/dbutil/Makefile.ov | 19 | ||||
| -rw-r--r-- | src/kadmin/dbutil/configure.in | 13 | ||||
| -rw-r--r-- | src/kadmin/dbutil/dump.c | 1957 | ||||
| -rw-r--r-- | src/kadmin/dbutil/dumpv4.c | 411 | ||||
| -rw-r--r-- | src/kadmin/dbutil/kadm5_create.c | 241 | ||||
| -rw-r--r-- | src/kadmin/dbutil/kdb5_create.c | 449 | ||||
| -rw-r--r-- | src/kadmin/dbutil/kdb5_destroy.c | 117 | ||||
| -rw-r--r-- | src/kadmin/dbutil/kdb5_edit.M | 179 | ||||
| -rw-r--r-- | src/kadmin/dbutil/kdb5_stash.c | 153 | ||||
| -rw-r--r-- | src/kadmin/dbutil/kdb5_util.M | 122 | ||||
| -rw-r--r-- | src/kadmin/dbutil/kdb5_util.c | 416 | ||||
| -rw-r--r-- | src/kadmin/dbutil/kdb5_util.h | 49 | ||||
| -rw-r--r-- | src/kadmin/dbutil/kdb5_util_ct.ct | 56 | ||||
| -rw-r--r-- | src/kadmin/dbutil/loadv4.c | 881 | ||||
| -rw-r--r-- | src/kadmin/dbutil/ss_wrapper.c | 85 | ||||
| -rw-r--r-- | src/kadmin/dbutil/string_table.c | 91 | ||||
| -rw-r--r-- | src/kadmin/dbutil/string_table.h | 40 | ||||
| -rw-r--r-- | src/kadmin/dbutil/tcl_wrapper.c | 235 | ||||
| -rw-r--r-- | src/kadmin/dbutil/util.c | 155 |
21 files changed, 6127 insertions, 0 deletions
diff --git a/src/kadmin/dbutil/ChangeLog b/src/kadmin/dbutil/ChangeLog new file mode 100644 index 0000000000..7719cc749b --- /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 0000000000..b5bba09d99 --- /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 0000000000..f762282f25 --- /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 0000000000..c9234524ef --- /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 0000000000..8bd54ca4dd --- /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, + ®exp_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 0000000000..a51626db34 --- /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 0000000000..d31ce33192 --- /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 0000000000..b7520d98d1 --- /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 0000000000..7c6873df7b --- /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 0000000000..8405c01cd1 --- /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 0000000000..6952db7ec1 --- /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 0000000000..746e018c01 --- /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 0000000000..3f31fcb146 --- /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 0000000000..b580e2f6a5 --- /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 0000000000..bac1df125c --- /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 0000000000..a1d37edc77 --- /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 0000000000..ada85efc9a --- /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 0000000000..b9f86a3634 --- /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 0000000000..e8cb45367c --- /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 0000000000..d527fa0d18 --- /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 0000000000..78de2cd6f9 --- /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); +} + |
