From 892f77f6b49d8d31813c997e3bc1a805e66f400c Mon Sep 17 00:00:00 2001 From: Ezra Peisach Date: Sat, 24 Aug 1996 16:03:45 +0000 Subject: [PATCH] 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 --- src/lib/kadm/.Sanitize | 49 ++ src/lib/kadm/ChangeLog | 334 +++++++++++++ src/lib/kadm/Makefile.in | 92 ++++ src/lib/kadm/adm_conn.c | 762 +++++++++++++++++++++++++++++ src/lib/kadm/adm_kt_dec.c | 127 +++++ src/lib/kadm/adm_kt_enc.c | 162 +++++++ src/lib/kadm/adm_kw_dec.c | 578 ++++++++++++++++++++++ src/lib/kadm/adm_kw_enc.c | 433 +++++++++++++++++ src/lib/kadm/adm_rw.c | 534 ++++++++++++++++++++ src/lib/kadm/alt_prof.c | 447 +++++++++++++++++ src/lib/kadm/configure.in | 16 + src/lib/kadm/keysalt.c | 207 ++++++++ src/lib/kadm/krb5strings.M | 250 ++++++++++ src/lib/kadm/logger.c | 940 ++++++++++++++++++++++++++++++++++++ src/lib/kadm/str_conv.c | 221 +++++++++ src/lib/kadm/t_dbentry.c | 965 +++++++++++++++++++++++++++++++++++++ src/lib/kadm/t_ktentry.c | 402 +++++++++++++++ 17 files changed, 6519 insertions(+) create mode 100644 src/lib/kadm/.Sanitize create mode 100644 src/lib/kadm/ChangeLog create mode 100644 src/lib/kadm/Makefile.in create mode 100644 src/lib/kadm/adm_conn.c create mode 100644 src/lib/kadm/adm_kt_dec.c create mode 100644 src/lib/kadm/adm_kt_enc.c create mode 100644 src/lib/kadm/adm_kw_dec.c create mode 100644 src/lib/kadm/adm_kw_enc.c create mode 100644 src/lib/kadm/adm_rw.c create mode 100644 src/lib/kadm/alt_prof.c create mode 100644 src/lib/kadm/configure.in create mode 100644 src/lib/kadm/keysalt.c create mode 100644 src/lib/kadm/krb5strings.M create mode 100644 src/lib/kadm/logger.c create mode 100644 src/lib/kadm/str_conv.c create mode 100644 src/lib/kadm/t_dbentry.c create mode 100644 src/lib/kadm/t_ktentry.c 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 + + * configure.in: remove ref to ET_RULES + +Mon Jun 10 21:42:26 1996 Theodore Ts'o + + * 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 + + * Makefile.in (check-unix): Use KRB5_RUN_FLAGS + +Sun May 12 00:46:57 1996 Marc Horowitz + + * alt_prof.c (krb5_read_realm_params): added "acl_file" variable + for the admin server. + +Wed Mar 13 17:37:00 1996 Ken Raeburn + + * configure.in: Use AC_HEADER_STDARG. + +Sun Dec 10 11:02:56 1995 Ezra Peisach + + * str_conv.c (krb5_input_flag_to_string): Add new routine. + +Wed Nov 8 02:46:54 1995 Theodore Y. Ts'o + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * logger.c: #ifdef the entire file so it's not built under Windows. + +Tue Sep 27 12:00:00 1995 + + * 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 + + * 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 + + * Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the + Makefile. + +Fri Sep 22 12:00:00 1995 James Mattly + + * adm_conn.c: for sockets changed close to closesocket, sockets on + macintosh arn't files. + +Fri Sep 22 15:44:02 1995 Mark Eichin + + * 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 + + * 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 + + * adm_conn.c: For Macintosh hardwire cache name. Various casting + fixes. + +Thu Sep 7 17:50:15 1995 Theodore Y. Ts'o + + * 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 + + * .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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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_ 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 + + * 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 +#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 = [:[]] + */ + 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; ilength >= 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= 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= 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= 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, ×tring))) { + 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=... 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 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; imax_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= 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= 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= 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 =... 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> 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> 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 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= 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 +#include + +/* + * 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 + * or + * + */ + 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 +#if HAVE_SYSLOG_H +#include +#endif /* HAVE_SYSLOG_H */ +#if HAVE_STDARG_H +#include +#else /* HAVE_STDARG_H */ +#include +#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 + * SYSLOG[=[:]] + * STDERR + * CONSOLE + * DEVICE= + * + * Where: + * is ":" for open/append, "=" for open/create. + * is a valid path name. + * is one of: (default = ERR) + * EMERG + * ALERT + * CRIT + * ERR + * WARNING + * NOTICE + * INFO + * DEBUG + * is one of: (default = AUTH) + * KERN + * USER + * MAIL + * DAEMON + * AUTH + * LPR + * NEWS + * UUCP + * CRON + * LOCAL0..LOCAL7 + * 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]-> 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 + * 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; ilog_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) + * [](): + * + * (short form) + * + */ + 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) 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; itl_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; in_key_data; i++) { + found = 0; + for (j=0; jn_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; jn_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; jn_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; ikey_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; ikey_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; ie_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; imax_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; jkey_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; jkey_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; je_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 ] [-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; ikey.contents = (krb5_octet *) malloc(keylen); + if (ktentp->key.contents) { + ktentp->key.length = keylen; + for (i=0; ikey.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; ikey.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 ] [-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