summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorEzra Peisach <epeisach@mit.edu>1996-08-24 16:03:45 +0000
committerEzra Peisach <epeisach@mit.edu>1996-08-24 16:03:45 +0000
commit892f77f6b49d8d31813c997e3bc1a805e66f400c (patch)
tree66790aee50958422384b73e7a1341321745d5b4b /src/lib
parent2240d3c96c105f0d19ba2a197b34772f70000c7c (diff)
downloadkrb5-892f77f6b49d8d31813c997e3bc1a805e66f400c.tar.gz
krb5-892f77f6b49d8d31813c997e3bc1a805e66f400c.tar.xz
krb5-892f77f6b49d8d31813c997e3bc1a805e66f400c.zip
Ack - kadm is still used by the Mac and dos build trees
Everything restored... git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@8982 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/kadm/.Sanitize49
-rw-r--r--src/lib/kadm/ChangeLog334
-rw-r--r--src/lib/kadm/Makefile.in92
-rw-r--r--src/lib/kadm/adm_conn.c762
-rw-r--r--src/lib/kadm/adm_kt_dec.c127
-rw-r--r--src/lib/kadm/adm_kt_enc.c162
-rw-r--r--src/lib/kadm/adm_kw_dec.c578
-rw-r--r--src/lib/kadm/adm_kw_enc.c433
-rw-r--r--src/lib/kadm/adm_rw.c534
-rw-r--r--src/lib/kadm/alt_prof.c447
-rw-r--r--src/lib/kadm/configure.in16
-rw-r--r--src/lib/kadm/keysalt.c207
-rw-r--r--src/lib/kadm/krb5strings.M250
-rw-r--r--src/lib/kadm/logger.c940
-rw-r--r--src/lib/kadm/str_conv.c221
-rw-r--r--src/lib/kadm/t_dbentry.c965
-rw-r--r--src/lib/kadm/t_ktentry.c402
17 files changed, 6519 insertions, 0 deletions
diff --git a/src/lib/kadm/.Sanitize b/src/lib/kadm/.Sanitize
new file mode 100644
index 000000000..4f33eec41
--- /dev/null
+++ b/src/lib/kadm/.Sanitize
@@ -0,0 +1,49 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize". All keyword lines must exist,
+# and must exist in the order specified by this file. Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done. Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept. All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called. Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+adm_conn.c
+adm_kw_dec.c
+adm_kw_enc.c
+adm_kt_dec.c
+adm_kt_enc.c
+adm_rw.c
+alt_prof.c
+configure.in
+configure
+keysalt.c
+krb5strings.M
+logger.c
+str_conv.c
+t_dbentry.c
+t_ktentry.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/src/lib/kadm/ChangeLog b/src/lib/kadm/ChangeLog
new file mode 100644
index 000000000..ac07e1981
--- /dev/null
+++ b/src/lib/kadm/ChangeLog
@@ -0,0 +1,334 @@
+Thu Jun 13 22:12:21 1996 Tom Yu <tlyu@voltage-multiplier.mit.edu>
+
+ * configure.in: remove ref to ET_RULES
+
+Mon Jun 10 21:42:26 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
+
+ * adm_conn.c:
+ * adm_kw_dec.c:
+ * adm_kw_enc.c: Change use of _WINDOWS to _MSDOS, and add check
+ for _WIN32
+
+Tue May 21 20:51:06 1996 Sam Hartman <hartmans@mit.edu>
+
+ * Makefile.in (check-unix): Use KRB5_RUN_FLAGS
+
+Sun May 12 00:46:57 1996 Marc Horowitz <marc@mit.edu>
+
+ * alt_prof.c (krb5_read_realm_params): added "acl_file" variable
+ for the admin server.
+
+Wed Mar 13 17:37:00 1996 Ken Raeburn <raeburn@cygnus.com>
+
+ * configure.in: Use AC_HEADER_STDARG.
+
+Sun Dec 10 11:02:56 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * str_conv.c (krb5_input_flag_to_string): Add new routine.
+
+Wed Nov 8 02:46:54 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * alt_prof.c (krb5_free_realm_params): Free the realm_kdc_ports
+ element of the structure.
+
+Fri Oct 6 00:30:16 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * Makefile.in: Remove ##DOS!include of config/windows.in.
+ config/windows.in is now included by wconfig.
+
+ * logger.c (klog_vsyslog): Make the logs less verbose, by omitting
+ the hostname, pid, etc. information.
+
+Thu Oct 5 19:46:40 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * alt_prof.c (krb5_read_realm_params): Remove the profile
+ relation, since it's really a bad idea. Removed the
+ "port" and "secondary_port" relations, and replaced them
+ with the "kdc_port" relation, which takes a list of ports.
+
+Mon Oct 2 15:08:53 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * logger.c (krb5_klog_init): If the log file can't be opened,
+ print an intelligent error message.
+
+Thu Oct 5 12:06:35 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * alt_prof.c (krb5_read_realm_params): If secure flag is set in
+ context, do not allow for environment variables to specify
+ configuration files.
+
+Tue Sep 26 02:31:38 1995 Mark Eichin <eichin@cygnus.com>
+
+ * adm_conn.c (kadm_get_creds): zero out creds->server after
+ freeing it to protect later attempts.
+
+Fri Sep 29 17:06:18 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * logger.c: #ifdef the entire file so it's not built under Windows.
+
+Tue Sep 27 12:00:00 1995 <jrivlin@fusion.com>
+
+ * adm_kw_dec.c (krb5_adm_proto_to_dbent): Routine removed for
+ Windows and Mac to match with the prototype.
+
+ * adm_kw_dec.c (krb5_adm_dbent_to_proto): Routine removed for
+ Windows and Mac to match with the prototype.
+
+Tue Sep 26 16:24:00 1995 <tytso@rsts-11.mit.edu>
+
+ * alt_prof.c (krb5_read_realm_params): On an error, initialize the
+ returned rparams pointer to NULL.
+
+Mon Sep 25 16:54:18 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+ Makefile.
+
+Fri Sep 22 12:00:00 1995 James Mattly <mattly@fusion.com>
+
+ * adm_conn.c: for sockets changed close to closesocket, sockets on
+ macintosh arn't files.
+
+Fri Sep 22 15:44:02 1995 Mark Eichin <eichin@cygnus.com>
+
+ * logger.c (klog_com_err_proc): pass whoami in failure messages
+ for error log failures to match format string.
+
+Wed Sep 13 10:45:25 1995 Keith Vetter (keithv@fusion.com)
+
+ * keysalt.c: 16/32 bit integer mismatch.
+ * str_conv.c: sftime_format_table is conditional upon HAVE_STRFTIME,
+ cast some constants to long so that math wouldn't overflow,
+ 16/32 bit integer size mismatch.
+
+Wed Sep 13 18:17:30 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * alt_prof.c (krb5_read_realm_params): Fix memory leak. Free the
+ default realm when we're done. Remove the "profile"
+ parameter from the kdc.conf file. This is bad idea,
+ architecturally.
+
+Tue Sep 12 13:18:42 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * adm_conn.c: For Macintosh hardwire cache name. Various casting
+ fixes.
+
+Thu Sep 7 17:50:15 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * adm_conn.c (kadm_get_creds): Use KRB5_ADM_SERVICE_INSTANCE for
+ the instance name, instead of KRB5_ADM_SERVICE_NAME.
+
+Wed Sep 06 14:20:57 1995 Chris Provenzano (proven@mit.edu)
+
+ * adm_kt_dec.c, adm_kt_enc.c, alt_prof.c, keysalt.c, str_conv.c :
+ s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995 Chris Provenzano (proven@mit.edu)
+
+ * adm_kt_dec.c, adm_kt_enc.c, alt_prof.c, str_conv.c:
+ Remove krb5_enctype references, and replace
+ with krb5_keytype where appropriate
+
+Tue Aug 29 15:31:50 EDT 1995 Paul Park (pjpark@mit.edu)
+ * .Sanitize, krb5strings.M - Add new manpage describing string syntax
+ for common datatypes handled by str_conv.c.
+
+Thu Aug 24 18:53:32 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * .Sanitize: Update file list
+
+Mon Aug 21 17:07:56 EDT 1995 Paul Park (pjpark@mit.edu)
+ * str_conv.c - Add krb5_timestamp_to_sfstring(). This converts time
+ to a short string, potentially filled. Use strftime() for
+ krb5_timestamp_to_string() if present so that locale-dependent
+ time format is used.
+
+
+Tue Aug 8 17:35:10 EDT 1995 Paul Park (pjpark@mit.edu)
+ * str_conv.c - Fix Purify complaint.
+
+
+Mon Aug 7 17:38:45 EDT 1995 Paul Park (pjpark@mit.edu)
+ * keysalt.c(krb5_string_to_keysalt) - Don't do the silly whitespace
+ filling logic. If the string has imbedded whitespace, then
+ it's just tough rocks. Save replaced string separators and
+ terminators so that they string looks the same coming out as
+ going in.
+
+
+Fri Aug 4 16:21:50 EDT 1995 Paul Park (pjpark@mit.edu)
+ * Makefile.in, .Sanitize, keysalt.c - Add keysalt.c modules.
+
+
+Thu Aug 3 11:51:14 EDT 1995 Paul Park (pjpark@mit.edu)
+ * alt_prof.c - Actually pass back the parsed string value in krb5_aprof_
+ get_deltat().
+
+
+Mon Jul 31 15:52:40 EDT 1995 Paul Park (pjpark@mit.edu)
+ * adm_kw_{enc,dec}.c - Add support for new kadmin protocol.
+ * alt_prof.c - Remove string conversion routine, use the ones in str_
+ conv.c. Convert krb5_read_realm_params() to use these string
+ conversion routines so that the KDC profile is more textual
+ as opposed to being numeric.
+ * str_conv.c - String conversion routines.
+ * Makefile.in, configure.in - Add support for str_conv.c
+ * t_dbentry.c - Test new kadmin protocol.
+
+Mon Jul 17 15:16:26 EDT 1995 Paul Park (pjpark@mit.edu)
+ * alt_prof.c - Add krb5_{read,free}_realm_params() to read in per-
+ realm KDC data and to free the allocated structure.
+
+Mon Jul 10 17:59:23 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * adm_kt_dec.c, adm_kt_enc.c, adm_kw_dec.c, adm_kw_enc.c,
+ alt_prof.c, logger.c: Include adm_proto.h for prototypes.
+
+Fri Jul 7 16:23:57 EDT 1995 Paul Park (pjpark@mit.edu)
+ * Makefile.in - Remove LDFLAGS, it's set by configure. Find com_err
+ library in TOPLIBD now.
+
+Thu Jul 6 17:34:22 1995 Tom Yu <tlyu@lothlorien.MIT.EDU>
+
+ * adm_conn.c (kadm_get_creds): Pass kcontext to os_localaddr.
+
+Tue Jun 27 15:50:31 EDT 1995 Paul Park (pjpark@mit.edu)
+ * alt_prof.c - Change filename and hierarchy lists to be const char.
+
+
+Thu Jun 22 11:56:15 EDT 1995 Paul Park (pjpark@mit.edu)
+ * alt_prof.c - New jacket routines for handling profiles. This includes
+ the ability to parse certain string values to appropriate types
+ (e.g. delta time or 32-bit integer).
+ * Makefile.in - Add alt_prof.c
+
+
+Thu Jun 15 18:03:40 EDT 1995 Paul Park (pjpark@mit.edu)
+ * Makefile.in - Remove explicit copying of archive library to library
+ directory.
+ * configure.in - Create symlink for archive when we build it.
+
+Wed Jun 14 14:36:13 1995 Sam Hartman <hartmans@tardis.MIT.EDU>
+
+ * t_dbentry.c (main): option should be an int so that comparisons
+ against EOF work when char unsigned.
+
+Tue Jun 13 14:37:25 1995 Sam Hartman <hartmans@tardis.MIT.EDU>
+
+ * logger.c: Don't check to make sure unix is defined for
+ DEVICE_OPEN et al. Currently, there are no special cases where
+ special handling is required; if they are, then they should be
+ checked for, and the generic case taken if no special case fits.
+ The previous behavior broke under AIX.
+
+
+Sun Jun 11 09:24:06 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * Makefile.in (clean-unix): Remove $(UNIX_OBJS)
+
+Sat Jun 10 23:05:23 1995 Tom Yu (tlyu@dragons-lair)
+
+ * adm_conn.c, adm_rw.c: krb5_auth_context redefinitions
+
+Fri Jun 9 19:26:44 1995 <tytso@rsx-11.mit.edu>
+
+ * configure.in: Remove standardized set of autoconf macros, which
+ are now handled by CONFIG_RULES.
+
+Thu Jun 8 23:32:28 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * Makefile.in: $($(WHAT)_OBJS) is not accepted by all Makes! We
+ assume for now that libkadm.a rule is only used by Unix,
+ which should be a valid assumption, and build handle
+ $(UNIX_OBJS) there.
+
+Thu Jun 8 14:32:33 EDT 1995 Paul Park (pjpark@mit.edu)
+ * logger.c - New module to provide profile-controlled logging. This
+ can optionally take over control of com_err(3) output to also
+ direct this output to where the profile specifies. Also
+ includes a syslog(3) compatible interface which also follows
+ the profile's direction.
+ * Makefile.in, configure.in - update for logger.c
+
+
+Mon Jun 5 14:15:37 EDT 1995 Paul Park (pjpark@mit.edu)
+ * adm_conn.c - Rework kadm_get_ccache() and kadm_get_creds() so that
+ we can specify differing credentials caches and the lifetime
+ of obtained tickets if not using an existing ccache. This
+ changes the calling sequence of krb5_adm_connect(), adding
+ two arguments: a ccache name and a (delta) lifetime. Default
+ ccache name changes formats to tkt_kadm_<pid> and default
+ lifetime is 10 minutes.
+
+Fri Jun 2 17:56:03 1995 Keith Vetter (keithv@fusion.com)
+
+ * adm_conn.c: used SOCKET_ERRNO instead of errno and
+ added prototypes for the local functions.
+ * adm_rw.c: added prototypes for the local functions so that
+ ints get promoted to longs correctly on the PC.
+
+Wed May 31 08:10:13 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * Makefile.in (DB_OBJS): Change DBOBJS to DB_OBJS to match rest of
+ Makefile.in
+
+Tue May 30 17:36:47 1995 Keith Vetter (keithv@fusion.com)
+
+ * adm_rw.c: removed INTERFACE from two routines.
+
+Tue May 30 10:35:07 1995 Keith Vetter (keithv@fusion.com)
+
+ * adm_conn.c: used Windows specific way of creating a temp file.
+ * Makefile.in: PC doesn't need to compile adm_kw_*.c files.
+
+Thu May 25 17:49:06 1995 Keith Vetter (keithv@fusion.com)
+
+ First pass to make the code compile cleanly on the PC.
+ * Makefile.in: made to work on the PC.
+ * adm_conn.c: used atoi instead of sscanf since it can't be
+ used in a windows DLL. Why not? Ask Microsoft.
+ * adm_kt_e.c, adm_kw_e.c, adm_rw.c: made the explicit the
+ cast to a char when pulling out bytes from an int.
+ * adm_kw_d.c: size_t != off_t on the PC. Fixed the equation.
+ * adm_rw.c: two parameters were declared as int but prototyped
+ as krb5_int32.
+
+Tue May 16 13:58:30 EDT 1995 Paul Park (pjpark@mit.edu)
+ * configure.in - Check for srand48, srand and srandom along with
+ network libraries.
+ * t_ktentry.c, t_dbentry.c - Use available random number generator
+ and also make sure memory is freed so we don't
+ chew up memory in tester.
+
+
+Tue May 16 13:19:04 EDT 1995 Paul Park (pjpark@mit.edu)
+ * t_dbentry.c - Change isset to is_a_set to keep Ultrix happy. Also
+ correctly calculate the length of the standard pwd.
+ so that we don't overwrite the end of the malloc()ed
+ string.
+ * t_ktentry.c - Remove isset logic, no differentiation for keytabs.
+
+
+Tue May 16 10:35:54 EDT 1995 Paul Park (pjpark@mit.edu)
+ * t_dbentry.c, t_ktentry.c - new test modules for encode/decode
+ functions. These convert to and from krb5_db_entry and
+ krb5_keytab_entry and verify contents.
+ * adm_kt_enc.c - Fix bug encoding integer values.
+
+
+Tue May 9 15:21:49 EDT 1995 Paul Park (pjpark@mit.edu)
+ * adm_conn.c - use profile information to locate the admin_server.
+ Also, return the correct value from krb5_adm_connect
+ instead of always returning zero.
+ * adm_{kw,kt}_{enc,dec}.c - New modules to [en/de]code administrative
+ protocol keyword=value pairs and keytab entries.
+
+
+Fri Apr 28 09:47:29 EDT 1995 Paul Park (pjpark@mit.edu)
+
+ Create a new library consisting of functions which communicate with
+ the administrative server here. These modules replace the originals
+ which used to be in libkrb5.
+
+ adm_rw.c - Remove ntohl/htonl in favor of byte blasting.
+
diff --git a/src/lib/kadm/Makefile.in b/src/lib/kadm/Makefile.in
new file mode 100644
index 000000000..62cda2cc9
--- /dev/null
+++ b/src/lib/kadm/Makefile.in
@@ -0,0 +1,92 @@
+CFLAGS = $(CCOPTS) $(DEFS)
+
+##DOSBUILDTOP = ..\..
+##DOSLIBNAME=kadm.lib
+RUN_SETUP=@KRB5_RUN_ENV@
+BASE_OBJS= adm_conn.$(OBJEXT) \
+ adm_kt_dec.$(OBJEXT) \
+ adm_kt_enc.$(OBJEXT) \
+ adm_rw.$(OBJEXT) \
+ alt_prof.$(OBJEXT) \
+ str_conv.$(OBJEXT) \
+ keysalt.$(OBJEXT)
+
+UNIX_OBJS = logger.$(OBJEXT)
+
+DB_OBJS= adm_kw_dec.$(OBJEXT) \
+ adm_kw_enc.$(OBJEXT)
+
+OBJS= $(BASE_OBJS) $(DB_OBJS)
+
+SRCS= $(srcdir)/adm_conn.c \
+ $(srcdir)/adm_kt_dec.c \
+ $(srcdir)/adm_kt_enc.c \
+ $(srcdir)/adm_rw.c \
+ $(srcdir)/adm_kw_dec.c \
+ $(srcdir)/adm_kw_enc.c \
+ $(srcdir)/logger.c \
+ $(srcdir)/alt_prof.c \
+ $(srcdir)/str_conv.c \
+ $(srcdir)/keysalt.c
+
+all:: $(BASE_OBJS)
+
+all-unix:: $(DB_OBJS) $(UNIX_OBJS)
+all-unix:: libkadm.a
+all-mac:: $(DB_OBJS)
+all-windows::
+
+libkadm.a: $(OBJS) $(UNIX_OBJS)
+ $(RM) $@
+ $(ARADD) $@ $(OBJS) $(UNIX_OBJS)
+ $(RANLIB) $@
+
+install:: libkadm.a
+ $(INSTALL_DATA) libkadm.a $(DESTDIR)$(KRB5_LIBDIR)/libkadm.a
+ $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libkadm.a
+
+clean-unix::
+ $(RM) libkadm.$(LIBEXT) $(UNIX_OBJS)
+clean-mac::
+ $(RM) libkadm.$(LIBEXT)
+clean-windows::
+ $(RM) kadm.lib kadm.bak
+
+#
+# t_dbentry
+#
+T_DBENTRY_OBJS = t_dbentry.$(OBJEXT) \
+ $(TOPLIBD)/libkadm.a $(TOPLIBD)/libkdb5.a \
+ $(TOPLIBD)/libkrb5.a $(TOPLIBD)/libcrypto.a \
+ $(TOPLIBD)/libcom_err.a
+
+t_dbentry: $(T_DBENTRY_OBJS)
+ $(LD) -o t_dbentry $(T_DBENTRY_OBJS) $(LIBS)
+
+#
+# t_ktentry
+#
+T_KTENTRY_OBJS = t_ktentry.$(OBJEXT) \
+ $(TOPLIBD)/libkadm.a $(TOPLIBD)/libkrb5.a \
+ $(TOPLIBD)/libcrypto.a $(TOPLIBD)/libcom_err.a
+
+t_ktentry: $(T_KTENTRY_OBJS)
+ $(LD) -o t_ktentry $(T_KTENTRY_OBJS) $(LIBS)
+
+TEST_PROGS = t_dbentry t_ktentry
+
+check-unix:: $(TEST_PROGS)
+ $(RUN_SETUP) ./t_dbentry -r 100
+ $(RUN_SETUP) ./t_ktentry -r 100
+
+check-mac::
+
+check-windows::
+
+clean-unix::
+ $(RM) t_dbentry$(EXEEXT) t_dbentry.$(OBJEXT)
+ $(RM) t_ktentry$(EXEEXT) t_ktentry.$(OBJEXT)
+clean-mac::
+ $(RM) t_dbentry$(EXEEXT) t_dbentry.$(OBJEXT)
+ $(RM) t_ktentry$(EXEEXT) t_ktentry.$(OBJEXT)
+
diff --git a/src/lib/kadm/adm_conn.c b/src/lib/kadm/adm_conn.c
new file mode 100644
index 000000000..1534b4b02
--- /dev/null
+++ b/src/lib/kadm/adm_conn.c
@@ -0,0 +1,762 @@
+/*
+ * lib/kadm/adm_conn.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+/*
+ * Routines to contact an administrative protocol server.
+ */
+#define NEED_SOCKETS
+#define NEED_LOWLEVEL_IO
+#include "k5-int.h"
+#include "adm.h"
+#include "adm_proto.h"
+
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif /* HAVE_PWD_H */
+
+/* Default ticket life is 10 minutes */
+#define KADM_DEFAULT_LIFETIME (10*60)
+
+/*
+ * Strings
+ */
+static char *kadm_cache_name_fmt = "FILE:/tmp/tkt_kadm_%d";
+
+/*
+ * Prototypes for local functions
+ */
+static krb5_error_code kadm_get_ccache
+ PROTOTYPE((krb5_context,
+ char *,
+ char *,
+ krb5_ccache *,
+ krb5_principal *));
+static krb5_error_code kadm_get_creds
+ PROTOTYPE((krb5_context,
+ krb5_ccache ,
+ krb5_principal,
+ krb5_creds *,
+ char *,
+ char *,
+ krb5_timestamp));
+static krb5_error_code kadm_contact_server
+ PROTOTYPE((krb5_context,
+ krb5_data *,
+ int *,
+ krb5_address **,
+ krb5_address **));
+static krb5_error_code kadm_get_auth
+ PROTOTYPE((krb5_context,
+ krb5_auth_context *,
+ krb5_address *,
+ krb5_address *));
+
+/*
+ * kadm_get_ccache() - Initialze a credentials cache.
+ *
+ * Cleanup after success by calling krb5_cc_destroy() and krb5_free_principal()
+ * Allocates new ccache and client.
+ */
+static krb5_error_code
+kadm_get_ccache(kcontext, user, ccname, ccache, client)
+ krb5_context kcontext;
+ char *user;
+ char *ccname;
+ krb5_ccache *ccache;
+ krb5_principal *client;
+{
+ krb5_error_code kret;
+ char *name;
+ int did_malloc = 0;
+ char new_cache[MAXPATHLEN];
+ krb5_principal tprinc;
+
+ /* Initialize. */
+ *client = (krb5_principal) NULL;
+ tprinc = (krb5_principal) NULL;
+
+ /*
+ * If a name specified, then use that one, else get it from our
+ * current uid.
+ */
+ if (user) {
+ name = user;
+ }
+ else {
+#if HAVE_PWD_H
+ struct passwd *pw;
+
+ pw = getpwuid(getuid());
+ if (pw) {
+ name = (char *) malloc(strlen(pw->pw_name)+1);
+ did_malloc = 1;
+ strcpy(name, pw->pw_name);
+ }
+ else {
+ kret = errno;
+ goto cleanup;
+ }
+#else /* HAVE_PWD_H */
+ kret = ENOENT;
+ goto cleanup;
+#endif /* HAVE_PWD_H */
+ }
+
+ /* Parse the name and form our principal */
+ if (kret = krb5_parse_name(kcontext, name, client))
+ goto cleanup;
+
+ if (!ccname) {
+#if defined(_MSDOS) || defined(_WIN32)
+ strcpy (new_cache, "FILE:");
+ GetTempFileName (0, "tkt", 0, new_cache+5);
+#else
+#ifdef _MACINTOSH
+ (void) sprintf(new_cache, "STDIO:admcc");
+#else
+ (void) sprintf(new_cache, kadm_cache_name_fmt, getpid());
+#endif /* _MACINTOSH */
+#endif /* _MSDOS || _WIN32 */
+ }
+ else
+ sprintf(new_cache, "FILE:%s", ccname);
+
+ /*
+ * We only need to resolve the credentials cache if one hasn't
+ * been supplied to us.
+ */
+ if (!(*ccache) && (kret = krb5_cc_resolve(kcontext, new_cache, ccache)))
+ goto cleanup;
+
+ /* XXX assumes a file ccache */
+ if ((kret = krb5_cc_get_principal(kcontext, *ccache, &tprinc)) ==
+ KRB5_FCC_NOFILE)
+ kret = krb5_cc_initialize(kcontext, *ccache, *client);
+
+
+ cleanup:
+ if (did_malloc)
+ free(name);
+
+ if (tprinc)
+ krb5_free_principal(kcontext, tprinc);
+
+ if (kret) {
+ if (*client)
+ krb5_free_principal(kcontext, *client);
+ }
+
+ return(kret);
+}
+
+/*
+ * kadm_get_creds() - Get initial credentials.
+ *
+ * Cleanup after success by calling krb5_free_principal().
+ * Allocates new principal for creds->server.
+ */
+static krb5_error_code
+kadm_get_creds(kcontext, ccache, client, creds, prompt, oldpw, tlife)
+ krb5_context kcontext;
+ krb5_ccache ccache;
+ krb5_principal client;
+ krb5_creds *creds;
+ char *prompt;
+ char *oldpw;
+ krb5_timestamp tlife;
+{
+ char *client_name;
+ krb5_error_code kret;
+ krb5_address **my_addresses;
+ int old_pwsize;
+ krb5_creds tcreds;
+
+ /* Initialize */
+ my_addresses = (krb5_address **) NULL;
+ client_name = (char *) NULL;
+
+ /* Get the string form for our principal */
+ if (kret = krb5_unparse_name(kcontext, client, &client_name))
+ return(kret);
+
+ if (kret = krb5_os_localaddr(kcontext, &my_addresses))
+ goto cleanup;
+
+ creds->client = client;
+ /*
+ * Build server principal name:
+ * "changepw" is service
+ * realm name is instance
+ * realm name is realm name
+ */
+ if (kret = krb5_build_principal_ext(kcontext,
+ &creds->server,
+ client->realm.length,
+ client->realm.data,
+ strlen(KRB5_ADM_SERVICE_INSTANCE),
+ KRB5_ADM_SERVICE_INSTANCE,
+ client->realm.length,
+ client->realm.data,
+ 0))
+ goto cleanup;
+
+ /* Attempt to retrieve an appropriate entry from the credentials cache. */
+ if ((kret = krb5_cc_retrieve_cred(kcontext,
+ ccache,
+ KRB5_TC_MATCH_SRV_NAMEONLY,
+ creds,
+ &tcreds))
+ == KRB5_CC_NOTFOUND) {
+ krb5_timestamp jetzt;
+
+ if (prompt != (char *) NULL) {
+ /* Read the password */
+ old_pwsize = KRB5_ADM_MAX_PASSWORD_LEN;
+ if (kret = krb5_read_password(kcontext,
+ prompt,
+ (char *) NULL,
+ oldpw,
+ &old_pwsize))
+ goto cleanup;
+ }
+ if (kret = krb5_timeofday(kcontext, &jetzt))
+ goto cleanup;
+ if (tlife > 0)
+ creds->times.endtime = jetzt + tlife;
+ else
+ creds->times.endtime = jetzt + KADM_DEFAULT_LIFETIME;
+
+ /* Get our initial ticket */
+ kret = krb5_get_in_tkt_with_password(kcontext,
+ 0,
+ my_addresses,
+ NULL,
+ NULL,
+ oldpw,
+ ccache,
+ creds,
+ 0);
+ }
+ else {
+ krb5_principal sclient, sserver;
+
+ if (!kret) {
+ /*
+ * We found the credentials cache entry - copy it out.
+ *
+ * We'd like to just blast tcreds on top of creds, but we cannot.
+ * other logic uses the client data, and rather than going and
+ * chasing all that logic down, might as well pretend that we just
+ * filled in all the other muck.
+ */
+ sclient = creds->client;
+ sserver = creds->server;
+ memcpy((char *) creds, (char *) &tcreds, sizeof(tcreds));
+ if (creds->client)
+ krb5_free_principal(kcontext, creds->client);
+ if (creds->server)
+ krb5_free_principal(kcontext, creds->server);
+ creds->client = sclient;
+ creds->server = sserver;
+ }
+ }
+
+ cleanup:
+ if (kret) {
+ if (creds->server) {
+ krb5_free_principal(kcontext, creds->server);
+ creds->server = 0;
+ }
+ }
+ if (my_addresses)
+ krb5_free_addresses(kcontext, my_addresses);
+ if (client_name)
+ krb5_xfree(client_name);
+ return(kret);
+}
+
+/*
+ * kadm_contact_server() - Establish a connection to the server.
+ *
+ * Cleanup after success by calling close() and free().
+ * Opens/connects socket *sockp. Allocates address storage for local/remote.
+ */
+static krb5_error_code
+kadm_contact_server(kcontext, realmp, sockp, local, remote)
+ krb5_context kcontext;
+ krb5_data *realmp;
+ int *sockp;
+ krb5_address **local;
+ krb5_address **remote;
+{
+ struct hostent *remote_host;
+ struct servent *service;
+ char **hostlist;
+ int i, count;
+
+ krb5_error_code kret;
+
+ struct sockaddr_in in_local;
+ struct sockaddr_in in_remote;
+ int addr_len;
+
+ const char *realm_admin_names[4];
+ char *realm_name;
+ krb5_boolean found;
+
+ /* Initialize */
+ hostlist = (char **) NULL;
+ *sockp = -1;
+ realm_name = (char *) NULL;
+
+ /*
+ * XXX - only know ADDRTYPE_INET.
+ */
+#ifdef KRB5_USE_INET
+ *local = (krb5_address *) malloc(sizeof(krb5_address));
+ *remote = (krb5_address *) malloc(sizeof(krb5_address));
+ realm_name = (char *) malloc((size_t) realmp->length + 1);
+ if ((*local == (krb5_address *) NULL) ||
+ (*remote == (krb5_address *) NULL) ||
+ (realm_name == (char *) NULL)) {
+ kret = ENOMEM;
+ goto cleanup;
+ }
+ (*local)->addrtype = (*remote)->addrtype = ADDRTYPE_INET;
+ (*local)->length = (*remote)->length = sizeof(struct in_addr);
+ (*local)->contents = (krb5_octet *) malloc(sizeof(struct in_addr));
+ (*remote)->contents = (krb5_octet *) malloc(sizeof(struct in_addr));
+ if (((*local)->contents == NULL) || ((*remote)->contents == NULL)) {
+ kret = ENOMEM;
+ goto cleanup;
+ }
+
+ /*
+ * First attempt to find addresses from our config file, if we cannot
+ * find an entry, then try getservbyname().
+ */
+ found = 0;
+#ifndef OLD_CONFIG_FILES
+ strncpy(realm_name, realmp->data, (size_t) realmp->length);
+ realm_name[realmp->length] = '\0';
+ realm_admin_names[0] = "realms";
+ realm_admin_names[1] = realm_name;
+ realm_admin_names[2] = "admin_server";
+ realm_admin_names[3] = (char *) NULL;
+ if (!(kret = profile_get_values(kcontext->profile,
+ realm_admin_names,
+ &hostlist))) {
+ int hi;
+ char *cport;
+ char *cp;
+ krb5_int32 pport;
+
+ for (hi = 0; hostlist[hi]; hi++) {
+ /*
+ * This knows a little too much about the format of profile
+ * entries. Shouldn't it just be some sort of tuple?
+ *
+ * The form is assumed to be:
+ * admin_server = <hostname>[:<portname>[<whitespace>]]
+ */
+ cport = (char *) NULL;
+ pport = (u_short) KRB5_ADM_DEFAULT_PORT;
+ cp = strchr(hostlist[hi], ' ');
+ if (cp)
+ *cp = '\0';
+ cp = strchr(hostlist[hi], '\t');
+ if (cp)
+ *cp = '\0';
+ cport = strchr(hostlist[hi], ':');
+ if (cport) {
+ *cport = '\0';
+ cport++;
+
+ pport = atoi (cport);
+ if (pport == 0) {
+ kret = KRB5_CONFIG_BADFORMAT;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Now that we have a host name, get the host entry.
+ */
+ remote_host = gethostbyname(hostlist[hi]);
+ if (remote_host == (struct hostent *) NULL) {
+ kret = KRB5_CONFIG_BADFORMAT;
+ goto cleanup;
+ }
+
+ /*
+ * Fill in our address values.
+ */
+ in_remote.sin_family = remote_host->h_addrtype;
+ (void) memcpy((char *) &in_remote.sin_addr,
+ (char *) remote_host->h_addr,
+ sizeof(in_remote.sin_addr));
+ in_remote.sin_port = htons((u_short) pport);
+
+ /* Open a tcp socket */
+ *sockp = (int) socket(PF_INET, SOCK_STREAM, 0);
+ if (*sockp < 0) {
+ kret = SOCKET_ERRNO;
+ goto cleanup;
+ }
+ else kret = 0;
+
+ /* Attempt to connect to the remote address. */
+ if (connect(*sockp,
+ (struct sockaddr *) &in_remote,
+ sizeof(in_remote)) < 0) {
+ /* Failed, go to next address */
+ kret = SOCKET_ERRNO;
+ closesocket((SOCKET)*sockp);
+ *sockp = -1;
+ continue;
+ }
+
+ /* Find out local address */
+ addr_len = sizeof(in_local);
+ if (getsockname((SOCKET) *sockp,
+ (struct sockaddr *) &in_local,
+ &addr_len) < 0) {
+ /* Couldn't get our local address? */
+ kret = SOCKET_ERRNO;
+ goto cleanup;
+ }
+ else {
+ /* Connection established. */
+ memcpy((char *) (*remote)->contents,
+ (char *) &in_remote.sin_addr,
+ sizeof(struct in_addr));
+ memcpy((char *) (*local)->contents,
+ (char *) &in_local.sin_addr,
+ sizeof(struct in_addr));
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ krb5_xfree(hostlist);
+ hostlist = (char **) NULL;
+ }
+ }
+#endif /* OLD_CONFIG_FILES */
+ if (!found) {
+ /*
+ * Use the old way of finding our administrative server.
+ *
+ * This consists of looking up an entry in /etc/services and if
+ * we don't find it, then we are just out of luck. Then, we use
+ * that port number along with the address of the kdc.
+ */
+ if ((service = getservbyname(KRB5_ADM_SERVICE_NAME, "tcp")) == NULL) {
+ kret = ENOENT;
+ goto cleanup;
+ }
+ in_remote.sin_port = service->s_port;
+
+ if (kret = krb5_get_krbhst(kcontext, realmp, &hostlist))
+ goto cleanup;
+
+ /* Now count the number of hosts in the realm */
+ count = 0;
+ for (i=0; hostlist[i]; i++)
+ count++;
+ if (count == 0) {
+ kret = ENOENT; /* something better? */
+ goto cleanup;
+ }
+
+ /* Now find an available host */
+ for (i=0; hostlist[i]; i++) {
+ remote_host = gethostbyname(hostlist[i]);
+ if (remote_host != (struct hostent *) NULL) {
+ in_remote.sin_family = remote_host->h_addrtype;
+ (void) memcpy((char *) &in_remote.sin_addr,
+ (char *) remote_host->h_addr,
+ sizeof(in_remote.sin_addr));
+
+ /* Open a tcp socket */
+ *sockp = (int) socket(PF_INET, SOCK_STREAM, 0);
+ if (*sockp < 0) {
+ kret = SOCKET_ERRNO;
+ goto cleanup;
+ }
+ else kret = 0;
+
+ if (connect(*sockp,
+ (struct sockaddr *) &in_remote,
+ sizeof(in_remote)) < 0) {
+ kret = SOCKET_ERRNO;
+ closesocket((SOCKET)*sockp);
+ *sockp = -1;
+ continue;
+ }
+
+ /* Find out local address */
+ addr_len = sizeof(in_local);
+ if (getsockname((SOCKET)*sockp,
+ (struct sockaddr *) &in_local,
+ &addr_len) < 0) {
+ kret = SOCKET_ERRNO;
+ goto cleanup;
+ }
+ else {
+ memcpy((char *) (*remote)->contents,
+ (char *) &in_remote.sin_addr,
+ sizeof(struct in_addr));
+
+ memcpy((char *) (*local)->contents,
+ (char *) &in_local.sin_addr,
+ sizeof(struct in_addr));
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found)
+ kret = KRB5_SERVICE_UNKNOWN;
+ }
+#else /* KRB5_USE_INET */
+ kret = ENOENT;
+#endif /* KRB5_USE_INET */
+
+ cleanup:
+ if (kret) {
+ if (*sockp >= 0)
+ closesocket((SOCKET)*sockp);
+ if (*local && (*local)->contents)
+ free((*local)->contents);
+ if (*remote && (*remote)->contents)
+ free((*remote)->contents);
+ if (*local) {
+ memset((char *) (*local), 0, sizeof(krb5_address));
+ free(*local);
+ *local = (krb5_address *) NULL;
+ }
+ if (*remote) {
+ memset((char *) (*remote), 0, sizeof(krb5_address));
+ free(*remote);
+ *remote = (krb5_address *) NULL;
+ }
+ }
+ if (realm_name)
+ free(realm_name);
+ if (hostlist)
+ krb5_xfree(hostlist);
+ return(kret);
+}
+
+/*
+ * kadm_get_auth() - Get authorization context.
+ *
+ * Cleanup after success by calling krb5_xfree().
+ * New krb5_auth_context allocated in *ctxp
+ */
+static krb5_error_code
+kadm_get_auth(kcontext, ctxp, local, remote)
+ krb5_context kcontext;
+ krb5_auth_context *ctxp;
+ krb5_address *local;
+ krb5_address *remote;
+{
+ krb5_auth_con_init(kcontext, ctxp);
+ krb5_auth_con_setflags(kcontext, *ctxp,
+ KRB5_AUTH_CONTEXT_RET_SEQUENCE|
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+ krb5_auth_con_setaddrs(kcontext, *ctxp, local, remote);
+ return(0);
+}
+
+/*
+ * krb5_adm_connect() - Establish the connection to the service.
+ *
+ * If *ccachep is not null, then that ccache is used to establish the identity
+ * of the caller. (Argument list is ugly, I know)
+ *
+ * Errors are not reported by this routine.
+ * Cleanup after successful invocation must:
+ * destroy/close ccache.
+ * free auth_context
+ * close socket.
+ */
+krb5_error_code INTERFACE
+krb5_adm_connect(kcontext, user, prompt, opassword, sockp, ctxp,
+ ccachep, ccname, tlife)
+ krb5_context kcontext; /* Context handle (In ) */
+ char *user; /* User specified (In ) */
+ char *prompt; /* Old password prompt (In ) */
+ char *opassword; /* Old Password (I/O) */
+ int *sockp; /* Socket for conn. (Out) */
+ krb5_auth_context *ctxp; /* Auth context (Out) */
+ krb5_ccache *ccachep; /* Credentials cache (I/O) */
+ char *ccname; /* Cred cache name (In ) */
+ krb5_timestamp tlife; /* Ticket lifetime (In ) */
+{
+ krb5_error_code kret;
+ krb5_principal client;
+ krb5_creds creds;
+ krb5_data server_realm;
+ krb5_data request_data, suppl_data;
+ krb5_data response_data;
+ krb5_address *local_addr;
+ krb5_address *remote_addr;
+ krb5_boolean ccache_supplied;
+
+ char *server;
+
+ /* Initialize */
+ memset((char *) &creds, 0, sizeof(krb5_creds));
+ server = (char *) NULL;
+ *sockp = -1;
+ local_addr = remote_addr = (krb5_address *) NULL;
+ client = (krb5_principal) NULL;
+ *ctxp = (krb5_auth_context) NULL;
+ ccache_supplied = (*ccachep != (krb5_ccache) NULL);
+
+ /*
+ * Find the appropriate credentials cache and set up our identity.
+ */
+ if (kret = kadm_get_ccache(kcontext, user, ccname, ccachep, &client))
+ goto cleanup;
+
+ /*
+ * Get initial credentials.
+ */
+ if (kret = kadm_get_creds(kcontext,
+ *ccachep,
+ client,
+ &creds,
+ prompt,
+ opassword,
+ tlife))
+ goto cleanup;
+
+ /*
+ * Establish connection to server.
+ */
+ if ((server_realm.data = (char *) malloc(client->realm.length+1)) ==
+ (char *) NULL)
+ goto cleanup;
+
+ server_realm.length = client->realm.length;
+ memcpy(server_realm.data, client->realm.data, server_realm.length);
+ server_realm.data[server_realm.length] = '\0';
+ if (kret = kadm_contact_server(kcontext,
+ &server_realm,
+ sockp,
+ &local_addr,
+ &remote_addr))
+ goto cleanup;
+
+ /*
+ * Obtain our authorization context
+ */
+ if (kret = kadm_get_auth(kcontext, ctxp, local_addr, remote_addr))
+ goto cleanup;
+
+ /*
+ * Format, then send the KRB_AP_REQ
+ */
+ suppl_data.data = NULL;
+ suppl_data.length = 0;
+ if (kret = krb5_mk_req_extended(kcontext,
+ ctxp,
+ AP_OPTS_MUTUAL_REQUIRED,
+ &suppl_data,
+ &creds,
+ &request_data))
+ goto cleanup;
+
+ if (kret = krb5_write_message(kcontext, sockp, &request_data))
+ goto cleanup;
+
+ /*
+ * Now read back the response.
+ */
+ if (kret = krb5_read_message(kcontext, sockp, &response_data)) {
+ goto cleanup;
+ }
+ else {
+ krb5_ap_rep_enc_part *reply = NULL;
+
+ kret = krb5_rd_rep(kcontext, *ctxp, &response_data, &reply);
+ if (reply)
+ krb5_free_ap_rep_enc_part(kcontext, reply);
+ }
+ cleanup:
+ if (server)
+ free(server);
+ if (kret) {
+ if (*ctxp) {
+ krb5_xfree(*ctxp);
+ *ctxp = (krb5_auth_context) NULL;
+ }
+ if (*sockp >= 0) {
+ closesocket((SOCKET)*sockp);
+ *sockp = -1;
+ }
+ if (local_addr && local_addr->contents)
+ free(local_addr->contents);
+ if (remote_addr && remote_addr->contents)
+ free(remote_addr->contents);
+ if (local_addr)
+ free(local_addr);
+ if (remote_addr)
+ free(remote_addr);
+ if (creds.server)
+ krb5_free_principal(kcontext, creds.server);
+ if (client)
+ krb5_free_principal(kcontext, client);
+ if (*ccachep && !ccache_supplied) {
+ krb5_cc_destroy(kcontext, *ccachep);
+ *ccachep = (krb5_ccache) NULL;
+ }
+ }
+ return(kret);
+
+}
+
+/*
+ * krb5_adm_disconnect() - Disconnect from the administrative service.
+ *
+ * If ccache is supplied, then it is destroyed. Otherwise, the ccache is
+ * the caller's responsibility to close.
+ */
+void INTERFACE
+krb5_adm_disconnect(kcontext, socketp, auth_context, ccache)
+ krb5_context kcontext;
+ int *socketp;
+ krb5_auth_context auth_context;
+ krb5_ccache ccache;
+{
+ if (ccache)
+ krb5_cc_destroy(kcontext, ccache);
+ if (auth_context)
+ krb5_xfree(auth_context);
+ if (*socketp >= 0)
+ closesocket((SOCKET)*socketp);
+}
+
diff --git a/src/lib/kadm/adm_kt_dec.c b/src/lib/kadm/adm_kt_dec.c
new file mode 100644
index 000000000..7886a70da
--- /dev/null
+++ b/src/lib/kadm/adm_kt_dec.c
@@ -0,0 +1,127 @@
+/*
+ * lib/kadm/adm_kt_dec.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * adm_kt_dec.c - Decode keytab entry according to protocol.
+ */
+#include "k5-int.h"
+#include "adm.h"
+#include "adm_proto.h"
+
+/*
+ * krb5_adm_proto_to_ktent() - Convert a list of reply components to
+ * a keytab entry according to procotol.
+ *
+ * Successful callers of this routine should free ktentp->principal
+ * and ktentp->key.contents.
+ */
+krb5_error_code
+krb5_adm_proto_to_ktent(kcontext, ncomp, complist, ktentp)
+ krb5_context kcontext;
+ krb5_int32 ncomp;
+ krb5_data *complist;
+ krb5_keytab_entry *ktentp;
+{
+ krb5_error_code kret;
+ char *v;
+
+ /*
+ * Clear out the keytab entry.
+ */
+ memset((char *) ktentp, 0, sizeof(krb5_keytab_entry));
+
+ /*
+ * Figure out how many components we have. We expect KRB5_ADM_KT_NCOMPS
+ * components.
+ */
+ if (ncomp != KRB5_ADM_KT_NCOMPS)
+ return(EINVAL);
+
+ /* Parse the supplied principal name */
+ if (kret = krb5_parse_name(kcontext,
+ complist[KRB5_ADM_KT_PRINCIPAL].data,
+ &ktentp->principal))
+ goto done;
+
+ /* Parse the supplied timestamp */
+ if (complist[KRB5_ADM_KT_TIMESTAMP].length < sizeof(krb5_timestamp)) {
+ kret = EINVAL;
+ goto done;
+ }
+ v = complist[KRB5_ADM_KT_TIMESTAMP].data;
+ ktentp->timestamp = (krb5_timestamp)
+ (((krb5_int32) ((unsigned char) v[0]) << 24) +
+ ((krb5_int32) ((unsigned char) v[1]) << 16) +
+ ((krb5_int32) ((unsigned char) v[2]) << 8) +
+ ((krb5_int32) ((unsigned char) v[3])));
+
+ /* Parse the supplied vno */
+ if (complist[KRB5_ADM_KT_VNO].length < sizeof(krb5_kvno)) {
+ kret = EINVAL;
+ goto done;
+ }
+ v = complist[KRB5_ADM_KT_VNO].data;
+ ktentp->vno = (krb5_kvno)
+ (((krb5_int32) ((unsigned char) v[0]) << 24) +
+ ((krb5_int32) ((unsigned char) v[1]) << 16) +
+ ((krb5_int32) ((unsigned char) v[2]) << 8) +
+ ((krb5_int32) ((unsigned char) v[3])));
+
+ /* Parse the supplied key_enctype */
+ if (complist[KRB5_ADM_KT_KEY_ENCTYPE].length < sizeof(krb5_enctype)) {
+ kret = EINVAL;
+ goto done;
+ }
+ v = complist[KRB5_ADM_KT_KEY_ENCTYPE].data;
+ ktentp->key.enctype = (krb5_enctype)
+ (((krb5_int32) ((unsigned char) v[0]) << 24) +
+ ((krb5_int32) ((unsigned char) v[1]) << 16) +
+ ((krb5_int32) ((unsigned char) v[2]) << 8) +
+ ((krb5_int32) ((unsigned char) v[3])));
+
+ /* Finally, shuck the key contents */
+ if (ktentp->key.contents = (krb5_octet *)
+ malloc((size_t) complist[KRB5_ADM_KT_KEY_KEY].length)) {
+ ktentp->key.length = complist[KRB5_ADM_KT_KEY_KEY].length;
+ memcpy(ktentp->key.contents,
+ complist[KRB5_ADM_KT_KEY_KEY].data,
+ (size_t) ktentp->key.length);
+ kret = 0;
+ }
+ else
+ kret = ENOMEM;
+
+ done:
+ if (kret) {
+ if (ktentp->principal)
+ krb5_free_principal(kcontext, ktentp->principal);
+ if (ktentp->key.contents) {
+ memset((char *) ktentp->key.contents, 0,
+ (size_t) ktentp->key.length);
+ krb5_xfree(ktentp->key.contents);
+ }
+ memset((char *) ktentp, 0, sizeof(krb5_keytab_entry));
+ }
+ return(kret);
+}
diff --git a/src/lib/kadm/adm_kt_enc.c b/src/lib/kadm/adm_kt_enc.c
new file mode 100644
index 000000000..d7dc65af1
--- /dev/null
+++ b/src/lib/kadm/adm_kt_enc.c
@@ -0,0 +1,162 @@
+/*
+ * lib/kadm/adm_kt_enc.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * adm_kt_enc.c - Encode keytab entry according to protocol.
+ */
+#include "k5-int.h"
+#include "adm.h"
+#include "adm_proto.h"
+
+
+/*
+ * krb5_adm_ktent_to_proto() - Convert a keytab entry into an external
+ * list of reply components.
+ *
+ * Successful callers must free the storage for complistp and complistp->data
+ * either manually or by using krb5_free_adm_data().
+ */
+krb5_error_code
+krb5_adm_ktent_to_proto(kcontext, ktentp, ncompp, complistp)
+ krb5_context kcontext;
+ krb5_keytab_entry *ktentp;
+ krb5_int32 *ncompp;
+ krb5_data **complistp;
+{
+ krb5_error_code kret;
+ krb5_data *clist;
+ krb5_int32 nents;
+
+ kret = ENOMEM;
+ nents = 0;
+ if (clist = (krb5_data *) malloc((size_t) KRB5_ADM_KT_NCOMPS *
+ sizeof(krb5_data))) {
+ memset((char *) clist, 0, ((size_t) KRB5_ADM_KT_NCOMPS *
+ sizeof(krb5_data)));
+ /*
+ * Fill in the principal field.
+ */
+ if (kret = krb5_unparse_name(kcontext,
+ ktentp->principal,
+ &clist[KRB5_ADM_KT_PRINCIPAL].data))
+ goto done;
+ clist[KRB5_ADM_KT_PRINCIPAL].length =
+ strlen(clist[KRB5_ADM_KT_PRINCIPAL].data);
+ nents++;
+
+ /*
+ * Fill in timestamp.
+ */
+ if (kret = krb5_timeofday(kcontext, &ktentp->timestamp))
+ goto done;
+ if (clist[KRB5_ADM_KT_TIMESTAMP].data =
+ (char *) malloc(sizeof(krb5_ui_4))) {
+ clist[KRB5_ADM_KT_TIMESTAMP].length = sizeof(krb5_ui_4);
+ clist[KRB5_ADM_KT_TIMESTAMP].data[0] =
+ (char) ((ktentp->timestamp >> 24) & 0xff);
+ clist[KRB5_ADM_KT_TIMESTAMP].data[1] =
+ (char) ((ktentp->timestamp >> 16) & 0xff);
+ clist[KRB5_ADM_KT_TIMESTAMP].data[2] =
+ (char) ((ktentp->timestamp >> 8) & 0xff);
+ clist[KRB5_ADM_KT_TIMESTAMP].data[3] =
+ (char) (ktentp->timestamp & 0xff);
+ nents++;
+ }
+ else {
+ kret = ENOMEM;
+ goto done;
+ }
+
+ /*
+ * Fill in vno.
+ */
+ if (clist[KRB5_ADM_KT_VNO].data =
+ (char *) malloc(sizeof(krb5_ui_4))) {
+ clist[KRB5_ADM_KT_VNO].length = sizeof(krb5_ui_4);
+ clist[KRB5_ADM_KT_VNO].data[0] = (ktentp->vno >> 24) & 0xff;
+ clist[KRB5_ADM_KT_VNO].data[1] = (ktentp->vno >> 16) & 0xff;
+ clist[KRB5_ADM_KT_VNO].data[2] = (ktentp->vno >> 8) & 0xff;
+ clist[KRB5_ADM_KT_VNO].data[3] = ktentp->vno & 0xff;
+ nents++;
+ }
+ else {
+ kret = ENOMEM;
+ goto done;
+ }
+
+ /*
+ * Fill in key_enctype.
+ */
+ if (clist[KRB5_ADM_KT_KEY_ENCTYPE].data =
+ (char *) malloc(sizeof(krb5_ui_4))) {
+ clist[KRB5_ADM_KT_KEY_ENCTYPE].length = sizeof(krb5_ui_4);
+ clist[KRB5_ADM_KT_KEY_ENCTYPE].data[0] =
+ (ktentp->key.enctype >> 24) & 0xff;
+ clist[KRB5_ADM_KT_KEY_ENCTYPE].data[1] =
+ (ktentp->key.enctype >> 16) & 0xff;
+ clist[KRB5_ADM_KT_KEY_ENCTYPE].data[2] =
+ (ktentp->key.enctype >> 8) & 0xff;
+ clist[KRB5_ADM_KT_KEY_ENCTYPE].data[3] =
+ ktentp->key.enctype & 0xff;
+ nents++;
+ }
+ else {
+ kret = ENOMEM;
+ goto done;
+ }
+
+ /*
+ * Fill in key_key.
+ */
+ if (clist[KRB5_ADM_KT_KEY_KEY].data =
+ (char *) malloc((size_t) ktentp->key.length)) {
+ memcpy(clist[KRB5_ADM_KT_KEY_KEY].data,
+ ktentp->key.contents,
+ (size_t) ktentp->key.length);
+ clist[KRB5_ADM_KT_KEY_KEY].length = ktentp->key.length;
+ nents++;
+ kret = 0;
+ }
+ else
+ kret = ENOMEM;
+ }
+ done:
+ if (kret) {
+ if (clist) {
+ int i;
+ for (i=0; i<KRB5_ADM_KT_NCOMPS; i++) {
+ if (clist[i].data) {
+ memset(clist[i].data, 0, (size_t) clist[i].length);
+ krb5_xfree(clist[i].data);
+ }
+ }
+ krb5_xfree(clist);
+ }
+ clist = (krb5_data *) NULL;
+ nents = 0;
+ }
+ *complistp = clist;
+ *ncompp = nents;
+ return(kret);
+}
diff --git a/src/lib/kadm/adm_kw_dec.c b/src/lib/kadm/adm_kw_dec.c
new file mode 100644
index 000000000..35097383b
--- /dev/null
+++ b/src/lib/kadm/adm_kw_dec.c
@@ -0,0 +1,578 @@
+/*
+ * lib/kadm/adm_kw_dec.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * adm_kw_dec.c - routines to decode keyword-value pairs.
+ */
+#include "k5-int.h"
+#include "adm.h"
+#include "adm_proto.h"
+
+#define char2int(c) ((c) - '0')
+
+/*
+ * keyword_value() - Find index of keyword value if keyword is present.
+ *
+ * If a value is required, then the index of the keyword value is returned,
+ * otherwise the index of the first character past the end of the keyword
+ * string is returned.
+ */
+static off_t
+keyword_value(dataentp, keyword, value_req)
+ krb5_data *dataentp;
+ char *keyword;
+ krb5_boolean value_req;
+{
+ off_t len_req;
+
+ len_req = strlen(keyword);
+ if (value_req)
+ len_req++;
+ if ((dataentp->length >= len_req) &&
+ (!strncmp(dataentp->data, keyword, strlen(keyword))) &&
+ (!value_req || (dataentp->data[strlen(keyword)] == '=')))
+ return(len_req);
+ else
+ return(-1);
+}
+
+/*
+ * decode_kw_string() - Decode a keyword=<string> pair and return the
+ * string value if the pair is present.
+ *
+ * Note: successful callers must free the string storage.
+ */
+static krb5_error_code
+decode_kw_string(dataentp, keyword, stringp)
+ krb5_data *dataentp;
+ char *keyword;
+ char **stringp;
+{
+ krb5_error_code kret;
+ off_t valueoff;
+ size_t len2copy;
+
+ kret = ENOENT;
+ if ((valueoff = keyword_value(dataentp, keyword, 1)) >= 0) {
+ kret = ENOMEM;
+ len2copy = (size_t) ((off_t) dataentp->length - valueoff);
+ *stringp = (char *) malloc(len2copy+1);
+ if (*stringp) {
+ strncpy(*stringp, &dataentp->data[valueoff], len2copy);
+ (*stringp)[len2copy] = '\0';
+ kret = 0;
+ }
+ }
+ return(kret);
+}
+
+/*
+ * decode_kw_integer() - Decode a keyword=<integer> pair and return the value
+ * if the pair is present.
+ */
+static krb5_error_code
+decode_kw_integer(dataentp, keyword, uintp)
+ krb5_data *dataentp;
+ char *keyword;
+ krb5_ui_4 *uintp;
+{
+ krb5_error_code kret;
+ off_t voff;
+ size_t len2copy;
+
+ kret = ENOENT;
+ if ((voff = keyword_value(dataentp, keyword, 1)) >= 0) {
+ kret = EINVAL;
+ len2copy = (size_t) ((off_t) dataentp->length - voff);
+ if (len2copy == sizeof(krb5_ui_4)) {
+ *uintp = (((krb5_int32) ((unsigned char) dataentp->data[voff])
+ << 24) +
+ ((krb5_int32) ((unsigned char) dataentp->data[voff+1])
+ << 16) +
+ ((krb5_int32) ((unsigned char) dataentp->data[voff+2])
+ << 8) +
+ ((krb5_int32) ((unsigned char) dataentp->data[voff+3])));
+ kret = 0;
+ }
+ }
+ return(kret);
+}
+
+/*
+ * decode_kw_gentime() - Decode a keyword=<general-time> pair and return the
+ * time result if the pair is present.
+ *
+ * XXX - this knows too much about how Kerberos time is encoded.
+ */
+static krb5_error_code
+decode_kw_gentime(dataentp, keyword, gtimep)
+ krb5_data *dataentp;
+ char *keyword;
+ krb5_timestamp *gtimep;
+{
+ krb5_error_code kret;
+ char *timestring;
+ struct tm tval;
+ time_t temp_time;
+
+ memset((char *) &tval, 0, sizeof(tval));
+ timestring = (char *) NULL;
+ if (!(kret = decode_kw_string(dataentp, keyword, &timestring))) {
+ kret = EINVAL;
+ if ((strlen(timestring) == 15) &&
+ (timestring[14] == 'Z')) {
+ tval.tm_year = 1000*char2int(timestring[0]) +
+ 100*char2int(timestring[1]) +
+ 10*char2int(timestring[2]) +
+ char2int(timestring[3]) - 1900;
+ tval.tm_mon = 10*char2int(timestring[4]) +
+ char2int(timestring[5]) - 1;
+ tval.tm_mday = 10*char2int(timestring[6]) +
+ char2int(timestring[7]);
+ tval.tm_hour = 10*char2int(timestring[8]) +
+ char2int(timestring[9]);
+ tval.tm_min = 10*char2int(timestring[10]) +
+ char2int(timestring[11]);
+ tval.tm_sec = 10*char2int(timestring[12]) +
+ char2int(timestring[13]);
+ tval.tm_isdst = -1;
+ temp_time = gmt_mktime(&tval);
+ if (temp_time >= 0) {
+ kret = 0;
+ *gtimep = (krb5_timestamp) temp_time;
+ }
+ }
+ free(timestring);
+ }
+ return(kret);
+}
+
+/*
+ * decode_kw_tagged() - Decode a keyword=<taglist>...<data> list and return
+ * the values of the tags and the data if the list is
+ * present.
+ */
+static krb5_error_code
+decode_kw_tagged(dataentp, keyword, ntags, taglist, lenp, datap)
+ krb5_data *dataentp;
+ char *keyword;
+ krb5_int32 ntags;
+ krb5_int32 *taglist;
+ size_t *lenp;
+ krb5_octet **datap;
+{
+ krb5_error_code kret;
+ off_t valueoff;
+ size_t len2copy;
+ unsigned char *cp, *ep;
+ int i;
+
+ kret = ENOENT;
+ if ((valueoff = keyword_value(dataentp, keyword, 1)) >= 0) {
+ /*
+ * Blast through the tags.
+ */
+ kret = 0;
+ cp = (unsigned char *) &dataentp->data[valueoff];
+ ep = (unsigned char *) &dataentp->data[dataentp->length];
+ for (i=0; i<ntags; i++) {
+ if (&cp[sizeof(krb5_int32)] > ep) {
+ kret = EINVAL;
+ break;
+ }
+ taglist[i] = (((krb5_int32) ((unsigned char) cp[0]) << 24) +
+ ((krb5_int32) ((unsigned char) cp[1]) << 16) +
+ ((krb5_int32) ((unsigned char) cp[2]) << 8) +
+ ((krb5_int32) ((unsigned char) cp[3])));
+ cp += sizeof(krb5_int32);
+ }
+ if (!kret) {
+ /*
+ * If we were successful, copy out the remaining bytes for value.
+ */
+ len2copy = (size_t) (ep - cp);
+ if (len2copy &&
+ (*datap = (krb5_octet *) malloc(len2copy+1))) {
+ memcpy(*datap, cp, len2copy);
+ (*datap)[len2copy] = '\0';
+ }
+ if (len2copy && !*datap)
+ kret = ENOMEM;
+ else
+ *lenp = len2copy;
+ }
+ }
+ return(kret);
+}
+
+#if !defined(_MSDOS) && !defined(_WIN32) && !defined(_MACINTOSH)
+/*
+ * krb5_adm_proto_to_dbent() - Convert external attribute list into a
+ * database entry.
+ *
+ * Scan through the keyword=value pairs in "data" until either the end of
+ * the list (as determined from "nent") is reached, or an error occurs.
+ * Return a mask of attributes which are set in "validp", the actual
+ * attribute values in "dbentp" and "pwordp" if a password is specified.
+ *
+ * Successful callers must allocate the storage for "validp", "dbentp" and
+ * must free the storage allocated for "pwordp" if a password is specified
+ * and free the storage allocated for "validp->mod_name" if a modifier name
+ * is specified.
+ */
+krb5_error_code
+krb5_adm_proto_to_dbent(kcontext, nent, data, validp, dbentp, pwordp)
+ krb5_context kcontext; /* Kerberos context */ /* In */
+ krb5_int32 nent; /* Number of components */ /* In */
+ krb5_data *data; /* Component list */ /* In */
+ krb5_ui_4 *validp; /* Valid bitmask */ /* Out */
+ krb5_db_entry *dbentp; /* Database entry */ /* Out */
+ char **pwordp; /* Password string */ /* Out */
+{
+ int i;
+ krb5_error_code retval;
+ krb5_ui_4 parsed_mask;
+ krb5_int32 taglist[4];
+ size_t data_length;
+ krb5_octet *tagged_data;
+ struct key_tag_correlator {
+ krb5_int32 key_tag;
+ int key_data_index;
+ } *correlators, *correlation;
+ int ncorrelations;
+
+ /* Initialize */
+ retval = 0;
+ parsed_mask = 0;
+ *pwordp = (char *) NULL;
+ correlators = (struct key_tag_correlator *) NULL;
+ ncorrelations = 0;
+
+ /* Loop through all the specified keyword=value pairs. */
+ for (i=0; i<nent; i++) {
+ /* Check for password */
+ if (!(retval = decode_kw_string(&data[i],
+ KRB5_ADM_KW_PASSWORD,
+ pwordp))) {
+ parsed_mask |= KRB5_ADM_M_PASSWORD;
+ continue;
+ }
+ else {
+ if (retval != ENOENT)
+ break;
+ }
+
+ /* Check for maximum lifetime */
+ if (!(retval = decode_kw_integer(&data[i],
+ KRB5_ADM_KW_MAXLIFE,
+ (krb5_ui_4 *) &dbentp->max_life))) {
+ parsed_mask |= KRB5_ADM_M_MAXLIFE;
+ continue;
+ }
+ else {
+ if (retval != ENOENT)
+ break;
+ }
+
+ /* Check for maximum renewable lifetime */
+ if (!(retval = decode_kw_integer(&data[i],
+ KRB5_ADM_KW_MAXRENEWLIFE,
+ (krb5_ui_4 *)
+ &dbentp->max_renewable_life))) {
+ parsed_mask |= KRB5_ADM_M_MAXRENEWLIFE;
+ continue;
+ }
+ else {
+ if (retval != ENOENT)
+ break;
+ }
+
+ /* Check for principal expiration */
+ if (!(retval = decode_kw_gentime(&data[i],
+ KRB5_ADM_KW_EXPIRATION,
+ &dbentp->expiration))) {
+ parsed_mask |= KRB5_ADM_M_EXPIRATION;
+ continue;
+ }
+ else {
+ if (retval != ENOENT)
+ break;
+ }
+
+ /* Check for password expiration */
+ if (!(retval = decode_kw_gentime(&data[i],
+ KRB5_ADM_KW_PWEXPIRATION,
+ &dbentp->pw_expiration))) {
+ parsed_mask |= KRB5_ADM_M_PWEXPIRATION;
+ continue;
+ }
+ else {
+ if (retval != ENOENT)
+ break;
+ }
+
+ /* random key - value optional */
+ if (keyword_value(&data[i],
+ KRB5_ADM_KW_RANDOMKEY,
+ 0) >= 0) {
+ krb5_ui_4 value;
+
+ if (retval = decode_kw_integer(&data[i],
+ KRB5_ADM_KW_RANDOMKEY,
+ &value)) {
+ value = 1;
+ retval = 0;
+ }
+ if (value)
+ parsed_mask |= KRB5_ADM_M_RANDOMKEY;
+ else
+ parsed_mask &= ~KRB5_ADM_M_RANDOMKEY;
+ continue;
+ }
+
+ /* Check for flags */
+ if (!(retval = decode_kw_integer(&data[i],
+ KRB5_ADM_KW_FLAGS,
+ (krb5_ui_4 *) &dbentp->attributes))) {
+ parsed_mask |= KRB5_ADM_M_FLAGS;
+ continue;
+ }
+ else {
+ if (retval != ENOENT)
+ break;
+ }
+
+ /* Check for last successful password entry */
+ if (!(retval = decode_kw_gentime(&data[i],
+ KRB5_ADM_KW_LASTSUCCESS,
+ &dbentp->last_success))) {
+ parsed_mask |= KRB5_ADM_M_LASTSUCCESS;
+ continue;
+ }
+ else {
+ if (retval != ENOENT)
+ break;
+ }
+
+ /* Check for last failed entry */
+ if (!(retval = decode_kw_gentime(&data[i],
+ KRB5_ADM_KW_LASTFAILED,
+ &dbentp->last_failed))) {
+ parsed_mask |= KRB5_ADM_M_LASTFAILED;
+ continue;
+ }
+ else {
+ if (retval != ENOENT)
+ break;
+ }
+
+ /* Check for failure count */
+ if (!(retval = decode_kw_integer(&data[i],
+ KRB5_ADM_KW_FAILCOUNT,
+ (krb5_ui_4 *)
+ &dbentp->fail_auth_count))) {
+ parsed_mask |= KRB5_ADM_M_FAILCOUNT;
+ continue;
+ }
+ else {
+ if (retval != ENOENT)
+ break;
+ }
+
+ /* Check for auxiliary data */
+ if (!(retval = decode_kw_tagged(&data[i],
+ KRB5_ADM_KW_AUXDATA,
+ 1,
+ taglist,
+ &data_length,
+ &tagged_data))) {
+ krb5_tl_data **fixupp;
+ krb5_tl_data *tl_data, *new_tl;
+
+ /*
+ * We've got a tagged data value here. We've got to do a little
+ * work to put it in the right place. First, find the right place.
+ */
+ fixupp = &dbentp->tl_data;
+ for (tl_data = dbentp->tl_data;
+ tl_data;
+ tl_data = tl_data->tl_data_next)
+ fixupp = &tl_data->tl_data_next;
+
+ /* Get memory */
+ if (new_tl = (krb5_tl_data *) malloc(sizeof(krb5_tl_data))) {
+ /* Fill in the supplied values */
+ new_tl->tl_data_type = (krb5_int16) taglist[0];
+ new_tl->tl_data_length = (krb5_int16) data_length;
+ new_tl->tl_data_contents = tagged_data;
+
+ /* Link in the right place */
+ new_tl->tl_data_next= *fixupp;
+ *fixupp = new_tl;
+
+ /* Update counters and flags */
+ dbentp->n_tl_data++;
+ parsed_mask |= KRB5_ADM_M_AUXDATA;
+ }
+ else {
+ retval = ENOMEM;
+ break;
+ }
+ continue;
+ }
+ else {
+ if ((retval != ENOENT) && (retval != EINVAL))
+ break;
+ }
+
+ /* Check for key data */
+ if (!(retval = decode_kw_tagged(&data[i],
+ KRB5_ADM_KW_KEYDATA,
+ 3,
+ taglist,
+ &data_length,
+ &tagged_data))) {
+ krb5_boolean corr_found;
+ int cindex, kindex;
+ krb5_key_data *kdata;
+
+ /*
+ * See if we already have a correlation betwen our key-tag and
+ * an index into the key table.
+ */
+ corr_found = 0;
+ for (cindex = 0; cindex < ncorrelations; cindex++) {
+ if (correlators[cindex].key_tag == taglist[0]) {
+ correlation = &correlators[cindex];
+ corr_found = 1;
+ break;
+ }
+ }
+
+ /* If not, then we had better make one up */
+ if (!corr_found) {
+ /* Get a new list */
+ if (correlation = (struct key_tag_correlator *)
+ malloc((ncorrelations+1)*
+ sizeof(struct key_tag_correlator))) {
+ /* Save the contents of the old one. */
+ if (ncorrelations) {
+ memcpy(correlation, correlators,
+ ncorrelations*
+ sizeof(struct key_tag_correlator));
+ /* Free the old one */
+ free(correlators);
+ }
+ /* Point us at the new relation */
+ correlators = correlation;
+ correlation = &correlators[ncorrelations];
+ ncorrelations++;
+ correlation->key_tag = taglist[0];
+ /* Make a new key data entry */
+ if (kdata = (krb5_key_data *)
+ malloc((dbentp->n_key_data+1)*sizeof(krb5_key_data))) {
+ /* Copy the old list */
+ if (dbentp->n_key_data) {
+ memcpy(kdata, dbentp->key_data,
+ dbentp->n_key_data*sizeof(krb5_key_data));
+ free(dbentp->key_data);
+ }
+ dbentp->key_data = kdata;
+ correlation->key_data_index = dbentp->n_key_data;
+ memset(&kdata[dbentp->n_key_data], 0,
+ sizeof(krb5_key_data));
+ kdata[dbentp->n_key_data].key_data_ver = 1;
+ dbentp->n_key_data++;
+ corr_found = 1;
+ }
+ else
+ retval = ENOMEM;
+ }
+ else
+ retval = ENOMEM;
+ }
+
+ /* Check to see if we either found a correlation or made one */
+ if (corr_found) {
+ /* Special case for key version number */
+ if (taglist[1] == -1) {
+ dbentp->key_data[correlation->key_data_index].
+ key_data_kvno = taglist[2];
+ }
+ else {
+ dbentp->key_data[correlation->key_data_index].
+ key_data_type[taglist[1]] = taglist[2];
+ dbentp->key_data[correlation->key_data_index].
+ key_data_length[taglist[1]] = (krb5_int16) data_length;
+ dbentp->key_data[correlation->key_data_index].
+ key_data_contents[taglist[1]] = tagged_data;
+ }
+ parsed_mask |= KRB5_ADM_M_KEYDATA;
+ }
+ else
+ break;
+ continue;
+ }
+ else {
+ if ((retval != ENOENT) && (retval != EINVAL))
+ break;
+ }
+
+ /* Check for extra data */
+ if (!(retval = decode_kw_tagged(&data[i],
+ KRB5_ADM_KW_EXTRADATA,
+ 0,
+ taglist,
+ &data_length,
+ &dbentp->e_data))) {
+ dbentp->e_length = (krb5_int16) data_length;
+ parsed_mask |= KRB5_ADM_M_EXTRADATA;
+ continue;
+ }
+ else {
+ if ((retval != ENOENT) && (retval != EINVAL))
+ break;
+ }
+
+ /* If we fall through here, we've got something unrecognized */
+ if (retval) {
+ retval = EINVAL;
+ break;
+ }
+ }
+
+ if (retval) {
+ if (*pwordp) {
+ memset(*pwordp, 0, strlen(*pwordp));
+ free(*pwordp);
+ *pwordp = (char *) NULL;
+ }
+ parsed_mask = 0;
+ }
+ if (correlators)
+ free(correlators);
+ *validp |= parsed_mask;
+ return(retval);
+}
+#endif
diff --git a/src/lib/kadm/adm_kw_enc.c b/src/lib/kadm/adm_kw_enc.c
new file mode 100644
index 000000000..b98725f91
--- /dev/null
+++ b/src/lib/kadm/adm_kw_enc.c
@@ -0,0 +1,433 @@
+/*
+ * lib/kadm/adm_kw_enc.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * adm_kw_enc.c - routines to encode principal attributes in keyword-value
+ * pairs.
+ */
+#include "k5-int.h"
+#include "adm.h"
+#include "adm_proto.h"
+
+
+/*
+ * format_kw_string() - Format a keyword=<string> pair.
+ *
+ * Work routine for other string-based formatters also.
+ */
+static krb5_error_code
+format_kw_string(datap, kwordp, valp)
+ krb5_data *datap;
+ char *kwordp;
+ char *valp;
+{
+ krb5_error_code retval;
+ char fbuffer[BUFSIZ];
+
+ retval = ENOMEM;
+ sprintf(fbuffer,"%s=%s", kwordp, valp);
+ datap->data = (char *) malloc(strlen(fbuffer)+1);
+ if (datap->data) {
+ datap->length = strlen(fbuffer);
+ strcpy(datap->data, fbuffer);
+ retval = 0;
+ }
+ return(retval);
+}
+
+/*
+ * format_kw_integer() - Format a keyword=<integer> pair.
+ */
+static krb5_error_code
+format_kw_integer(datap, kwordp, val)
+ krb5_data *datap;
+ char *kwordp;
+ krb5_ui_4 val;
+{
+ krb5_error_code retval;
+ char fbuffer[BUFSIZ];
+
+ retval = ENOMEM;
+ sprintf(fbuffer,"%s=", kwordp);
+ datap->data = (char *) malloc(strlen(fbuffer)+sizeof(krb5_ui_4));
+ if (datap->data) {
+ datap->length = strlen(fbuffer);
+ strcpy(datap->data, fbuffer);
+ datap->data[datap->length] = (unsigned char) ((val >> 24) & 0xff);
+ datap->data[datap->length+1] = (unsigned char) ((val >> 16) & 0xff);
+ datap->data[datap->length+2] = (unsigned char) ((val >> 8) & 0xff);
+ datap->data[datap->length+3] = (unsigned char) (val & 0xff);
+ datap->length += sizeof(krb5_ui_4);
+ retval = 0;
+ }
+ return(retval);
+}
+
+/*
+ * format_kw_gentime() - Format a keyword=<general-time> pair.
+ *
+ * XXX - should this routine know so much about how generaltime is encoded?
+ */
+static krb5_error_code
+format_kw_gentime(datap, kwordp, timep)
+ krb5_data *datap;
+ char *kwordp;
+ krb5_timestamp *timep;
+{
+ krb5_error_code retval;
+ char fbuffer[BUFSIZ];
+ time_t tval;
+ struct tm *time_gmt;
+
+ retval = EINVAL;
+ tval = (time_t) *timep;
+ time_gmt = gmtime(&tval);
+ if (time_gmt) {
+ sprintf(fbuffer,"%04d%02d%02d%02d%02d%02dZ",
+ time_gmt->tm_year+1900,
+ time_gmt->tm_mon+1,
+ time_gmt->tm_mday,
+ time_gmt->tm_hour,
+ time_gmt->tm_min,
+ time_gmt->tm_sec);
+ retval = format_kw_string(datap, kwordp, fbuffer);
+ }
+ return(retval);
+}
+
+/*
+ * format_kw_tagged() - Format a <tagged>=<taglist>...<value> list.
+ */
+static krb5_error_code
+format_kw_tagged(datap, kwordp, ntags, taglist, vallen, val)
+ krb5_data *datap;
+ char *kwordp;
+ const int ntags;
+ krb5_int32 *taglist;
+ krb5_int32 vallen;
+ krb5_octet *val;
+{
+ krb5_error_code retval;
+ unsigned char *cp;
+ int i;
+
+ /* Calculate the size required:
+ * strlen(kwordp) + 1 for "kword"=
+ * 4 * ntags for tags
+ * vallen for value;
+ */
+ datap->data = (char *) malloc(strlen(kwordp)+
+ 1+
+ (ntags*sizeof(krb5_int32))+
+ vallen+1);
+ if (datap->data) {
+ datap->length = strlen(kwordp)+1+(ntags*sizeof(krb5_int32))+vallen;
+ cp = (unsigned char *) datap->data;
+ cp[datap->length] = '\0';
+ sprintf((char *) cp, "%s=", kwordp);
+ cp += strlen((char *) cp);
+ for (i=0; i<ntags; i++) {
+ cp[0] = (unsigned char) ((taglist[i] >> 24) & 0xff);
+ cp[1] = (unsigned char) ((taglist[i] >> 16) & 0xff);
+ cp[2] = (unsigned char) ((taglist[i] >> 8) & 0xff);
+ cp[3] = (unsigned char) (taglist[i] & 0xff);
+ cp += sizeof(krb5_int32);
+ }
+ if (val && vallen)
+ memcpy(cp, val, vallen);
+ retval = 0;
+ }
+ return(retval);
+}
+
+#if !defined(_MSDOS) && !defined(_WIN32) && !defined(_MACINTOSH)
+/*
+ * krb5_adm_dbent_to_proto() - Convert database a database entry into
+ * an external attribute list.
+ *
+ * "valid" controls the generation of "datap" and "nentp". For each
+ * corresponding bit in "valid" a keyword-value pair is generated from
+ * values in "dbentp" or "password" and put into "datap". The number of
+ * generated pairs is returned in "nentp". Additionally, the KRB5_ADM_M_SET
+ * and KRB5_ADM_M_GET bits control whether we are generating attribute lists
+ * for a "set" operation or a "get" operation. One of these bits must be
+ * specified.
+ *
+ * Successful callers must free the storage for datap and datap->data
+ * either manually or using krb5_free_adm_data().
+ */
+krb5_error_code
+krb5_adm_dbent_to_proto(kcontext, valid, dbentp, password, nentp, datap)
+ krb5_context kcontext; /* Kerberos context */ /* In */
+ krb5_ui_4 valid; /* Valid bitmask */ /* In */
+ krb5_db_entry *dbentp; /* Database entry */ /* In */
+ char *password; /* New password for set */ /* In */
+ krb5_int32 *nentp; /* Number of components */ /* Out */
+ krb5_data **datap; /* Output list */ /* Out */
+{
+ krb5_error_code kret;
+ krb5_data *outlist;
+ size_t n2alloc;
+ int outindex;
+ krb5_boolean is_set;
+ krb5_ui_4 tmp;
+ krb5_int32 taglist[4];
+ krb5_tl_data *tl_data;
+ int keyind, attrind;
+
+ kret = 0;
+ /* First check out whether this is a set or get and the mask */
+ is_set = ((valid & KRB5_ADM_M_SET) == KRB5_ADM_M_SET);
+ if ((is_set && ((valid & ~KRB5_ADM_M_SET_VALID) != 0)) ||
+ (!is_set && ((valid & ~KRB5_ADM_M_GET_VALID) != 0)) ||
+ (!is_set && ((valid & KRB5_ADM_M_GET) == 0)))
+ return(EINVAL);
+
+ /*
+ * Compute the number of elements to allocate. First count set bits.
+ */
+ n2alloc = 0;
+ for (tmp = valid & ~(KRB5_ADM_M_SET|KRB5_ADM_M_GET);
+ tmp;
+ tmp >>= 1) {
+ if (tmp & 1)
+ n2alloc++;
+ }
+ if (valid & KRB5_ADM_M_AUXDATA)
+ n2alloc += (dbentp->n_tl_data - 1);
+ /*
+ * NOTE: If the number of per-key attributes increases, you must increase
+ * the 3 below. The 3 represents 1 for key version, 1 for key type and
+ * one for salt type.
+ */
+ if (valid & KRB5_ADM_M_KEYDATA)
+ n2alloc += ((dbentp->n_key_data*3)-1);
+
+ n2alloc *= sizeof(krb5_data);
+ outindex = 0;
+ outlist = (krb5_data *) malloc(n2alloc);
+ if (outlist) {
+ /* Clear out the output data list */
+ memset((char *) outlist, 0, n2alloc);
+
+ /* Handle password only for set request */
+ if (is_set &&
+ ((valid & KRB5_ADM_M_PASSWORD) != 0) &&
+ password) {
+ if (kret = format_kw_string(&outlist[outindex],
+ KRB5_ADM_KW_PASSWORD,
+ password))
+ goto choke;
+ else
+ outindex++;
+ }
+ /* Handle maximum ticket lifetime */
+ if ((valid & KRB5_ADM_M_MAXLIFE) != 0) {
+ if (kret = format_kw_integer(&outlist[outindex],
+ KRB5_ADM_KW_MAXLIFE,
+ (krb5_ui_4) dbentp->max_life))
+ goto choke;
+ else
+ outindex++;
+ }
+ /* Handle maximum renewable ticket lifetime */
+ if ((valid & KRB5_ADM_M_MAXRENEWLIFE) != 0) {
+ if (kret =
+ format_kw_integer(&outlist[outindex],
+ KRB5_ADM_KW_MAXRENEWLIFE,
+ (krb5_ui_4) dbentp->max_renewable_life))
+ goto choke;
+ else
+ outindex++;
+ }
+ /* Handle principal expiration */
+ if ((valid & KRB5_ADM_M_EXPIRATION) != 0) {
+ if (kret = format_kw_gentime(&outlist[outindex],
+ KRB5_ADM_KW_EXPIRATION,
+ &dbentp->expiration))
+ goto choke;
+ else
+ outindex++;
+ }
+ /* Handle password expiration */
+ if ((valid & KRB5_ADM_M_PWEXPIRATION) != 0) {
+ if (kret = format_kw_gentime(&outlist[outindex],
+ KRB5_ADM_KW_PWEXPIRATION,
+ &dbentp->pw_expiration))
+ goto choke;
+ else
+ outindex++;
+ }
+ /* Random key */
+ if ((valid & KRB5_ADM_M_RANDOMKEY) != 0) {
+ if (kret = format_kw_integer(&outlist[outindex],
+ KRB5_ADM_KW_RANDOMKEY,
+ 1))
+ goto choke;
+ else
+ outindex++;
+ }
+ /* Handle flags */
+ if ((valid & KRB5_ADM_M_FLAGS) != 0) {
+ if (kret = format_kw_integer(&outlist[outindex],
+ KRB5_ADM_KW_FLAGS,
+ (krb5_ui_4) dbentp->attributes))
+ goto choke;
+ else
+ outindex++;
+ }
+ /* Handle last successful password entry */
+ if (!is_set &&
+ ((valid & KRB5_ADM_M_LASTSUCCESS) != 0)) {
+ if (kret = format_kw_gentime(&outlist[outindex],
+ KRB5_ADM_KW_LASTSUCCESS,
+ &dbentp->last_success))
+ goto choke;
+ else
+ outindex++;
+ }
+ /* Handle last failed password attempt */
+ if (!is_set &&
+ ((valid & KRB5_ADM_M_LASTFAILED) != 0)) {
+ if (kret = format_kw_gentime(&outlist[outindex],
+ KRB5_ADM_KW_LASTFAILED,
+ &dbentp->last_failed))
+ goto choke;
+ else
+ outindex++;
+ }
+ /* Handle number of failed password attempts */
+ if (!is_set &&
+ ((valid & KRB5_ADM_M_FAILCOUNT) != 0)) {
+ if (kret = format_kw_integer(&outlist[outindex],
+ KRB5_ADM_KW_FAILCOUNT,
+ (krb5_ui_4) dbentp->fail_auth_count))
+ goto choke;
+ else
+ outindex++;
+ }
+
+ /* Handle the auxiliary data */
+ if ((valid & KRB5_ADM_M_AUXDATA) != 0) {
+ for (tl_data = dbentp->tl_data; tl_data; tl_data =
+ tl_data->tl_data_next) {
+ taglist[0] = (krb5_int32) tl_data->tl_data_type;
+ if (kret = format_kw_tagged(&outlist[outindex],
+ KRB5_ADM_KW_AUXDATA,
+ 1,
+ taglist,
+ (krb5_int32) tl_data->
+ tl_data_length,
+ tl_data->tl_data_contents))
+ goto choke;
+ else
+ outindex++;
+ }
+ }
+
+ /* Handle the key data */
+ if (!is_set &&
+ ((valid & KRB5_ADM_M_KEYDATA) != 0)) {
+ for (keyind = 0; keyind < dbentp->n_key_data; keyind++) {
+ /*
+ * First handle kvno
+ */
+ taglist[0] = (krb5_int32) keyind;
+ taglist[1] = (krb5_int32) -1;
+ taglist[2] = (krb5_int32) dbentp->key_data[keyind].
+ key_data_kvno;
+ if (kret = format_kw_tagged(&outlist[outindex],
+ KRB5_ADM_KW_KEYDATA,
+ 3,
+ taglist,
+ 0,
+ (krb5_octet *) NULL))
+ goto choke;
+ else
+ outindex++;
+
+ /*
+ * Then each attribute as supported.
+ */
+ for (attrind = 0;
+ attrind < KRB5_KDB_V1_KEY_DATA_ARRAY;
+ attrind++) {
+ taglist[1] = (krb5_int32) attrind;
+ taglist[2] = (krb5_int32) dbentp->key_data[keyind].
+ key_data_type[attrind];
+ if (kret = format_kw_tagged(&outlist[outindex],
+ KRB5_ADM_KW_KEYDATA,
+ 3,
+ taglist,
+ (krb5_int32) dbentp->
+ key_data[keyind].
+ key_data_length[attrind],
+ dbentp->key_data[keyind].
+ key_data_contents[attrind])
+ )
+ goto choke;
+ else
+ outindex++;
+ }
+ }
+ }
+
+ /* Finally, handle the extra data */
+ if ((valid & KRB5_ADM_M_EXTRADATA) != 0) {
+ if (kret = format_kw_tagged(&outlist[outindex],
+ KRB5_ADM_KW_EXTRADATA,
+ 0,
+ (krb5_int32 *) NULL,
+ (krb5_int32) dbentp->e_length,
+ dbentp->e_data))
+ goto choke;
+ else
+ outindex++;
+ }
+ }
+ else {
+ if (n2alloc)
+ kret = ENOMEM;
+ }
+ choke:
+ if (kret) {
+ if (outlist) {
+ int i;
+ for (i=0; i<outindex; i++) {
+ if (outlist[i].data) {
+ memset(outlist[i].data, 0, (size_t) outlist[i].length);
+ free(outlist[i].data);
+ }
+ }
+ free(outlist);
+ }
+ outlist = (krb5_data *) NULL;
+ outindex = 0;
+ }
+ *datap = outlist;
+ *nentp = outindex;
+ return(kret);
+}
+#endif
+
diff --git a/src/lib/kadm/adm_rw.c b/src/lib/kadm/adm_rw.c
new file mode 100644
index 000000000..bed4e4bb1
--- /dev/null
+++ b/src/lib/kadm/adm_rw.c
@@ -0,0 +1,534 @@
+/*
+ * lib/kadm/adm_rw.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * Routines to engage in the administrative (password changing) protocol.
+ */
+#define NEED_SOCKETS
+#include "k5-int.h"
+#include "adm_proto.h"
+
+/*
+ * Local prototypes (needed or else the PC will pass fail).
+ */
+static void kadm_copyin_int32 PROTOTYPE((char *, krb5_int32 *));
+static void kadm_copyout_int32 PROTOTYPE((krb5_int32, char *));
+
+/*
+ * Routines to [de]serialize integers.
+ *
+ * kadm_copyin_int32 - Move a 32-bit integer fron network byte order to
+ * host byte order.
+ * kadm_copyout_int32 - Move a 32-bit integer from host byte order to
+ * network byte order.
+ */
+static void
+kadm_copyin_int32(cp, ip)
+ char *cp;
+ krb5_int32 *ip;
+{
+ *ip = (((krb5_int32) ((unsigned char) cp[0]) << 24) +
+ ((krb5_int32) ((unsigned char) cp[1]) << 16) +
+ ((krb5_int32) ((unsigned char) cp[2]) << 8) +
+ ((krb5_int32) ((unsigned char) cp[3])));
+}
+
+static void
+kadm_copyout_int32(outint, cp)
+ krb5_int32 outint;
+ char *cp;
+{
+ cp[0] = (char) ((outint >> 24) & 0xff);
+ cp[1] = (char) ((outint >> 16) & 0xff);
+ cp[2] = (char) ((outint >> 8) & 0xff);
+ cp[3] = (char) (outint & 0xff);
+}
+
+/*
+ * krb5_free_adm_data() - Free data blocks allocated by read_adm... routines.
+ */
+void INTERFACE
+krb5_free_adm_data(kcontext, ncomp, datap)
+ krb5_context kcontext;
+ krb5_int32 ncomp;
+ krb5_data *datap;
+{
+ int i;
+
+ if (datap) {
+ for (i=0; i<ncomp; i++)
+ if (datap[i].data && (datap[i].length > 0))
+ krb5_xfree(datap[i].data);
+
+ krb5_xfree(datap);
+ }
+}
+
+/*
+ * krb5_send_adm_cmd() - Send an administrative command.
+ *
+ * Send a list of data in a KRB_PRIV message. Data takes the format:
+ * nargs (4 octets in network order)
+ * arg size 1 (4 octets in network order)
+ * arg data 1 ("arg size 1" octets)
+ * .
+ * .
+ * .
+ */
+krb5_error_code INTERFACE
+krb5_send_adm_cmd(kcontext, sock, ctx, nargs, arglist)
+ krb5_context kcontext; /* Context handle (In ) */
+ krb5_pointer sock; /* Socket to write to (In ) */
+ krb5_auth_context ctx; /* Auth context (In ) */
+ krb5_int32 nargs; /* Number of arguments (In ) */
+ krb5_data *arglist; /* Components to write (In ) */
+{
+ int writebufsize;
+ int i;
+ char *writebuf;
+ krb5_error_code ret;
+ krb5_int32 ac_flags;
+
+ /*
+ * First check that our auth context has the right flags in it.
+ */
+ if (ret = krb5_auth_con_getflags(kcontext, ctx, &ac_flags))
+ return(ret);
+
+ if ((ac_flags & (KRB5_AUTH_CONTEXT_RET_SEQUENCE|
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE)) !=
+ (KRB5_AUTH_CONTEXT_RET_SEQUENCE|KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
+ /* XXX - need a better error */
+ return(KRB5KRB_AP_ERR_MSG_TYPE);
+ }
+
+ ret = 0;
+ /* Calculate write buffer size */
+ writebufsize = sizeof(krb5_int32);
+ for (i=0; i<nargs; i++) {
+ writebufsize += sizeof(krb5_int32); /* for argument size */
+ writebufsize += arglist[i].length; /* for actual arg */
+ }
+
+ if (writebuf = (char *) malloc(writebufsize)) {
+ char *curr;
+ krb5_data write_data, out_data;
+ krb5_replay_data replay_data;
+
+ /* Serialize into write buffer - first number of arguments */
+ curr = writebuf;
+ kadm_copyout_int32(nargs, curr);
+ curr += sizeof(krb5_int32);
+
+ /* Then the arguments */
+ for (i=0; i<nargs; i++) {
+ kadm_copyout_int32(arglist[i].length, curr);
+ curr += sizeof(krb5_int32);
+ memcpy(curr, arglist[i].data, arglist[i].length);
+ curr += arglist[i].length;
+ }
+
+ /* Set up the message */
+ write_data.length = writebufsize;
+ write_data.data = writebuf;
+
+ /* Generate the message */
+ if (!(ret = krb5_mk_priv(kcontext,
+ ctx,
+ &write_data,
+ &out_data,
+ &replay_data))) {
+ /* Write the message */
+ if (ret = krb5_write_message(kcontext, sock, &out_data))
+ goto cleanup;
+ krb5_xfree(out_data.data);
+ }
+
+ cleanup:
+ /* Paranoia */
+ memset(writebuf, 0, writebufsize);
+ free(writebuf);
+ }
+ else {
+ /* error */
+ ret = ENOMEM;
+ }
+ return(ret);
+}
+
+/*
+ * krb5_send_adm_reply() - Send an administrative reply.
+ *
+ * Send a reply in a KRB_PRIV message. Data takes the format:
+ * status (4 octets in network order)
+ * ncomps (4 octets in network order)
+ * comp size 1 (4 octets in network order)
+ * comp data 1 ("comp size 1" octets)
+ * .
+ * .
+ * .
+ */
+krb5_error_code
+krb5_send_adm_reply(kcontext, sock, ctx, cmd_stat, ncomps, complist)
+ krb5_context kcontext; /* Context handle (In ) */
+ krb5_pointer sock; /* Socket to write to (In ) */
+ krb5_auth_context ctx; /* Auth context (In ) */
+ krb5_int32 cmd_stat; /* Command status (In ) */
+ krb5_int32 ncomps; /* Number of arguments (In ) */
+ krb5_data *complist; /* Components to write (In ) */
+{
+ int writebufsize;
+ int i;
+ char *writebuf;
+ krb5_error_code ret;
+ krb5_int32 ac_flags;
+
+ /*
+ * First check that our auth context has the right flags in it.
+ */
+ if (ret = krb5_auth_con_getflags(kcontext, ctx, &ac_flags))
+ return(ret);
+
+ if ((ac_flags & (KRB5_AUTH_CONTEXT_RET_SEQUENCE|
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE)) !=
+ (KRB5_AUTH_CONTEXT_RET_SEQUENCE|KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
+ /* XXX - need a better error */
+ return(KRB5KRB_AP_ERR_MSG_TYPE);
+ }
+
+ ret = 0;
+ /* Calculate write buffer size */
+ writebufsize = 2 * sizeof(krb5_int32);
+ for (i=0; i<ncomps; i++) {
+ writebufsize += sizeof(krb5_int32); /* for argument size */
+ writebufsize += complist[i].length; /* for actual arg */
+ }
+
+ if (writebuf = (char *) malloc(writebufsize)) {
+ char *curr;
+ krb5_data write_data, out_data;
+ krb5_replay_data replay_data;
+
+ /* Serialize into write buffer - first command status */
+ curr = writebuf;
+ kadm_copyout_int32(cmd_stat, curr);
+ curr += sizeof(krb5_int32);
+
+ /* Now number of reply components */
+ kadm_copyout_int32(ncomps, curr);
+ curr += sizeof(krb5_int32);
+
+ /* Then the arguments */
+ for (i=0; i<ncomps; i++) {
+ kadm_copyout_int32(complist[i].length, curr);
+ curr += sizeof(krb5_int32);
+ memcpy(curr, complist[i].data, complist[i].length);
+ curr += complist[i].length;
+ }
+
+ /* Set up the message */
+ write_data.length = writebufsize;
+ write_data.data = writebuf;
+
+ /* Generate the message */
+ if (!(ret = krb5_mk_priv(kcontext,
+ ctx,
+ &write_data,
+ &out_data,
+ &replay_data))) {
+ /* Write the message */
+ if (ret = krb5_write_message(kcontext, sock, &out_data))
+ goto cleanup;
+ krb5_xfree(out_data.data);
+ }
+
+ cleanup:
+ /* Paranoia */
+ memset(writebuf, 0, writebufsize);
+ free(writebuf);
+ }
+ else {
+ /* error */
+ ret = ENOMEM;
+ }
+ return(ret);
+}
+
+/*
+ * krb5_read_adm_cmd() - Read an administrative protocol command.
+ *
+ * Read an administrative command from the socket. Expect data in the
+ * same format as send_adm_cmd shoots them out in.
+ *
+ * It is the caller's responsibility to free the memory allocated for
+ * the read in argument list.
+ */
+krb5_error_code
+krb5_read_adm_cmd(kcontext, sock, ctx, nargs, arglist)
+ krb5_context kcontext; /* Context handle (In ) */
+ krb5_pointer sock; /* Socket to read from (In ) */
+ krb5_auth_context ctx; /* Auth context (In ) */
+ krb5_int32 *nargs; /* Number of arguments (Out) */
+ krb5_data **arglist; /* List of arguments (Out) */
+{
+ krb5_data read_data;
+ krb5_error_code ret;
+ krb5_data msg_data;
+ krb5_replay_data replay_data;
+ krb5_int32 ac_flags;
+ krb5_int32 len32;
+
+ /*
+ * First check that our auth context has the right flags in it.
+ */
+ if (ret = krb5_auth_con_getflags(kcontext, ctx, &ac_flags))
+ return(ret);
+
+ if ((ac_flags & (KRB5_AUTH_CONTEXT_RET_SEQUENCE|
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE)) !=
+ (KRB5_AUTH_CONTEXT_RET_SEQUENCE|KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
+ /* XXX - need a better error */
+ return(KRB5KRB_AP_ERR_MSG_TYPE);
+ }
+
+ if (!(ret = krb5_read_message(kcontext, sock, &read_data))) {
+ if (!(ret = krb5_rd_priv(kcontext,
+ ctx,
+ &read_data,
+ &msg_data,
+ &replay_data))) {
+ char *curr;
+ int replyok;
+ int i;
+
+ replyok = 0;
+ /* We'd better have at least one reply component */
+ if (msg_data.length >= sizeof(krb5_int32)) {
+ curr = msg_data.data;
+ kadm_copyin_int32(curr, nargs);
+ curr += sizeof(krb5_int32);
+
+ /* Are there any components to copy? */
+ if (*nargs > 0) {
+
+ /* Get the memory for the list */
+ if (*arglist = (krb5_data *)
+ malloc((size_t) (*nargs) * sizeof(krb5_data))) {
+ krb5_data *xarglist;
+
+ xarglist = *arglist;
+ memset((char *) (xarglist), 0,
+ (size_t) (*nargs) * sizeof(krb5_data));
+
+ replyok = 1;
+ /* Copy out each list entry */
+ for (i=0; i<*nargs; i++) {
+
+ /* First get the length of the reply component */
+ if (curr + sizeof(krb5_int32) - msg_data.data <=
+ msg_data.length) {
+
+ kadm_copyin_int32(curr, &len32);
+ xarglist[i].length = (int) len32;
+ curr += sizeof(krb5_int32);
+
+ /* Then get the memory for the actual data */
+ if ((curr + xarglist[i].length -
+ msg_data.data <= msg_data.length) &&
+ (xarglist[i].data = (char *)
+ malloc(xarglist[i].length+1))) {
+
+ /* Then copy it out */
+ memcpy(xarglist[i].data,
+ curr,
+ xarglist[i].length);
+ curr += xarglist[i].length;
+
+ /* Null terminate for convenience */
+ xarglist[i].data[xarglist[i].length]
+ = '\0';
+ }
+ else {
+ /* Not enough remaining data. */
+ replyok = 0;
+ break;
+ }
+ }
+ else {
+ /* Not enough remaining data */
+ replyok = 0;
+ break;
+ }
+ }
+ if (!replyok)
+ krb5_free_adm_data(kcontext, *nargs, *arglist);
+ }
+ }
+ else {
+ if (*nargs == 0) {
+ *arglist = (krb5_data *) NULL;
+ replyok = 1;
+ }
+ }
+ }
+ if (!replyok) {
+ ret = KRB5KRB_AP_ERR_MSG_TYPE; /* syntax error */
+ }
+ memset(msg_data.data, 0, msg_data.length);
+ krb5_xfree(msg_data.data);
+ }
+ krb5_xfree(read_data.data);
+ }
+ return(ret);
+}
+
+/*
+ * krb5_read_adm_reply() - Read an administrative protocol response.
+ *
+ * Expect to read them out in the same format as send_adm_reply shoots them
+ * in.
+ *
+ * It is the caller's responsibility to free the memory allocated for
+ * the read in component list.
+ */
+krb5_error_code INTERFACE
+krb5_read_adm_reply(kcontext, sock, ctx, cmd_stat, ncomps, complist)
+ krb5_context kcontext; /* Context handle (In ) */
+ krb5_pointer sock; /* Socket to read from (In ) */
+ krb5_auth_context ctx; /* Auth context (In ) */
+ krb5_int32 *cmd_stat; /* Command status (Out) */
+ krb5_int32 *ncomps; /* # of reply components(Out) */
+ krb5_data **complist; /* List of components (Out) */
+{
+ krb5_data read_data;
+ krb5_error_code ret;
+ krb5_data msg_data;
+ krb5_replay_data replay_data;
+ krb5_int32 ac_flags;
+ krb5_int32 len32;
+
+ /*
+ * First check that our auth context has the right flags in it.
+ */
+ if (ret = krb5_auth_con_getflags(kcontext, ctx, &ac_flags))
+ return(ret);
+
+ if ((ac_flags & (KRB5_AUTH_CONTEXT_RET_SEQUENCE|
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE)) !=
+ (KRB5_AUTH_CONTEXT_RET_SEQUENCE|KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
+ /* XXX - need a better error */
+ return(KRB5KRB_AP_ERR_MSG_TYPE);
+ }
+
+ if (!(ret = krb5_read_message(kcontext, sock, &read_data))) {
+ if (!(ret = krb5_rd_priv(kcontext,
+ ctx,
+ &read_data,
+ &msg_data,
+ &replay_data))) {
+ char *curr;
+ int replyok;
+ int i;
+
+ replyok = 0;
+ /* We'd better have at least two reply components */
+ if (msg_data.length >= (2*sizeof(krb5_int32))) {
+ curr = msg_data.data;
+ kadm_copyin_int32(curr, cmd_stat);
+ curr += sizeof(krb5_int32);
+ kadm_copyin_int32(curr, ncomps);
+ curr += sizeof(krb5_int32);
+
+ /* Are there any components to copy? */
+ if (*ncomps > 0) {
+
+ /* Get the memory for the list */
+ if (*complist = (krb5_data *)
+ malloc((size_t) ((*ncomps) * sizeof(krb5_data)))) {
+ krb5_data *xcomplist;
+
+ xcomplist = *complist;
+ memset((char *) (xcomplist), 0,
+ (size_t) ((*ncomps) * sizeof(krb5_data)));
+
+ replyok = 1;
+ /* Copy out each list entry */
+ for (i=0; i<*ncomps; i++) {
+
+ /* First get the length of the reply component */
+ if (curr + sizeof(krb5_int32) - msg_data.data <=
+ msg_data.length) {
+ kadm_copyin_int32(curr, &len32);
+ xcomplist[i].length = (int) len32;
+ curr += sizeof(krb5_int32);
+
+ /* Then get the memory for the actual data */
+ if ((curr + xcomplist[i].length -
+ msg_data.data <= msg_data.length) &&
+ (xcomplist[i].data = (char *)
+ malloc(xcomplist[i].length+1))) {
+
+ /* Then copy it out */
+ memcpy(xcomplist[i].data,
+ curr,
+ xcomplist[i].length);
+ curr += xcomplist[i].length;
+
+ /* Null terminate for convenience */
+ xcomplist[i].data[xcomplist[i].length]
+ = '\0';
+ }
+ else {
+ /* Not enough remaining data. */
+ replyok = 0;
+ break;
+ }
+ }
+ else {
+ /* Not enough remaining data */
+ replyok = 0;
+ break;
+ }
+ }
+ if (!replyok)
+ krb5_free_adm_data(kcontext, *ncomps, *complist);
+ }
+ }
+ else {
+ if (*ncomps == 0) {
+ *complist = (krb5_data *) NULL;
+ replyok = 1;
+ }
+ }
+ }
+ if (!replyok) {
+ ret = KRB5KRB_AP_ERR_MSG_TYPE; /* syntax error */
+ }
+ memset(msg_data.data, 0, msg_data.length);
+ krb5_xfree(msg_data.data);
+ }
+ krb5_xfree(read_data.data);
+ }
+ return(ret);
+}
diff --git a/src/lib/kadm/alt_prof.c b/src/lib/kadm/alt_prof.c
new file mode 100644
index 000000000..9556ac450
--- /dev/null
+++ b/src/lib/kadm/alt_prof.c
@@ -0,0 +1,447 @@
+/*
+ * lib/kadm/alt_prof.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * alt_prof.c - Implement alternate profile file handling.
+ */
+#include "k5-int.h"
+#include "adm.h"
+#include "adm_proto.h"
+#include <stdio.h>
+#include <ctype.h>
+
+/*
+ * krb5_aprof_init() - Initialize alternate profile context.
+ *
+ * Parameters:
+ * fname - default file name of the profile.
+ * envname - environment variable name which can override fname.
+ * acontextp - Pointer to opaque context for alternate profile.
+ *
+ * Returns:
+ * error codes from profile_init()
+ */
+krb5_error_code
+krb5_aprof_init(fname, envname, acontextp)
+ char *fname;
+ char *envname;
+ krb5_pointer *acontextp;
+{
+ krb5_error_code kret;
+ const char *namelist[2];
+ profile_t profile;
+
+ namelist[1] = (char *) NULL;
+ profile = (profile_t) NULL;
+ if (envname) {
+ if ((namelist[0] = getenv(envname))) {
+ if (!(kret = profile_init(namelist, &profile))) {
+ *acontextp = (krb5_pointer) profile;
+ return(0);
+ }
+ }
+ }
+ namelist[0] = fname;
+ profile = (profile_t) NULL;
+ if (!(kret = profile_init(namelist, &profile))) {
+ *acontextp = (krb5_pointer) profile;
+ return(0);
+ }
+ return(kret);
+}
+
+/*
+ * krb5_aprof_getvals() - Get values from alternate profile.
+ *
+ * Parameters:
+ * acontext - opaque context for alternate profile.
+ * hierarchy - hierarchy of value to retrieve.
+ * retdata - Returned data values.
+ *
+ * Returns:
+ * error codes from profile_get_values()
+ */
+krb5_error_code
+krb5_aprof_getvals(acontext, hierarchy, retdata)
+ krb5_pointer acontext;
+ const char **hierarchy;
+ char ***retdata;
+{
+ return(profile_get_values((profile_t) acontext,
+ hierarchy,
+ retdata));
+}
+
+/*
+ * krb5_aprof_get_deltat() - Get a delta time value from the alternate
+ * profile.
+ *
+ * Parameters:
+ * acontext - opaque context for alternate profile.
+ * hierarchy - hierarchy of value to retrieve.
+ * uselast - if true, use last value, otherwise use
+ * first value found.
+ * deltatp - returned delta time value.
+ *
+ * Returns:
+ * error codes from profile_get_values()
+ * error codes from krb5_string_to_deltat()
+ */
+krb5_error_code
+krb5_aprof_get_deltat(acontext, hierarchy, uselast, deltatp)
+ krb5_pointer acontext;
+ const char **hierarchy;
+ krb5_boolean uselast;
+ krb5_deltat *deltatp;
+{
+ krb5_error_code kret;
+ char **values;
+ char *valp;
+ int index;
+
+ if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
+ index = 0;
+ if (uselast) {
+ for (index=0; values[index]; index++);
+ index--;
+ }
+ valp = values[index];
+ kret = krb5_string_to_deltat(valp, deltatp);
+
+ /* Free the string storage */
+ for (index=0; values[index]; index++)
+ krb5_xfree(values[index]);
+ krb5_xfree(values);
+ }
+ return(kret);
+}
+
+/*
+ * krb5_aprof_get_string() - Get a string value from the alternate
+ * profile.
+ *
+ * Parameters:
+ * acontext - opaque context for alternate profile.
+ * hierarchy - hierarchy of value to retrieve.
+ * uselast - if true, use last value, otherwise use
+ * first value found.
+ * stringp - returned string value.
+ *
+ * Returns:
+ * error codes from profile_get_values()
+ */
+krb5_error_code
+krb5_aprof_get_string(acontext, hierarchy, uselast, stringp)
+ krb5_pointer acontext;
+ const char **hierarchy;
+ krb5_boolean uselast;
+ char **stringp;
+{
+ krb5_error_code kret;
+ char **values;
+ int index, i;
+
+ if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
+ index = 0;
+ if (uselast) {
+ for (index=0; values[index]; index++);
+ index--;
+ }
+
+ *stringp = values[index];
+
+ /* Free the string storage */
+ for (i=0; values[i]; i++)
+ if (i != index)
+ krb5_xfree(values[i]);
+ krb5_xfree(values);
+ }
+ return(kret);
+}
+
+/*
+ * krb5_aprof_get_int32() - Get a 32-bit integer value from the alternate
+ * profile.
+ *
+ * Parameters:
+ * acontext - opaque context for alternate profile.
+ * hierarchy - hierarchy of value to retrieve.
+ * uselast - if true, use last value, otherwise use
+ * first value found.
+ * intp - returned 32-bit integer value.
+ *
+ * Returns:
+ * error codes from profile_get_values()
+ * EINVAL - value is not an integer
+ */
+krb5_error_code
+krb5_aprof_get_int32(acontext, hierarchy, uselast, intp)
+ krb5_pointer acontext;
+ const char **hierarchy;
+ krb5_boolean uselast;
+ krb5_int32 *intp;
+{
+ krb5_error_code kret;
+ char **values;
+ int index;
+
+ if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
+ index = 0;
+ if (uselast) {
+ for (index=0; values[index]; index++);
+ index--;
+ }
+
+ if (sscanf(values[index], "%d", intp) != 1)
+ kret = EINVAL;
+
+ /* Free the string storage */
+ for (index=0; values[index]; index++)
+ krb5_xfree(values[index]);
+ krb5_xfree(values);
+ }
+ return(kret);
+}
+
+/*
+ * krb5_aprof_finish() - Finish alternate profile context.
+ *
+ * Parameter:
+ * acontext - opaque context for alternate profile.
+ *
+ * Returns:
+ * 0 on success, something else on failure.
+ */
+krb5_error_code
+krb5_aprof_finish(acontext)
+ krb5_pointer acontext;
+{
+ profile_release(acontext);
+ return(0);
+}
+
+/*
+ * krb5_read_realm_params() - Read per-realm parameters from KDC
+ * alternate profile.
+ */
+krb5_error_code
+krb5_read_realm_params(kcontext, realm, kdcprofile, kdcenv, rparamp)
+ krb5_context kcontext;
+ char *realm;
+ char *kdcprofile;
+ char *kdcenv;
+ krb5_realm_params **rparamp;
+{
+ char *filename;
+ char *envname;
+ char *lrealm;
+ krb5_pointer aprofile = 0;
+ krb5_realm_params *rparams;
+ const char *hierarchy[4];
+ char *svalue;
+ krb5_int32 ivalue;
+ krb5_deltat dtvalue;
+
+ krb5_error_code kret;
+
+ filename = (kdcprofile) ? kdcprofile : DEFAULT_KDC_PROFILE;
+ envname = (kdcenv) ? kdcenv : KDC_PROFILE_ENV;
+
+ if (kcontext->profile_secure == TRUE) envname = 0;
+
+ rparams = (krb5_realm_params *) NULL;
+ if (realm)
+ lrealm = strdup(realm);
+ else {
+ kret = krb5_get_default_realm(kcontext, &lrealm);
+ if (kret)
+ goto cleanup;
+ }
+
+ kret = krb5_aprof_init(filename, envname, &aprofile);
+ if (kret)
+ goto cleanup;
+
+ rparams = (krb5_realm_params *) malloc(sizeof(krb5_realm_params));
+ if (rparams == 0) {
+ kret = ENOMEM;
+ goto cleanup;
+ }
+
+ /* Initialize realm parameters */
+ memset((char *) rparams, 0, sizeof(krb5_realm_params));
+
+ /* Get the value for the database */
+ hierarchy[0] = "realms";
+ hierarchy[1] = lrealm;
+ hierarchy[2] = "database_name";
+ hierarchy[3] = (char *) NULL;
+ if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+ rparams->realm_dbname = svalue;
+
+ /* Get the value for the KDC port list */
+ hierarchy[2] = "kdc_ports";
+ if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+ rparams->realm_kdc_ports = svalue;
+
+ /* Get the name of the acl file */
+ hierarchy[2] = "acl_file";
+ if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+ rparams->realm_acl_file = svalue;
+
+ /* Get the value for the kadmind port */
+ hierarchy[2] = "kadmind_port";
+ if (!krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) {
+ rparams->realm_kadmind_port = ivalue;
+ rparams->realm_kadmind_port_valid = 1;
+ }
+
+ /* Get the value for the master key name */
+ hierarchy[2] = "master_key_name";
+ if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+ rparams->realm_mkey_name = svalue;
+
+ /* Get the value for the master key type */
+ hierarchy[2] = "master_key_type";
+ if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ if (!krb5_string_to_enctype(svalue, &rparams->realm_enctype))
+ rparams->realm_enctype_valid = 1;
+ krb5_xfree(svalue);
+ }
+
+ /* Get the value for the stashfile */
+ hierarchy[2] = "key_stash_file";
+ if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+ rparams->realm_stash_file = svalue;
+
+ /* Get the value for maximum ticket lifetime. */
+ hierarchy[2] = "max_life";
+ if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) {
+ rparams->realm_max_life = dtvalue;
+ rparams->realm_max_life_valid = 1;
+ }
+
+ /* Get the value for maximum renewable ticket lifetime. */
+ hierarchy[2] = "max_renewable_life";
+ if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) {
+ rparams->realm_max_rlife = dtvalue;
+ rparams->realm_max_rlife_valid = 1;
+ }
+
+ /* Get the value for the default principal expiration */
+ hierarchy[2] = "default_principal_expiration";
+ if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ if (!krb5_string_to_timestamp(svalue,
+ &rparams->realm_expiration))
+ rparams->realm_expiration_valid = 1;
+ krb5_xfree(svalue);
+ }
+
+ /* Get the value for the default principal flags */
+ hierarchy[2] = "default_principal_flags";
+ if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ char *sp, *ep, *tp;
+
+ sp = svalue;
+ rparams->realm_flags = 0;
+ while (sp) {
+ if ((ep = strchr(sp, (int) ',')) ||
+ (ep = strchr(sp, (int) ' ')) ||
+ (ep = strchr(sp, (int) '\t'))) {
+ /* Fill in trailing whitespace of sp */
+ tp = ep - 1;
+ while (isspace(*tp) && (tp < sp)) {
+ *tp = '\0';
+ tp--;
+ }
+ *ep = '\0';
+ ep++;
+ /* Skip over trailing whitespace of ep */
+ while (isspace(*ep) && (*ep)) ep++;
+ }
+ /* Convert this flag */
+ if (krb5_string_to_flags(sp,
+ "+",
+ "-",
+ &rparams->realm_flags))
+ break;
+ sp = ep;
+ }
+ if (!sp)
+ rparams->realm_flags_valid = 1;
+ krb5_xfree(svalue);
+ }
+
+ /* Get the value for the supported enctype/salttype matrix */
+ hierarchy[2] = "supported_enctypes";
+ if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ krb5_string_to_keysalts(svalue,
+ ", \t", /* Tuple separators */
+ ":.-", /* Key/salt separators */
+ 0, /* No duplicates */
+ &rparams->realm_keysalts,
+ &rparams->realm_num_keysalts);
+ krb5_xfree(svalue);
+ }
+
+cleanup:
+ if (aprofile)
+ krb5_aprof_finish(aprofile);
+ if (lrealm)
+ free(lrealm);
+ if (kret) {
+ if (rparams)
+ krb5_free_realm_params(kcontext, rparams);
+ rparams = 0;
+ }
+ *rparamp = rparams;
+ return(kret);
+}
+
+/*
+ * krb5_free_realm_params() - Free data allocated by above.
+ */
+krb5_error_code
+krb5_free_realm_params(kcontext, rparams)
+ krb5_context kcontext;
+ krb5_realm_params *rparams;
+{
+ if (rparams) {
+ if (rparams->realm_profile)
+ krb5_xfree(rparams->realm_profile);
+ if (rparams->realm_dbname)
+ krb5_xfree(rparams->realm_dbname);
+ if (rparams->realm_mkey_name)
+ krb5_xfree(rparams->realm_mkey_name);
+ if (rparams->realm_stash_file)
+ krb5_xfree(rparams->realm_stash_file);
+ if (rparams->realm_keysalts)
+ krb5_xfree(rparams->realm_keysalts);
+ if (rparams->realm_kdc_ports)
+ krb5_xfree(rparams->realm_kdc_ports);
+ krb5_xfree(rparams);
+ }
+ return(0);
+}
+
diff --git a/src/lib/kadm/configure.in b/src/lib/kadm/configure.in
new file mode 100644
index 000000000..a3d4ab55e
--- /dev/null
+++ b/src/lib/kadm/configure.in
@@ -0,0 +1,16 @@
+AC_INIT(configure.in)
+CONFIG_RULES
+AC_PROG_ARCHIVE
+AC_PROG_ARCHIVE_ADD
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+AC_HEADER_STDARG
+AC_HAVE_HEADERS(pwd.h syslog.h)
+AC_HAVE_FUNCS(srand48 srand srandom syslog openlog closelog)
+AC_FUNC_CHECK(vsprintf,AC_DEFINE(HAVE_VSPRINTF))
+AC_PROG_AWK
+KRB5_RUN_FLAGS
+LinkFileDir(../libkadm.a, libkadm.a, ./kadm)
+AppendRule([all-unix:: ../libkadm.a])
+AppendRule([all:: all-$(WHAT)])
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/lib/kadm/keysalt.c b/src/lib/kadm/keysalt.c
new file mode 100644
index 000000000..e8b9b4a33
--- /dev/null
+++ b/src/lib/kadm/keysalt.c
@@ -0,0 +1,207 @@
+/*
+ * lib/kadm/keysalt.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * keysalt.c - Routines to handle key/salt tuples.
+ */
+#include "k5-int.h"
+#include "adm.h"
+#include "adm_proto.h"
+
+static const char default_tupleseps[] = ", \t";
+static const char default_ksaltseps[] = ":.";
+
+/*
+ * krb5_keysalt_is_present() - Determine if a key/salt pair is present
+ * in a list of key/salt tuples.
+ *
+ * Salttype may be negative to indicate a search for only a enctype.
+ */
+krb5_boolean
+krb5_keysalt_is_present(ksaltlist, nksalts, enctype, salttype)
+ krb5_key_salt_tuple *ksaltlist;
+ krb5_int32 nksalts;
+ krb5_enctype enctype;
+ krb5_int32 salttype;
+{
+ krb5_boolean foundit;
+ int i;
+
+ foundit = 0;
+ if (ksaltlist) {
+ for (i=0; i<nksalts; i++) {
+ if ((ksaltlist[i].ks_enctype == enctype) &&
+ ((ksaltlist[i].ks_salttype == salttype) ||
+ (salttype < 0))) {
+ foundit = 1;
+ break;
+ }
+ }
+ }
+ return(foundit);
+}
+
+/*
+ * krb5_keysalt_iterate() - Do something for each unique key/salt
+ * combination.
+ *
+ * If ignoresalt set, then salttype is ignored.
+ */
+krb5_error_code
+krb5_keysalt_iterate(ksaltlist, nksalt, ignoresalt, iterator, arg)
+ krb5_key_salt_tuple *ksaltlist;
+ krb5_int32 nksalt;
+ krb5_boolean ignoresalt;
+ krb5_error_code (*iterator) KRB5_NPROTOTYPE((krb5_key_salt_tuple *,
+ krb5_pointer));
+ krb5_pointer arg;
+{
+ int i;
+ krb5_error_code kret;
+ krb5_key_salt_tuple scratch;
+
+ kret = 0;
+ for (i=0; i<nksalt; i++) {
+ scratch.ks_enctype = ksaltlist[i].ks_enctype;
+ scratch.ks_salttype = (ignoresalt) ? -1 : ksaltlist[i].ks_salttype;
+ if (!krb5_keysalt_is_present(ksaltlist,
+ i,
+ scratch.ks_enctype,
+ scratch.ks_salttype)) {
+ if (kret = (*iterator)(&scratch, arg))
+ break;
+ }
+ }
+ return(kret);
+}
+
+/*
+ * krb5_string_to_keysalts() - Convert a string representation to a list
+ * of key/salt tuples.
+ */
+krb5_error_code
+krb5_string_to_keysalts(string, tupleseps, ksaltseps, dups, ksaltp, nksaltp)
+ char *string;
+ const char *tupleseps;
+ const char *ksaltseps;
+ krb5_boolean dups;
+ krb5_key_salt_tuple **ksaltp;
+ krb5_int32 *nksaltp;
+{
+ krb5_error_code kret;
+ char *kp, *sp, *ep;
+ char sepchar, trailchar;
+ krb5_enctype ktype;
+ krb5_int32 stype;
+ krb5_key_salt_tuple *savep;
+ const char *tseplist;
+ const char *ksseplist;
+ const char *septmp;
+ size_t len;
+
+ kret = 0;
+ kp = string;
+ tseplist = (tupleseps) ? tupleseps : default_tupleseps;
+ ksseplist = (ksaltseps) ? ksaltseps : default_ksaltseps;
+ while (kp) {
+ /* Attempt to find a separator */
+ ep = (char *) NULL;
+ if (*tseplist) {
+ septmp = tseplist;
+ for (ep = strchr(kp, (int) *septmp);
+ *(++septmp) && !ep;
+ ep = strchr(kp, (int) *septmp));
+ }
+
+ if (ep) {
+ trailchar = *ep;
+ *ep = '\0';
+ ep++;
+ }
+ /*
+ * kp points to something (hopefully) of the form:
+ * <enctype><ksseplist><salttype>
+ * or
+ * <enctype>
+ */
+ sp = (char *) NULL;
+ /* Attempt to find a separator */
+ septmp = ksseplist;
+ for (sp = strchr(kp, (int) *septmp);
+ *(++septmp) && !sp;
+ ep = strchr(kp, (int) *septmp));
+
+ if (sp) {
+ /* Separate enctype from salttype */
+ sepchar = *sp;
+ *sp = '\0';
+ sp++;
+ }
+ else
+ stype = -1;
+
+ /*
+ * Attempt to parse enctype and salttype. If we parse well
+ * then make sure that it specifies a unique key/salt combo
+ */
+ if (!krb5_string_to_enctype(kp, &ktype) &&
+ (!sp || !krb5_string_to_salttype(sp, &stype)) &&
+ (dups ||
+ !krb5_keysalt_is_present(*ksaltp, *nksaltp, ktype, stype))) {
+
+ /* Squirrel away old keysalt array */
+ savep = *ksaltp;
+ len = (size_t) *nksaltp;
+
+ /* Get new keysalt array */
+ if (*ksaltp = (krb5_key_salt_tuple *)
+ malloc((len + 1) * sizeof(krb5_key_salt_tuple))) {
+
+ /* Copy old keysalt if appropriate */
+ if (savep) {
+ memcpy(*ksaltp, savep,
+ len * sizeof(krb5_key_salt_tuple));
+ krb5_xfree(savep);
+ }
+
+ /* Save our values */
+ (*ksaltp)[(*nksaltp)].ks_enctype = ktype;
+ (*ksaltp)[(*nksaltp)].ks_salttype = stype;
+ (*nksaltp)++;
+ }
+ else {
+ *ksaltp = savep;
+ break;
+ }
+ }
+ if (sp)
+ sp[-1] = sepchar;
+ if (ep)
+ ep[-1] = trailchar;
+ kp = ep;
+ }
+ return(kret);
+}
+
+
diff --git a/src/lib/kadm/krb5strings.M b/src/lib/kadm/krb5strings.M
new file mode 100644
index 000000000..de118ba8e
--- /dev/null
+++ b/src/lib/kadm/krb5strings.M
@@ -0,0 +1,250 @@
+.\" lib/kadm/krb5strings.M
+.\" Copyright 1995 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 KRB5STRINGS 3 "Kerberos Version 5.0" "MIT Project Athena"
+.SH NAME
+krb5strings \- String representations of Kerberos V5 internal data.
+.SH KEY TYPES
+The following strings specify valid key types for use by Kerberos V5.
+.TP 2i
+.I null
+Specifies KEYTYPE_NULL.
+.TP 2i
+.I des
+Specifies KEYTYPE_DES.
+
+.SH SALT TYPES
+The following strings specify valid salt types for use by Kerberos V5.
+.TP 2i
+.I normal
+Specifies KRB5_KDB_SALTTYPE_NORMAL.
+.TP 2i
+.I v4
+Specifies KRB5_KDB_SALTTYPE_V4.
+.TP 2i
+.I norealm
+Specifies KRB5_KDB_SALTTYPE_NOREALM.
+.TP 2i
+.I onlyrealm
+Specifies KRB5_KDB_SALTTYPE_ONLYREALM.
+.TP 2i
+.I afs3
+Specifies KRB5_KDB_SALTTYPE_AFS3.
+.TP 2i
+.I special
+Specifies KRB5_KDB_SALTTYPE_SPECIAL.
+
+.SH ENCRYPTION TYPES
+The following strings specify valid encryption types for use by Kerberos V5.
+.TP 2i
+.I null
+Specifies ETYPE_NULL.
+.TP 2i
+.I des-cbc-crc
+Specifies ETYPE_DES_CBC_CRC.
+.TP 2i
+.I des-cbc-md4
+Specifies ETYPE_DES_CBC_MD4.
+.TP 2i
+.I des-cbc-md5
+Specifies ETYPE_DES_CBC_MD5.
+.TP 2i
+.I raw-des-cbc
+Specifies ETYPE_RAW_DES_CBC.
+
+.SH CHECKSUM TYPES
+The following strings specify valid checksum types for use by Kerberos V5.
+.TP 2i
+.I crc32
+Specifies CKSUMTYPE_CRC32.
+.TP 2i
+.I md4
+Specifies CKSUMTYPE_RSA_MD4.
+.TP 2i
+.I md4-des
+Specifies CKSUMTYPE_RSA_MD4_DES.
+.TP 2i
+.I des-cbc
+Specifies CKSUMTYPE_DESCBC.
+.TP 2i
+.I md5
+Specifies CKSUMTYPE_RSA_MD5.
+.TP 2i
+.I md5-des
+Specifies CKSUMTYPE_RSA_MD5_DES.
+
+.SH PRINCIPAL FLAGS
+The following strings specify particular principal attributes for use by
+Kerberos V5.
+.TP 2i
+.I postdateable
+In the negative sense, specifies KRB5_KDB_DISALLOW_POSTDATED.
+.TP 2i
+.I forwardable
+In the negative sense, specifies KRB5_KDB_DISALLOW_FORWARDABLE.
+.TP 2i
+.I tgt-based
+In the negative sense, specifies KRB5_KDB_DISALLOW_TGT_BASED.
+.TP 2i
+.I renewable
+In the negative sense, specifies KRB5_KDB_DISALLOW_RENEWABLE.
+.TP 2i
+.I proxiable
+In the negative sense, specifies KRB5_KDB_DISALLOW_PROXIABLE.
+.TP 2i
+.I dup-skey
+In the negative sense, specifies KRB5_KDB_DISALLOW_DUP_SKEY.
+.TP 2i
+.I allow-tickets
+In the negative sense, specifies KRB5_KDB_DISALLOW_ALL_TIX.
+.TP 2i
+.I preauth
+Specifies KRB5_KDB_REQUIRES_PRE_AUTH.
+.TP 2i
+.I hwauth
+Specifies KRB5_KDB_REQUIRES_HW_AUTH.
+.TP 2i
+.I pwchange
+Specifies KRB5_KDB_REQUIRES_PWCHANGE.
+.TP 2i
+.I service
+In the negative sense, specifies KRB5_KDB_DISALLOW_SVR.
+.TP 2i
+.I pwservice
+Specifies KRB5_KDB_PWCHANGE_SERVICE.
+.TP 2i
+.I md5
+Specifies KRB5_KDB_SUPPORT_DESMD5.
+
+.SH ABSOLUTE TIME
+The following formats specify valid absolute time strings for use by Kerberos
+V5. In the description the following abbreviations are used:
+.in +1i
+.B yy
+denotes the last two digits of the year.
+
+.B mm
+denotes the two digits representing the month (01 = January, 12 = December).
+
+.B dd
+denotes the two digits representing the day of the month.
+
+.B HH
+denotes the two digits representing the hour of the day (24-hour format).
+
+.B MM
+denotes the two digits representing the minute of the hour.
+
+.B SS
+denotes the two digits representing the second of the minute.
+.in -1i
+
+.TP 2i
+.I yymmddHHMMSS
+e.g. 951225093023 specifies 9:30:23 a.m. on 25 December 1995.
+.TP 2i
+.I yy.mm.dd.HH.MM.SS
+e.g. 95.12.25.09.30.23 specifies 9:30:23 a.m. on 25 December 1995.
+.TP 2i
+.I yymmddHHMM
+e.g. 9512250930 specifies 9:30 a.m. on 25 December 1995.
+.TP 2i
+.I HHMMSS
+e.g. 123056 specifies 12:30:56 p.m. today.
+.TP 2i
+.I HHMM
+e.g. 2130 specifies 9:30 p.m. today.
+.TP 2i
+.I HH:MM:SS
+e.g. 12:30:56 specifies 12:30:56 p.m. today.
+.TP 2i
+.I HH:MM
+e.g. 21:30 specifies 9:30 p.m. today.
+.PP
+The following formats are recognized if the target operating system supports
+the
+.B strptime(3)
+function. See the
+.B strptime(3)
+manual page for a description of the format fields:
+.TP 2i
+.I %x:%X
+Specifies the locale-dependent short date format concatenated by a colon with
+the locale-dependent short time format.
+.TP 2i
+.I %d-%b-%Y:%T
+e.g. 10-January-1995:16:42:23 in U.S. locales.
+.TP 2i
+.I %d-%b-%Y:%R
+e.g. 10-January-1995:16:42 in U.S. locales.
+
+.SH DELTA TIME
+The following formats specify valid delta time strings for use by Kerberos
+V5. In the description the following abbreviations are used:
+.in +1i
+.B d
+denotes a number of days.
+
+.B h[h]
+denotes one or two digits representing a number of hours.
+
+.B m[m]
+denotes one or two digits representing a number of minutes.
+
+.B s[s]
+denotes one or two digits representing a number of seconds.
+.in -1i
+.TP 2i
+.I d-hh:mm:ss
+e.g. 7-04:30:01 specifies seven days, four hours 30 minutes and one second.
+.TP 2i
+.I ddhhmmss
+e.g. 7d4h30m1s specifies seven days, four hours 30 minutes and one second.
+.TP 2i
+.I h:mm:ss
+e.g. 6:23:16 specifies six hours, 23 minutes and 16 seconds.
+.TP 2i
+.I hhmmss
+e.g. 6h23m16s specifies six hours 23 minutes and 16 seconds.
+.TP 2i
+.I h:mm
+e.g. 2:30 specifies two hours and 30 minutes.
+.TP 2i
+.I hhmm
+e.g. 2h30m specifies two hours and 30 minutes.
+.TP 2i
+.I dd
+e.g. 2d specifies two days.
+.TP 2i
+.I hh
+e.g. 4h specifies four hours.
+.TP 2i
+.I mm
+e.g. 30m specifies 30 minutes.
+.TP 2i
+.I ss
+e.g. 3600s specifies 3600 seconds.
+
+.SH SEE ALSO
+kdc.conf(5), krb5kdc(8), kdb5_edit(8), kadmin5(8), strptime(3)
+
+
+
+
diff --git a/src/lib/kadm/logger.c b/src/lib/kadm/logger.c
new file mode 100644
index 000000000..425c1ccc7
--- /dev/null
+++ b/src/lib/kadm/logger.c
@@ -0,0 +1,940 @@
+/*
+ * lib/kadm/logger.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+#if !defined(_MSDOS)
+
+/*
+ * logger.c - Handle logging functions for those who want it.
+ */
+#include "k5-int.h"
+#include "adm_proto.h"
+#include "com_err.h"
+#include <stdio.h>
+#if HAVE_SYSLOG_H
+#include <syslog.h>
+#endif /* HAVE_SYSLOG_H */
+#if HAVE_STDARG_H
+#include <stdarg.h>
+#else /* HAVE_STDARG_H */
+#include <varargs.h>
+#endif /* HAVE_STDARG_H */
+
+#define KRB5_KLOG_MAX_ERRMSG_SIZE 1024
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif /* MAXHOSTNAMELEN */
+
+/* This is to assure that we have at least one match in the syslog stuff */
+#ifndef LOG_AUTH
+#define LOG_AUTH 0
+#endif /* LOG_AUTH */
+#ifndef LOG_ERR
+#define LOG_ERR 0
+#endif /* LOG_ERR */
+
+static const char lspec_parse_err_1[] = "%s: cannot parse <%s>\n";
+static const char lspec_parse_err_2[] = "%s: warning - logging entry syntax error\n";
+static const char log_file_err[] = "%s: error writing to %s\n";
+static const char log_device_err[] = "%s: error writing to %s device\n";
+static const char log_ufo_string[] = "???";
+static const char log_emerg_string[] = "EMERGENCY";
+static const char log_alert_string[] = "ALERT";
+static const char log_crit_string[] = "CRITICAL";
+static const char log_err_string[] = "Error";
+static const char log_warning_string[] = "Warning";
+static const char log_notice_string[] = "Notice";
+static const char log_info_string[] = "info";
+static const char log_debug_string[] = "debug";
+
+/*
+ * Output logging.
+ *
+ * Output logging is now controlled by the configuration file. We can specify
+ * the following syntaxes under the [logging]->entity specification.
+ * FILE<opentype><pathname>
+ * SYSLOG[=<severity>[:<facility>]]
+ * STDERR
+ * CONSOLE
+ * DEVICE=<device-spec>
+ *
+ * Where:
+ * <opentype> is ":" for open/append, "=" for open/create.
+ * <pathname> is a valid path name.
+ * <severity> is one of: (default = ERR)
+ * EMERG
+ * ALERT
+ * CRIT
+ * ERR
+ * WARNING
+ * NOTICE
+ * INFO
+ * DEBUG
+ * <facility> is one of: (default = AUTH)
+ * KERN
+ * USER
+ * MAIL
+ * DAEMON
+ * AUTH
+ * LPR
+ * NEWS
+ * UUCP
+ * CRON
+ * LOCAL0..LOCAL7
+ * <device-spec> is a valid device specification.
+ */
+struct log_entry {
+ enum log_type { K_LOG_FILE,
+ K_LOG_SYSLOG,
+ K_LOG_STDERR,
+ K_LOG_CONSOLE,
+ K_LOG_DEVICE,
+ K_LOG_NONE } log_type;
+ krb5_pointer log_2free;
+ union log_union {
+ struct log_file {
+ FILE *lf_filep;
+ char *lf_fname;
+ } log_file;
+ struct log_syslog {
+ int ls_facility;
+ int ls_severity;
+ } log_syslog;
+ struct log_device {
+ FILE *ld_filep;
+ char *ld_devname;
+ } log_device;
+ } log_union;
+};
+#define lfu_filep log_union.log_file.lf_filep
+#define lfu_fname log_union.log_file.lf_fname
+#define lsu_facility log_union.log_syslog.ls_facility
+#define lsu_severity log_union.log_syslog.ls_severity
+#define ldu_filep log_union.log_device.ld_filep
+#define ldu_devname log_union.log_device.ld_devname
+
+struct log_control {
+ struct log_entry *log_entries;
+ int log_nentries;
+ char *log_whoami;
+ char *log_hostname;
+ krb5_boolean log_opened;
+};
+
+static struct log_control log_control = {
+ (struct log_entry *) NULL,
+ 0,
+ (char *) NULL,
+ (char *) NULL,
+ 0
+};
+static struct log_entry def_log_entry;
+
+/*
+ * These macros define any special processing that needs to happen for
+ * devices. For unix, of course, this is hardly anything.
+ */
+#define DEVICE_OPEN(d, m) fopen(d, m)
+#define CONSOLE_OPEN(m) fopen("/dev/console", m)
+#define DEVICE_PRINT(f, m) ((fprintf(f, m) >= 0) ? \
+ (fprintf(f, "\r\n"), fflush(f), 0) : \
+ -1)
+#define DEVICE_CLOSE(d) fclose(d)
+
+
+/*
+ * klog_com_err_proc() - Handle com_err(3) messages as specified by the
+ * profile.
+ */
+static void
+klog_com_err_proc(whoami, code, format, ap)
+ const char *whoami;
+ long code;
+ const char *format;
+ va_list ap;
+{
+ char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE];
+ int lindex;
+ char *actual_format;
+#if HAVE_SYSLOG
+ int log_pri = -1;
+#endif /* HAVE_SYSLOG */
+ char *cp;
+ char *syslogp;
+
+ /* Make the header */
+ sprintf(outbuf, "%s: ", whoami);
+ /*
+ * Squirrel away address after header for syslog since syslog makes
+ * a header
+ */
+ syslogp = &outbuf[strlen(outbuf)];
+
+ /* If reporting an error message, separate it. */
+ if (code) {
+ strcat(outbuf, error_message(code));
+ strcat(outbuf, " - ");
+ }
+ cp = &outbuf[strlen(outbuf)];
+
+ actual_format = (char *) format;
+#if HAVE_SYSLOG
+ /*
+ * This is an unpleasant hack. If the first character is less than
+ * 8, then we assume that it is a priority.
+ *
+ * Since it is not guaranteed that there is a direct mapping between
+ * syslog priorities (e.g. Ultrix and old BSD), we resort to this
+ * intermediate representation.
+ */
+ if ((((unsigned char) *format) > 0) && (((unsigned char) *format) <= 8)) {
+ actual_format = (char *) (format + 1);
+ switch ((unsigned char) *format) {
+#ifdef LOG_EMERG
+ case 1:
+ log_pri = LOG_EMERG;
+ break;
+#endif /* LOG_EMERG */
+#ifdef LOG_ALERT
+ case 2:
+ log_pri = LOG_ALERT;
+ break;
+#endif /* LOG_ALERT */
+#ifdef LOG_CRIT
+ case 3:
+ log_pri = LOG_CRIT;
+ break;
+#endif /* LOG_CRIT */
+ default:
+ case 4:
+ log_pri = LOG_ERR;
+ break;
+#ifdef LOG_WARNING
+ case 5:
+ log_pri = LOG_WARNING;
+ break;
+#endif /* LOG_WARNING */
+#ifdef LOG_NOTICE
+ case 6:
+ log_pri = LOG_NOTICE;
+ break;
+#endif /* LOG_NOTICE */
+#ifdef LOG_INFO
+ case 7:
+ log_pri = LOG_INFO;
+ break;
+#endif /* LOG_INFO */
+#ifdef LOG_DEBUG
+ case 8:
+ log_pri = LOG_DEBUG;
+ break;
+#endif /* LOG_DEBUG */
+ }
+ }
+#endif /* HAVE_SYSLOG */
+
+ /* Now format the actual message */
+#if HAVE_VSPRINTF
+ vsprintf(cp, actual_format, ap);
+#else /* HAVE_VSPRINTF */
+ sprintf(cp, actual_format, ((int *) ap)[0], ((int *) ap)[1],
+ ((int *) ap)[2], ((int *) ap)[3],
+ ((int *) ap)[4], ((int *) ap)[5]);
+#endif /* HAVE_VSPRINTF */
+
+ /*
+ * Now that we have the message formatted, perform the output to each
+ * logging specification.
+ */
+ for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
+ switch (log_control.log_entries[lindex].log_type) {
+ case K_LOG_FILE:
+ case K_LOG_STDERR:
+ /*
+ * Files/standard error.
+ */
+ if (fprintf(log_control.log_entries[lindex].lfu_filep,
+ outbuf) < 0) {
+ /* Attempt to report error */
+ fprintf(stderr, log_file_err, whoami,
+ log_control.log_entries[lindex].lfu_fname);
+ }
+ else {
+ fprintf(log_control.log_entries[lindex].lfu_filep, "\n");
+ fflush(log_control.log_entries[lindex].lfu_filep);
+ }
+ break;
+ case K_LOG_CONSOLE:
+ case K_LOG_DEVICE:
+ /*
+ * Devices (may need special handling)
+ */
+ if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep,
+ outbuf) < 0) {
+ /* Attempt to report error */
+ fprintf(stderr, log_device_err, whoami,
+ log_control.log_entries[lindex].ldu_devname);
+ }
+ break;
+#if HAVE_SYSLOG
+ case K_LOG_SYSLOG:
+ /*
+ * System log.
+ */
+ /*
+ * If we have specified a priority through our hackery, then
+ * use it, otherwise use the default.
+ */
+ if (log_pri >= 0)
+ log_pri |= log_control.log_entries[lindex].lsu_facility;
+ else
+ log_pri = log_control.log_entries[lindex].lsu_facility |
+ log_control.log_entries[lindex].lsu_severity;
+
+ /* Log the message with our header trimmed off */
+ syslog(log_pri, syslogp);
+ break;
+#endif /* HAVE_SYSLOG */
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * krb5_klog_init() - Initialize logging.
+ *
+ * This routine parses the syntax described above to specify destinations for
+ * com_err(3) or krb5_klog_syslog() messages generated by the caller.
+ *
+ * Parameters:
+ * kcontext - Kerberos context.
+ * ename - Entity name as it is to appear in the profile.
+ * whoami - Entity name as it is to appear in error output.
+ * do_com_err - Take over com_err(3) processing.
+ *
+ * Implicit inputs:
+ * stderr - This is where STDERR output goes.
+ *
+ * Implicit outputs:
+ * log_nentries - Number of log entries, both valid and invalid.
+ * log_control - List of entries (log_nentries long) which contains
+ * data for klog_com_err_proc() to use to determine
+ * where/how to send output.
+ */
+krb5_error_code
+krb5_klog_init(kcontext, ename, whoami, do_com_err)
+ krb5_context kcontext;
+ char *ename;
+ char *whoami;
+ krb5_boolean do_com_err;
+{
+ const char *logging_profent[3];
+ const char *logging_defent[3];
+ char **logging_specs;
+ int i, ngood;
+ char *cp, *cp2;
+ char savec;
+ int error;
+ int do_openlog, log_facility;
+ FILE *f;
+
+ /* Initialize */
+ do_openlog = 0;
+ log_facility = 0;
+
+ /*
+ * Look up [logging]-><ename> in the profile. If that doesn't
+ * succeed, then look for [logging]->default.
+ */
+ logging_profent[0] = "logging";
+ logging_profent[1] = ename;
+ logging_profent[2] = (char *) NULL;
+ logging_defent[0] = "logging";
+ logging_defent[1] = "default";
+ logging_defent[2] = (char *) NULL;
+ logging_specs = (char **) NULL;
+ ngood = 0;
+ log_control.log_nentries = 0;
+ if (!profile_get_values(kcontext->profile,
+ logging_profent,
+ &logging_specs) ||
+ !profile_get_values(kcontext->profile,
+ logging_defent,
+ &logging_specs)) {
+ /*
+ * We have a match, so we first count the number of elements
+ */
+ for (log_control.log_nentries = 0;
+ logging_specs[log_control.log_nentries];
+ log_control.log_nentries++);
+
+ /*
+ * Now allocate our structure.
+ */
+ log_control.log_entries = (struct log_entry *)
+ malloc(log_control.log_nentries * sizeof(struct log_entry));
+ if (log_control.log_entries) {
+ /*
+ * Scan through the list.
+ */
+ for (i=0; i<log_control.log_nentries; i++) {
+ log_control.log_entries[i].log_type = K_LOG_NONE;
+ log_control.log_entries[i].log_2free = logging_specs[i];
+ /*
+ * The format is:
+ * <whitespace><data><whitespace>
+ * so, trim off the leading and trailing whitespace here.
+ */
+ for (cp = logging_specs[i]; isspace(*cp); cp++);
+ for (cp2 = &logging_specs[i][strlen(logging_specs[i])-1];
+ isspace(*cp2); cp2--);
+ cp2++;
+ *cp2 = '\0';
+ /*
+ * Is this a file?
+ */
+ if (!strncasecmp(cp, "FILE", 4)) {
+ /*
+ * Check for append/overwrite, then open the file.
+ */
+ if (cp[4] == ':' || cp[4] == '=') {
+ f = fopen(&cp[5], (cp[4] == ':') ? "a+" : "w");
+ if (f) {
+ log_control.log_entries[i].lfu_filep = f;
+ log_control.log_entries[i].log_type = K_LOG_FILE;
+ log_control.log_entries[i].lfu_fname = &cp[5];
+ } else {
+ fprintf(stderr,"Couldn't open log file %s: %s\n",
+ &cp[5], error_message(errno));
+ continue;
+ }
+ }
+ }
+#if HAVE_SYSLOG
+ /*
+ * Is this a syslog?
+ */
+ else if (!strncasecmp(cp, "SYSLOG", 6)) {
+ error = 0;
+ log_control.log_entries[i].lsu_facility = LOG_AUTH;
+ log_control.log_entries[i].lsu_severity = LOG_ERR;
+ /*
+ * Is there a severify specified?
+ */
+ if (cp[6] == ':') {
+ /*
+ * Find the end of the severity.
+ */
+ if (cp2 = strchr(&cp[7], ':')) {
+ savec = *cp2;
+ *cp2 = '\0';
+ cp2++;
+ }
+
+ /*
+ * Match a severity.
+ */
+ if (!strcasecmp(&cp[7], "ERR")) {
+ log_control.log_entries[i].lsu_severity = LOG_ERR;
+ }
+#ifdef LOG_EMERG
+ else if (!strcasecmp(&cp[7], "EMERG")) {
+ log_control.log_entries[i].lsu_severity =
+ LOG_EMERG;
+ }
+#endif /* LOG_EMERG */
+#ifdef LOG_ALERT
+ else if (!strcasecmp(&cp[7], "ALERT")) {
+ log_control.log_entries[i].lsu_severity =
+ LOG_ALERT;
+ }
+#endif /* LOG_ALERT */
+#ifdef LOG_CRIT
+ else if (!strcasecmp(&cp[7], "CRIT")) {
+ log_control.log_entries[i].lsu_severity = LOG_CRIT;
+ }
+#endif /* LOG_CRIT */
+#ifdef LOG_WARNING
+ else if (!strcasecmp(&cp[7], "WARNING")) {
+ log_control.log_entries[i].lsu_severity =
+ LOG_WARNING;
+ }
+#endif /* LOG_WARNING */
+#ifdef LOG_NOTICE
+ else if (!strcasecmp(&cp[7], "NOTICE")) {
+ log_control.log_entries[i].lsu_severity =
+ LOG_NOTICE;
+ }
+#endif /* LOG_NOTICE */
+#ifdef LOG_INFO
+ else if (!strcasecmp(&cp[7], "INFO")) {
+ log_control.log_entries[i].lsu_severity = LOG_INFO;
+ }
+#endif /* LOG_INFO */
+#ifdef LOG_DEBUG
+ else if (!strcasecmp(&cp[7], "DEBUG")) {
+ log_control.log_entries[i].lsu_severity =
+ LOG_DEBUG;
+ }
+#endif /* LOG_DEBUG */
+ else
+ error = 1;
+
+ /*
+ * If there is a facility present, then parse that.
+ */
+ if (cp2) {
+ if (!strcasecmp(cp2, "AUTH")) {
+ log_control.log_entries[i].lsu_facility = LOG_AUTH;
+ }
+#ifdef LOG_KERN
+ else if (!strcasecmp(cp2, "KERN")) {
+ log_control.log_entries[i].lsu_facility = LOG_KERN;
+ }
+#endif /* LOG_KERN */
+#ifdef LOG_USER
+ else if (!strcasecmp(cp2, "USER")) {
+ log_control.log_entries[i].lsu_facility = LOG_USER;
+ }
+#endif /* LOG_USER */
+#ifdef LOG_MAIL
+ else if (!strcasecmp(cp2, "MAIL")) {
+ log_control.log_entries[i].lsu_facility = LOG_MAIL;
+ }
+#endif /* LOG_MAIL */
+#ifdef LOG_DAEMON
+ else if (!strcasecmp(cp2, "DAEMON")) {
+ log_control.log_entries[i].lsu_facility = LOG_DAEMON;
+ }
+#endif /* LOG_DAEMON */
+#ifdef LOG_LPR
+ else if (!strcasecmp(cp2, "LPR")) {
+ log_control.log_entries[i].lsu_facility = LOG_LPR;
+ }
+#endif /* LOG_LPR */
+#ifdef LOG_NEWS
+ else if (!strcasecmp(cp2, "NEWS")) {
+ log_control.log_entries[i].lsu_facility = LOG_NEWS;
+ }
+#endif /* LOG_NEWS */
+#ifdef LOG_UUCP
+ else if (!strcasecmp(cp2, "UUCP")) {
+ log_control.log_entries[i].lsu_facility = LOG_UUCP;
+ }
+#endif /* LOG_UUCP */
+#ifdef LOG_CRON
+ else if (!strcasecmp(cp2, "CRON")) {
+ log_control.log_entries[i].lsu_facility = LOG_CRON;
+ }
+#endif /* LOG_CRON */
+#ifdef LOG_LOCAL0
+ else if (!strcasecmp(cp2, "LOCAL0")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL0;
+ }
+#endif /* LOG_LOCAL0 */
+#ifdef LOG_LOCAL1
+ else if (!strcasecmp(cp2, "LOCAL1")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL1;
+ }
+#endif /* LOG_LOCAL1 */
+#ifdef LOG_LOCAL2
+ else if (!strcasecmp(cp2, "LOCAL2")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL2;
+ }
+#endif /* LOG_LOCAL2 */
+#ifdef LOG_LOCAL3
+ else if (!strcasecmp(cp2, "LOCAL3")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL3;
+ }
+#endif /* LOG_LOCAL3 */
+#ifdef LOG_LOCAL4
+ else if (!strcasecmp(cp2, "LOCAL4")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL4;
+ }
+#endif /* LOG_LOCAL4 */
+#ifdef LOG_LOCAL5
+ else if (!strcasecmp(cp2, "LOCAL5")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL5;
+ }
+#endif /* LOG_LOCAL5 */
+#ifdef LOG_LOCAL6
+ else if (!strcasecmp(cp2, "LOCAL6")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL6;
+ }
+#endif /* LOG_LOCAL6 */
+#ifdef LOG_LOCAL7
+ else if (!strcasecmp(cp2, "LOCAL7")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL7;
+ }
+#endif /* LOG_LOCAL7 */
+ cp2--;
+ *cp2 = savec;
+ }
+ }
+ if (!error) {
+ log_control.log_entries[i].log_type = K_LOG_SYSLOG;
+ do_openlog = 1;
+ log_facility = log_control.log_entries[i].lsu_facility;
+ }
+ }
+#endif /* HAVE_SYSLOG */
+ /*
+ * Is this a standard error specification?
+ */
+ else if (!strcasecmp(cp, "STDERR")) {
+ if (log_control.log_entries[i].lfu_filep =
+ fdopen(fileno(stderr), "a+")) {
+ log_control.log_entries[i].log_type = K_LOG_STDERR;
+ log_control.log_entries[i].lfu_fname =
+ "standard error";
+ }
+ }
+ /*
+ * Is this a specification of the console?
+ */
+ else if (!strcasecmp(cp, "CONSOLE")) {
+ if (log_control.log_entries[i].ldu_filep =
+ CONSOLE_OPEN("a+")) {
+ log_control.log_entries[i].log_type = K_LOG_CONSOLE;
+ log_control.log_entries[i].ldu_devname = "console";
+ }
+ }
+ /*
+ * Is this a specification of a device?
+ */
+ else if (!strncasecmp(cp, "DEVICE", 6)) {
+ /*
+ * We handle devices very similarly to files.
+ */
+ if (cp[6] == '=') {
+ if (log_control.log_entries[i].ldu_filep =
+ DEVICE_OPEN(&cp[7], "w")) {
+ log_control.log_entries[i].log_type = K_LOG_DEVICE;
+ log_control.log_entries[i].ldu_devname = &cp[7];
+ }
+ }
+ }
+ /*
+ * See if we successfully parsed this specification.
+ */
+ if (log_control.log_entries[i].log_type == K_LOG_NONE) {
+ fprintf(stderr, lspec_parse_err_1, whoami, cp);
+ fprintf(stderr, lspec_parse_err_2, whoami);
+ }
+ else
+ ngood++;
+ }
+ }
+ /*
+ * If we didn't find anything, then free our lists.
+ */
+ if (ngood == 0) {
+ for (i=0; i<log_control.log_nentries; i++)
+ free(logging_specs[i]);
+ }
+ free(logging_specs);
+ }
+ /*
+ * If we didn't find anything, go for the default which is to log to
+ * the system log.
+ */
+ if (ngood == 0) {
+ if (log_control.log_entries)
+ free(log_control.log_entries);
+ log_control.log_entries = &def_log_entry;
+ log_control.log_entries->log_type = K_LOG_SYSLOG;
+ log_control.log_entries->log_2free = (krb5_pointer) NULL;
+ log_control.log_entries->lsu_facility = LOG_AUTH;
+ log_control.log_entries->lsu_severity = LOG_ERR;
+ log_control.log_nentries = 1;
+ }
+ if (log_control.log_nentries) {
+ if (log_control.log_whoami = (char *) malloc(strlen(whoami)+1))
+ strcpy(log_control.log_whoami, whoami);
+ if (log_control.log_hostname = (char *) malloc(MAXHOSTNAMELEN))
+ gethostname(log_control.log_hostname, MAXHOSTNAMELEN);
+#if HAVE_OPENLOG
+ if (do_openlog) {
+ openlog(whoami, LOG_NDELAY|LOG_PID, log_facility);
+ log_control.log_opened = 1;
+ }
+#endif /* HAVE_OPENLOG */
+ if (do_com_err)
+ (void) set_com_err_hook(klog_com_err_proc);
+ }
+ return((log_control.log_nentries) ? 0 : ENOENT);
+}
+
+/*
+ * krb5_klog_close() - Close the logging context and free all data.
+ */
+void
+krb5_klog_close(kcontext)
+ krb5_context kcontext;
+{
+ int lindex;
+ (void) reset_com_err_hook();
+ for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
+ switch (log_control.log_entries[lindex].log_type) {
+ case K_LOG_FILE:
+ case K_LOG_STDERR:
+ /*
+ * Files/standard error.
+ */
+ fclose(log_control.log_entries[lindex].lfu_filep);
+ break;
+ case K_LOG_CONSOLE:
+ case K_LOG_DEVICE:
+ /*
+ * Devices (may need special handling)
+ */
+ DEVICE_CLOSE(log_control.log_entries[lindex].ldu_filep);
+ break;
+#if HAVE_SYSLOG
+ case K_LOG_SYSLOG:
+ /*
+ * System log.
+ */
+ break;
+#endif /* HAVE_SYSLOG */
+ default:
+ break;
+ }
+ if (log_control.log_entries[lindex].log_2free)
+ free(log_control.log_entries[lindex].log_2free);
+ }
+ if (log_control.log_entries != &def_log_entry)
+ free(log_control.log_entries);
+ log_control.log_entries = (struct log_entry *) NULL;
+ log_control.log_nentries = 0;
+ if (log_control.log_whoami)
+ free(log_control.log_whoami);
+ log_control.log_whoami = (char *) NULL;
+ if (log_control.log_hostname)
+ free(log_control.log_hostname);
+ log_control.log_hostname = (char *) NULL;
+#if HAVE_CLOSELOG
+ if (log_control.log_opened)
+ closelog();
+#endif /* HAVE_CLOSELOG */
+}
+
+/*
+ * severity2string() - Convert a severity to a string.
+ */
+static char *
+severity2string(severity)
+ int severity;
+{
+ int s;
+ const char *ss;
+
+ s = severity & LOG_PRIMASK;
+ ss = log_ufo_string;
+ switch (s) {
+#ifdef LOG_EMERG
+ case LOG_EMERG:
+ ss = log_emerg_string;
+ break;
+#endif /* LOG_EMERG */
+#ifdef LOG_ALERT
+ case LOG_ALERT:
+ ss = log_alert_string;
+ break;
+#endif /* LOG_ALERT */
+#ifdef LOG_CRIT
+ case LOG_CRIT:
+ ss = log_crit_string;
+ break;
+#endif /* LOG_CRIT */
+ case LOG_ERR:
+ ss = log_err_string;
+ break;
+#ifdef LOG_WARNING
+ case LOG_WARNING:
+ ss = log_warning_string;
+ break;
+#endif /* LOG_WARNING */
+#ifdef LOG_NOTICE
+ case LOG_NOTICE:
+ ss = log_notice_string;
+ break;
+#endif /* LOG_NOTICE */
+#ifdef LOG_INFO
+ case LOG_INFO:
+ ss = log_info_string;
+ break;
+#endif /* LOG_INFO */
+#ifdef LOG_DEBUG
+ case LOG_DEBUG:
+ ss = log_debug_string;
+ break;
+#endif /* LOG_DEBUG */
+ }
+ return((char *) ss);
+}
+
+/*
+ * krb5_klog_syslog() - Simulate the calling sequence of syslog(3), while
+ * also performing the logging redirection as specified
+ * by krb5_klog_init().
+ */
+static int
+klog_vsyslog(priority, format, arglist)
+ int priority;
+ const char *format;
+ va_list arglist;
+{
+ char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE];
+ int lindex;
+ char *syslogp;
+ char *cp;
+ time_t now;
+#if HAVE_STRFTIME
+ size_t soff;
+#endif /* HAVE_STRFTIME */
+
+ /*
+ * Format a syslog-esque message of the format:
+ *
+ * (verbose form)
+ * <date> <hostname> <id>[<pid>](<priority>): <message>
+ *
+ * (short form)
+ * <date> <message>
+ */
+ cp = outbuf;
+ (void) time(&now);
+#if HAVE_STRFTIME
+ /*
+ * Format the date: mon dd hh:mm:ss
+ */
+ soff = strftime(outbuf, sizeof(outbuf), "%b %d %H:%M:%S", localtime(&now));
+ if (soff > 0)
+ cp += soff;
+ else
+ return(-1);
+#else /* HAVE_STRFTIME */
+ /*
+ * Format the date:
+ * We ASSUME here that the output of ctime is of the format:
+ * dow mon dd hh:mm:ss tzs yyyy\n
+ * 012345678901234567890123456789
+ */
+ strncpy(outbuf, ctime(&now) + 4, 15);
+ cp += 15;
+#endif /* HAVE_STRFTIME */
+#ifdef VERBOSE_LOGS
+ sprintf(cp, " %s %s[%d](%s): ",
+ log_control.log_hostname, log_control.log_whoami, getpid(),
+ severity2string(priority));
+#else
+ sprintf(cp, " ");
+#endif
+ syslogp = &outbuf[strlen(outbuf)];
+
+ /* Now format the actual message */
+#if HAVE_VSPRINTF
+ vsprintf(syslogp, format, arglist);
+#else /* HAVE_VSPRINTF */
+ sprintf(syslogp, format, ((int *) arglist)[0], ((int *) arglist)[1],
+ ((int *) arglist)[2], ((int *) arglist)[3],
+ ((int *) arglist)[4], ((int *) arglist)[5]);
+#endif /* HAVE_VSPRINTF */
+
+ /*
+ * Now that we have the message formatted, perform the output to each
+ * logging specification.
+ */
+ for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
+ switch (log_control.log_entries[lindex].log_type) {
+ case K_LOG_FILE:
+ case K_LOG_STDERR:
+ /*
+ * Files/standard error.
+ */
+ if (fprintf(log_control.log_entries[lindex].lfu_filep,
+ outbuf) < 0) {
+ /* Attempt to report error */
+ fprintf(stderr, log_file_err,
+ log_control.log_entries[lindex].lfu_fname);
+ }
+ else {
+ fprintf(log_control.log_entries[lindex].lfu_filep, "\n");
+ fflush(log_control.log_entries[lindex].lfu_filep);
+ }
+ break;
+ case K_LOG_CONSOLE:
+ case K_LOG_DEVICE:
+ /*
+ * Devices (may need special handling)
+ */
+ if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep,
+ outbuf) < 0) {
+ /* Attempt to report error */
+ fprintf(stderr, log_device_err,
+ log_control.log_entries[lindex].ldu_devname);
+ }
+ break;
+#if HAVE_SYSLOG
+ case K_LOG_SYSLOG:
+ /*
+ * System log.
+ */
+
+ /* Log the message with our header trimmed off */
+ syslog(priority, syslogp);
+ break;
+#endif /* HAVE_SYSLOG */
+ default:
+ break;
+ }
+ }
+ return(0);
+}
+
+#if HAVE_STDARG_H
+int
+krb5_klog_syslog(int priority, const char *format, ...)
+#else /* HAVE_STDARG_H */
+int
+krb5_klog_syslog(priority, format, va_alist)
+ int priority;
+ const char *format;
+ va_dcl
+#endif /* HAVE_STDARG_H */
+{
+ int retval;
+ va_list pvar;
+
+#if HAVE_STDARG_H
+ va_start(pvar, format);
+#else /* HAVE_STDARG_H */
+ va_start(pvar);
+#endif /* HAVE_STDARG_H */
+ retval = klog_vsyslog(priority, format, pvar);
+ va_end(pvar);
+ return(retval);
+}
+#endif /* !defined(_MSDOS) */
diff --git a/src/lib/kadm/str_conv.c b/src/lib/kadm/str_conv.c
new file mode 100644
index 000000000..ccd0da030
--- /dev/null
+++ b/src/lib/kadm/str_conv.c
@@ -0,0 +1,221 @@
+/*
+ * lib/kadm/str_conv.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * str_conv.c - Convert between strings and Kerberos internal data.
+ */
+
+/*
+ * Table of contents:
+ *
+ * String decoding:
+ * ----------------
+ * krb5_string_to_flags() - Convert string to krb5_flags.
+ *
+ * String encoding:
+ * ----------------
+ * krb5_flags_to_string() - Convert krb5_flags to string.
+ */
+
+#include "k5-int.h"
+#include "adm.h"
+#include "adm_proto.h"
+
+/*
+ * Local data structures.
+ */
+struct flags_lookup_entry {
+ krb5_flags fl_flags; /* Flag */
+ krb5_boolean fl_sense; /* Sense of the flag */
+ const char * fl_specifier; /* How to recognize it */
+ const char * fl_output; /* How to spit it out */
+};
+
+/*
+ * Local strings
+ */
+
+/* Keytype strings */
+/* Flags strings */
+static const char flags_pdate_in[] = "postdateable";
+static const char flags_fwd_in[] = "forwardable";
+static const char flags_tgtbased_in[] = "tgt-based";
+static const char flags_renew_in[] = "renewable";
+static const char flags_proxy_in[] = "proxiable";
+static const char flags_dup_skey_in[] = "dup-skey";
+static const char flags_tickets_in[] = "allow-tickets";
+static const char flags_preauth_in[] = "preauth";
+static const char flags_hwauth_in[] = "hwauth";
+static const char flags_pwchange_in[] = "pwchange";
+static const char flags_service_in[] = "service";
+static const char flags_pwsvc_in[] = "pwservice";
+static const char flags_md5_in[] = "md5";
+static const char flags_pdate_out[] = "Not Postdateable";
+static const char flags_fwd_out[] = "Not Forwardable";
+static const char flags_tgtbased_out[] = "No TGT-based requests";
+static const char flags_renew_out[] = "Not renewable";
+static const char flags_proxy_out[] = "Not proxiable";
+static const char flags_dup_skey_out[] = "No DUP_SKEY requests";
+static const char flags_tickets_out[] = "All Tickets Disallowed";
+static const char flags_preauth_out[] = "Preauthorization required";
+static const char flags_hwauth_out[] = "HW Authorization required";
+static const char flags_pwchange_out[] = "Password Change required";
+static const char flags_service_out[] = "Service Disabled";
+static const char flags_pwsvc_out[] = "Password Changing Service";
+static const char flags_md5_out[] = "RSA-MD5 supported";
+static const char flags_default_neg[] = "-";
+static const char flags_default_sep[] = " ";
+
+/*
+ * Lookup tables.
+ */
+
+static const struct flags_lookup_entry flags_table[] = {
+/* flag sense input specifier output string */
+/*----------------------------- ------- ------------------ ------------------*/
+{ KRB5_KDB_DISALLOW_POSTDATED, 0, flags_pdate_in, flags_pdate_out },
+{ KRB5_KDB_DISALLOW_FORWARDABLE,0, flags_fwd_in, flags_fwd_out },
+{ KRB5_KDB_DISALLOW_TGT_BASED, 0, flags_tgtbased_in, flags_tgtbased_out},
+{ KRB5_KDB_DISALLOW_RENEWABLE, 0, flags_renew_in, flags_renew_out },
+{ KRB5_KDB_DISALLOW_PROXIABLE, 0, flags_proxy_in, flags_proxy_out },
+{ KRB5_KDB_DISALLOW_DUP_SKEY, 0, flags_dup_skey_in, flags_dup_skey_out},
+{ KRB5_KDB_DISALLOW_ALL_TIX, 0, flags_tickets_in, flags_tickets_out },
+{ KRB5_KDB_REQUIRES_PRE_AUTH, 1, flags_preauth_in, flags_preauth_out },
+{ KRB5_KDB_REQUIRES_HW_AUTH, 1, flags_hwauth_in, flags_hwauth_out },
+{ KRB5_KDB_REQUIRES_PWCHANGE, 1, flags_pwchange_in, flags_pwchange_out},
+{ KRB5_KDB_DISALLOW_SVR, 0, flags_service_in, flags_service_out },
+{ KRB5_KDB_PWCHANGE_SERVICE, 1, flags_pwsvc_in, flags_pwsvc_out },
+{ KRB5_KDB_SUPPORT_DESMD5, 1, flags_md5_in, flags_md5_out }
+};
+static const int flags_table_nents = sizeof(flags_table)/
+ sizeof(flags_table[0]);
+
+
+krb5_error_code
+krb5_string_to_flags(string, positive, negative, flagsp)
+ char * string;
+ const char * positive;
+ const char * negative;
+ krb5_flags * flagsp;
+{
+ int i;
+ int found;
+ const char *neg;
+ size_t nsize, psize;
+ int cpos;
+ int sense;
+
+ found = 0;
+ /* We need to have a way to negate it. */
+ neg = (negative) ? negative : flags_default_neg;
+ nsize = strlen(neg);
+ psize = (positive) ? strlen(positive) : 0;
+
+ cpos = 0;
+ sense = 1;
+ /* First check for positive or negative sense */
+ if (!strncasecmp(neg, string, nsize)) {
+ sense = 0;
+ cpos += (int) nsize;
+ }
+ else if (psize && !strncasecmp(positive, string, psize)) {
+ cpos += (int) psize;
+ }
+
+ for (i=0; i<flags_table_nents; i++) {
+ if (!strcasecmp(&string[cpos], flags_table[i].fl_specifier)) {
+ found = 1;
+ if (sense == (int) flags_table[i].fl_sense)
+ *flagsp |= flags_table[i].fl_flags;
+ else
+ *flagsp &= ~flags_table[i].fl_flags;
+
+ break;
+ }
+ }
+ return((found) ? 0 : EINVAL);
+}
+
+krb5_error_code
+krb5_flags_to_string(flags, sep, buffer, buflen)
+ krb5_flags flags;
+ const char * sep;
+ char * buffer;
+ size_t buflen;
+{
+ int i;
+ krb5_flags pflags;
+ const char *sepstring;
+ char *op;
+ int initial;
+ krb5_error_code retval;
+
+ retval = 0;
+ op = buffer;
+ pflags = 0;
+ initial = 1;
+ sepstring = (sep) ? sep : flags_default_sep;
+ /* Blast through the table matching all we can */
+ for (i=0; i<flags_table_nents; i++) {
+ if (flags & flags_table[i].fl_flags) {
+ /* Found a match, see if it'll fit into the output buffer */
+ if ((op+strlen(flags_table[i].fl_output)+strlen(sepstring)) <
+ (buffer + buflen)) {
+ if (!initial) {
+ strcpy(op, sep);
+ op += strlen(sep);
+ }
+ initial = 0;
+ strcpy(op, flags_table[i].fl_output);
+ op += strlen(flags_table[i].fl_output);
+ }
+ else {
+ retval = ENOMEM;
+ break;
+ }
+ /* Keep track of what we matched */
+ pflags |= flags_table[i].fl_flags;
+ }
+ }
+ if (!retval) {
+ /* See if there's any leftovers */
+ if (flags & ~pflags)
+ retval = EINVAL;
+ else if (initial)
+ *buffer = '\0';
+ }
+ return(retval);
+}
+
+krb5_error_code
+krb5_input_flag_to_string(flag, buffer, buflen)
+ int flag;
+ char * buffer;
+ size_t buflen;
+{
+ if(flag < 0 || flag >= flags_table_nents) return ENOENT; /* End of list */
+ if(strlen(flags_table[flag].fl_specifier) > buflen) return ENOMEM;
+ strcpy(buffer, flags_table[flag].fl_specifier);
+ return 0;
+}
diff --git a/src/lib/kadm/t_dbentry.c b/src/lib/kadm/t_dbentry.c
new file mode 100644
index 000000000..6c71234b3
--- /dev/null
+++ b/src/lib/kadm/t_dbentry.c
@@ -0,0 +1,965 @@
+/*
+ * lib/kadm/t_dbentry.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * t_dbentry.c - Test function of krb5_adm_{proto_to_dbent,dbent_to_proto}.
+ */
+
+#include "k5-int.h"
+#include "adm.h"
+#include "adm_proto.h"
+
+#if HAVE_SRAND48
+#define SRAND srand48
+#define RAND lrand48
+#define RAND_TYPE long
+#endif /* HAVE_SRAND48 */
+
+#if !defined(RAND_TYPE) && defined(HAVE_SRAND)
+#define SRAND srand
+#define RAND rand
+#define RAND_TYPE int
+#endif /* !defined(RAND_TYPE) && defined(HAVE_SRAND) */
+
+#if !defined(RAND_TYPE) && defined(HAVE_SRANDOM)
+#define SRAND srandom
+#define RAND random
+#define RAND_TYPE long
+#endif /* !defined(RAND_TYPE) && defined(HAVE_SRANDOM) */
+
+#if !defined(RAND_TYPE)
+There is no random number generator.
+#endif /* !defined(RAND_TYPE) */
+
+/*
+ * Generate a random event that has an a/b chance of succeeding
+ */
+#define RANDOM_EVENT(a,b) ((RAND() % b) < a)
+/* Define probabilities of generating each attribute type */
+#define PASSWORD_EVENT RANDOM_EVENT(3,5)
+#define KVNO_EVENT RANDOM_EVENT(2,5)
+#define MAXLIFE_EVENT RANDOM_EVENT(1,4)
+#define MAXRENEWLIFE_EVENT RANDOM_EVENT(1,4)
+#define EXPIRATION_EVENT RANDOM_EVENT(1,3)
+#define PWEXPIRATION_EVENT RANDOM_EVENT(1,3)
+#define RANDOMKEY_EVENT RANDOM_EVENT(1,8)
+#define FLAGS_EVENT RANDOM_EVENT(9,10)
+#define SALT_EVENT RANDOM_EVENT(7,16)
+#define MKVNO_EVENT RANDOM_EVENT(2,5)
+#define LASTPWCHANGE_EVENT RANDOM_EVENT(2,5)
+#define LASTSUCCESS_EVENT RANDOM_EVENT(2,5)
+#define LASTFAILED_EVENT RANDOM_EVENT(2,5)
+#define FAILCOUNT_EVENT RANDOM_EVENT(2,5)
+#define MODNAME_EVENT RANDOM_EVENT(2,5)
+#define MODDATE_EVENT RANDOM_EVENT(2,5)
+#define EXTRA_EVENT RANDOM_EVENT(1,5)
+#define SET_EVENT RANDOM_EVENT(1,4)
+
+/*
+ * Convert a time value to a string for output messages.
+ */
+static char *
+time2string(ts)
+ krb5_timestamp ts;
+{
+ static char buf[1024];
+
+ strcpy(buf, ctime((time_t *) &ts));
+ /* Remove trailing \n */
+ buf[strlen(buf)-1] = '\0';
+ return(buf);
+}
+
+static krb5_boolean
+aux_data_inequal(in, out)
+ krb5_db_entry *in, *out;
+{
+ krb5_tl_data *intl, *outtl;
+ krb5_boolean found;
+
+ if (in->n_tl_data != out->n_tl_data)
+ return(1);
+ found = 1;
+ for (intl = in->tl_data; intl; intl = intl->tl_data_next) {
+ found = 0;
+ for (outtl = out->tl_data; outtl; outtl = outtl->tl_data_next) {
+ if ((intl->tl_data_type == outtl->tl_data_type) &&
+ (intl->tl_data_length == outtl->tl_data_length) &&
+ !memcmp(intl->tl_data_contents,
+ outtl->tl_data_contents,
+ intl->tl_data_length)) {
+ outtl->tl_data_length = -outtl->tl_data_length;
+ found = 1;
+ }
+ }
+ if (!found)
+ break;
+ }
+ for (outtl = out->tl_data; outtl; outtl = outtl->tl_data_next) {
+ if (outtl->tl_data_length < 0)
+ outtl->tl_data_length = -outtl->tl_data_length;
+ }
+ return(!found);
+}
+
+static void
+print_auxdata(entp)
+ krb5_db_entry *entp;
+{
+ krb5_tl_data *tl;
+ int i;
+
+ for (tl = entp->tl_data; tl; tl = tl->tl_data_next) {
+ printf("tl_data(%d)[len=%d] ", tl->tl_data_type, tl->tl_data_length);
+ for (i=0; i<tl->tl_data_length; i++)
+ printf("%02x ", tl->tl_data_contents[i]);
+ printf("\n");
+ }
+}
+
+static krb5_boolean
+key_data_inequal(in, out)
+ krb5_db_entry *in, *out;
+{
+ krb5_boolean found;
+ int i, j;
+
+ if (in->n_key_data != out->n_key_data)
+ return(1);
+ found = 1;
+ for (i=0; i<in->n_key_data; i++) {
+ found = 0;
+ for (j=0; j<out->n_key_data; j++) {
+ if ((in->key_data[i].key_data_kvno ==
+ out->key_data[j].key_data_kvno) &&
+ (in->key_data[i].key_data_type[0] ==
+ out->key_data[j].key_data_type[0]) &&
+ (in->key_data[i].key_data_type[1] ==
+ out->key_data[j].key_data_type[1]) &&
+ (in->key_data[i].key_data_length[0] ==
+ out->key_data[j].key_data_length[0]) &&
+ (in->key_data[i].key_data_length[1] ==
+ out->key_data[j].key_data_length[1]) &&
+ !memcmp(in->key_data[i].key_data_contents[0],
+ out->key_data[j].key_data_contents[0],
+ in->key_data[i].key_data_length[0]) &&
+ (!in->key_data[i].key_data_length[1] ||
+ !memcmp(in->key_data[i].key_data_contents[1],
+ out->key_data[j].key_data_contents[1],
+ in->key_data[i].key_data_length[1]))) {
+ out->key_data[j].key_data_length[0] =
+ -out->key_data[j].key_data_length[0];
+ found = 1;
+ }
+ }
+ if (!found)
+ break;
+ }
+ for (j=0; j<out->n_key_data; j++) {
+ if (out->key_data[j].key_data_length[0] < 0)
+ out->key_data[j].key_data_length[0] =
+ -out->key_data[j].key_data_length[0];
+ }
+ return(!found);
+}
+
+static void
+print_keydata(entp)
+ krb5_db_entry *entp;
+{
+ int i, j;
+
+ for (j=0; j<entp->n_key_data; j++) {
+ printf("key(vno=%d):key(type=%d)[contents= ",
+ entp->key_data[j].key_data_kvno,
+ entp->key_data[j].key_data_type[0]);
+ for (i=0; i<entp->key_data[j].key_data_length[0]; i++)
+ printf("%02x ", entp->key_data[j].key_data_contents[0][i]);
+ printf("] salt(type=%d)", entp->key_data[j].key_data_type[1]);
+ if (entp->key_data[j].key_data_length[1]) {
+ printf("[contents= ");
+ for (i=0; i<entp->key_data[j].key_data_length[1]; i++)
+ printf("%02x ", entp->key_data[j].key_data_contents[1][i]);
+ printf("]");
+ }
+ printf("\n");
+ }
+}
+
+static krb5_boolean
+extra_data_inequal(in, out)
+ krb5_db_entry *in, *out;
+{
+ if (in->e_length != out->e_length)
+ return(1);
+ if (in->e_length && memcmp(in->e_data, out->e_data, (size_t) in->e_length))
+ return(1);
+ return(0);
+}
+
+static void
+print_extradata(entp)
+ krb5_db_entry *entp;
+{
+ int i;
+
+ printf("extra:");
+ for (i=0; i<entp->e_length; i++)
+ printf("%02x ", entp->e_data[i]);
+ printf("\n");
+}
+
+/*
+ * Generate a database entry, either randomly, or using well known values.
+ */
+static void
+gen_dbent(kcontext, dbentp, isrand, validp, pwdp, expectp)
+ krb5_context kcontext;
+ krb5_db_entry *dbentp;
+ krb5_boolean isrand;
+ krb5_ui_4 *validp;
+ char **pwdp;
+ krb5_boolean *expectp;
+{
+ time_t now;
+ krb5_boolean is_set;
+ size_t pwlen;
+ int i;
+ static char *defpass = "testpassword";
+ static char *defprinc = "testprinc/instance@realm";
+
+ now = time((time_t *) NULL);
+ is_set = ((*validp & KRB5_ADM_M_SET) != 0);
+
+ /* Do password on set */
+ if (isrand) {
+ if (PASSWORD_EVENT) {
+ pwlen = 9 + (RAND() % 56);
+ *pwdp = (char *) malloc(pwlen);
+ for (i=0; i<pwlen-1; i++) {
+ (*pwdp)[i] = RAND() % 128;
+ while (!isalnum((int) (*pwdp)[i]))
+ (*pwdp)[i] = RAND() % 128;
+ }
+ (*pwdp)[pwlen-1] = '\0';
+ *validp |= KRB5_ADM_M_PASSWORD;
+ }
+ }
+ else {
+ if (is_set) {
+ *pwdp = (char *) malloc(strlen(defpass)+1);
+ strcpy(*pwdp, defpass);
+ *validp |= KRB5_ADM_M_PASSWORD;
+ }
+ }
+
+ /* Do maxlife */
+ if (isrand) {
+ if (MAXLIFE_EVENT) {
+ dbentp->max_life = RAND();
+ *validp |= KRB5_ADM_M_MAXLIFE;
+ }
+ }
+ else {
+ dbentp->max_life = KRB5_KDB_MAX_LIFE;
+ *validp |= KRB5_ADM_M_MAXLIFE;
+ }
+
+ /* Do maxrenewlife */
+ if (isrand) {
+ if (MAXRENEWLIFE_EVENT) {
+ dbentp->max_renewable_life = RAND();
+ *validp |= KRB5_ADM_M_MAXRENEWLIFE;
+ }
+ }
+ else {
+ dbentp->max_renewable_life = KRB5_KDB_MAX_RLIFE;
+ *validp |= KRB5_ADM_M_MAXRENEWLIFE;
+ }
+
+ /* Do expiration */
+ if (isrand) {
+ if (EXPIRATION_EVENT) {
+ dbentp->expiration = RAND();
+ *validp |= KRB5_ADM_M_EXPIRATION;
+ }
+ }
+ else {
+ dbentp->expiration = KRB5_KDB_EXPIRATION;
+ *validp |= KRB5_ADM_M_EXPIRATION;
+ }
+
+ /* Do pw_expiration */
+ if (isrand) {
+ if (PWEXPIRATION_EVENT) {
+ dbentp->pw_expiration = RAND();
+ *validp |= KRB5_ADM_M_PWEXPIRATION;
+ }
+ }
+ else {
+ dbentp->pw_expiration = (krb5_timestamp) now + 3600;
+ *validp |= KRB5_ADM_M_PWEXPIRATION;
+ }
+
+ /* Do randomkey - 1/8 probability of doing randomkey */
+ if (isrand && (RANDOMKEY_EVENT)) {
+ *validp |= KRB5_ADM_M_RANDOMKEY;
+ }
+
+ /* Do flags */
+ if (isrand) {
+ if (FLAGS_EVENT) {
+ dbentp->attributes = RAND();
+ *validp |= KRB5_ADM_M_FLAGS;
+ }
+ }
+ else {
+ dbentp->attributes = KRB5_KDB_DEF_FLAGS;
+ *validp |= KRB5_ADM_M_FLAGS;
+ }
+
+ /* Do lastsuccess */
+ if (isrand) {
+ if (LASTSUCCESS_EVENT) {
+ dbentp->last_success = RAND();
+ *validp |= KRB5_ADM_M_LASTSUCCESS;
+ }
+ }
+ else {
+ if (!is_set) {
+ dbentp->last_success = (krb5_timestamp) now - 3600;
+ *validp |= KRB5_ADM_M_LASTSUCCESS;
+ }
+ }
+
+ /* Do lastfailed */
+ if (isrand) {
+ if (LASTFAILED_EVENT) {
+ dbentp->last_failed = RAND();
+ *validp |= KRB5_ADM_M_LASTFAILED;
+ }
+ }
+ else {
+ if (!is_set) {
+ dbentp->last_failed = (krb5_timestamp) now - 3600;
+ *validp |= KRB5_ADM_M_LASTFAILED;
+ }
+ }
+
+ /* Do failcount */
+ if (isrand) {
+ if (FAILCOUNT_EVENT) {
+ dbentp->fail_auth_count = RAND();
+ *validp |= KRB5_ADM_M_FAILCOUNT;
+ }
+ }
+ else {
+ if (!is_set) {
+ dbentp->fail_auth_count = 0;
+ *validp |= KRB5_ADM_M_FAILCOUNT;
+ }
+ }
+
+ /*
+ * Generate auxiliary data.
+ */
+ if (isrand) {
+ krb5_octet *lpw_change;
+ krb5_tl_data *tldata;
+ krb5_timestamp lpw;
+ krb5_tl_mod_princ mprinc;
+ int didone;
+
+ didone = 0;
+ if (LASTPWCHANGE_EVENT) {
+ if ((tldata = (krb5_tl_data *) malloc(sizeof(krb5_tl_data))) &&
+ (lpw_change = (krb5_octet *) malloc(sizeof(krb5_timestamp)))) {
+ lpw = (krb5_timestamp) RAND();
+ lpw_change[0] = (unsigned char) ((lpw >> 24) & 0xff);
+ lpw_change[1] = (unsigned char) ((lpw >> 16) & 0xff);
+ lpw_change[2] = (unsigned char) ((lpw >> 8) & 0xff);
+ lpw_change[3] = (unsigned char) (lpw & 0xff);
+ tldata->tl_data_next = (krb5_tl_data *) NULL;
+ tldata->tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
+ tldata->tl_data_length = sizeof(krb5_timestamp);
+ tldata->tl_data_contents = lpw_change;
+ dbentp->n_tl_data = 1;
+ dbentp->tl_data = tldata;
+ didone++;
+ }
+ }
+ if (MODNAME_EVENT || MODDATE_EVENT) {
+ mprinc.mod_date = (krb5_timestamp) RAND();
+ if (!krb5_parse_name(kcontext, defprinc, &mprinc.mod_princ)) {
+ if (!krb5_dbe_encode_mod_princ_data(kcontext, &mprinc, dbentp))
+ didone++;
+ }
+ }
+ if (didone)
+ *validp |= KRB5_ADM_M_AUXDATA;
+ }
+ else {
+ krb5_octet *lpw_change;
+ krb5_tl_data *tldata;
+ krb5_timestamp lpw;
+ krb5_tl_mod_princ mprinc;
+
+ if ((tldata = (krb5_tl_data *) malloc(sizeof(krb5_tl_data))) &&
+ (lpw_change = (krb5_octet *) malloc(sizeof(krb5_timestamp)))) {
+ lpw = (krb5_timestamp) now - 3600;
+ lpw_change[0] = (unsigned char) ((lpw >> 24) & 0xff);
+ lpw_change[1] = (unsigned char) ((lpw >> 16) & 0xff);
+ lpw_change[2] = (unsigned char) ((lpw >> 8) & 0xff);
+ lpw_change[3] = (unsigned char) (lpw & 0xff);
+ tldata->tl_data_next = (krb5_tl_data *) NULL;
+ tldata->tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
+ tldata->tl_data_length = sizeof(krb5_timestamp);
+ tldata->tl_data_contents = lpw_change;
+ dbentp->n_tl_data = 1;
+ dbentp->tl_data = tldata;
+ }
+ mprinc.mod_date = (krb5_timestamp) now;
+ if (!krb5_parse_name(kcontext, defprinc, &mprinc.mod_princ))
+ krb5_dbe_encode_mod_princ_data(kcontext, &mprinc, dbentp);
+ *validp |= KRB5_ADM_M_AUXDATA;
+ }
+
+ /* Make key data */
+ if (isrand) {
+ int i, j, kl, sl;
+
+ if (!is_set) {
+ for (i=0; i<(1+(RAND()%8)); i++) {
+ if (!krb5_dbe_create_key_data(kcontext, dbentp)) {
+ dbentp->key_data[i].key_data_kvno = RAND() % 32768;
+ dbentp->key_data[i].key_data_type[0] = RAND() % 32768;
+ dbentp->key_data[i].key_data_type[1] = RAND() % 32768;
+ kl = dbentp->key_data[i].key_data_length[0] =
+ 8 + (RAND() % 128);
+ sl = dbentp->key_data[i].key_data_length[1] =
+ 0 + (RAND() % 128);
+ if (dbentp->key_data[i].key_data_contents[0] =
+ (krb5_octet *) malloc(kl)) {
+ for (j=0; j<kl; j++) {
+ dbentp->key_data[i].key_data_contents[0][j] =
+ RAND() % 256;
+ }
+ }
+ if (dbentp->key_data[i].key_data_contents[1] =
+ (krb5_octet *) malloc(sl)) {
+ for (j=0; j<sl; j++) {
+ dbentp->key_data[i].key_data_contents[1][j] =
+ RAND() % 256;
+ }
+ }
+ *validp |= KRB5_ADM_M_KEYDATA;
+ }
+ }
+ }
+ }
+ else {
+ if (!is_set) {
+ if (!krb5_dbe_create_key_data(kcontext, dbentp)) {
+ int i;
+
+ dbentp->key_data[0].key_data_kvno = 1;
+ dbentp->key_data[0].key_data_type[0] = 1;
+ dbentp->key_data[0].key_data_type[1] = 0;
+ dbentp->key_data[0].key_data_length[0] = 24;
+ dbentp->key_data[0].key_data_length[1] = 0;
+ if (dbentp->key_data[0].key_data_contents[0] =
+ (krb5_octet *) malloc(24)) {
+ for (i=0; i<24; i++)
+ dbentp->key_data[0].key_data_contents[0][i] = RAND() % 256;
+ }
+ dbentp->key_data[0].key_data_contents[1] = (krb5_octet *) NULL;
+ *validp |= KRB5_ADM_M_KEYDATA;
+ }
+ }
+ }
+
+ /* Make extra data */
+ if (isrand && EXTRA_EVENT) {
+ dbentp->e_length = 8 + (RAND() % 504);
+ if (dbentp->e_data = (krb5_octet *)
+ malloc((size_t) dbentp->e_length)) {
+ int j;
+ for (j=0; j<dbentp->e_length; j++) {
+ dbentp->e_data[j] = RAND() % 256;
+ }
+ *validp |= KRB5_ADM_M_EXTRADATA;
+ }
+ else
+ dbentp->e_length = 0;
+ }
+
+ if (is_set) {
+ /* Only 25% may fail at most */
+ if (isrand && ((RAND() % 100) < 75)) {
+ *validp &= KRB5_ADM_M_SET_VALID;
+ }
+#ifdef notdef
+ if ((*validp & KRB5_ADM_M_PASSWORD) != 0)
+ *validp &= ~KRB5_ADM_M_RANDOMKEY;
+#endif /* notdef */
+ *expectp = ((*validp & ~KRB5_ADM_M_SET_VALID) != 0) ? 1 : 0;
+ }
+ else {
+ /* Only 25% may fail at most */
+ if (isrand && ((RAND() % 100) < 75))
+ *validp &= KRB5_ADM_M_GET_VALID;
+ *expectp = ((*validp & ~KRB5_ADM_M_GET_VALID) != 0) ? 1 : 0;
+ }
+}
+
+/*
+ * Compare two entries.
+ */
+static krb5_boolean
+compare_entries(kcontext, ivalid, ientp, ipwd, ovalid, oentp, opwd)
+ krb5_context kcontext;
+ krb5_ui_4 ivalid;
+ krb5_db_entry *ientp;
+ char *ipwd;
+ krb5_ui_4 ovalid;
+ krb5_db_entry *oentp;
+ char *opwd;
+{
+ /* Handle/compare password */
+ if (((ivalid & KRB5_ADM_M_PASSWORD) != 0) &&
+ (((ovalid & KRB5_ADM_M_PASSWORD) == 0) ||
+ strcmp(ipwd, opwd)))
+ return(0);
+
+ /* Handle/compare maxlife */
+ if (((ivalid & KRB5_ADM_M_MAXLIFE) != 0) &&
+ (((ovalid & KRB5_ADM_M_MAXLIFE) == 0) ||
+ (ientp->max_life != oentp->max_life)))
+ return(0);
+
+ /* Handle/compare maxrenewlife */
+ if (((ivalid & KRB5_ADM_M_MAXRENEWLIFE) != 0) &&
+ (((ovalid & KRB5_ADM_M_MAXRENEWLIFE) == 0) ||
+ (ientp->max_renewable_life != oentp->max_renewable_life)))
+ return(0);
+
+ /* Handle/compare expiration */
+ if (((ivalid & KRB5_ADM_M_EXPIRATION) != 0) &&
+ (((ovalid & KRB5_ADM_M_EXPIRATION) == 0) ||
+ (ientp->expiration != oentp->expiration)))
+ return(0);
+
+ /* Handle/compare pwexpiration */
+ if (((ivalid & KRB5_ADM_M_PWEXPIRATION) != 0) &&
+ (((ovalid & KRB5_ADM_M_PWEXPIRATION) == 0) ||
+ (ientp->pw_expiration != oentp->pw_expiration)))
+ return(0);
+
+#ifdef notdef
+ /* Handle/compare random key */
+ if (((ivalid & KRB5_ADM_M_RANDOMKEY) != 0) &&
+ ((ovalid & KRB5_ADM_M_PASSWORD) != 0))
+ return(0);
+#endif /* notdef */
+
+ /* Handle/compare flags */
+ if (((ivalid & KRB5_ADM_M_FLAGS) != 0) &&
+ (((ovalid & KRB5_ADM_M_FLAGS) == 0) ||
+ (ientp->attributes != oentp->attributes)))
+ return(0);
+
+ /* Handle/compare lastsuccess */
+ if (((ivalid & KRB5_ADM_M_LASTSUCCESS) != 0) &&
+ (((ovalid & KRB5_ADM_M_LASTSUCCESS) == 0) ||
+ (ientp->last_success != oentp->last_success)))
+ return(0);
+
+ /* Handle/compare lastfailed */
+ if (((ivalid & KRB5_ADM_M_LASTFAILED) != 0) &&
+ (((ovalid & KRB5_ADM_M_LASTFAILED) == 0) ||
+ (ientp->last_failed != oentp->last_failed)))
+ return(0);
+
+ /* Handle/compare failcount */
+ if (((ivalid & KRB5_ADM_M_FAILCOUNT) != 0) &&
+ (((ovalid & KRB5_ADM_M_FAILCOUNT) == 0) ||
+ (ientp->fail_auth_count != oentp->fail_auth_count)))
+ return(0);
+
+ /* Handle/compare auxiliary data */
+ if (((ivalid & KRB5_ADM_M_AUXDATA) != 0) &&
+ (((ovalid & KRB5_ADM_M_AUXDATA) == 0) ||
+ aux_data_inequal(ientp, oentp)))
+ return(0);
+
+ /* Handle/compare key data */
+ if (((ivalid & KRB5_ADM_M_KEYDATA) != 0) &&
+ (((ovalid & KRB5_ADM_M_KEYDATA) == 0) ||
+ key_data_inequal(ientp, oentp)))
+ return(0);
+
+ /* Handle/compare extra data */
+ if (((ivalid & KRB5_ADM_M_EXTRADATA) != 0) &&
+ (((ovalid & KRB5_ADM_M_EXTRADATA) == 0) ||
+ extra_data_inequal(ientp, oentp)))
+ return(0);
+
+ return(1);
+}
+
+/*
+ * Print out an entry.
+ */
+static void
+print_dbent(kcontext, ivalid, ientp, ipwd)
+ krb5_context kcontext;
+ krb5_ui_4 ivalid;
+ krb5_db_entry *ientp;
+ char *ipwd;
+{
+ printf("Valid mask:\t%08x\n", ivalid);
+
+ /* Print password */
+ if ((ivalid & KRB5_ADM_M_PASSWORD) != 0)
+ printf("Password:\t%s\n", ipwd);
+
+ /* Print maxlife */
+ if ((ivalid & KRB5_ADM_M_MAXLIFE) != 0)
+ printf("max_life:\t%8d\t%08x\n", ientp->max_life, ientp->max_life);
+
+ /* Print maxrenewlife */
+ if ((ivalid & KRB5_ADM_M_MAXRENEWLIFE) != 0)
+ printf("max_rlife:\t%8d\t%08x\n", ientp->max_renewable_life,
+ ientp->max_renewable_life);
+
+ /* Print expiration */
+ if ((ivalid & KRB5_ADM_M_EXPIRATION) != 0)
+ printf("expires:\t%8d\t%08x\t%s\n", ientp->expiration,
+ ientp->expiration, time2string(ientp->expiration));
+
+ /* Print pwexpiration */
+ if ((ivalid & KRB5_ADM_M_PWEXPIRATION) != 0)
+ printf("pw expires:\t%8d\t%08x\t%s\n", ientp->pw_expiration,
+ ientp->pw_expiration, time2string(ientp->pw_expiration));
+
+ /* Print random key */
+ if ((ivalid & KRB5_ADM_M_RANDOMKEY) != 0)
+ printf("random key\n");
+
+ /* Print flags */
+ if ((ivalid & KRB5_ADM_M_FLAGS) != 0)
+ printf("flags:\t\t%8d\t%08x\n", ientp->attributes, ientp->attributes);
+
+ /* Print lastsuccess */
+ if ((ivalid & KRB5_ADM_M_LASTSUCCESS) != 0)
+ printf("lastsucc:\t%8d\t%08x\t%s\n", ientp->last_success,
+ ientp->last_success, time2string(ientp->last_success));
+
+ /* Print lastfailed */
+ if ((ivalid & KRB5_ADM_M_LASTFAILED) != 0)
+ printf("lastfail:\t%8d\t%08x\t%s\n", ientp->last_failed,
+ ientp->last_failed, time2string(ientp->last_failed));
+
+ /* Print failcount */
+ if ((ivalid & KRB5_ADM_M_FAILCOUNT) != 0)
+ printf("failcount:\t%8d\t%08x\n", ientp->fail_auth_count,
+ ientp->fail_auth_count);
+
+ /* Print auxiliary data */
+ if ((ivalid & KRB5_ADM_M_AUXDATA) != 0)
+ print_auxdata(ientp);
+
+ /* Print key data */
+ if ((ivalid & KRB5_ADM_M_KEYDATA) != 0)
+ print_keydata(ientp);
+
+ /* Print extra data */
+ if ((ivalid & KRB5_ADM_M_EXTRADATA) != 0)
+ print_extradata(ientp);
+}
+
+/*
+ * Do a test case.
+ *
+ * Strategy: Generate the desired database entry type, then convert it using
+ * krb5_adm_dbent_to_proto, then convert it back to a database entry
+ * using krb5_adm_proto_to_dbent. Then verify the match.
+ */
+static krb5_int32
+do_test(pname, verbose, isrand, is_a_set, title, passno)
+ char *pname;
+ krb5_boolean verbose;
+ krb5_boolean isrand;
+ krb5_boolean is_a_set;
+ char *title;
+ krb5_int32 passno;
+{
+ krb5_context kcontext;
+ krb5_db_entry *in_dbent;
+ krb5_db_entry *out_dbent;
+ krb5_error_code kret;
+ krb5_int32 ncomps;
+ krb5_data *complist;
+ krb5_ui_4 in_validmask;
+ krb5_ui_4 out_validmask;
+ char *in_password;
+ char *out_password;
+ krb5_boolean should_fail;
+
+ if (verbose) {
+ printf("* Begin %s", title);
+ if (isrand)
+ printf(" pass %d", passno);
+ printf("\n");
+ }
+
+ kret = 0;
+ krb5_init_context(&kcontext);
+ krb5_init_ets(kcontext);
+ in_dbent = (krb5_db_entry *) malloc(sizeof(krb5_db_entry));
+ out_dbent = (krb5_db_entry *) malloc(sizeof(krb5_db_entry));
+ if (in_dbent && out_dbent) {
+ /* Initialize our data */
+ memset((char *) in_dbent, 0, sizeof(krb5_db_entry));
+ memset((char *) out_dbent, 0, sizeof(krb5_db_entry));
+ in_password = out_password = (char *) NULL;
+ out_validmask = 0;
+ ncomps = 0;
+ complist = (krb5_data *) NULL;
+ should_fail = 0;
+ if (!isrand) {
+ if (is_a_set)
+ in_validmask = KRB5_ADM_M_SET;
+ else
+ in_validmask = KRB5_ADM_M_GET;
+ }
+ else {
+ if (SET_EVENT)
+ in_validmask = KRB5_ADM_M_SET;
+ else
+ in_validmask = KRB5_ADM_M_GET;
+ }
+
+ /* Generate the database entry. */
+ gen_dbent(kcontext,
+ in_dbent, isrand, &in_validmask, &in_password, &should_fail);
+
+ /* Convert it to the o-t-w protocol */
+ if (!(kret = krb5_adm_dbent_to_proto(kcontext,
+ in_validmask,
+ in_dbent,
+ in_password,
+ &ncomps,
+ &complist))) {
+ /* If this should fail, then we've got a problem here */
+ if (!should_fail) {
+
+ /* Otherwise, convert it back to a database entry */
+ if (!(kret = krb5_adm_proto_to_dbent(kcontext,
+ ncomps,
+ complist,
+ &out_validmask,
+ out_dbent,
+ &out_password))) {
+ /* Compare the entries */
+ if (compare_entries(kcontext,
+ in_validmask,
+ in_dbent,
+ in_password,
+ out_validmask,
+ out_dbent,
+ out_password)) {
+ /* Success */
+ if (verbose) {
+ printf("Successful translation");
+ printf(" during %s", title);
+ if (isrand)
+ printf(" pass %d", passno);
+ printf(" of:\n");
+ print_dbent(kcontext,
+ in_validmask, in_dbent, in_password);
+ }
+ }
+ else {
+ /* Failed */
+ fprintf(stderr, "%s: comparison mismatch", pname);
+ fprintf(stderr, " during %s", title);
+ if (isrand)
+ fprintf(stderr, " pass %d", passno);
+ fprintf(stderr, "\n");
+ if (verbose) {
+ printf("Input entry is as follows:\n");
+ print_dbent(kcontext,
+ in_validmask, in_dbent, in_password);
+ printf("Output entry is as follows:\n");
+ print_dbent(kcontext,
+ out_validmask,
+ out_dbent,
+ out_password);
+ }
+ kret = KRB5KRB_ERR_GENERIC;
+ }
+ if (out_password)
+ krb5_xfree(out_password);
+ }
+ else {
+ /* Conversion to database entry failed */
+ fprintf(stderr, "%s: protocol decode failed with %d",
+ pname, kret);
+ fprintf(stderr, " during %s", title);
+ if (isrand)
+ fprintf(stderr, " pass %d", passno);
+ fprintf(stderr, "\n");
+ }
+ }
+ else {
+ /* Should have failed */
+ fprintf(stderr, "%s: protocol encode unexpectedly succeeded",
+ pname);
+ kret = KRB5KRB_ERR_GENERIC;
+ fprintf(stderr, " during %s", title);
+ if (isrand)
+ fprintf(stderr, " pass %d", passno);
+ fprintf(stderr, "\n");
+ }
+ krb5_free_adm_data(kcontext, ncomps, complist);
+ }
+ else {
+ /* Convert to protocol failed */
+ if (!should_fail) {
+ /* Unexpected failure */
+ fprintf(stderr, "%s: protocol encode failed with %d",
+ pname, kret);
+ fprintf(stderr, " during %s", title);
+ if (isrand)
+ fprintf(stderr, " pass %d", passno);
+ fprintf(stderr, "\n");
+ }
+ else {
+ /* Success */
+ if (verbose)
+ printf("- Expected failure OK\n");
+ kret = 0;
+ }
+ }
+ /* Cleanup */
+ if (in_password)
+ free(in_password);
+ if (in_dbent->tl_data) {
+ krb5_tl_data *xxx, *xxx1;
+
+ for (xxx=in_dbent->tl_data; xxx; ) {
+ xxx1 = xxx;
+ xxx = xxx->tl_data_next;
+ free(xxx1);
+ }
+ }
+ free(in_dbent);
+ if (out_dbent->tl_data) {
+ krb5_tl_data *xxx, *xxx1;
+
+ for (xxx=out_dbent->tl_data; xxx; ) {
+ xxx1 = xxx;
+ xxx = xxx->tl_data_next;
+ free(xxx1);
+ }
+ }
+ free(out_dbent);
+ }
+ else {
+ fprintf(stderr, "%s: no memory\n", pname);
+ kret = ENOMEM;
+ }
+
+ krb5_free_context(kcontext);
+ if (verbose) {
+ printf("* End %s ", title);
+ if (isrand)
+ printf(" pass %d ", passno);
+ printf("%s", (kret) ? "FAILURE" : "SUCCESS");
+ if (kret)
+ printf("%d - %s", kret, error_message(kret));
+ printf("\n");
+ }
+ return((kret) ? 1 : 0);
+}
+
+/*
+ * usage is: t_dbentry [-r <nnn>] [-v]
+ */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_boolean verbose;
+ krb5_int32 randompasses;
+ krb5_int32 error;
+ int option;
+ extern char *optarg;
+ char *programname;
+ int i;
+ time_t now;
+
+ randompasses = 0;
+ verbose = 0;
+ error = 0;
+ programname = argv[0];
+
+ now = time((time_t *) NULL);
+ SRAND((RAND_TYPE) now);
+ while ((option = getopt(argc, argv, "r:v")) != EOF) {
+ switch (option) {
+ case 'r':
+ if (sscanf(optarg, "%d", &randompasses) != 1) {
+ fprintf(stderr, "%s: %s is not a number\n", argv[0], optarg);
+ error++;
+ }
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ fprintf(stderr, "%s: usage is %s [-r number] [-v]\n",
+ argv[0], argv[0]);
+ error++;
+ break;
+ }
+ }
+ if (error)
+ return(error);
+
+ error += do_test(programname, verbose, 0, 1, "Standard set test", 0);
+ error += do_test(programname, verbose, 0, 0, "Standard get test", 0);
+ for (i=0; i<randompasses; i++)
+ error += do_test(programname, verbose, 1, 0, "Random test", i+1);
+ if (verbose) {
+ if (error)
+ printf("%s: %d errors in %d tests (%5.2f%%)\n", argv[0], error,
+ randompasses+2,
+ (float) (error*100) / (float) (randompasses+2));
+ }
+ return(error);
+}
+
diff --git a/src/lib/kadm/t_ktentry.c b/src/lib/kadm/t_ktentry.c
new file mode 100644
index 000000000..0367947f2
--- /dev/null
+++ b/src/lib/kadm/t_ktentry.c
@@ -0,0 +1,402 @@
+/*
+ * lib/kadm/t_ktentry.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * t_ktentry.c - Test function of krb5_adm_{proto_to_ktent,ktent_to_proto}.
+ */
+
+#include "k5-int.h"
+#include "adm.h"
+#include "adm_proto.h"
+
+#if HAVE_SRAND48
+#define SRAND srand48
+#define RAND lrand48
+#define RAND_TYPE long
+#endif /* HAVE_SRAND48 */
+
+#if !defined(RAND_TYPE) && defined(HAVE_SRAND)
+#define SRAND srand
+#define RAND rand
+#define RAND_TYPE int
+#endif /* !defined(RAND_TYPE) && defined(HAVE_SRAND) */
+
+#if !defined(RAND_TYPE) && defined(HAVE_SRANDOM)
+#define SRAND srandom
+#define RAND random
+#define RAND_TYPE long
+#endif /* !defined(RAND_TYPE) && defined(HAVE_SRANDOM) */
+
+#if !defined(RAND_TYPE)
+There is no random number generator.
+#endif /* !defined(RAND_TYPE) */
+
+/*
+ * Generate a principal name.
+ */
+static char *
+gen_princname(isrand)
+ krb5_boolean isrand;
+{
+ static char *defprinc = "testprinc/instance@realm";
+ char *pptr;
+
+ if (isrand) {
+ int i, j;
+ int ncomps;
+ size_t compsize[9];
+ char * complist[9];
+ size_t totsize;
+
+ for (i=0; i<9; i++) {
+ compsize[i] = 0;
+ complist[i] = (char *) NULL;
+ }
+ ncomps = 2 + (RAND() % 7);
+ totsize = 0;
+ for (i=0; i<ncomps; i++) {
+ compsize[i] = 1 + (RAND() % 32);
+ complist[i] = (char *) malloc(compsize[i]+1);
+ if (complist[i]) {
+ for (j=0; j<compsize[i]; j++) {
+ (complist[i])[j] = RAND() % 128;
+ while (!isalnum((int) (complist[i])[j]))
+ (complist[i])[j] = RAND() % 128;
+ }
+ (complist[i])[compsize[i]] = '\0';
+ totsize += (compsize[i] + 1);
+ }
+ else
+ break;
+ }
+ pptr = (char *) malloc(totsize+1);
+ if (pptr) {
+ pptr[0] = '\0';
+ for (i=1; i<ncomps; i++) {
+ if (complist[i]) {
+ strcat(pptr, complist[i]);
+ strcat(pptr, "/");
+ free(complist[i]);
+ }
+ else
+ break;
+ }
+ pptr[strlen(pptr)-1] = '\0';
+ strcat(pptr, "@");
+ strcat(pptr, complist[0]);
+ free(complist[0]);
+ }
+ }
+ else {
+ pptr = (char *) malloc(strlen(defprinc)+1);
+ if (pptr)
+ strcpy(pptr, defprinc);
+ }
+ return(pptr);
+}
+
+static void
+gen_key(ktentp, isrand)
+ krb5_keytab_entry *ktentp;
+ krb5_boolean isrand;
+{
+ static unsigned char defkey[8] = { 0x01, 0xfe, 0xab, 0xc3,
+ 0x23, 0x16, 0x84, 0x23 };
+
+ if (isrand) {
+ size_t keylen;
+ int i;
+
+ keylen = 4 + (RAND() % 64);
+ ktentp->key.contents = (krb5_octet *) malloc(keylen);
+ if (ktentp->key.contents) {
+ ktentp->key.length = keylen;
+ for (i=0; i<keylen; i++)
+ ktentp->key.contents[i] = RAND() & 255;
+ }
+ }
+ else {
+ ktentp->key.contents = (krb5_octet *) malloc(sizeof(defkey));
+ if (ktentp->key.contents) {
+ ktentp->key.length = 8;
+ memcpy(ktentp->key.contents, defkey, sizeof(defkey));
+ }
+ }
+}
+
+/*
+ * Generate a keytab entry.
+ */
+static void
+gen_ktent(kcontext, ktentp, isrand)
+ krb5_context kcontext;
+ krb5_keytab_entry *ktentp;
+ krb5_boolean isrand;
+{
+ char *princname;
+
+ princname = gen_princname(isrand);
+ if (princname && !krb5_parse_name(kcontext,
+ princname,
+ &ktentp->principal)
+ ) {
+ ktentp->vno = (isrand) ? RAND() : 1;
+ gen_key(ktentp, isrand);
+ free(princname);
+ }
+}
+
+/*
+ * Compare two entries.
+ */
+static krb5_boolean
+compare_entries(kcontext, ientp, oentp)
+ krb5_context kcontext;
+ krb5_keytab_entry *ientp;
+ krb5_keytab_entry *oentp;
+{
+ if (ientp->vno != oentp->vno)
+ return(0);
+
+ if ((ientp->key.length != oentp->key.length) ||
+ memcmp(ientp->key.contents, oentp->key.contents, ientp->key.length))
+ return(0);
+
+ if (!krb5_principal_compare(kcontext, ientp->principal, oentp->principal))
+ return(0);
+ return(1);
+}
+
+/*
+ * Print out an entry.
+ */
+static void
+print_ktent(kcontext, ientp)
+ krb5_context kcontext;
+ krb5_keytab_entry *ientp;
+{
+ char *princname;
+ int i;
+
+ if (!krb5_unparse_name(kcontext, ientp->principal, &princname)) {
+ printf("Principal: %s (version %d[%x])\n", princname, ientp->vno);
+ printf("Key:");
+ for (i=0; i<ientp->key.length; i++)
+ printf(" %02x", ientp->key.contents[i]);
+ printf("\n");
+ krb5_xfree(princname);
+ }
+}
+
+/*
+ * Do a test case.
+ *
+ * Strategy: Generate the desired keytab entry type, then convert it using
+ * krb5_adm_ktent_to_proto, then convert it back to a keytab entry
+ * using krb5_adm_proto_to_ktent. Then verify the match.
+ */
+static krb5_int32
+do_test(pname, verbose, isrand, title, passno)
+ char *pname;
+ krb5_boolean verbose;
+ krb5_boolean isrand;
+ char *title;
+ krb5_int32 passno;
+{
+ krb5_context kcontext;
+ krb5_keytab_entry *in_ktent;
+ krb5_keytab_entry *out_ktent;
+ krb5_error_code kret;
+ krb5_int32 ncomps;
+ krb5_data *complist;
+
+ if (verbose) {
+ printf("* Begin %s", title);
+ if (isrand)
+ printf(" pass %d", passno);
+ printf("\n");
+ }
+
+ kret = 0;
+ krb5_init_context(&kcontext);
+ krb5_init_ets(kcontext);
+ in_ktent = (krb5_keytab_entry *) malloc(sizeof(krb5_keytab_entry));
+ out_ktent = (krb5_keytab_entry *) malloc(sizeof(krb5_keytab_entry));
+ if (in_ktent && out_ktent) {
+ /* Initialize our data */
+ memset((char *) in_ktent, 0, sizeof(krb5_keytab_entry));
+ memset((char *) out_ktent, 0, sizeof(krb5_keytab_entry));
+ ncomps = 0;
+ complist = (krb5_data *) NULL;
+
+ /* Generate the keytab entry. */
+ gen_ktent(kcontext, in_ktent, isrand);
+
+ /* Convert it to the o-t-w protocol */
+ if (!(kret = krb5_adm_ktent_to_proto(kcontext,
+ in_ktent,
+ &ncomps,
+ &complist))) {
+ /* Otherwise, convert it back to a keytab entry */
+ if (!(kret = krb5_adm_proto_to_ktent(kcontext,
+ ncomps,
+ complist,
+ out_ktent))) {
+ /* Compare the entries */
+ if (compare_entries(kcontext,
+ in_ktent,
+ out_ktent)) {
+ /* Success */
+ if (verbose) {
+ printf("Successful translation");
+ printf(" during %s", title);
+ if (isrand)
+ printf(" pass %d", passno);
+ printf(" of:\n");
+ print_ktent(kcontext, in_ktent);
+ }
+ }
+ else {
+ /* Failed */
+ fprintf(stderr, "%s: comparison mismatch", pname);
+ fprintf(stderr, " during %s", title);
+ if (isrand)
+ fprintf(stderr, " pass %d", passno);
+ fprintf(stderr, "\n");
+ if (verbose) {
+ printf("Input entry is as follows:\n");
+ print_ktent(kcontext, in_ktent);
+ printf("Output entry is as follows:\n");
+ print_ktent(kcontext, out_ktent);
+ }
+ kret = KRB5KRB_ERR_GENERIC;
+ }
+ }
+ else {
+ /* Conversion to keytab entry failed */
+ fprintf(stderr, "%s: protocol decode failed with %d",
+ pname, kret);
+ fprintf(stderr, " during %s", title);
+ if (isrand)
+ fprintf(stderr, " pass %d", passno);
+ fprintf(stderr, "\n");
+ }
+ krb5_free_adm_data(kcontext, ncomps, complist);
+ }
+ else {
+ /* Convert to protocol failed */
+ fprintf(stderr, "%s: protocol encode failed with %d",
+ pname, kret);
+ fprintf(stderr, " during %s", title);
+ if (isrand)
+ fprintf(stderr, " pass %d", passno);
+ fprintf(stderr, "\n");
+ }
+ /* Cleanup */
+ if (in_ktent->principal)
+ krb5_free_principal(kcontext, in_ktent->principal);
+ if (in_ktent->key.contents)
+ free(in_ktent->key.contents);
+ free(in_ktent);
+ if (out_ktent->principal)
+ krb5_free_principal(kcontext, out_ktent->principal);
+ if (out_ktent->key.contents)
+ free(out_ktent->key.contents);
+ free(out_ktent);
+ }
+ else {
+ fprintf(stderr, "%s: no memory\n", pname);
+ kret = ENOMEM;
+ }
+
+ krb5_free_context(kcontext);
+ if (verbose) {
+ printf("* End %s ", title);
+ if (isrand)
+ printf(" pass %d ", passno);
+ printf("%s", (kret) ? "FAILURE" : "SUCCESS");
+ if (kret)
+ printf("%d - %s", kret, error_message(kret));
+ printf("\n");
+ }
+ return((kret) ? 1 : 0);
+}
+
+/*
+ * usage is: t_ktentry [-r <nnn>] [-v]
+ */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_boolean verbose;
+ krb5_int32 randompasses;
+ krb5_int32 error;
+ int option;
+ extern char *optarg;
+ char *programname;
+ int i;
+ time_t now;
+
+ randompasses = 0;
+ verbose = 0;
+ error = 0;
+ programname = argv[0];
+
+ now = time((time_t *) NULL);
+ SRAND((RAND_TYPE) now);
+ while ((option = getopt(argc, argv, "r:v")) != EOF) {
+ switch (option) {
+ case 'r':
+ if (sscanf(optarg, "%d", &randompasses) != 1) {
+ fprintf(stderr, "%s: %s is not a number\n", argv[0], optarg);
+ error++;
+ }
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ fprintf(stderr, "%s: usage is %s [-r number] [-v]\n",
+ argv[0], argv[0]);
+ error++;
+ break;
+ }
+ }
+ if (error)
+ return(error);
+
+ error += do_test(programname, verbose, 0, "Standard test", 0);
+ for (i=0; i<randompasses; i++)
+ error += do_test(programname, verbose, 1, 0, "Random test", i+1);
+ if (verbose) {
+ if (error)
+ printf("%s: %d errors in %d tests (%5.2f%%)\n", argv[0], error,
+ randompasses+2,
+ (float) (error*100) / (float) (randompasses+2));
+ }
+ return(error);
+}
+