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