Index: krb5-1.0.5UM/src/configure
diff -c krb5-1.0.5UM/src/configure:1.1.1.1 krb5-1.0.5UM/src/configure:1.3
*** krb5-1.0.5UM/src/configure:1.1.1.1	Fri Apr 24 09:47:22 1998
--- krb5-1.0.5UM/src/configure	Mon Dec  7 17:26:18 1998
***************
*** 1568,1574 ****
  kadminv4=kadmin.v4
  krb524=krb524
  fi
! subdirs="util include lib $krb524 kdc kadmin slave clients appl tests config-files gen-manpages"
  
  ALL_RECURSE="all-recurse"
  CLEAN_RECURSE="clean-recurse"
--- 1568,1578 ----
  kadminv4=kadmin.v4
  krb524=krb524
  fi
! #
! # UMICH MOD:
! # 	Add replication to list of subdirs
! #
! subdirs="util include lib $krb524 kdc kadmin slave replication clients appl tests config-files gen-manpages"
  
  ALL_RECURSE="all-recurse"
  CLEAN_RECURSE="clean-recurse"
***************
*** 1895,1901 ****
      esac
    done
  
!   for ac_config_dir in util include lib $krb524 kdc kadmin slave clients appl tests config-files gen-manpages; do
  
      # Do not complain, so a configure script can configure whichever
      # parts of a large source tree are present.
--- 1899,1909 ----
      esac
    done
  
! #
! # UMICH MOD:
! # 	Add replication to list of subdirs
! #
!   for ac_config_dir in util include lib $krb524 kdc kadmin slave replication clients appl tests config-files gen-manpages; do
  
      # Do not complain, so a configure script can configure whichever
      # parts of a large source tree are present.
Index: krb5-1.0.5UM/src/configure.in
diff -c krb5-1.0.5UM/src/configure.in:1.1.1.1 krb5-1.0.5UM/src/configure.in:1.2
*** krb5-1.0.5UM/src/configure.in:1.1.1.1	Fri Apr 24 09:47:21 1998
--- krb5-1.0.5UM/src/configure.in	Mon Apr 27 05:34:05 1998
***************
*** 252,258 ****
  krb524=krb524
  fi
  dnl
! CONFIG_DIRS(util include lib $krb524 kdc kadmin slave clients appl tests config-files gen-manpages)
  dnl $kadminv4 removed from the above
  DO_SUBDIRS
  dnl AC_OUTPUT(Makefile,[EXTRA_RULES])
--- 252,258 ----
  krb524=krb524
  fi
  dnl
! CONFIG_DIRS(util include lib $krb524 kdc kadmin slave replication clients appl tests config-files gen-manpages)
  dnl $kadminv4 removed from the above
  DO_SUBDIRS
  dnl AC_OUTPUT(Makefile,[EXTRA_RULES])
Index: krb5-1.0.5UM/src/include/krb5/stock/osconf.h
diff -c krb5-1.0.5UM/src/include/krb5/stock/osconf.h:1.1.1.1 krb5-1.0.5UM/src/include/krb5/stock/osconf.h:1.2
*** krb5-1.0.5UM/src/include/krb5/stock/osconf.h:1.1.1.1	Fri Apr 24 09:49:05 1998
--- krb5-1.0.5UM/src/include/krb5/stock/osconf.h	Mon Apr 27 05:38:26 1998
***************
*** 111,114 ****
--- 111,126 ----
  #define KPROPD_DEFAULT_KRB_DB DEFAULT_KDB_FILE
  #define KPROPD_ACL_FILE "@LOCALSTATEDIR/krb5kdc/kpropd.acl"
  
+ #if defined(UMICH_REPLICATION)
+ /*
+  * krb5 incremental replication support follows
+  */
+ 
+ #define KREP_DEFAULT_FILE "@LOCALSTATEDIR/krb5kdc/master_delta"
+ #define KREPD_DEFAULT_FILE "@LOCALSTATEDIR/krb5kdc/slave_delta"
+ #define KREPD_ACL_FILE "@LOCALSTATEDIR/krb5kdc/kpropd.acl"
+ #define KREPD_DEFAULT_KRB_DB DEFAULT_KDB_FILE
+ 
+ #endif        /* UMICH_REPLICATION */
+ 
  #endif /* KRB5_OSCONF__ */
Index: krb5-1.0.5UM/src/lib/kadm5/srv/Makefile.in
diff -c krb5-1.0.5UM/src/lib/kadm5/srv/Makefile.in:1.1.1.1 krb5-1.0.5UM/src/lib/kadm5/srv/Makefile.in:1.4
*** krb5-1.0.5UM/src/lib/kadm5/srv/Makefile.in:1.1.1.1	Fri Apr 24 09:50:11 1998
--- krb5-1.0.5UM/src/lib/kadm5/srv/Makefile.in	Mon Dec  7 17:39:39 1998
***************
*** 7,12 ****
--- 7,16 ----
  	$(CC) $(CFLAGS) -c $(srcdir)/$*.c
  @SHARED_RULE@
  
+ #
+ # UMICH MOD:
+ #    Add krep_dump to list of sources
+ #
  SRCS =	$(srcdir)/svr_policy.c \
  	$(srcdir)/svr_principal.c \
  	$(srcdir)/server_acl.c \
***************
*** 19,26 ****
  	$(srcdir)/adb_xdr.c \
  	$(srcdir)/adb_policy.c \
  	$(srcdir)/adb_free.c \
! 	$(srcdir)/adb_openclose.c
  
  OBJS =	svr_policy.$(OBJEXT) \
  	svr_principal.$(OBJEXT) \
  	server_acl.$(OBJEXT) \
--- 23,37 ----
  	$(srcdir)/adb_xdr.c \
  	$(srcdir)/adb_policy.c \
  	$(srcdir)/adb_free.c \
! 	$(srcdir)/adb_openclose.c \
! 	$(srcdir)/krep_dump.c
  
+ #
+ # UMICH MOD:
+ #    Add krep_dump to list of objects
+ #
  OBJS =	svr_policy.$(OBJEXT) \
  	svr_principal.$(OBJEXT) \
  	server_acl.$(OBJEXT) \
***************
*** 33,39 ****
  	adb_xdr.$(OBJEXT) \
  	adb_policy.$(OBJEXT) \
  	adb_free.$(OBJEXT) \
! 	adb_openclose.$(OBJEXT)
  
  LIBUPDATE=$(BUILDTOP)/util/libupdate
  
--- 44,53 ----
  	adb_xdr.$(OBJEXT) \
  	adb_policy.$(OBJEXT) \
  	adb_free.$(OBJEXT) \
! 	adb_openclose.$(OBJEXT) \
! 	krep_dump.$(OBJEXT)
  
  LIBUPDATE=$(BUILDTOP)/util/libupdate
  
Index: krb5-1.0.5UM/src/lib/kadm5/srv/krep_dump.c
diff -c /dev/null krb5-1.0.5UM/src/lib/kadm5/srv/krep_dump.c:1.6
*** /dev/null	Thu Sep 16 18:06:28 1999
--- krb5-1.0.5UM/src/lib/kadm5/srv/krep_dump.c	Tue Jan  5 15:42:56 1999
***************
*** 0 ****
--- 1,1374 ----
+ /*
+  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+  * All Rights Reserved.
+  *
+  * Export of this software from the United States of America may
+  *   require a specific license from the United States Government.
+  *   It is the responsibility of any person or organization contemplating
+  *   export to obtain such a license before exporting.
+  * 
+  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+  * distribute this software and its documentation for any purpose and
+  * without fee is hereby granted, provided that the above copyright
+  * notice appear in all copies and that both that copyright notice and
+  * this permission notice appear in supporting documentation, and that
+  * the name of M.I.T. not be used in advertising or publicity pertaining
+  * to distribution of the software without specific, written prior
+  * permission.  M.I.T. makes no representations about the suitability of
+  * this software for any purpose.  It is provided "as is" without express
+  * or implied warranty.
+  * 
+  *
+  * Dump/restore entries within a KDC database
+  * 
+  * This module started as a copy of kadmin/dbutil/dump.c
+  *
+  * All fprintf(stderr, ...); messages are changed to com_err(....);
+  * to avoid problems when krepd is run under inetd.
+  * 
+  */
+ 
+ #if defined(UMICH_REPLICATION)	/* Entire module */
+ 
+ #include <stdio.h>
+ #include <k5-int.h>
+ #include <kadm5/admin.h>
+ #include <kadm5/adb.h>
+ #include <com_err.h>
+ /*				#include "kdb5_util.h"			*/
+ 
+ #if	HAVE_REGEX_H
+ #include <regex.h>
+ #endif	/* HAVE_REGEX_H */
+ 
+ #if defined(UMICH_REPLICATION)
+ #include <regex.h>
+ #include "krep_dump.h"
+ #endif	/* UMICH_REPLICATION */
+ /*
+  * Use compile(3) if no regcomp present.
+  */
+ #if	!defined(HAVE_REGCOMP) && defined(HAVE_REGEXP_H)
+ #define	INIT		char *sp = instring;
+ #define	GETC()		(*sp++)
+ #define	PEEKC()		(*sp)
+ #define	UNGETC(c)	(--sp)
+ #define	RETURN(c)	return(c)
+ #define	ERROR(c)	
+ #define	RE_BUF_SIZE	1024
+ #include <regexp.h>
+ #endif	/* !HAVE_REGCOMP && HAVE_REGEXP_H */
+ 
+ struct dump_args {
+ 	char		*programname;
+ 	FILE		*ofile;
+ 	krb5_context	kcontext;
+ 	char		**names;
+ 	int			nnames;
+ 	int			verbose;
+ };
+ 
+ typedef krb5_error_code (*dump_func)PROTOTYPE((krb5_pointer,
+ 						   krb5_db_entry *));
+ 
+ typedef krb5_error_code (*load_func)PROTOTYPE((char *, krb5_context,
+ 						   FILE *, int, int *, void *));
+ int process_umichrep_record PROTOTYPE((char *, krb5_context, FILE *,
+ 					  int, int *, void *));
+ 
+ typedef struct _dump_version {
+ 	 char *name;
+ 	 char *header;
+ 	 int updateonly;
+ 	 int create_kadm5;
+ 	 dump_func dump_princ;
+ 	 osa_adb_iter_policy_func dump_policy;
+ 	 load_func load_record;
+ } dump_version;
+ 
+ dump_version umichrep_version_1 = {
+ 	 "Kerberos version 5",
+ 	 "Replication version 1.0\n",
+ 	 0,
+ 	 0,
+ 	 krb5_umichrep_princ,
+ 	 krb5_umichrep_policy,
+ 	 process_umichrep_record,
+ };
+ 
+ struct dump_args rep_args;
+ krb5_context umichrep_context;
+ 
+ 
+ /* External data */
+ extern char		*current_dbname;
+ extern krb5_boolean	dbactive;
+ extern int		exit_status;
+ extern krb5_context	util_context;
+ extern kadm5_config_params global_params;
+ 
+ /* Strings */
+ 
+ /* These aren't used, otherwise the k5beta7 one is incorrect!!! KWC */
+ static const char k5beta_dump_header[] = "kdb5_edit load_dump version 2.0\n";
+ static const char k5beta6_dump_header[] = "kdb5_edit load_dump version 3.0\n";
+ static const char k5beta7_dump_header[] = "kdb5_edit load_dump version 4\n";
+ 
+ static const char null_mprinc_name[] = "kdb5_dump@MISSING";
+ 
+ /* Message strings */
+ static const char regex_err[] = "%s: regular expression error - %s\n";
+ static const char regex_merr[] = "%s: regular expression match error - %s\n";
+ static const char pname_unp_err[] = "%s: cannot unparse principal name (%s)\n";
+ static const char mname_unp_err[] = "%s: cannot unparse modifier name (%s)\n";
+ static const char nokeys_err[] = "%s: cannot find any standard key for %s\n";
+ static const char sdump_tl_inc_err[] = "%s: tagged data list inconsistency for %s (counted %d, stored %d)\n";
+ static const char stand_fmt_name[] = "Kerberos version 5";
+ static const char old_fmt_name[] = "Kerberos version 5 old format";
+ static const char b6_fmt_name[] = "Kerberos version 5 beta 6 format";
+ static const char ofopen_error[] = "%s: cannot open %s for writing (%s)\n";
+ static const char oflock_error[] = "%s: cannot lock %s (%s)\n";
+ static const char dumprec_err[] = "%s: error performing %s dump (%s)\n";
+ static const char dumphdr_err[] = "%s: error dumping %s header (%s)\n";
+ static const char trash_end_fmt[] = "%s(%d): ignoring trash at end of line: ";
+ static const char read_name_string[] = "name string";
+ static const char read_key_type[] = "key type";
+ static const char read_key_data[] = "key data";
+ static const char read_pr_data1[] = "first set of principal attributes";
+ static const char read_mod_name[] = "modifier name";
+ static const char read_pr_data2[] = "second set of principal attributes";
+ static const char read_salt_data[] = "salt data";
+ static const char read_akey_type[] = "alternate key type";
+ static const char read_akey_data[] = "alternate key data";
+ static const char read_asalt_type[] = "alternate salt type";
+ static const char read_asalt_data[] = "alternate salt data";
+ static const char read_exp_data[] = "expansion data";
+ static const char store_err_fmt[] = "%s(%d): cannot store %s(%s)\n";
+ static const char add_princ_fmt[] = "%s\n";
+ static const char parse_err_fmt[] = "%s(%d): cannot parse %s (%s)\n";
+ static const char read_err_fmt[] = "%s(%d): cannot read %s\n";
+ static const char no_mem_fmt[] = "%s(%d): no memory for buffers\n";
+ static const char rhead_err_fmt[] = "%s(%d): cannot match size tokens\n";
+ static const char err_line_fmt[] = "%s: error processing line %d of %s\n";
+ static const char head_bad_fmt[] = "%s: dump header bad in %s\n";
+ static const char read_bytecnt[] = "record byte count";
+ static const char read_encdata[] = "encoded data";
+ static const char n_name_unp_fmt[] = "%s(%s): cannot unparse name\n";
+ static const char n_dec_cont_fmt[] = "%s(%s): cannot decode contents\n";
+ static const char read_nint_data[] = "principal static attributes";
+ static const char read_tcontents[] = "tagged data contents";
+ static const char read_ttypelen[] = "tagged data type and length";
+ static const char read_kcontents[] = "key data contents";
+ static const char read_ktypelen[] = "key data type and length";
+ static const char read_econtents[] = "extra data contents";
+ static const char k5beta_fmt_name[] = "Kerberos version 5 old format";
+ static const char standard_fmt_name[] = "Kerberos version 5 format";
+ static const char no_name_mem_fmt[] = "%s: cannot get memory for temporary name\n";
+ static const char ctx_err_fmt[] = "%s: cannot initialize Kerberos context\n";
+ static const char stdin_name[] = "standard input";
+ static const char restfail_fmt[] = "%s: %s restore failed\n";
+ static const char close_err_fmt[] = "%s: cannot close database (%s)\n";
+ static const char dbinit_err_fmt[] = "%s: cannot initialize database (%s)\n";
+ static const char dblock_err_fmt[] = "%s: cannot initialize database lock (%s)\n";
+ static const char dbname_err_fmt[] = "%s: cannot set database name to %s (%s)\n";
+ static const char dbdelerr_fmt[] = "%s: cannot delete bad database %s (%s)\n";
+ static const char dbunlockerr_fmt[] = "%s: cannot unlock database %s (%s)\n";
+ static const char dbrenerr_fmt[] = "%s: cannot rename database %s to %s (%s)\n";
+ static const char dbcreaterr_fmt[] = "%s: cannot create database %s (%s)\n";
+ static const char dfile_err_fmt[] = "%s: cannot open %s (%s)\n";
+ 
+ static const char delete_princ_fmt[] = "deleting %s\n";
+ static const char delete_err_fmt[] = "%s(%d): cannot delete %s(%s)\n";
+ static const char delete_policy_fmt[] = "deleting policy %s\n";
+ 
+ static const char oldoption[] = "-old";
+ static const char b6option[] = "-b6";
+ static const char verboseoption[] = "-verbose";
+ static const char updateoption[] = "-update";
+ static const char ovoption[] = "-ov";
+ static const char dump_tmptrail[] = "~";
+ 
+ /*
+  * name_matches()	- See if a principal name matches a regular expression
+  *			  or string.
+  */
+ static int
+ name_matches(name, arglist)
+ 	char		*name;
+ 	struct dump_args	*arglist;
+ {
+ #if	HAVE_REGCOMP
+ 	regex_t	match_exp;
+ 	regmatch_t	match_match;
+ 	int		match_error;
+ 	char	match_errmsg[BUFSIZ];
+ 	size_t	errmsg_size;
+ #elif	HAVE_REGEXP_H
+ 	char	regexp_buffer[RE_BUF_SIZE];
+ #elif	HAVE_RE_COMP
+ 	extern char	*re_comp();
+ 	char	*re_result;
+ #endif	/* HAVE_RE_COMP */
+ 	int		i, match;
+ 
+ 	/*
+ 	 * Plow, brute force, through the list of names/regular expressions.
+ 	 */
+ 	match = (arglist->nnames) ? 0 : 1;
+ 	for (i=0; i<arglist->nnames; i++) {
+ #if	HAVE_REGCOMP
+ 	/*
+ 	 * Compile the regular expression.
+ 	 */
+ 	if (match_error = regcomp(&match_exp,
+ 				  arglist->names[i],
+ 				  REG_EXTENDED)) {
+ 		errmsg_size = regerror(match_error,
+ 				   &match_exp,
+ 				   match_errmsg,
+ 				   sizeof(match_errmsg));
+ 		com_err(arglist->programname, 0,
+ 				regex_err, arglist->programname, match_errmsg);
+ 		break;
+ 	}
+ 	/*
+ 	 * See if we have a match.
+ 	 */
+ 	if (match_error = regexec(&match_exp, name, 1, &match_match, 0)) {
+ 		if (match_error != REG_NOMATCH) {
+ 			errmsg_size = regerror(match_error,
+ 						   &match_exp,
+ 						   match_errmsg,
+ 						   sizeof(match_errmsg));
+ 			com_err(arglist->programname, 0, regex_merr,
+ 				arglist->programname, match_errmsg);
+ 			break;
+ 		}
+ 	}
+ 	else {
+ 		/*
+ 		 * We have a match.  See if it matches the whole
+ 		 * name.
+ 		 */
+ 		if ((match_match.rm_so == 0) &&
+ 						(match_match.rm_eo == strlen(name)))
+ 			match = 1;
+ 	}
+ 	regfree(&match_exp);
+ #elif	HAVE_REGEXP_H
+ 	/*
+ 	 * Compile the regular expression.
+ 	 */
+ 	compile(arglist->names[i],
+ 		regexp_buffer, 
+ 		&regexp_buffer[RE_BUF_SIZE],
+ 		'\0');
+ 	if (step(name, regexp_buffer)) {
+ 		if ((loc1 == name) &&
+ 		(loc2 == &name[strlen(name)]))
+ 		match = 1;
+ 	}
+ #elif	HAVE_RE_COMP
+ 	/*
+ 	 * Compile the regular expression.
+ 	 */
+ 	if (re_result = re_comp(arglist->names[i])) {
+ 		com_err(arglist->programname, 0,
+ 				regex_err, arglist->programname, re_result);
+ 		break;
+ 	}
+ 	if (re_exec(name))
+ 		match = 1;
+ #else	/* HAVE_RE_COMP */
+ 	/*
+ 	 * If no regular expression support, then just compare the strings.
+ 	 */
+ 	if (!strcmp(arglist->names[i], name))
+ 		match = 1;
+ #endif	/* HAVE_REGCOMP */
+ 	if (match)
+ 		break;
+ 	}
+ 	return(match);
+ }
+ 
+ /*
+  * dump_umichrep_k5beta6_iterator()	- Output a dump record in krb5b6 format.
+  */
+ static krb5_error_code
+ dump_umichrep_k5beta6_iterator(ptr, entry)
+ 	krb5_pointer	ptr;
+ 	krb5_db_entry	*entry;
+ {
+ 	krb5_error_code	retval;
+ 	struct dump_args	*arg;
+ 	char		*name;
+ 	krb5_tl_data	*tlp;
+ 	krb5_key_data	*kdata;
+ 	int			counter, i, j;
+ 
+ 	/* Initialize */
+ 	arg = (struct dump_args *) ptr;
+ 	name = (char *) NULL;
+ 
+ 	/*
+ 	 * Flatten the principal name.
+ 	 */
+ 	if ((retval = krb5_unparse_name(arg->kcontext,
+ 					entry->princ,
+ 					&name))) {
+ 		com_err("krep", 0, pname_unp_err, 
+ 			arg->programname, error_message(retval));
+ 		return(retval);
+ 	}
+ 	/*
+ 	 * If we don't have any match strings, or if our name matches, then
+ 	 * proceed with the dump, otherwise, just forget about it.
+ 	 */
+ 	if (!arg->nnames || name_matches(name, arg)) {
+ 		/*
+ 		 * We'd like to just blast out the contents as they would appear in
+ 		 * the database so that we can just suck it back in, but it doesn't
+ 		 * lend itself to easy editing.
+ 		 */
+ 
+ 		/*
+ 		 * The dump format is as follows:
+ 		 *	len strlen(name) n_tl_data n_key_data e_length
+ 		 *	name
+ 		 *	attributes max_life max_renewable_life expiration
+ 		 *	pw_expiration last_success last_failed fail_auth_count
+ 		 *	n_tl_data*[type length <contents>]
+ 		 *	n_key_data*[ver kvno ver*(type length <contents>)]
+ 		 *	<e_data>
+ 		 * Fields which are not encapsulated by angle-brackets are to appear
+ 		 * verbatim.  Bracketed fields absence is indicated by a -1 in its
+ 		 * place
+ 		 */
+ 
+ 		/*
+ 		 * Make sure that the tagged list is reasonably correct.
+ 		 */
+ 		counter = 0;
+ 		for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
+ 			counter++;
+ 		}
+ 	
+ 		if (counter == entry->n_tl_data) {
+ 			/* Pound out header */
+ 			fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
+ 				(int) entry->len,
+ 				strlen(name),
+ 				counter,
+ 				(int) entry->n_key_data,
+ 				(int) entry->e_length,
+ 				name);
+ 			fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
+ 				entry->attributes,
+ 				entry->max_life,
+ 				entry->max_renewable_life,
+ 				entry->expiration,
+ 				entry->pw_expiration,
+ 				entry->last_success,
+ 				entry->last_failed,
+ 				entry->fail_auth_count);
+ 			/* Pound out tagged data. */
+ 			for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
+ /*DBG			com_err("krep debug dump", 0, "Pounding out %d bytes for data type %d",
+ 					tlp->tl_data_length, tlp->tl_data_type); */
+ 				fprintf(arg->ofile, "%d\t%d\t",
+ 					(int) tlp->tl_data_type,
+ 					(int) tlp->tl_data_length);
+ 				if (tlp->tl_data_length)
+ 					for (i=0; i<tlp->tl_data_length; i++)
+ 						fprintf(arg->ofile, "%02x", tlp->tl_data_contents[i]);
+ 				else
+ 					fprintf(arg->ofile, "%d", -1);
+ 				fprintf(arg->ofile, "\t");
+ 			}
+ 
+ 			/* Pound out key data */
+ 			for (counter=0; counter<entry->n_key_data; counter++) {
+ 				kdata = &entry->key_data[counter];
+ 				fprintf(arg->ofile, "%d\t%d\t",
+ 					(int) kdata->key_data_ver,
+ 					(int) kdata->key_data_kvno);
+ 				for (i=0; i<kdata->key_data_ver; i++) {
+ 					fprintf(arg->ofile, "%d\t%d\t",
+ 						kdata->key_data_type[i],
+ 						kdata->key_data_length[i]);
+ 					if (kdata->key_data_length[i])
+ 						for (j=0; j<kdata->key_data_length[i]; j++)
+ 							fprintf(arg->ofile, "%02x",
+ 								kdata->key_data_contents[i][j]);
+ 					else
+ 						fprintf(arg->ofile, "%d", -1);
+ 					fprintf(arg->ofile, "\t");
+ 				}
+ 			}
+ 
+ 			/* Pound out extra data */
+ 			if (entry->e_length)
+ 				for (i=0; i<entry->e_length; i++)
+ 					fprintf(arg->ofile, "%02x", entry->e_data[i]);
+ 			else
+ 				fprintf(arg->ofile, "%d", -1);
+ 
+ 			/* Print trailer */
+ 			fprintf(arg->ofile, ";\n");
+ 
+ 			if (arg->verbose)
+ 				com_err(arg->programname, 0, "%s\n", name);
+ 		}
+ 		else {
+ 			com_err(arg->programname, 0, sdump_tl_inc_err,
+ 				arg->programname, name, counter, (int) entry->n_tl_data); 
+ 			retval = EINVAL;
+ 		}
+ 	}
+ 	krb5_xfree(name);
+ 	return(retval);
+ }
+ 
+ /*
+  * dump_umichrep_k5beta7_iterator()	- Output a dump record in krb5b7 format.
+  */
+ static krb5_error_code
+ dump_umichrep_k5beta7_princ(ptr, entry)
+ 	krb5_pointer	ptr;
+ 	krb5_db_entry	*entry;
+ {
+ 	krb5_error_code retval;
+ 	struct dump_args *arg;
+ 	char *name;
+ 	int tmp_nnames;
+ 
+ 	/* Initialize */
+ 	arg = (struct dump_args *) ptr;
+ 	name = (char *) NULL;
+ 
+ 	/*
+ 	 * Flatten the principal name.
+ 	 */
+ 	if ((retval = krb5_unparse_name(arg->kcontext,
+ 					 entry->princ,
+ 					 &name))) {
+ 		com_err(arg->programname, 0, pname_unp_err, 
+ 				arg->programname, error_message(retval));
+ 		return(retval);
+ 	}
+ 	/*
+ 	 * If we don't have any match strings, or if our name matches, then
+ 	 * proceed with the dump, otherwise, just forget about it.
+ 	 */
+ 	if (!arg->nnames || name_matches(name, arg)) {
+ 	 	fprintf(arg->ofile, "princ\t");
+ 	  
+ 		/* save the callee from matching the name again */
+ 		tmp_nnames = arg->nnames;
+ 		arg->nnames = 0;
+ 		retval = dump_umichrep_k5beta6_iterator(ptr, entry);
+ 		arg->nnames = tmp_nnames;
+ 	}
+ 
+ 	free(name);
+ 	return retval;
+ }
+ 
+ void dump_umichrep_k5beta7_policy(void *data, osa_policy_ent_t entry)
+ {
+ 	struct dump_args *arg;
+ 
+ 	arg = (struct dump_args *) data;
+ 	fprintf(arg->ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n", entry->name,
+ 			entry->pw_min_life, entry->pw_max_life, entry->pw_min_length,
+ 			entry->pw_min_classes, entry->pw_history_num,
+ 			entry->policy_refcnt);
+ }
+ 
+ #if defined(UMICH_REPLICATION)
+ 
+ /*
+  * dump_umichrep_delprinc()	- Output a dump record to delete a principal.
+  */
+ static krb5_error_code
+ dump_umichrep_delprinc(ptr, princ)
+ 	krb5_pointer		ptr;
+ 	krb5_principal	princ;
+ {
+ 	krb5_error_code retval;
+ 	struct dump_args *arg;
+ 	char *name;
+ 
+ 	/* Initialize */
+ 	arg = (struct dump_args *) ptr;
+ 	name = (char *) NULL;
+ 
+ 	/*
+ 	 * Flatten the principal name.
+ 	 */
+ 	if ((retval = krb5_unparse_name(arg->kcontext,
+ 									princ,
+ 									&name))) {
+ 		com_err(arg->programname, 0, pname_unp_err, 
+ 				arg->programname, error_message(retval));
+ 		return(retval);
+ 	}
+ 
+ 	fprintf(arg->ofile, "%d\t%s", strlen(name), name);
+ 
+ 	/* Print trailer */
+ 	fprintf(arg->ofile, ";\n");
+ 
+ 	if (arg->verbose)
+ 		com_err(arg->programname, 0, "deleting %s\n", name);
+ 
+ 	free(name);
+ 	return retval;
+ }
+ 
+ /*
+  * dump_umichrep_delpolicy()	- Output a dump record to delete a policy.
+  */
+ static krb5_error_code
+ dump_umichrep_delpolicy(ptr, policyName)
+ 	krb5_pointer		ptr;
+ 	kadm5_policy_t	policyName;
+ {
+ 	krb5_error_code retval = 0;
+ 	struct dump_args *arg;
+ 
+ 	/* Initialize */
+ 	arg = (struct dump_args *) ptr;
+ 
+ 	fprintf(arg->ofile, "%d\t%s", strlen(policyName), policyName);
+ 
+ 	/* Print trailer */
+ 	fprintf(arg->ofile, ";\n");
+ 
+ 	if (arg->verbose)
+ 		com_err(arg->programname, 0, "deleting policy %s\n", policyName);
+ 
+ 	return retval;
+ }
+ 
+ /*
+  * krb5_umichrep_princ() - Output a dump record to add/modify a principal.
+  */
+ krb5_error_code
+ krb5_umichrep_princ(entry)
+ 	krb5_db_entry	   *entry;
+ {
+ 	krb5_error_code retval = 0;
+ 	krb5_error_code lockval;
+ 
+ 	/* Get an exclusive lock on the file so it is not truncated on us */
+ 	if ((lockval = krb5_lock_file(umichrep_context,
+ 				fileno(rep_args.ofile),
+ 				KRB5_LOCKMODE_EXCLUSIVE)) == 0)
+ 	{
+ 
+ 		/* Go to the end of the file - it may have been truncated... */
+ 		fseek(rep_args.ofile, 0, SEEK_END);
+ 
+ 		fprintf(rep_args.ofile, "princ\t");
+ 		retval = dump_umichrep_k5beta6_iterator(&rep_args, entry);
+ 
+ 		/* flush our changes */
+ 		fflush(rep_args.ofile);
+ 
+ 		/* Release the lock on the file */
+ 		if (lockval = krb5_lock_file(umichrep_context,
+ 					fileno(rep_args.ofile),
+ 					KRB5_LOCKMODE_UNLOCK)) {
+ 			com_err(rep_args.programname, errno,
+ 					"unlocking replication delta file in krb5_umichrep_princ()\n");
+ 		}
+ 	}
+ 	else 
+ 	{
+ 		retval = -1;
+ 		com_err(rep_args.programname, errno,
+ 				"locking replication delta file in krb5_umichrep_princ()\n");
+ 	}
+ 	return retval;
+ }
+ 
+ /*
+  * krb5_umichrep_policy() - Output a dump record to add/modify a policy.
+  */
+ krb5_error_code
+ krb5_umichrep_policy(osa_policy_ent_t entry)
+ {
+ 	krb5_error_code retval = 0;
+ 	krb5_error_code lockval;
+ 
+ 	/* Get an exclusive lock on the file so it is not truncated on us */
+ 	if ((lockval = krb5_lock_file(umichrep_context,
+ 				fileno(rep_args.ofile),
+ 				KRB5_LOCKMODE_EXCLUSIVE)) == 0)
+ 	{
+ 		/* Go to the end of the file - it may have been truncated... */
+ 		fseek(rep_args.ofile, 0, SEEK_END);
+ 
+ 		fprintf(rep_args.ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n",
+ 			entry->name,
+ 			entry->pw_min_life, entry->pw_max_life, entry->pw_min_length,
+ 			entry->pw_min_classes, entry->pw_history_num,
+ 			entry->policy_refcnt);
+ 
+ 		/* flush our changes */
+ 		fflush(rep_args.ofile);
+ 
+ 		/* Release the lock on the file */
+ 		if (lockval = krb5_lock_file(umichrep_context,
+ 					fileno(rep_args.ofile),
+ 					KRB5_LOCKMODE_UNLOCK)) {
+ 			com_err(rep_args.programname, errno,
+ 					"unlocking replication delta file in krb5_umichrep_policy()\n");
+ 		}
+ 	}
+ 	else
+ 	{
+ 		retval = -1;
+ 		com_err(rep_args.programname, errno,
+ 				"locking replication delta file in krb5_umichrep_policy()\n");
+ 	}
+ 	return retval;
+ }
+ 
+ /*
+  * krb5_umichrep_delprinc() - Output a dump recode to delete principal.
+  */
+ krb5_error_code
+ krb5_umichrep_delprinc(princ)
+ 	krb5_principal	  princ;
+ {
+ 	krb5_error_code retval = 0;
+ 	krb5_error_code lockval;
+ 
+ 	/* Get an exclusive lock on the file so it is not truncated on us */
+ 	if ((lockval = krb5_lock_file(umichrep_context,
+ 				fileno(rep_args.ofile),
+ 				KRB5_LOCKMODE_EXCLUSIVE)) == 0)
+ 	{
+ 		/* Go to the end of the file - it may have been truncated... */
+ 		fseek(rep_args.ofile, 0, SEEK_END);
+ 
+ 		/* Write the record */
+ 		fprintf(rep_args.ofile, "delprinc\t");
+ 		retval = dump_umichrep_delprinc(&rep_args, princ);
+ 
+ 		/* flush our changes */
+ 		fflush(rep_args.ofile);
+ 
+ 		/* Release the lock on the file */
+ 		if (lockval = krb5_lock_file(umichrep_context,
+ 					fileno(rep_args.ofile),
+ 					KRB5_LOCKMODE_UNLOCK)) {
+ 			com_err(rep_args.programname, errno,
+ 					"unlocking replication delta file in krb5_umichrep_delprinc()\n");
+ 		}
+ 	}
+ 	else
+ 	{
+ 		retval = -1;
+ 		com_err(rep_args.programname, errno,
+ 				"locking replication delta file in krb5_umichrep_delprinc()\n");
+ 	}
+ 	return retval;
+ }
+ 
+ /*
+  * krb5_umichrep_delpolicy() - Output a dump record to delete a policy.
+  */
+ krb5_error_code
+ krb5_umichrep_delpolicy(policyName)
+ 	kadm5_policy_t	  policyName;
+ {
+ 	krb5_error_code retval = 0;
+ 	krb5_error_code lockval;
+ 
+ 	/* Get an exclusive lock on the file so it is not truncated on us */
+ 	if ((lockval = krb5_lock_file(umichrep_context,
+ 				fileno(rep_args.ofile),
+ 				KRB5_LOCKMODE_EXCLUSIVE)) == 0)
+ 	{
+ 		/* Go to the end of the file - it may have been truncated... */
+ 		fseek(rep_args.ofile, 0, SEEK_END);
+ 
+ 		/* Write the record */
+ 		fprintf(rep_args.ofile, "delpolicy\t");
+ 		retval = dump_umichrep_delpolicy(&rep_args, policyName);
+ 
+ 		/* flush our changes */
+ 		fflush(rep_args.ofile);
+ 
+ 		/* Release the lock on the file */
+ 		if (lockval = krb5_lock_file(umichrep_context,
+ 					fileno(rep_args.ofile),
+ 					KRB5_LOCKMODE_UNLOCK)) {
+ 			com_err(rep_args.programname, errno,
+ 					"unlocking replication delta file in krb5_umichrep_delpolicy()\n");
+ 		}
+ 	}
+ 	else
+ 	{
+ 		retval = -1;
+ 		com_err(rep_args.programname, errno,
+ 				"locking replication delta file in krb5_umichrep_delpolicy()\n");
+ 	}
+ 	return retval;
+ }
+ 
+ /*
+  * krb5_umichrep_init()	  - Initialize rep_args
+  */
+ krb5_error_code
+ krb5_umichrep_init(char *programname, char *replfile)
+ {
+ 	krb5_error_code retval, kret;
+ 	FILE * f;
+ 
+ 	retval = krb5_init_context(&umichrep_context);
+ 	if (retval) {
+ 		com_err(programname, retval,
+ 				"from krb5_init_context() in krb5_umichrep_init\n");
+ 		return retval;
+ 	}
+ 
+ 	/* Init rep_args struct, open replication file, etc. */
+ 
+ 	rep_args.programname = (char *) malloc(strlen(programname) + 1);
+ 	if (!rep_args.programname) {
+ 		com_err(programname, 0, "Error allocating %d bytes for programname\n",
+ 				strlen(programname)+1);
+ 		retval++;
+ 		return retval;
+ 	}
+ 	strcpy(rep_args.programname, programname);
+ 
+ 	/*
+ 	 * Open the replication file
+ 	 */
+ 	if (!replfile) replfile = strdup(KREP_DEFAULT_FILE);
+ 
+ 	if ((f = fopen(replfile, "a+")) == NULL) {
+ 		com_err(programname, errno, dfile_err_fmt, programname, replfile,
+ 			error_message(errno)); 
+ 		retval++;
+ 		return retval;
+ 	}
+ 	rep_args.ofile = f;
+ 	rep_args.kcontext = umichrep_context;
+ 	rep_args.names = NULL;
+ 	rep_args.nnames = 0;
+ 	rep_args.verbose = 0;
+ 
+ 	return 0;
+ }
+ 
+ #endif	/* UMICH_REPLICATION */
+ 
+ 
+ /*
+  * Read a string of bytes while counting the number of lines passed.
+  */
+ static int
+ read_string(f, buf, len, lp)
+ 	FILE	*f;
+ 	char	*buf;
+ 	int		len;
+ 	int		*lp;
+ {
+ 	int c;
+ 	int i, retval;
+ 
+ 	retval = 0;
+ 	for (i=0; i<len; i++) {
+ 		c = fgetc(f);
+ 		if (c < 0) {
+ 			retval = 1;
+ 			break;
+ 		}
+ 		if (c == '\n')
+ 			(*lp)++;
+ 		buf[i] = (char) c;
+ 	}
+ 	buf[len] = '\0';
+ 	return(retval);
+ }
+ 
+ /*
+  * Read a string of two character representations of bytes.
+  */
+ static int
+ read_octet_string(f, buf, len)
+ 	FILE	*f;
+ 	krb5_octet	*buf;
+ 	int		len;
+ {
+ 	int c;
+ 	int i, retval;
+ 
+ 	retval = 0;
+ 	for (i=0; i<len; i++) {
+ 		if (fscanf(f, "%02x", &c) != 1) {
+ 			retval = 1;
+ 			break;
+ 		}
+ 		buf[i] = (krb5_octet) c;
+ 	}
+ 	return(retval);
+ }
+ 
+ /*
+  * Find the end of an old format record.
+  */
+ static void
+ find_record_end(f, fn, lineno)
+ 	FILE	*f;
+ 	char	*fn;
+ 	int		lineno;
+ {
+ 	int	ch;
+ 
+ 	if (((ch = fgetc(f)) != ';') || ((ch = fgetc(f)) != '\n')) {
+ 		com_err("krepd", 0, trash_end_fmt, fn, lineno);
+ 		while (ch != '\n') {
+ 			ch = fgetc(f);
+ 		}
+ 	}
+ }
+ 
+ 
+ /*
+  * process_umichrep_k5beta6_record()	- Handle a dump record in krb5b6 format.
+  *
+  * Returns -1 for end of file, 0 for success and 1 for failure.
+  */
+ static int
+ process_umichrep_k5beta6_record(fname, kcontext, filep, verbose, linenop, pol_db)
+ 	char		*fname;
+ 	krb5_context	kcontext;
+ 	FILE		*filep;
+ 	int			verbose;
+ 	int			*linenop;
+ 	void *pol_db;
+ {
+ 	int			retval;
+ 	krb5_db_entry	dbentry;
+ 	krb5_int32		t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ 	int			nread;
+ 	int			error;
+ 	int			i, j, one;
+ 	char		*name;
+ 	krb5_key_data	*kp, *kdatap;
+ 	krb5_tl_data	**tlp, *tl;
+ 	krb5_octet 		*op;
+ 	krb5_error_code	kret;
+ 	const char		*try2read;
+ 
+ 	try2read = (char *) NULL;
+ 	memset((char *) &dbentry, 0, sizeof(dbentry));
+ 	(*linenop)++;
+ 	retval = 1;
+ 	name = (char *) NULL;
+ 	kp = (krb5_key_data *) NULL;
+ 	op = (krb5_octet *) NULL;
+ 	error = 0;
+ 	kret = 0;
+ 	nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t", &t1, &t2, &t3, &t4, &t5);
+ 	if (nread == 5) {
+ 		/* Get memory for flattened principal name */
+ 		if (!(name = (char *) malloc((size_t) t2 + 1)))
+ 			error++;
+ 
+ 		/* Get memory for and form tagged data linked list */
+ 		tlp = &dbentry.tl_data;
+ 		for (i=0; i<t3; i++) {
+ 			if ((*tlp = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
+ 				memset(*tlp, 0, sizeof(krb5_tl_data));
+ 				tlp = &((*tlp)->tl_data_next);
+ 				dbentry.n_tl_data++;
+ 			}
+ 			else {
+ 				error++;
+ 				break;
+ 			}
+ 		}
+ 
+ 		/* Get memory for key list */
+ 		if (t4 && !(kp = (krb5_key_data *) malloc((size_t)
+ 							  (t4*sizeof(krb5_key_data)))))
+ 			error++;
+ 
+ 		/* Get memory for extra data */
+ 		if (t5 && !(op = (krb5_octet *) malloc((size_t) t5)))
+ 			error++;
+ 
+ 		if (!error) {
+ 			dbentry.len = t1;
+ 			dbentry.n_key_data = t4;
+ 			dbentry.e_length = t5;
+ 			if (kp) {
+ 				memset(kp, 0, (size_t) (t4*sizeof(krb5_key_data)));
+ 				dbentry.key_data = kp;
+ 				kp = (krb5_key_data *) NULL;
+ 			}
+ 			if (op) {
+ 				memset(op, 0, (size_t) t5);
+ 				dbentry.e_data = op;
+ 				op = (krb5_octet *) NULL;
+ 			}
+ 
+ 			/* Read in and parse the principal name */
+ 			if (!read_string(filep, name, t2, linenop) &&
+ 				!(kret = krb5_parse_name(kcontext, name, &dbentry.princ))) {
+ 
+ 				/* Get the fixed principal attributes */
+ 				nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
+ 							   &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9);
+ 				if (nread == 8) {
+ 					dbentry.attributes = (krb5_flags) t2;
+ 					dbentry.max_life = (krb5_deltat) t3;
+ 					dbentry.max_renewable_life = (krb5_deltat) t4;
+ 					dbentry.expiration = (krb5_timestamp) t5;
+ 					dbentry.pw_expiration = (krb5_timestamp) t6;
+ 					dbentry.last_success = (krb5_timestamp) t7;
+ 					dbentry.last_failed = (krb5_timestamp) t8;
+ 					dbentry.fail_auth_count = (krb5_kvno) t9;
+ 				} else {
+ 					try2read = read_nint_data;
+ 					error++;
+ 				}
+ 
+ 				/*
+ 				 * Get the tagged data.
+ 				 *
+ 				 * Really, this code ought to discard tl data types
+ 				 * that it knows are special to the current version
+ 				 * and were not supported in the previous version.
+ 				 * But it's a pain to implement that here, and doing
+ 				 * it at dump time has almost as good an effect, so
+ 				 * that's what I did.  [krb5-admin/89/
+ 				 */
+ 				if (!error && dbentry.n_tl_data) {
+ 					for (tl = dbentry.tl_data; tl; tl = tl->tl_data_next) {
+ 						nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
+ 						if (nread == 2) {
+ 							tl->tl_data_type = (krb5_int16) t1;
+ 							tl->tl_data_length = (krb5_int16) t2;
+ /*DBG		com_err("krep debug restore", 0, "Reading %d bytes for data type %d",
+ 					tl->tl_data_length, tl->tl_data_type); */
+ 							if (tl->tl_data_length) {
+ 								if (!(tl->tl_data_contents =
+ 									  (krb5_octet *) malloc((size_t) t2+1)) ||
+ 									read_octet_string(filep,
+ 											  tl->tl_data_contents,
+ 											  t2)) {
+ 									try2read = read_tcontents;
+ 									error++;
+ 									break;
+ 								}
+ 							}
+ 							else {
+ 								/* Should be a null field */
+ 								nread = fscanf(filep, "%d", &t9);
+ 								if ((nread != 1) || (t9 != -1)) {
+ 									error++;
+ 									try2read = read_tcontents;
+ 									break;
+ 								}
+ 							}
+ 						}
+ 						else {
+ 							try2read = read_ttypelen;
+ 							error++;
+ 							break;
+ 						}
+ 					}
+ 				}
+ 	
+ 				/* Get the key data */
+ 				if (!error && dbentry.n_key_data) {
+ 					for (i=0; !error && (i<dbentry.n_key_data); i++) {
+ 						kdatap = &dbentry.key_data[i];
+ 						nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
+ 						if (nread == 2) {
+ 							kdatap->key_data_ver = (krb5_int16) t1;
+ 							kdatap->key_data_kvno = (krb5_int16) t2;
+ 	
+ 							for (j=0; j<t1; j++) {
+ 								nread = fscanf(filep, "%d\t%d\t", &t3, &t4);
+ 								if (nread == 2) {
+ 									kdatap->key_data_type[j] = t3;
+ 									kdatap->key_data_length[j] = t4;
+ 									if (t4) {
+ 										if (!(kdatap->key_data_contents[j] =
+ 											  (krb5_octet *)
+ 											  malloc((size_t) t4+1)) ||
+ 											read_octet_string(filep,
+ 													  kdatap->key_data_contents[j],
+ 													  t4)) {
+ 										try2read = read_kcontents;
+ 										error++;
+ 										break;
+ 										}
+ 									}
+ 									else {
+ 										/* Should be a null field */
+ 										nread = fscanf(filep, "%d", &t9);
+ 										if ((nread != 1) || (t9 != -1)) {
+ 											error++;
+ 											try2read = read_kcontents;
+ 											break;
+ 										}
+ 									}
+ 								}
+ 								else {
+ 									try2read = read_ktypelen;
+ 									error++;
+ 									break;
+ 								}
+ 							}
+ 						}
+ 					}
+ 				}
+ 
+ 				/* Get the extra data */
+ 				if (!error && dbentry.e_length) {
+ 					if (read_octet_string(filep,
+ 							  dbentry.e_data,
+ 							  (int) dbentry.e_length)) {
+ 						try2read = read_econtents;
+ 						error++;
+ 					}
+ 				}
+ 				else {
+ 					nread = fscanf(filep, "%d", &t9);
+ 					if ((nread != 1) || (t9 != -1)) {
+ 						error++;
+ 						try2read = read_econtents;
+ 					}
+ 				}
+ 	
+ 				/* Finally, find the end of the record. */
+ 				if (!error)
+ 					find_record_end(filep, fname, *linenop);
+ 
+ 				/*
+ 				 * We have either read in all the data or choked.
+ 				 */
+ 				if (!error) {
+ 					one = 1;
+ 					if ((kret = krb5_db_put_principal(kcontext,
+ 									  &dbentry,
+ 									  &one))) {
+ 						com_err("krepd", 0, store_err_fmt,
+ 							fname, *linenop,
+ 							name, error_message(kret));
+ 					}
+ 					else {
+ 						if (verbose)
+ 							com_err("krepd", 0, add_princ_fmt, name);
+ 						retval = 0;
+ 					}
+ 				}
+ 				else {
+ 					com_err("krepd", 0, read_err_fmt, fname, *linenop, try2read);
+ 				}
+ 			}
+ 			else {
+ 				if (kret)
+ 					com_err("krepd", 0, parse_err_fmt,
+ 						fname, *linenop, name, error_message(kret));
+ 				else
+ 					com_err("krepd", 0, no_mem_fmt, fname, *linenop);
+ 			}
+ 		}
+ 		else {
+ 			com_err("krepd", 0, rhead_err_fmt, fname, *linenop);
+ 		}
+ 
+ 		if (op)
+ 			free(op);
+ 		if (kp)
+ 			free(kp);
+ 		if (name)
+ 			free(name);
+ 		krb5_db_free_principal(kcontext, &dbentry, 1);
+ 	}
+ 	else {
+ 			if (nread == EOF)
+ 				retval = -1;
+ 	}
+ 	return(retval);
+ }
+ 
+ int process_umichrep_k5beta7_policy(fname, kcontext, filep, verbose, linenop, pol_db)
+ 	char		*fname;
+ 	krb5_context	kcontext;
+ 	FILE		*filep;
+ 	int			verbose;
+ 	int			*linenop;
+ 	void *pol_db;
+ {
+ 	osa_policy_ent_rec rec;
+ 	char namebuf[1024];
+ 	int nread, ret;
+ 
+ 	(*linenop)++;
+ 	rec.name = namebuf;
+ 
+ 	nread = fscanf(filep, "%1024s\t%d\t%d\t%d\t%d\t%d\t%d", rec.name,
+ 		   &rec.pw_min_life, &rec.pw_max_life,
+ 		   &rec.pw_min_length, &rec.pw_min_classes,
+ 		   &rec.pw_history_num, &rec.policy_refcnt);
+ 	if (nread == EOF)
+ 		return -1;
+ 	else if (nread != 7) {
+ 		com_err("krepd", 0, "cannot parse policy on line %d (%d read)\n",
+ 			*linenop, nread);
+ 		return 1;
+ 	}
+ 
+ 	if (ret = osa_adb_create_policy(pol_db, &rec)) {
+ 		if (ret == OSA_ADB_DUP) {
+ 			if (ret = osa_adb_put_policy(pol_db, &rec)) {
+ 				com_err("krepd", 0,
+ 						"cannot create/modify policy on line %d: %s\n",
+ 						*linenop, error_message(ret));
+ 				return 1;
+ 			}
+ 			else {
+ 				if (verbose)
+ 					com_err("krepd", 0, "modified policy %s\n", rec.name);
+ 			}
+ 		}
+ 		else {
+ 			com_err("krepd", 0, "cannot create policy on line %d: %s\n",
+ 					*linenop, error_message(ret));
+ 		}
+ 	}
+ 	else {
+ 		if (verbose)
+ 			com_err("krepd", 0, "created policy %s\n", rec.name);
+ 	}
+ 	
+ 	return 0;
+ }
+ 
+ #if defined(UMICH_REPLICATION)
+ 
+ /*
+  * process_umichrep_delprinc()	- Handle a delete dump record.
+  *
+  * Returns -1 for end of file, 0 for success and 1 for failure.
+  */
+ static int
+ process_umichrep_delprinc(fname, kcontext, filep, verbose, linenop, pol_db)
+ 	char		*fname;
+ 	krb5_context	kcontext;
+ 	FILE		*filep;
+ 	int			verbose;
+ 	int			*linenop;
+ 	void *pol_db;
+ {
+ 	int			retval;
+ 	krb5_principal	princ;
+ 	krb5_int32		t2;
+ 	int			nread;
+ 	int			error;
+ 	int			one;
+ 	char		*name;
+ 	krb5_error_code	kret;
+ 
+ 	(*linenop)++;
+ 	retval = 1;
+ 	name = (char *) NULL;
+ 	princ = (krb5_principal) NULL;
+ 	error = 0;
+ 	kret = 0;
+ 	nread = fscanf(filep, "%d\t", &t2);
+ 	if (nread == 1) {
+ 		/* Get memory for flattened principal name */
+ 		if (!(name = (char *) malloc((size_t) t2 + 1)))
+ 			error++;
+ 
+ 		if (!error) {
+ 			/* Read in and parse the principal name */
+ 			if (!read_string(filep, name, t2, linenop) &&
+ 				!(kret = krb5_parse_name(kcontext, name, &princ))) {
+ 
+ 				/* Finally, find the end of the record. */
+ 				if (!error)
+ 					find_record_end(filep, fname, *linenop);
+ 
+ 				/*
+ 				 * We have either read in all the data or choked.
+ 				 */
+ 				if (!error) {
+ 					one = 1;
+ 					if ((kret = krb5_db_delete_principal(kcontext,
+ 														 princ,
+ 														 &one))) {
+ 						com_err("krepd", 0, delete_err_fmt,
+ 								fname, *linenop,
+ 								name, error_message(kret));
+ 					}
+ 					else {
+ 						if (verbose)
+ 							com_err("krepd", 0, delete_princ_fmt, name);
+ 							retval = 0;
+ 					}
+ 				}
+ 			}
+ 			else {
+ 				if (kret)
+ 					com_err("krepd", 0, parse_err_fmt,
+ 							fname, *linenop, name, error_message(kret));
+ 				else
+ 					com_err("krepd", 0, no_mem_fmt, fname, *linenop);
+ 			}
+ 		}
+ 		else {
+ 			com_err("krepd", 0, rhead_err_fmt, fname, *linenop);
+ 		}
+ 
+ 		if (name)
+ 			free(name);
+ 		if (princ)
+ 			krb5_free_principal(kcontext, princ);
+ 	}
+ 	else {
+ 		if (nread == EOF)
+ 			retval = -1;
+ 	}
+ 	return(retval);
+ }
+ 
+ /*
+  * process_umichrep_delpolicy()	- Handle a policy deletion dump record.
+  *
+  * Returns -1 for end of file, 0 for success and 1 for failure.
+  */
+ static int
+ process_umichrep_delpolicy(fname, kcontext, filep, verbose, linenop, pol_db)
+ 	char		*fname;
+ 	krb5_context	kcontext;
+ 	FILE		*filep;
+ 	int			verbose;
+ 	int			*linenop;
+ 	void *pol_db;
+ {
+ 	int			retval;
+ 	krb5_int32		t2;
+ 	int			nread;
+ 	int			error;
+ 	int			one;
+ 	char		*name;
+ 	int			ret;
+ 
+ 	(*linenop)++;
+ 	retval = 1;
+ 	name = (char *) NULL;
+ 	error = 0;
+ 	ret = 0;
+ 	nread = fscanf(filep, "%d\t", &t2);
+ 	if (nread == 1) {
+ 		/* Get memory for policy name */
+ 		if (!(name = (char *) malloc((size_t) t2 + 1)))
+ 			error++;
+ 	
+ 		if (!error) {
+ 			/* Read in the policy name */
+ 			if (!read_string(filep, name, t2, linenop) ) {
+ 	
+ 				/* Finally, find the end of the record. */
+ 				if (!error)
+ 					find_record_end(filep, fname, *linenop);
+ 	
+ 				/*
+ 				 * We have either read in all the data or choked.
+ 				 */
+ 				if (!error) {
+ 					if (ret = osa_adb_destroy_policy(pol_db, name)) {
+ 						com_err("krepd", 0, delete_err_fmt,
+ 							fname, *linenop,
+ 							name, error_message(ret));
+ 					}
+ 					else {
+ 						if (verbose)
+ 							com_err("krepd", 0, delete_policy_fmt, name);
+ 						retval = 0;
+ 					}
+ 				}
+ 			}
+ 			else {
+ 			if (ret)
+ 				com_err("krepd", 0, parse_err_fmt,
+ 					fname, *linenop, name, error_message(ret));
+ 			else
+ 				com_err("krepd", 0, no_mem_fmt, fname, *linenop);
+ 			}
+ 		}
+ 		else {
+ 			com_err("krepd", 0, rhead_err_fmt, fname, *linenop);
+ 		}
+ 	
+ 		if (name)
+ 			free(name);
+ 	}
+ 	else {
+ 		if (nread == EOF)
+ 			retval = -1;
+ 	}
+ 	return(retval);
+ }
+ 
+ /*
+  * process_umichrep_record()	- Handle a dump record in umichrep format.
+  *
+  * Returns -1 for end of file, 0 for success and 1 for failure.
+  */
+ int
+ process_umichrep_record(fname, kcontext, filep, verbose, linenop, pol_db)
+ 	char		*fname;
+ 	krb5_context	kcontext;
+ 	FILE		*filep;
+ 	int			verbose;
+ 	int			*linenop;
+    void *pol_db;
+ {
+ 	 int nread;
+ 	 char rectype[100];
+ 
+ 	 nread = fscanf(filep, "%100s\t", rectype);
+ 	 if (nread == EOF)
+ 	 	return -1;
+ 	 else if (nread != 1)
+ 	 	return 1;
+ 	 if (strcmp(rectype, "princ") == 0)
+ 	 	process_umichrep_k5beta6_record(fname, kcontext, filep, verbose,
+ 				 linenop, pol_db);
+ 	 else if (strcmp(rectype, "delprinc") == 0)
+ 	 	process_umichrep_delprinc(fname, kcontext, filep, verbose,
+ 				 linenop, pol_db);
+ 	 else if (strcmp(rectype, "policy") == 0)
+ 	 	process_umichrep_k5beta7_policy(fname, kcontext, filep, verbose,
+ 				 linenop, pol_db);
+ 	 else if (strcmp(rectype, "delpolicy") == 0)
+ 	 	process_umichrep_delpolicy(fname, kcontext, filep, verbose,
+ 				 linenop, pol_db);
+ 	 else {
+ 	 	com_err("krepd", 0, "unknown record type \"%s\" on line %d\n",
+ 				rectype, *linenop);
+ 	 	return 1;
+ 	 }
+ 
+ 	 return 0;
+ }
+ #endif	/* UMICH_REPLICATION */
+ 
+ #endif	/* UMICH_REPLICATION */
Index: krb5-1.0.5UM/src/lib/kadm5/srv/krep_dump.h
diff -c /dev/null krb5-1.0.5UM/src/lib/kadm5/srv/krep_dump.h:1.2
*** /dev/null	Thu Sep 16 18:06:30 1999
--- krb5-1.0.5UM/src/lib/kadm5/srv/krep_dump.h	Mon Apr 27 07:57:00 1998
***************
*** 0 ****
--- 1,33 ----
+ #ifndef _KREP_DUMP_H
+ #define _KREP_DUMP_H
+ 
+ #if defined(UMICH_REPLICATION)
+ 
+ /*
+  * begin replication stuff
+  */
+ 
+ #include "krb5/kdb.h"
+ 
+ krb5_error_code
+ krb5_umichrep_init KRB5_PROTOTYPE((char *, char *));
+ 
+ krb5_error_code
+ krb5_umichrep_princ KRB5_PROTOTYPE((krb5_db_entry *));
+ 
+ krb5_error_code
+ krb5_umichrep_delprinc KRB5_PROTOTYPE((krb5_principal));
+ 
+ krb5_error_code
+ krb5_umichrep_policy KRB5_PROTOTYPE((osa_policy_ent_t));
+ 
+ krb5_error_code
+ krb5_umichrep_delpolicy KRB5_PROTOTYPE((kadm5_policy_t));
+ 
+ /*
+  * end replication stuff
+  */
+ 
+ #endif  /* UMICH_REPLICATION */
+ 
+ #endif	/* _KREP_DUMP_H */
Index: krb5-1.0.5UM/src/lib/kadm5/srv/server_init.c
diff -c krb5-1.0.5UM/src/lib/kadm5/srv/server_init.c:1.1.1.1 krb5-1.0.5UM/src/lib/kadm5/srv/server_init.c:1.2
*** krb5-1.0.5UM/src/lib/kadm5/srv/server_init.c:1.1.1.1	Fri Apr 24 09:50:12 1998
--- krb5-1.0.5UM/src/lib/kadm5/srv/server_init.c	Mon Jul 27 17:17:24 1998
***************
*** 181,191 ****
--- 181,199 ----
  	  return KADM5_MISSING_CONF_PARAMS;
       }
  
+ #if defined(UMICH_REPLICATION)
+      if (ret = krb5_umichrep_init(client_name, NULL/* use default */)) {
+ 	  krb5_free_context(handle->context);
+ 	  free(handle);
+ 	  return KADM5_UMICHREP_INIT_ERR;
+      }
+ #endif  /* UMICH_REPLICATION */
+ 
      /*
       * Set the db_name based on configuration before calling
       * krb5_db_init, so it will get used.
       */
      if (ret = krb5_dbm_db_set_name(handle->context,
  				   handle->params.dbname)) {
  	 free(handle);
  	 return(ret);
Index: krb5-1.0.5UM/src/lib/kadm5/srv/server_kdb.c
diff -c krb5-1.0.5UM/src/lib/kadm5/srv/server_kdb.c:1.1.1.1 krb5-1.0.5UM/src/lib/kadm5/srv/server_kdb.c:1.2
*** krb5-1.0.5UM/src/lib/kadm5/srv/server_kdb.c:1.1.1.1	Fri Apr 24 09:50:13 1998
--- krb5-1.0.5UM/src/lib/kadm5/srv/server_kdb.c	Mon Apr 27 05:41:04 1998
***************
*** 376,381 ****
--- 376,392 ----
      if (ret = krb5_db_put_principal(handle->context, kdb, &one))
  	return(ret);
  
+ #if defined(UMICH_REPLICATION)
+     if (ret = krb5_umichrep_princ(kdb)) {
+ 	/*
+ 	 * Notify someone that synchronization has broken!
+ 	 * The DB is actually correct, but the user will get
+ 	 * an error back and the replicas won't see the change...
+ 	 */
+ 	return(ret);
+     }
+ #endif  /* UMICH_REPLICATION */
+ 
      return(0);
  }
  
***************
*** 386,391 ****
--- 397,414 ----
      krb5_error_code ret;
      
      ret = krb5_db_delete_principal(handle->context, name, &one);
+ 
+ #if defined(UMICH_REPLICATION)
+     if (ret) return ret;
+ 
+     if (ret = krb5_umichrep_delprinc(name)) {
+ 	/*
+ 	 * Notify someone that synchronization has broken!
+ 	 * The DB is actually correct, but the user will get
+ 	 * an error back and the replicas won't see the change...
+ 	 */
+     }
+ #endif  /* UMICH_REPLICATION */
  
      return ret;
  }
Index: krb5-1.0.5UM/src/lib/kadm5/srv/svr_iters.c
diff -c krb5-1.0.5UM/src/lib/kadm5/srv/svr_iters.c:1.1.1.1 krb5-1.0.5UM/src/lib/kadm5/srv/svr_iters.c:1.3
*** krb5-1.0.5UM/src/lib/kadm5/srv/svr_iters.c:1.1.1.1	Fri Apr 24 09:50:13 1998
--- krb5-1.0.5UM/src/lib/kadm5/srv/svr_iters.c	Mon Dec  7 17:39:42 1998
***************
*** 85,91 ****
--- 85,96 ----
       /* and trailing null.  If glob has no @, also allocate space for */
       /* the realm. */
       append_realm = (realm != NULL) && (strchr(glob, '@') == NULL);
+ #if defined(UMICH)
+      /* UMICH MOD:  Make room for extra 'dot' character below */
+      p = (char *) malloc(strlen(glob)*2+ 3 + (append_realm ? 3 : 0));
+ #else
       p = (char *) malloc(strlen(glob)*2+ 3 + (append_realm ? 2 : 0));
+ #endif
       if (p == NULL)
  	  return ENOMEM;
       *regexp = p;
***************
*** 119,124 ****
--- 124,133 ----
  
       if (append_realm) {
  	  *p++ = '@';
+ #if defined(UMICH)
+ 	  /* UMICH MOD: make this ".*" instead of just "*" */
+ 	  *p++ = '.';
+ #endif
  	  *p++ = '*';
       }
  
Index: krb5-1.0.5UM/src/lib/kadm5/srv/svr_policy.c
diff -c krb5-1.0.5UM/src/lib/kadm5/srv/svr_policy.c:1.1.1.1 krb5-1.0.5UM/src/lib/kadm5/srv/svr_policy.c:1.2
*** krb5-1.0.5UM/src/lib/kadm5/srv/svr_policy.c:1.1.1.1	Fri Apr 24 09:50:13 1998
--- krb5-1.0.5UM/src/lib/kadm5/srv/svr_policy.c	Mon Apr 27 05:41:33 1998
***************
*** 140,146 ****
      else
  	pent.policy_refcnt = entry->policy_refcnt;
      if ((ret = osa_adb_create_policy(handle->policy_db, &pent)) == OSA_ADB_OK)
! 	return KADM5_OK;
      else
  	return ret;
  }
--- 140,153 ----
      else
  	pent.policy_refcnt = entry->policy_refcnt;
      if ((ret = osa_adb_create_policy(handle->policy_db, &pent)) == OSA_ADB_OK)
! #if defined(UMICH_REPLICATION)
!   {
!         krb5_umichrep_policy(&pent);
!         return KADM5_OK;
!   }
! #else /* UMICH_REPLICATION */
!         return KADM5_OK;
! #endif    /* UMICH_REPLICATION */
      else
  	return ret;
  }
***************
*** 166,172 ****
      }
      osa_free_policy_ent(entry);
      if ((ret = osa_adb_destroy_policy(handle->policy_db, name)) == OSA_ADB_OK)
! 	return KADM5_OK;
      else
  	return ret;
  }
--- 173,186 ----
      }
      osa_free_policy_ent(entry);
      if ((ret = osa_adb_destroy_policy(handle->policy_db, name)) == OSA_ADB_OK)
! #if defined(UMICH_REPLICATION)
!     {
!         krb5_umichrep_delpolicy(name);
!         return KADM5_OK;
!     }
! #else /* UMICH_REPLICATION */
!         return KADM5_OK;
! #endif    /* UMICH_REPLICATION */
      else
  	return ret;
  }
***************
*** 244,249 ****
--- 258,266 ----
  	p->policy_refcnt = entry->policy_refcnt;
      switch ((ret = osa_adb_put_policy(handle->policy_db, p))) {
      case OSA_ADB_OK:
+ #if defined(UMICH_REPLICATION)
+         krb5_umichrep_policy(p);
+ #endif    /* UMICH_REPLICATION */
  	ret = KADM5_OK;
  	break;
      case OSA_ADB_NOENT:	/* this should not happen here ... */
Index: krb5-1.0.5UM/src/replication/Makefile.in
diff -c /dev/null krb5-1.0.5UM/src/replication/Makefile.in:1.2
*** /dev/null	Thu Sep 16 18:06:33 1999
--- krb5-1.0.5UM/src/replication/Makefile.in	Mon Apr 27 07:57:33 1998
***************
*** 0 ****
--- 1,36 ----
+ CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+ 
+ CC = cc_r
+ LD = cc_r
+ all::
+ 
+ CLIENTSRCS= $(srcdir)/krep.c $(srcdir)/getslaves.c
+ CLIENTOBJS= krep.o getslaves.o
+ 
+ SERVERSRCS= $(srcdir)/krepd.c
+ SERVEROBJS= krepd.o
+ 
+ SRCS= $(CLIENTSRCS) $(SERVERSRCS)
+ 
+ all::	krep krepd
+ 
+ krep: $(CLIENTOBJS) $(DEPLIBS)
+ 	$(LD) $(LDFLAGS) $(LDARGS) -o krep $(CLIENTOBJS) $(LIBS)
+ 
+ krepd: $(SERVEROBJS) $(DEPLIBS)
+ 	$(LD) $(LDFLAGS) $(LDARGS) -o krepd $(SERVEROBJS) $(LIBS)
+ 
+ install::
+ 	for f in krep krepd; do \
+ 	  $(INSTALL_PROGRAM) $$f \
+ 		$(DESTDIR)$(SERVER_BINDIR)/`echo $$f|sed '$(transform)'`; \
+ 	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+ 		${DESTDIR}$(SERVER_MANDIR)/`echo $$f|sed '$(transform)'`.8; \
+ 	done
+ 
+ clean::
+ 	$(RM) $(CLIENTOBJS) $(SERVEROBJS)
+ 
+ clean::
+ 	$(RM) krep krepd
+ 
Index: krb5-1.0.5UM/src/replication/configure
diff -c /dev/null krb5-1.0.5UM/src/replication/configure:1.2
*** /dev/null	Thu Sep 16 18:06:33 1999
--- krb5-1.0.5UM/src/replication/configure	Mon Apr 27 07:57:41 1998
***************
*** 0 ****
--- 1,1687 ----
+ #! /bin/sh
+ 
+ # Guess values for system-dependent variables and create Makefiles.
+ # Generated automatically using autoconf version 2.10 
+ # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+ #
+ # This configure script is free software; the Free Software Foundation
+ # gives unlimited permission to copy, distribute and modify it.
+ 
+ # Defaults:
+ ac_help=
+ ac_default_prefix=/usr/local
+ # Any additions from configure.in:
+ ac_help="$ac_help
+   --with-cc=COMPILER      select compiler to use"
+ ac_help="$ac_help
+   --with-ccopts=CCOPTS    select compiler command line options"
+ ac_help="$ac_help
+   --with-linker=LINKER    select linker to use"
+ ac_help="$ac_help
+   --with-ldopts=LDOPTS    select linker command line options"
+ ac_help="$ac_help
+   --with-cppopts=CPPOPTS  select compiler preprocessor command line options"
+ ac_help="$ac_help
+   --without-krb4          don't include Kerberos V4 backwards compatibility
+   --with-krb4             use V4 libraries included with V5 (default)
+   --with-krb4=KRB4DIR     use preinstalled V4 libraries"
+ ac_help="$ac_help
+   --with-netlib[=libs]    use user defined resolve library"
+ ac_help="$ac_help
+   --with-shared	use shared libraries (default)
+   --without-shared	don't use shared libraries"
+ 
+ # Initialize some variables set by options.
+ # The variables have the same names as the options, with
+ # dashes changed to underlines.
+ build=NONE
+ cache_file=./config.cache
+ exec_prefix=NONE
+ host=NONE
+ no_create=
+ nonopt=NONE
+ no_recursion=
+ prefix=NONE
+ program_prefix=NONE
+ program_suffix=NONE
+ program_transform_name=s,x,x,
+ silent=
+ site=
+ srcdir=
+ target=NONE
+ verbose=
+ x_includes=NONE
+ x_libraries=NONE
+ bindir='${exec_prefix}/bin'
+ sbindir='${exec_prefix}/sbin'
+ libexecdir='${exec_prefix}/libexec'
+ datadir='${prefix}/share'
+ sysconfdir='${prefix}/etc'
+ sharedstatedir='${prefix}/com'
+ localstatedir='${prefix}/var'
+ libdir='${exec_prefix}/lib'
+ includedir='${prefix}/include'
+ oldincludedir='/usr/include'
+ infodir='${prefix}/info'
+ mandir='${prefix}/man'
+ 
+ # Initialize some other variables.
+ subdirs=
+ MFLAGS= MAKEFLAGS=
+ 
+ ac_prev=
+ for ac_option
+ do
+ 
+   # If the previous option needs an argument, assign it.
+   if test -n "$ac_prev"; then
+     eval "$ac_prev=\$ac_option"
+     ac_prev=
+     continue
+   fi
+ 
+   case "$ac_option" in
+   -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+   *) ac_optarg= ;;
+   esac
+ 
+   # Accept the important Cygnus configure options, so we can diagnose typos.
+ 
+   case "$ac_option" in
+ 
+   -bindir | --bindir | --bindi | --bind | --bin | --bi)
+     ac_prev=bindir ;;
+   -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+     bindir="$ac_optarg" ;;
+ 
+   -build | --build | --buil | --bui | --bu)
+     ac_prev=build ;;
+   -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+     build="$ac_optarg" ;;
+ 
+   -cache-file | --cache-file | --cache-fil | --cache-fi \
+   | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+     ac_prev=cache_file ;;
+   -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+   | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+     cache_file="$ac_optarg" ;;
+ 
+   -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+     ac_prev=datadir ;;
+   -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+   | --da=*)
+     datadir="$ac_optarg" ;;
+ 
+   -disable-* | --disable-*)
+     ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+     # Reject names that are not valid shell variable names.
+     if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+       { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+     fi
+     ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+     eval "enable_${ac_feature}=no" ;;
+ 
+   -enable-* | --enable-*)
+     ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+     # Reject names that are not valid shell variable names.
+     if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+       { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+     fi
+     ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+     case "$ac_option" in
+       *=*) ;;
+       *) ac_optarg=yes ;;
+     esac
+     eval "enable_${ac_feature}='$ac_optarg'" ;;
+ 
+   -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+   | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+   | --exec | --exe | --ex)
+     ac_prev=exec_prefix ;;
+   -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+   | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+   | --exec=* | --exe=* | --ex=*)
+     exec_prefix="$ac_optarg" ;;
+ 
+   -gas | --gas | --ga | --g)
+     # Obsolete; use --with-gas.
+     with_gas=yes ;;
+ 
+   -help | --help | --hel | --he)
+     # Omit some internal or obsolete options to make the list less imposing.
+     # This message is too long to be a string in the A/UX 3.1 sh.
+     cat << EOF
+ Usage: configure [options] [host]
+ Options: [defaults in brackets after descriptions]
+ Configuration:
+   --cache-file=FILE       cache test results in FILE
+   --help                  print this message
+   --no-create             do not create output files
+   --quiet, --silent       do not print \`checking...' messages
+   --version               print the version of autoconf that created configure
+ Directory and file names:
+   --prefix=PREFIX         install architecture-independent files in PREFIX
+                           [$ac_default_prefix]
+   --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                           [same as prefix]
+   --bindir=DIR            user executables in DIR [EPREFIX/bin]
+   --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+   --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+   --datadir=DIR           read-only architecture-independent data in DIR
+                           [PREFIX/share]
+   --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+   --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                           [PREFIX/com]
+   --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+   --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+   --includedir=DIR        C header files in DIR [PREFIX/include]
+   --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+   --infodir=DIR           info documentation in DIR [PREFIX/info]
+   --mandir=DIR            man documentation in DIR [PREFIX/man]
+   --srcdir=DIR            find the sources in DIR [configure dir or ..]
+   --program-prefix=PREFIX prepend PREFIX to installed program names
+   --program-suffix=SUFFIX append SUFFIX to installed program names
+   --program-transform-name=PROGRAM
+                           run sed PROGRAM on installed program names
+ EOF
+     cat << EOF
+ Host type:
+   --build=BUILD           configure for building on BUILD [BUILD=HOST]
+   --host=HOST             configure for HOST [guessed]
+   --target=TARGET         configure for TARGET [TARGET=HOST]
+ Features and packages:
+   --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+   --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+   --x-includes=DIR        X include files are in DIR
+   --x-libraries=DIR       X library files are in DIR
+ EOF
+     if test -n "$ac_help"; then
+       echo "--enable and --with options recognized:$ac_help"
+     fi
+     exit 0 ;;
+ 
+   -host | --host | --hos | --ho)
+     ac_prev=host ;;
+   -host=* | --host=* | --hos=* | --ho=*)
+     host="$ac_optarg" ;;
+ 
+   -includedir | --includedir | --includedi | --included | --include \
+   | --includ | --inclu | --incl | --inc)
+     ac_prev=includedir ;;
+   -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+   | --includ=* | --inclu=* | --incl=* | --inc=*)
+     includedir="$ac_optarg" ;;
+ 
+   -infodir | --infodir | --infodi | --infod | --info | --inf)
+     ac_prev=infodir ;;
+   -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+     infodir="$ac_optarg" ;;
+ 
+   -libdir | --libdir | --libdi | --libd)
+     ac_prev=libdir ;;
+   -libdir=* | --libdir=* | --libdi=* | --libd=*)
+     libdir="$ac_optarg" ;;
+ 
+   -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+   | --libexe | --libex | --libe)
+     ac_prev=libexecdir ;;
+   -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+   | --libexe=* | --libex=* | --libe=*)
+     libexecdir="$ac_optarg" ;;
+ 
+   -localstatedir | --localstatedir | --localstatedi | --localstated \
+   | --localstate | --localstat | --localsta | --localst \
+   | --locals | --local | --loca | --loc | --lo)
+     ac_prev=localstatedir ;;
+   -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+   | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+   | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+     localstatedir="$ac_optarg" ;;
+ 
+   -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+     ac_prev=mandir ;;
+   -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+     mandir="$ac_optarg" ;;
+ 
+   -nfp | --nfp | --nf)
+     # Obsolete; use --without-fp.
+     with_fp=no ;;
+ 
+   -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+   | --no-cr | --no-c)
+     no_create=yes ;;
+ 
+   -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+   | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+     no_recursion=yes ;;
+ 
+   -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+   | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+   | --oldin | --oldi | --old | --ol | --o)
+     ac_prev=oldincludedir ;;
+   -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+   | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+   | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+     oldincludedir="$ac_optarg" ;;
+ 
+   -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+     ac_prev=prefix ;;
+   -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+     prefix="$ac_optarg" ;;
+ 
+   -program-prefix | --program-prefix | --program-prefi | --program-pref \
+   | --program-pre | --program-pr | --program-p)
+     ac_prev=program_prefix ;;
+   -program-prefix=* | --program-prefix=* | --program-prefi=* \
+   | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+     program_prefix="$ac_optarg" ;;
+ 
+   -program-suffix | --program-suffix | --program-suffi | --program-suff \
+   | --program-suf | --program-su | --program-s)
+     ac_prev=program_suffix ;;
+   -program-suffix=* | --program-suffix=* | --program-suffi=* \
+   | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+     program_suffix="$ac_optarg" ;;
+ 
+   -program-transform-name | --program-transform-name \
+   | --program-transform-nam | --program-transform-na \
+   | --program-transform-n | --program-transform- \
+   | --program-transform | --program-transfor \
+   | --program-transfo | --program-transf \
+   | --program-trans | --program-tran \
+   | --progr-tra | --program-tr | --program-t)
+     ac_prev=program_transform_name ;;
+   -program-transform-name=* | --program-transform-name=* \
+   | --program-transform-nam=* | --program-transform-na=* \
+   | --program-transform-n=* | --program-transform-=* \
+   | --program-transform=* | --program-transfor=* \
+   | --program-transfo=* | --program-transf=* \
+   | --program-trans=* | --program-tran=* \
+   | --progr-tra=* | --program-tr=* | --program-t=*)
+     program_transform_name="$ac_optarg" ;;
+ 
+   -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+   | -silent | --silent | --silen | --sile | --sil)
+     silent=yes ;;
+ 
+   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+     ac_prev=sbindir ;;
+   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+   | --sbi=* | --sb=*)
+     sbindir="$ac_optarg" ;;
+ 
+   -sharedstatedir | --sharedstatedir | --sharedstatedi \
+   | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+   | --sharedst | --shareds | --shared | --share | --shar \
+   | --sha | --sh)
+     ac_prev=sharedstatedir ;;
+   -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+   | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+   | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+   | --sha=* | --sh=*)
+     sharedstatedir="$ac_optarg" ;;
+ 
+   -site | --site | --sit)
+     ac_prev=site ;;
+   -site=* | --site=* | --sit=*)
+     site="$ac_optarg" ;;
+ 
+   -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+     ac_prev=srcdir ;;
+   -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+     srcdir="$ac_optarg" ;;
+ 
+   -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+   | --syscon | --sysco | --sysc | --sys | --sy)
+     ac_prev=sysconfdir ;;
+   -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+   | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+     sysconfdir="$ac_optarg" ;;
+ 
+   -target | --target | --targe | --targ | --tar | --ta | --t)
+     ac_prev=target ;;
+   -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+     target="$ac_optarg" ;;
+ 
+   -v | -verbose | --verbose | --verbos | --verbo | --verb)
+     verbose=yes ;;
+ 
+   -version | --version | --versio | --versi | --vers)
+     echo "configure generated by autoconf version 2.10"
+     exit 0 ;;
+ 
+   -with-* | --with-*)
+     ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+     # Reject names that are not valid shell variable names.
+     if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+       { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+     fi
+     ac_package=`echo $ac_package| sed 's/-/_/g'`
+     case "$ac_option" in
+       *=*) ;;
+       *) ac_optarg=yes ;;
+     esac
+     eval "with_${ac_package}='$ac_optarg'" ;;
+ 
+   -without-* | --without-*)
+     ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+     # Reject names that are not valid shell variable names.
+     if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+       { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+     fi
+     ac_package=`echo $ac_package| sed 's/-/_/g'`
+     eval "with_${ac_package}=no" ;;
+ 
+   --x)
+     # Obsolete; use --with-x.
+     with_x=yes ;;
+ 
+   -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+   | --x-incl | --x-inc | --x-in | --x-i)
+     ac_prev=x_includes ;;
+   -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+   | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+     x_includes="$ac_optarg" ;;
+ 
+   -x-libraries | --x-libraries | --x-librarie | --x-librari \
+   | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+     ac_prev=x_libraries ;;
+   -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+   | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+     x_libraries="$ac_optarg" ;;
+ 
+   -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+     ;;
+ 
+   *)
+     if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+       echo "configure: warning: $ac_option: invalid host type" 1>&2
+     fi
+     if test "x$nonopt" != xNONE; then
+       { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+     fi
+     nonopt="$ac_option"
+     ;;
+ 
+   esac
+ done
+ 
+ if test -n "$ac_prev"; then
+   { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+ fi
+ 
+ trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+ 
+ # File descriptor usage:
+ # 0 standard input
+ # 1 file creation
+ # 2 errors and warnings
+ # 3 some systems may open it to /dev/tty
+ # 4 used on the Kubota Titan
+ # 6 checking for... messages and results
+ # 5 compiler messages saved in config.log
+ if test "$silent" = yes; then
+   exec 6>/dev/null
+ else
+   exec 6>&1
+ fi
+ exec 5>./config.log
+ 
+ echo "\
+ This file contains any messages produced by compilers while
+ running configure, to aid debugging if configure makes a mistake.
+ " 1>&5
+ 
+ # Strip out --no-create and --no-recursion so they do not pile up.
+ # Also quote any args containing shell metacharacters.
+ ac_configure_args=
+ for ac_arg
+ do
+   case "$ac_arg" in
+   -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+   | --no-cr | --no-c) ;;
+   -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+   | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+   *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+   ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+   *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+   esac
+ done
+ 
+ # NLS nuisances.
+ # Only set LANG and LC_ALL to C if already set.
+ # These must not be set unconditionally because not all systems understand
+ # e.g. LANG=C (notably SCO).
+ if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+ if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+ 
+ # confdefs.h avoids OS command line length limits that DEFS can exceed.
+ rm -rf conftest* confdefs.h
+ # AIX cpp loses on an empty file, so make sure it contains at least a newline.
+ echo > confdefs.h
+ 
+ # A filename unique to this package, relative to the directory that
+ # configure is in, which we can look for to find out if srcdir is correct.
+ ac_unique_file=krep.c
+ 
+ # Find the source files, if location was not specified.
+ if test -z "$srcdir"; then
+   ac_srcdir_defaulted=yes
+   # Try the directory containing this script, then its parent.
+   ac_prog=$0
+   ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+   test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+   srcdir=$ac_confdir
+   if test ! -r $srcdir/$ac_unique_file; then
+     srcdir=..
+   fi
+ else
+   ac_srcdir_defaulted=no
+ fi
+ if test ! -r $srcdir/$ac_unique_file; then
+   if test "$ac_srcdir_defaulted" = yes; then
+     { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+   else
+     { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+   fi
+ fi
+ srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+ 
+ # Prefer explicitly selected file to automatically selected ones.
+ if test -z "$CONFIG_SITE"; then
+   if test "x$prefix" != xNONE; then
+     CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+   else
+     CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+   fi
+ fi
+ for ac_site_file in $CONFIG_SITE; do
+   if test -r "$ac_site_file"; then
+     echo "loading site script $ac_site_file"
+     . "$ac_site_file"
+   fi
+ done
+ 
+ if test -r "$cache_file"; then
+   echo "loading cache $cache_file"
+   . $cache_file
+ else
+   echo "creating cache $cache_file"
+   > $cache_file
+ fi
+ 
+ ac_ext=c
+ # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ ac_cpp='$CPP $CPPFLAGS'
+ ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+ 
+ if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+   # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+   if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+     ac_n= ac_c='
+ ' ac_t='	'
+   else
+     ac_n=-n ac_c= ac_t=
+   fi
+ else
+   ac_n= ac_c='\c' ac_t=
+ fi
+ 
+ 
+ ac_reltopdir=../.
+ case "$ac_reltopdir" in 
+ /*)
+ 	echo "Configure script built with absolute localdir pathname"
+ 	exit 1
+ 	;;
+ "")
+ 	ac_reltopdir=.
+ 	;;
+ esac
+ ac_topdir=$srcdir/$ac_reltopdir
+ ac_config_fragdir=$ac_reltopdir/config
+ ac_prepend=$ac_config_fragdir/pre.in
+ ac_postpend=$ac_config_fragdir/post.in
+ BUILDTOP=$ac_reltopdir
+ SRCTOP=$srcdir/$ac_reltopdir
+ if test -d "$srcdir/$ac_config_fragdir"; then
+   ac_aux_dir=
+ for ac_dir in $ac_config_fragdir $srcdir/$ac_config_fragdir; do
+   if test -f $ac_dir/install-sh; then
+     ac_aux_dir=$ac_dir
+     ac_install_sh="$ac_aux_dir/install-sh -c"
+     break
+   elif test -f $ac_dir/install.sh; then
+     ac_aux_dir=$ac_dir
+     ac_install_sh="$ac_aux_dir/install.sh -c"
+     break
+   fi
+ done
+ if test -z "$ac_aux_dir"; then
+   { echo "configure: error: can not find install-sh or install.sh in $ac_config_fragdir $srcdir/$ac_config_fragdir" 1>&2; exit 1; }
+ fi
+ ac_config_guess=$ac_aux_dir/config.guess
+ ac_config_sub=$ac_aux_dir/config.sub
+ ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+ 
+ else
+   { echo "configure: error: can not find config/ directory in $ac_reltopdir" 1>&2; exit 1; }
+ fi
+  #
+ # Work around a bug in autoconf; unset the cache variable for the install 
+ # program if it is a relative path.
+ #
+ case "$ac_cv_path_install" in
+ ../*|./*|[a-zA-Z]*)
+ 	unset ac_cv_path_install
+ 	;;
+ esac
+  
+ # Check whether --with-cc or --without-cc was given.
+ if test "${with_cc+set}" = set; then
+   withval="$with_cc"
+   :
+ fi
+ 
+ echo $ac_n "checking for C compiler""... $ac_c" 1>&6
+ if test "$with_cc" != ""; then
+   if test "$ac_cv_prog_cc" != "" && test "$ac_cv_prog_cc" != "$with_cc"; then
+     { echo "configure: error: Specified compiler doesn't match cached compiler name;
+ 	remove cache and try again." 1>&2; exit 1; }
+   else
+     CC="$with_cc"
+   fi
+ fi
+ if eval "test \"`echo '$''{'ac_cv_prog_cc'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+     test -z "$CC" && CC=cc
+   cat > conftest.$ac_ext <<EOF
+ #line 604 "configure"
+ #include "confdefs.h"
+ #include <stdio.h>
+ int main() { return 0; }
+ int t() {
+ printf("hi\n");
+ ; return 0; }
+ EOF
+ if { (eval echo configure:612: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+   :
+ else
+   rm -rf conftest*
+   { echo "configure: error: Can't find a working compiler." 1>&2; exit 1; }
+ fi
+ rm -f conftest*
+ 
+   ac_cv_prog_cc="$CC"
+ 
+ fi
+ 
+ CC="$ac_cv_prog_cc"
+ echo "$ac_t""$CC" 1>&6
+ # Extract the first word of "gcc", so it can be a program name with args.
+ set dummy gcc; ac_word=$2
+ echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   if test -n "$CC"; then
+   ac_cv_prog_CC="$CC" # Let the user override the test.
+ else
+   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+   for ac_dir in $PATH; do
+     test -z "$ac_dir" && ac_dir=.
+     if test -f $ac_dir/$ac_word; then
+       ac_cv_prog_CC="gcc"
+       break
+     fi
+   done
+   IFS="$ac_save_ifs"
+ fi
+ fi
+ CC="$ac_cv_prog_CC"
+ if test -n "$CC"; then
+   echo "$ac_t""$CC" 1>&6
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ if test -z "$CC"; then
+   # Extract the first word of "cc", so it can be a program name with args.
+ set dummy cc; ac_word=$2
+ echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   if test -n "$CC"; then
+   ac_cv_prog_CC="$CC" # Let the user override the test.
+ else
+   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+   ac_prog_rejected=no
+   for ac_dir in $PATH; do
+     test -z "$ac_dir" && ac_dir=.
+     if test -f $ac_dir/$ac_word; then
+       if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+         ac_prog_rejected=yes
+ 	continue
+       fi
+       ac_cv_prog_CC="cc"
+       break
+     fi
+   done
+   IFS="$ac_save_ifs"
+ if test $ac_prog_rejected = yes; then
+   # We found a bogon in the path, so make sure we never use it.
+   set dummy $ac_cv_prog_CC
+   shift
+   if test $# -gt 0; then
+     # We chose a different compiler from the bogus one.
+     # However, it has the same basename, so the bogon will be chosen
+     # first if we set CC to just the basename; use the full file name.
+     shift
+     set dummy "$ac_dir/$ac_word" "$@"
+     shift
+     ac_cv_prog_CC="$@"
+   fi
+ fi
+ fi
+ fi
+ CC="$ac_cv_prog_CC"
+ if test -n "$CC"; then
+   echo "$ac_t""$CC" 1>&6
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+   test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+ fi
+ 
+ echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.c <<EOF
+ #ifdef __GNUC__
+   yes;
+ #endif
+ EOF
+ if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:712: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+   ac_cv_prog_gcc=yes
+ else
+   ac_cv_prog_gcc=no
+ fi
+ fi
+ 
+ echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+ if test $ac_cv_prog_gcc = yes; then
+   GCC=yes
+   if test "${CFLAGS+set}" != set; then
+     echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   echo 'void f(){}' > conftest.c
+ if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+   ac_cv_prog_gcc_g=yes
+ else
+   ac_cv_prog_gcc_g=no
+ fi
+ rm -f conftest*
+ 
+ fi
+ 
+ echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6
+     if test $ac_cv_prog_gcc_g = yes; then
+       CFLAGS="-g -O"
+     else
+       CFLAGS="-O"
+     fi
+   fi
+ else
+   GCC=
+   test "${CFLAGS+set}" = set || CFLAGS="-g"
+ fi
+ 
+  
+ # Check whether --with-ccopts or --without-ccopts was given.
+ if test "${with_ccopts+set}" = set; then
+   withval="$with_ccopts"
+   echo "$ac_t""CCOPTS is $withval" 1>&6
+ CCOPTS=$withval
+ CFLAGS="$CFLAGS $withval"
+ else
+   CCOPTS=
+ fi
+  
+ # Check whether --with-linker or --without-linker was given.
+ if test "${with_linker+set}" = set; then
+   withval="$with_linker"
+   echo "$ac_t""LD=$withval" 1>&6
+ LD=$withval
+ else
+   if test -z "$LD" ; then LD=$CC; fi
+ echo "$ac_t""LD defaults to $LD" 1>&6
+ fi
+  
+ # Check whether --with-ldopts or --without-ldopts was given.
+ if test "${with_ldopts+set}" = set; then
+   withval="$with_ldopts"
+   echo "$ac_t""LDFLAGS is $withval" 1>&6
+ LDFLAGS=$withval
+ else
+   LDFLAGS=
+ fi
+  
+ # Check whether --with-cppopts or --without-cppopts was given.
+ if test "${with_cppopts+set}" = set; then
+   withval="$with_cppopts"
+   echo "$ac_t""CPPOPTS=$withval" 1>&6
+ CPPOPTS=$withval
+ CPPFLAGS="$CPPFLAGS $withval"
+ else
+   echo "$ac_t""CPPOPTS defaults to $CPPOPTS" 1>&6
+ fi
+  
+ # Check whether --with-krb4 or --without-krb4 was given.
+ if test "${with_krb4+set}" = set; then
+   withval="$with_krb4"
+   :
+ else
+   withval=yes
+ 
+ fi
+ if test $withval = no; then
+ 	echo "$ac_t""no krb4 support" 1>&6
+ 	KRB4_LIB=
+ 	DEPKRB4_LIB=
+ 	KRB4_CRYPTO_LIB=
+ 	DEPKRB4_CRYPTO_LIB=
+ 	KRB4_INCLUDES=
+ 	LDARGS=
+ 	krb5_cv_build_krb4_libs=no
+ 	krb5_cv_krb4_libdir=
+ else 
+  
+ CPPFLAGS="$CPPFLAGS "'-DKRB5_KRB4_COMPAT'
+ 
+  if test $withval = yes; then
+ 	echo "$ac_t""built in krb4 support" 1>&6
+ 	KRB4_INCLUDE="-I$SRCTOP/include/kerberosIV"
+ 	KRB4_LIB='-lkrb4'
+ 	DEPKRB4_LIB='$(TOPLIBD)/libkrb4.a'
+ 	KRB4_CRYPTO_LIB='-ldes425'
+ 	DEPKRB4_CRYPTO_LIB='$(TOPLIBD)/libdes425.a'
+ 	KRB4_INCLUDES='-I$(SRCTOP)/include/kerberosIV'
+ 	LDARGS=
+ 	krb5_cv_build_krb4_libs=yes
+ 	krb5_cv_krb4_libdir=
+  else
+ 	echo "$ac_t""preinstalled krb4 in $withval" 1>&6
+ 	KRB4_INCLUDE="-I$withval/include"
+ 	KRB4_LIB="-lkrb"
+ 	DEPKRB4_LIB="$withval/lib/libkrb.a"
+ 	KRB4_CRYPTO_LIB='-ldes425'
+ 	DEPKRB4_CRYPTO_LIB='$(TOPLIBD)/libdes425.a'
+ 	KRB4_INCLUDES="-I$withval/include"
+ 	LDARGS="-L$withval/lib"
+ 	krb5_cv_build_krb4_libs=no
+ 	krb5_cv_krb4_libdir="$withval/lib"
+  fi
+ fi
+ 
+ 
+ 
+ 
+ 
+  echo $ac_n "checking for working const""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 845 "configure"
+ #include "confdefs.h"
+ 
+ int main() { return 0; }
+ int t() {
+ 
+ /* Ultrix mips cc rejects this.  */
+ typedef int charset[2]; const charset x;
+ /* SunOS 4.1.1 cc rejects this.  */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this.  */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+    It does not let you subtract one const X* pointer from another in an arm
+    of an if-expression whose if-part is not a constant expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this.  */
+   char *t;
+   char const *s = 0 ? (char *) 0 : (char const *) 0;
+ 
+   *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+   int x[] = {25, 17};
+   const int *foo = &x[0];
+   ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+   typedef const int *iptr;
+   iptr p = 0;
+   ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+      "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+   struct s { int j; const int *ap[3]; };
+   struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+   const int foo = 10;
+ }
+ 
+ ; return 0; }
+ EOF
+ if { (eval echo configure:895: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+   rm -rf conftest*
+   ac_cv_c_const=yes
+ else
+   rm -rf conftest*
+   ac_cv_c_const=no
+ fi
+ rm -f conftest*
+ 
+ fi
+ 
+ echo "$ac_t""$ac_cv_c_const" 1>&6
+ if test $ac_cv_c_const = no; then
+   cat >> confdefs.h <<\EOF
+ #define const 
+ EOF
+ 
+ fi
+  
+ # Check whether --with-netlib or --without-netlib was given.
+ if test "${with_netlib+set}" = set; then
+   withval="$with_netlib"
+   if test "$withval" = yes -o "$withval" = no ; then
+ 	echo "$ac_t"""netlib will link with C library resolver only"" 1>&6
+   else
+ 	LIBS="$LIBS $withval"
+ 	echo "$ac_t"""netlib will use \'$withval\'"" 1>&6
+   fi
+ 
+ else
+   if test "`(uname) 2>/dev/null`" != IRIX ; then
+   echo $ac_n "checking for -lsocket""... $ac_c" 1>&6
+ ac_lib_var=`echo socket'_'main | tr './+\055' '__p_'`
+ if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   ac_save_LIBS="$LIBS"
+ LIBS="-lsocket  $LIBS"
+ cat > conftest.$ac_ext <<EOF
+ #line 934 "configure"
+ #include "confdefs.h"
+ 
+ int main() { return 0; }
+ int t() {
+ main()
+ ; return 0; }
+ EOF
+ if { (eval echo configure:942: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=yes"
+ else
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=no"
+ fi
+ rm -f conftest*
+ LIBS="$ac_save_LIBS"
+ 
+ fi
+ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+     ac_tr_lib=HAVE_LIB`echo socket | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+   cat >> confdefs.h <<EOF
+ #define $ac_tr_lib 1
+ EOF
+ 
+   LIBS="-lsocket $LIBS"
+ 
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ fi
+ echo $ac_n "checking for -lnsl""... $ac_c" 1>&6
+ ac_lib_var=`echo nsl'_'main | tr './+\055' '__p_'`
+ if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   ac_save_LIBS="$LIBS"
+ LIBS="-lnsl  $LIBS"
+ cat > conftest.$ac_ext <<EOF
+ #line 975 "configure"
+ #include "confdefs.h"
+ 
+ int main() { return 0; }
+ int t() {
+ main()
+ ; return 0; }
+ EOF
+ if { (eval echo configure:983: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=yes"
+ else
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=no"
+ fi
+ rm -f conftest*
+ LIBS="$ac_save_LIBS"
+ 
+ fi
+ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+     ac_tr_lib=HAVE_LIB`echo nsl | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+   cat >> confdefs.h <<EOF
+ #define $ac_tr_lib 1
+ EOF
+ 
+   LIBS="-lnsl $LIBS"
+ 
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ 
+ fi
+  
+ 
+ CPPFLAGS="$CPPFLAGS "'-I$(BUILDTOP)/include -I$(SRCTOP)/include -I$(BUILDTOP)/include/krb5 -I$(SRCTOP)/include/krb5'
+  if test "$program_transform_name" = s,x,x,; then
+   program_transform_name=
+ else
+   # Double any \ or $.  echo might interpret backslashes.
+   cat <<\EOF_SED > conftestsed
+ s,\\,\\\\,g; s,\$,$$,g
+ EOF_SED
+   program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+   rm -f conftestsed
+ fi
+ test "$program_prefix" != NONE &&
+   program_transform_name="s,^,${program_prefix},; $program_transform_name"
+ # Use a double $ so make ignores it.
+ test "$program_suffix" != NONE &&
+   program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+ 
+ # sed with no file args requires a program.
+ test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+  
+ 
+ 
+ 
+ 
+ 
+ # Find a good install program.  We prefer a C program (faster),
+ # so one script is as good as another.  But avoid the broken or
+ # incompatible versions:
+ # SysV /etc/install, /usr/sbin/install
+ # SunOS /usr/etc/install
+ # IRIX /sbin/install
+ # AIX /bin/install
+ # AFS /usr/afsws/bin/install, which mishandles nonexistent args
+ # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+ # ./install, which can be erroneously created by make from ./install.sh.
+ echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+ if test -z "$INSTALL"; then
+ if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+     IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+   for ac_dir in $PATH; do
+     # Account for people who put trailing slashes in PATH elements.
+     case "$ac_dir/" in
+     /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+     *)
+       # OSF1 and SCO ODT 3.0 have their own names for install.
+       for ac_prog in ginstall installbsd scoinst install; do
+         if test -f $ac_dir/$ac_prog; then
+ 	  if test $ac_prog = install &&
+             grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ 	    # AIX install.  It has an incompatible calling convention.
+ 	    # OSF/1 installbsd also uses dspmsg, but is usable.
+ 	    :
+ 	  else
+ 	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+ 	    break 2
+ 	  fi
+ 	fi
+       done
+       ;;
+     esac
+   done
+   IFS="$ac_save_ifs"
+ 
+ fi
+   if test "${ac_cv_path_install+set}" = set; then
+     INSTALL="$ac_cv_path_install"
+   else
+     # As a last resort, use the slow shell script.  We don't cache a
+     # path for INSTALL within a source directory, because that will
+     # break other packages using the cache if that directory is
+     # removed, or if the path is relative.
+     INSTALL="$ac_install_sh"
+   fi
+ fi
+ echo "$ac_t""$INSTALL" 1>&6
+ 
+ # Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+ # It thinks the first close brace ends the variable substitution.
+ test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+ 
+ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+ 
+ echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+ # On Suns, sometimes $CPP names a directory.
+ if test -n "$CPP" && test -d "$CPP"; then
+   CPP=
+ fi
+ if test -z "$CPP"; then
+ if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+     # This must be in double quotes, not single quotes, because CPP may get
+   # substituted into the Makefile and "${CC-cc}" will confuse make.
+   CPP="${CC-cc} -E"
+   # On the NeXT, cc -E runs the code through the compiler's parser,
+   # not just through cpp.
+   cat > conftest.$ac_ext <<EOF
+ #line 1110 "configure"
+ #include "confdefs.h"
+ #include <assert.h>
+ Syntax Error
+ EOF
+ ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ { (eval echo configure:1116: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ ac_err=`grep -v '^ *+' conftest.out`
+ if test -z "$ac_err"; then
+   :
+ else
+   echo "$ac_err" >&5
+   rm -rf conftest*
+   CPP="${CC-cc} -E -traditional-cpp"
+   cat > conftest.$ac_ext <<EOF
+ #line 1125 "configure"
+ #include "confdefs.h"
+ #include <assert.h>
+ Syntax Error
+ EOF
+ ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ { (eval echo configure:1131: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ ac_err=`grep -v '^ *+' conftest.out`
+ if test -z "$ac_err"; then
+   :
+ else
+   echo "$ac_err" >&5
+   rm -rf conftest*
+   CPP=/lib/cpp
+ fi
+ rm -f conftest*
+ fi
+ rm -f conftest*
+   ac_cv_prog_CPP="$CPP"
+ fi
+   CPP="$ac_cv_prog_CPP"
+ else
+   ac_cv_prog_CPP="$CPP"
+ fi
+ echo "$ac_t""$CPP" 1>&6
+ 
+ ac_safe=`echo "termios.h" | tr './\055' '___'`
+ echo $ac_n "checking for termios.h""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 1157 "configure"
+ #include "confdefs.h"
+ #include <termios.h>
+ EOF
+ ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ { (eval echo configure:1162: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ ac_err=`grep -v '^ *+' conftest.out`
+ if test -z "$ac_err"; then
+   rm -rf conftest*
+   eval "ac_cv_header_$ac_safe=yes"
+ else
+   echo "$ac_err" >&5
+   rm -rf conftest*
+   eval "ac_cv_header_$ac_safe=no"
+ fi
+ rm -f conftest*
+ fi
+ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+   echo $ac_n "checking for tcsetattr""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'ac_cv_func_tcsetattr'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 1181 "configure"
+ #include "confdefs.h"
+ /* System header to define __stub macros and hopefully few prototypes,
+     which can conflict with char tcsetattr(); below.  */
+ #include <assert.h>
+ /* Override any gcc2 internal prototype to avoid an error.  */
+ /* We use char because int might match the return type of a gcc2
+     builtin and then its argument prototype would still apply.  */
+ char tcsetattr();
+ 
+ int main() { return 0; }
+ int t() {
+ 
+ /* The GNU C library defines this for functions which it implements
+     to always fail with ENOSYS.  Some functions are actually named
+     something starting with __ and the normal name is an alias.  */
+ #if defined (__stub_tcsetattr) || defined (__stub___tcsetattr)
+ choke me
+ #else
+ tcsetattr();
+ #endif
+ 
+ ; return 0; }
+ EOF
+ if { (eval echo configure:1205: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+   rm -rf conftest*
+   eval "ac_cv_func_tcsetattr=yes"
+ else
+   rm -rf conftest*
+   eval "ac_cv_func_tcsetattr=no"
+ fi
+ rm -f conftest*
+ 
+ fi
+ if eval "test \"`echo '$ac_cv_func_'tcsetattr`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+   cat >> confdefs.h <<\EOF
+ #define POSIX_TERMIOS 1
+ EOF
+ 
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ echo $ac_n "checking for -lutil""... $ac_c" 1>&6
+ ac_lib_var=`echo util'_'main | tr './+\055' '__p_'`
+ if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   ac_save_LIBS="$LIBS"
+ LIBS="-lutil  $LIBS"
+ cat > conftest.$ac_ext <<EOF
+ #line 1237 "configure"
+ #include "confdefs.h"
+ 
+ int main() { return 0; }
+ int t() {
+ main()
+ ; return 0; }
+ EOF
+ if { (eval echo configure:1245: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=yes"
+ else
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=no"
+ fi
+ rm -f conftest*
+ LIBS="$ac_save_LIBS"
+ 
+ fi
+ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+     ac_tr_lib=HAVE_LIB`echo util | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+   cat >> confdefs.h <<EOF
+ #define $ac_tr_lib 1
+ EOF
+ 
+   LIBS="-lutil $LIBS"
+ 
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ 
+ kadmsrv_deplib="\$(TOPLIBD)/libkadm5srv.a"
+ kadmsrv_lib=-lkadm5srv
+ 
+ gssrpc_deplib="\$(TOPLIBD)/libgssrpc.a"
+ gssrpc_lib=-lgssrpc
+ 
+ kdb5_deplib="\$(TOPLIBD)/libkdb5.a"
+ kdb5_lib=-lkdb5
+ 
+ db_deplib="\$(TOPLIBD)/libdb.a"
+ db_lib="\$(TOPLIBD)/libdb.a"
+ 
+ dyn_deplib="\$(TOPLIBD)/libdyn.a"
+ dyn_lib=-ldyn
+ 
+ 
+ save_LIBS="$LIBS"
+ LIBS=-lgen
+ for ac_func in compile step
+ do
+ echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 1287 "configure"
+ #include "confdefs.h"
+ /* System header to define __stub macros and hopefully few prototypes,
+     which can conflict with char $ac_func(); below.  */
+ #include <assert.h>
+ /* Override any gcc2 internal prototype to avoid an error.  */
+ /* We use char because int might match the return type of a gcc2
+     builtin and then its argument prototype would still apply.  */
+ char $ac_func();
+ 
+ int main() { return 0; }
+ int t() {
+ 
+ /* The GNU C library defines this for functions which it implements
+     to always fail with ENOSYS.  Some functions are actually named
+     something starting with __ and the normal name is an alias.  */
+ #if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+ choke me
+ #else
+ $ac_func();
+ #endif
+ 
+ ; return 0; }
+ EOF
+ if { (eval echo configure:1311: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+   rm -rf conftest*
+   eval "ac_cv_func_$ac_func=yes"
+ else
+   rm -rf conftest*
+   eval "ac_cv_func_$ac_func=no"
+ fi
+ rm -f conftest*
+ 
+ fi
+ if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+     ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+   cat >> confdefs.h <<EOF
+ #define $ac_tr_func 1
+ EOF
+  
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ done
+ 
+ if test "$ac_cv_func_compile" = yes ; then
+ 	LIBS="$save_LIBS -lgen"
+ else
+ 	LIBS="$save_LIBS"
+ fi
+ SRVDEPLIBS="\$(DEPLOCAL_LIBRARIES) $kadmsrv_deplib $gssrpc_deplib $gssapi_deplib $kdb5_deplib $kutil_deplib \$(TOPLIBD)/libkrb5.a $krb4_deplib \$(TOPLIBD)/libcrypto.a $ss_deplib $dyn_deplib $db_deplib \$(TOPLIBD)/libcom_err.a"
+ SRVLIBS="\$(LOCAL_LIBRARIES) $kadmsrv_lib $gssrpc_lib $gssapi_lib $kdb5_lib $kutil_lib $krb4_lib -lkrb5 -lcrypto $ss_lib $dyn_lib $db_lib -lcom_err $LIBS"
+ CLNTDEPLIBS="\$(DEPLOCAL_LIBRARIES) $kadmclnt_deplib $gssrpc_deplib $gssapi_deplib $kdb5_deplib $kutil_deplib \$(TOPLIBD)/libkrb5.a $krb4_deplib \$(TOPLIBD)/libcrypto.a $ss_deplib $dyn_deplib $db_deplib \$(TOPLIBD)/libcom_err.a"
+ CLNTLIBS="\$(LOCAL_LIBRARIES) $kadmclnt_lib $gssrpc_lib $gssapi_lib $kdb5_lib $kutil_lib $krb4_lib -lkrb5 -lcrypto $ss_lib $dyn_lib $db_lib -lcom_err $LIBS"
+ DEPLIBS="\$(DEPLOCAL_LIBRARIES) $kadmclnt_deplib $kadmsrv_deplib $gssrpc_deplib $gssapi_deplib $kdb5_deplib $kutil_deplib \$(TOPLIBD)/libkrb5.a $krb4_deplib \$(TOPLIBD)/libcrypto.a $ss_deplib $dyn_deplib $db_deplib \$(TOPLIBD)/libcom_err.a"
+ LIBS="\$(LOCAL_LIBRARIES) $kadmclnt_lib $kadmsrv_lib $gssrpc_lib $gssapi_lib $kdb5_lib $kutil_lib $krb4_lib -lkrb5 -lcrypto $ss_lib $dyn_lib $db_lib -lcom_err $LIBS"
+ LDFLAGS="$LDFLAGS -L\$(TOPLIBD)"
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ # Check whether --with-shared or --without-shared was given.
+ if test "${with_shared+set}" = set; then
+   withval="$with_shared"
+   :
+ else
+   withval=yes
+ 
+ fi
+ if test "$krb5_cv_shlibs_enabled" = yes ; then
+   if test "$withval" = yes; then
+ 	echo "$ac_t""Using shared libraries" 1>&6
+ 	LDARGS="$krb5_cv_shlibs_ldflag -L\$(TOPLIBD) $LDARGS"
+ 	if test "$krb5_cv_exe_need_dirs" = yes; then
+ 		LDARGS="$LDARGS ${krb5_cv_shlibs_dirhead}\$(KRB5_SHLIBDIR)"
+ 	fi
+ 	SHLIB_TAIL_COMP=$krb5_cv_shlibs_tail_comp
+ 	
+   else
+ 	echo "$ac_t""Using archive libraries" 1>&6
+ 	LDARGS="$krb5_cv_noshlibs_ldflag -L\$(TOPLIBD) $LDARGS"
+   fi
+ else
+   LDARGS="-L\$(TOPLIBD) $LDARGS"
+ fi
+ 
+ 
+ ac_v5_makefile_dirs=.
+ filelist=""
+ for x in $ac_v5_makefile_dirs; do
+   filelist="$filelist $x/Makefile.tmp:$ac_prepend+$x/Makefile.in+$ac_postpend"
+ done
+ trap '' 1 2 15
+ cat > confcache <<\EOF
+ # This file is a shell script that caches the results of configure
+ # tests run on this system so they can be shared between configure
+ # scripts and configure runs.  It is not useful on other systems.
+ # If it contains results you don't want to keep, you may remove or edit it.
+ #
+ # By default, configure uses ./config.cache as the cache file,
+ # creating it if it does not exist already.  You can give configure
+ # the --cache-file=FILE option to use a different cache file; that is
+ # what configure does when it calls configure scripts in
+ # subdirectories, so they share the cache.
+ # Giving --cache-file=/dev/null disables caching, for debugging configure.
+ # config.status only pays attention to the cache file if you give it the
+ # --recheck option to rerun configure.
+ #
+ EOF
+ # Ultrix sh set writes to stderr and can't be redirected directly,
+ # and sets the high bit in the cache file unless we assign to the vars.
+ (set) 2>&1 |
+   sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \
+   >> confcache
+ if cmp -s $cache_file confcache; then
+   :
+ else
+   if test -w $cache_file; then
+     echo "updating cache $cache_file"
+     cat confcache > $cache_file
+   else
+     echo "not updating unwritable cache $cache_file"
+   fi
+ fi
+ rm -f confcache
+ 
+ trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+ 
+ test "x$prefix" = xNONE && prefix=$ac_default_prefix
+ # Let make expand exec_prefix.
+ test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+ 
+ # Any assignment to VPATH causes Sun make to only execute
+ # the first set of double-colon rules, so remove it if not needed.
+ # If there is a colon in the path, we need to keep it.
+ if test "x$srcdir" = x.; then
+   ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+ fi
+ 
+ trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+ 
+ # Transform confdefs.h into DEFS.
+ # Protect against shell expansion while executing Makefile rules.
+ # Protect against Makefile macro expansion.
+ cat > conftest.defs <<\EOF
+ s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+ s%[ 	`~#$^&*(){}\\|;'"<>?]%\\&%g
+ s%\[%\\&%g
+ s%\]%\\&%g
+ s%\$%$$%g
+ EOF
+ DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+ rm -f conftest.defs
+ 
+ 
+ # Without the "./", some shells look in PATH for config.status.
+ : ${CONFIG_STATUS=./config.status}
+ 
+ echo creating $CONFIG_STATUS
+ rm -f $CONFIG_STATUS
+ cat > $CONFIG_STATUS <<EOF
+ #! /bin/sh
+ # Generated automatically by configure.
+ # Run this file to recreate the current configuration.
+ # This directory was configured as follows,
+ # on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+ #
+ # $0 $ac_configure_args
+ #
+ # Compiler output produced by configure, useful for debugging
+ # configure, is in ./config.log if it exists.
+ 
+ ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+ for ac_option
+ do
+   case "\$ac_option" in
+   -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+     echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+     exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+   -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+     echo "$CONFIG_STATUS generated by autoconf version 2.10"
+     exit 0 ;;
+   -help | --help | --hel | --he | --h)
+     echo "\$ac_cs_usage"; exit 0 ;;
+   *) echo "\$ac_cs_usage"; exit 1 ;;
+   esac
+ done
+ 
+ ac_given_srcdir=$srcdir
+ ac_given_INSTALL="$INSTALL"
+ 
+ trap 'rm -fr `echo "$filelist" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+ EOF
+ cat >> $CONFIG_STATUS <<EOF
+ 
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+  s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+ $ac_vpsub
+ $extrasub
+ s%@CFLAGS@%$CFLAGS%g
+ s%@CPPFLAGS@%$CPPFLAGS%g
+ s%@CXXFLAGS@%$CXXFLAGS%g
+ s%@DEFS@%$DEFS%g
+ s%@LDFLAGS@%$LDFLAGS%g
+ s%@LIBS@%$LIBS%g
+ s%@exec_prefix@%$exec_prefix%g
+ s%@prefix@%$prefix%g
+ s%@program_transform_name@%$program_transform_name%g
+ s%@bindir@%$bindir%g
+ s%@sbindir@%$sbindir%g
+ s%@libexecdir@%$libexecdir%g
+ s%@datadir@%$datadir%g
+ s%@sysconfdir@%$sysconfdir%g
+ s%@sharedstatedir@%$sharedstatedir%g
+ s%@localstatedir@%$localstatedir%g
+ s%@libdir@%$libdir%g
+ s%@includedir@%$includedir%g
+ s%@oldincludedir@%$oldincludedir%g
+ s%@infodir@%$infodir%g
+ s%@mandir@%$mandir%g
+ s%@CC@%$CC%g
+ s%@CCOPTS@%$CCOPTS%g
+ s%@LD@%$LD%g
+ s%@CPPOPTS@%$CPPOPTS%g
+ s%@KRB4_INCLUDES@%$KRB4_INCLUDES%g
+ s%@KRB4_LIB@%$KRB4_LIB%g
+ s%@KRB4_CRYPTO_LIB@%$KRB4_CRYPTO_LIB%g
+ s%@DEPKRB4_LIB@%$DEPKRB4_LIB%g
+ s%@DEPKRB4_CRYPTO_LIB@%$DEPKRB4_CRYPTO_LIB%g
+ s%@ALL_RECURSE@%$ALL_RECURSE%g
+ s%@CLEAN_RECURSE@%$CLEAN_RECURSE%g
+ s%@INSTALL_RECURSE@%$INSTALL_RECURSE%g
+ s%@CHECK_RECURSE@%$CHECK_RECURSE%g
+ s%@MAKEFILES_RECURSE@%$MAKEFILES_RECURSE%g
+ s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+ s%@INSTALL_DATA@%$INSTALL_DATA%g
+ s%@CPP@%$CPP%g
+ s%@LDARGS@%$LDARGS%g
+ s%@DEPLIBS@%$DEPLIBS%g
+ s%@SRVDEPLIBS@%$SRVDEPLIBS%g
+ s%@SRVLIBS@%$SRVLIBS%g
+ s%@CLNTDEPLIBS@%$CLNTDEPLIBS%g
+ s%@CLNTLIBS@%$CLNTLIBS%g
+ s%@SHLIB_TAIL_COMP@%$SHLIB_TAIL_COMP%g
+ 
+ CEOF
+ EOF
+ cat >> $CONFIG_STATUS <<EOF
+ 
+ CONFIG_FILES=\${CONFIG_FILES-"$filelist"}
+ EOF
+ cat >> $CONFIG_STATUS <<\EOF
+ for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+   # Support "outfile[:infile]", defaulting infile="outfile.in".
+   case "$ac_file" in
+   *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+        ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+   *) ac_file_in="${ac_file}.in" ;;
+   esac
+ 
+   # Adjust relative srcdir, etc. for subdirectories.
+ 
+   # Remove last slash and all that follows it.  Not all systems have dirname.
+   ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+   if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+     # The file is in a subdirectory.
+     test ! -d "$ac_dir" && mkdir "$ac_dir"
+     ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+     # A "../" for each directory in $ac_dir_suffix.
+     ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+   else
+     ac_dir_suffix= ac_dots=
+   fi
+ 
+   case "$ac_given_srcdir" in
+   .)  srcdir=.
+       if test -z "$ac_dots"; then top_srcdir=.
+       else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+   /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+   *) # Relative path.
+     srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+     top_srcdir="$ac_dots$ac_given_srcdir" ;;
+   esac
+ 
+   case "$ac_given_INSTALL" in
+   [/$]*) INSTALL="$ac_given_INSTALL" ;;
+   *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+   esac
+   echo creating "$ac_file"
+   rm -f "$ac_file"
+   # allow for outfile[:infile1[+infile2[+infile3...]]] syntax
+   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}+"
+   ac_files_in=
+   for ac_file_name in $ac_file_in
+   do
+     ac_files_in="$ac_files_in $ac_given_srcdir/$ac_file_name"
+   done
+   IFS="$ac_save_ifs"
+   configure_input=`echo $ac_files_in | sed 's%/./%/%g
+ s%  *./%%g
+ s%  *%+%g
+ s%^%Generated automatically from %
+ s%$% by configure.%'`
+   case "$ac_file" in
+   *Makefile*) ac_comsub="1i\\
+ # $configure_input" ;;
+   *) ac_comsub= ;;
+   esac
+   sed -e "$ac_comsub
+ s%@configure_input@%$configure_input%g
+ s%@srcdir@%$srcdir%g
+ s%@top_srcdir@%$top_srcdir%g
+ s%@INSTALL@%$INSTALL%g
+ " -f conftest.subs $ac_files_in > $ac_file
+ fi; done
+ rm -f conftest.subs
+ 
+ EOF
+ cat >> $CONFIG_STATUS <<EOF
+ CONF_FRAGDIR=$srcdir/${ac_config_fragdir} 
+ EOF
+ cat >> $CONFIG_STATUS <<\EOF
+ EOF
+ ac_reltopdir=`echo $ac_reltopdir | sed   \
+ 	-e ':LOOP'		\
+ 	-e 's,/\./,/,'		\
+ 	-e 'tLOOP'		\
+ 	-e 's,^\./,,'		\
+ 	-e 's,/\.$,,g'		\
+ 	`
+ test "$ac_reltopdir" = "" && ac_reltopdir=.
+ cat >> $CONFIG_STATUS <<EOF
+ ac_v5_makefile_dirs="$ac_v5_makefile_dirs"
+ ac_reltopdir=$ac_reltopdir
+ EOF
+ >> append.out
+ cat - append.out >> $CONFIG_STATUS <<\EOF
+ cat >> append.tmp <<\CEOF
+ #
+ # rules appended by configure
+ 
+ EOF
+ rm append.out
+ cat >> $CONFIG_STATUS <<\EOF
+ CEOF
+ for d in $ac_v5_makefile_dirs; do
+   # If CONFIG_FILES was set from Makefile, skip unprocessed directories.
+   if test -r $d/Makefile.tmp; then
+     x=`echo $d/ | sed   \
+ 	-e 's,//*$,/,'		\
+ 	-e ':LOOP'		\
+ 	-e 's,/\./,/,'		\
+ 	-e 'tLOOP'		\
+ 	-e 's,^\./,,'		\
+ 	-e 's,[^/]*/,../,g'	\
+ 	`
+     test "$x" = "" && x=./
+     case $srcdir in
+     /*)  s=$ac_given_srcdir/$ac_reltopdir ;;
+     *)   s=$x$ac_given_srcdir/$ac_reltopdir ;;
+     esac
+     s=`echo $s | sed   \
+ 	-e 's,//*$,/,'		\
+ 	-e ':LOOP'		\
+ 	-e 's,/\./,/,'		\
+ 	-e 'tLOOP'		\
+ 	-e 's,^\./,,'		\
+ 	-e 's,/\.$,,g'		\
+ 	`
+     test "$s" = "" && s=.
+     echo creating $d/Makefile
+     cat - $d/Makefile.tmp append.tmp > $d/Makefile <<EOX
+ thisconfigdir=$x
+ SRCTOP=$s
+ BUILDTOP=$x$ac_reltopdir
+ EOX
+     rm  $d/Makefile.tmp
+ # sed -f $CONF_FRAGDIR/mac-mf.sed < Makefile > MakeFile
+   fi
+ done
+ rm append.tmp
+ 
+ exit 0
+ EOF
+ chmod +x $CONFIG_STATUS
+ rm -fr confdefs* $ac_clean_files
+ test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+ 
Index: krb5-1.0.5UM/src/replication/configure.in
diff -c /dev/null krb5-1.0.5UM/src/replication/configure.in:1.2
*** /dev/null	Thu Sep 16 18:06:34 1999
--- krb5-1.0.5UM/src/replication/configure.in	Mon Apr 27 07:57:48 1998
***************
*** 0 ****
--- 1,12 ----
+ AC_INIT(krep.c)
+ CONFIG_RULES
+ AC_PROG_INSTALL
+ AC_HEADER_CHECK(termios.h,AC_FUNC_CHECK([tcsetattr],AC_DEFINE(POSIX_TERMIOS)))
+ AC_CHECK_LIB(util,main)
+ USE_KDB5_LIBRARY
+ USE_KADMSRV_LIBRARY
+ USE_GSSRPC_LIBRARY
+ USE_DYN_LIBRARY
+ KRB5_LIBRARIES
+ V5_USE_SHARED_LIB
+ V5_AC_OUTPUT_MAKEFILE
Index: krb5-1.0.5UM/src/replication/getslaves.c
diff -c /dev/null krb5-1.0.5UM/src/replication/getslaves.c:1.4
*** /dev/null	Thu Sep 16 18:06:34 1999
--- krb5-1.0.5UM/src/replication/getslaves.c	Fri Sep  3 08:43:30 1999
***************
*** 0 ****
--- 1,89 ----
+ /*
+  *  COPYRIGHT    1998
+  *  THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+  *  ALL RIGHTS RESERVED
+  *
+  *  PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+  *  AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+  *  FOR ANY PURPOSE, SO LONG AS NO FEE IS CHARGED, AND SO LONG
+  *  AS THE COPYRIGHT NOTICE ABOVE, THIS GRANT OF PERMISSION,
+  *  AND THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND SO
+  *  LONG AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED
+  *  IN ANY ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR
+  *  DISTRIBUTION OF THIS SOFTWARE WITHOUT SPECIFIC, WRITTEN
+  *  PRIOR AUTHORIZATION.
+  *
+  *  THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+  *  FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+  *  PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+  *  MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+  *  WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+  *  REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+  *  FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+  *  CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+  *  OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+  *  IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+  *  SUCH DAMAGES.
+ */
+ 
+ /* Routine to obtain a list of all the slave KDCs we need to replicate to */
+ 
+ #include "k5-int.h"
+ #include <netdb.h>			/* for MAXHOSTNAMELEN definition on Solaris 2.6 */
+ 
+ krb5_error_code
+ krb5_getslavelist(kcontext, realmp, slave_hosts, num_hosts)
+     krb5_context   kcontext;
+     krb5_data      *realmp;
+     char           ***slave_hosts;
+     int            *num_hosts;
+ {
+     krb5_error_code kret;
+     char my_hostname[MAXHOSTNAMELEN];
+     int rc;
+     int i, j, k;
+     char **hostlist = NULL;
+ 
+     *num_hosts = 0;
+     kret = 0;
+ 
+     if (rc = gethostname(my_hostname, sizeof(my_hostname)))
+ 	return (krb5_error_code) rc;
+ 
+     if (kret = krb5_get_krbhst(kcontext, realmp, &hostlist))
+         return kret;
+ 
+     /* Now count the number of hosts in the realm */
+     *num_hosts = 0;
+     for (i=0; hostlist[i]; i++)
+         (*num_hosts)++;
+     if (*num_hosts == 0) {
+         kret = KRB5_REALM_UNKNOWN;
+         return kret;
+     }
+ 
+     /* Now find and remove ourself (the master) from the list */
+     for (i=0; hostlist[i]; i++) {
+         if (!strcmp(hostlist[i], my_hostname))
+ 	    break;
+     }
+     if (i < *num_hosts) {
+ 	for (j=i, k=i+1; k < *num_hosts; j++, k++)
+ 	    hostlist[j] = hostlist[k];
+ 	(*num_hosts)--;
+ 	hostlist[*num_hosts] = NULL;		/* blank out last entry */
+     }
+     else {
+ 	/* XXX Could not find ourself on the list ??? */
+     }
+ 
+     if (*num_hosts == 0) {
+ 	kret = 0;			/* We're the only one, but that's OK */
+ 	return kret;
+     }
+ 
+     *slave_hosts = hostlist;
+     return kret;
+ }
+ 
Index: krb5-1.0.5UM/src/replication/krep.M
diff -c /dev/null krb5-1.0.5UM/src/replication/krep.M:1.2
*** /dev/null	Thu Sep 16 18:06:35 1999
--- krb5-1.0.5UM/src/replication/krep.M	Mon Apr 27 07:57:58 1998
***************
*** 0 ****
--- 1,105 ----
+ .\" replication/krep.M
+ .\"
+ .\" Copyright 1992 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.
+ .\" 
+ .\"
+ .\" COPYRIGHT    1998
+ .\" THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ .\" ALL RIGHTS RESERVED
+ .\"
+ .\" PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+ .\" AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+ .\" FOR ANY PURPOSE, SO LONG AS NO FEE IS CHARGED, AND SO LONG
+ .\" AS THE COPYRIGHT NOTICE ABOVE, THIS GRANT OF PERMISSION,
+ .\" AND THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND SO
+ .\" LONG AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED
+ .\" IN ANY ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR
+ .\" DISTRIBUTION OF THIS SOFTWARE WITHOUT SPECIFIC, WRITTEN
+ .\" PRIOR AUTHORIZATION.
+ .\"
+ .\" THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ .\" FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ .\" PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ .\" MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ .\" WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ .\" REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ .\" FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ .\" CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ .\" OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ .\" IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ .\" SUCH DAMAGES.
+ .\"
+ .\"
+ .TH KREP 8
+ .SH NAME
+ krep \- replicate Kerberos V5 principal database changes to all slave servers
+ .SH SYNOPSIS
+ .B krep
+ [\fB\-r\fP \fIrealm\fP] [\fB\-f\fP \fIfile\fP] [\fB\-d\fP] [\fB\-P\fP
+ \fIport\fP] [\fB\-s\fP \fIkeytab\fP] [\fB\-S\fP \fIslave\-interval\fP] 
+ [\fB\-T\fP \fItruncation\-interval\fP]
+ .br
+ .SH DESCRIPTION
+ .I krep
+ is used to replicate changes in a Kerberos V5 database from the master
+ Kerberos server to all slave servers defined in the kerberos configuration
+ file.
+ This is done by transmitting dump records to the slave servers over
+ an encrypted, secure channel.  The dump records are created by
+ .IR kadmind (8)
+ as it writes changes to the database.  The changes are normally collected
+ in file KREP_DEFAULT_FILE (/usr/local/var/krb5kdc/master_delta).
+ .P
+ There are threads to monitor the file for new updates, truncate the file
+ when all slaves have been updated, and a separate thread to transmit
+ changes to each slave server.
+ .SH OPTIONS
+ .TP
+ \fB\-r\fP \fIrealm\fP
+ specifies the realm of the master server; by default the realm returned
+ by
+ .IR krb5_default_local_realm (3)
+ is used.
+ .TP
+ \fB\-f\fP \fIfile\fP
+ specifies the filename where the file containing delta dump records is to
+ be found; by default this file is KREP_DEFAULT_FILE
+ (normally /usr/local/var/krb5kdc/master_delta).
+ .TP
+ \fB\-P\fP \fIport\fP
+ specifies the port to use to contact the
+ .I krepd
+ server on the remote host.
+ .TP
+ .B \-d
+ prints debugging information.
+ .TP
+ \fB\-s\fP \fIkeytab\fP
+ specifies the location of the keytab file.
+ .TP
+ \fB\-S\fP \fIslave\-interval\fP
+ specifies the time in seconds that each slave thread will wait before
+ checking for new changes to be propagated. 
+ .TP
+ \fB\-T\fP \fItruncation\-interval\fP
+ specifies the time in seconds that the truncation thread will wait
+ between checks to see if the delta file can be safely truncated.
+ .SH SEE ALSO
+ krepd(8), kadmind(8)
Index: krb5-1.0.5UM/src/replication/krep.c
diff -c /dev/null krb5-1.0.5UM/src/replication/krep.c:1.9
*** /dev/null	Thu Sep 16 18:06:35 1999
--- krb5-1.0.5UM/src/replication/krep.c	Fri Sep  3 08:43:32 1999
***************
*** 0 ****
--- 1,1512 ----
+ /*
+  * replication/krep.c
+  *
+  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+  * All Rights Reserved.
+  *
+  * Export of this software from the United States of America may
+  *   require a specific license from the United States Government.
+  *   It is the responsibility of any person or organization contemplating
+  *   export to obtain such a license before exporting.
+  * 
+  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+  * distribute this software and its documentation for any purpose and
+  * without fee is hereby granted, provided that the above copyright
+  * notice appear in all copies and that both that copyright notice and
+  * this permission notice appear in supporting documentation, and that
+  * the name of M.I.T. not be used in advertising or publicity pertaining
+  * to distribution of the software without specific, written prior
+  * permission.  M.I.T. makes no representations about the suitability of
+  * this software for any purpose.  It is provided "as is" without express
+  * or implied warranty.
+  * 
+  *
+  */
+ /*
+  *  COPYRIGHT    1998
+  *  THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+  *  ALL RIGHTS RESERVED
+  *
+  *  PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+  *  AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+  *  FOR ANY PURPOSE, SO LONG AS NO FEE IS CHARGED, AND SO LONG
+  *  AS THE COPYRIGHT NOTICE ABOVE, THIS GRANT OF PERMISSION,
+  *  AND THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND SO
+  *  LONG AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED
+  *  IN ANY ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR
+  *  DISTRIBUTION OF THIS SOFTWARE WITHOUT SPECIFIC, WRITTEN
+  *  PRIOR AUTHORIZATION.
+  *
+  *  THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+  *  FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+  *  PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+  *  MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+  *  WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+  *  REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+  *  FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+  *  CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+  *  OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+  *  IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+  *  SUCH DAMAGES.
+ */
+ 
+ #if defined(UMICH_REPLICATION)
+ #if defined(sun)
+ #define _REENTRANT    /* basic 3-lines for threads */
+ #include <pthread.h>
+ #include <thread.h>
+ #else
+ #include <pthread.h>
+ #endif
+ #endif	/* UMICH_REPLICATION */
+ #include <errno.h>
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <sys/file.h>
+ #include <signal.h>
+ #include <string.h>
+ #include <sys/types.h>
+ #include <sys/time.h>
+ #include <sys/stat.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <sys/param.h>
+ #include <netdb.h>
+ #include <fcntl.h>
+ #include <syslog.h>
+ 
+ #include "k5-int.h"
+ #include "com_err.h"
+ #include "krep.h"
+ 
+ #define SYSLOG_CLASS LOG_DAEMON
+ 
+ static char *krep_version = KREP_PROT_VERSION;
+ 
+ char	*progname = 0;
+ int	debug = 0;
+ char	*srvtab = 0;
+ char	*realm = 0;
+ char	*file = KREP_DEFAULT_FILE;
+ short	port = 0;
+ 
+ #if defined(UMICH_REPLICATION)
+ 
+ int	nofork = 0;
+ int	verbose = 1;
+ 
+ /*
+  * The following values are defaults and may
+  * be changed via command line
+  */
+ int	slaveThreadCheckTime = 15;	   /* # of secs between checks for more work */
+ int	truncThreadCheckTime = 30;	   /* # of secs between checks for truncation */
+ 
+ /*
+  * Made the following global so that the status signal
+  * handler can have access to them...
+  */
+ 
+ int		num_hosts;
+ /* The following data items are protected via repl_stateMutex */
+ pthread_mutex_t	repl_stateMutex;
+ slave_data	*slave_info;
+ trunc_info	t_thread;
+ int		truncation_count = 0;
+ /* End of items protected via repl_stateMutex */
+ 
+ /* Another mutex to serialize calls to kerberos libraries */
+ pthread_mutex_t repl_kerblibMutex;
+ 
+ #endif	/* UMICH_REPLICATION */
+ 
+ krb5_principal	my_principal;		/* The Kerberos principal we'll be */
+ 					/* running under, initialized in */
+ 					/* get_tickets() */
+ krb5_address	sender_addr;
+ krb5_address	receiver_addr;
+ 
+ void	PRS
+ 	PROTOTYPE((int, char **));
+ void	get_tickets
+ 	PROTOTYPE((krb5_context, char *, slave_data *tt));
+ static void usage 
+ 	PROTOTYPE((void));
+ krb5_error_code open_connection 
+ 	PROTOTYPE((char *, int *, char *));
+ int	kerberos_authenticate 
+ 	PROTOTYPE((krb5_context, krb5_auth_context *, 
+ 		   int, krb5_principal, krb5_creds **, slave_data *tt));
+ void	send_error 
+ 	PROTOTYPE((krb5_context, krb5_creds *, int, char *, krb5_error_code));
+ 
+ #if defined(UMICH_REPLICATION)
+ 
+ krb5_error_code krb5_getslavelist
+ 	PROTOTYPE((krb5_context, krb5_data *, char ***, int *));
+ int	xmit_dbinfo 
+ 	PROTOTYPE((krb5_context, krb5_auth_context, krb5_creds *, 
+ 		   int, char *, int, char*));
+ 
+ void signalBrokenPipe(int code)
+ {
+ 	com_err(progname, 0, "Caught broken pipe signal");
+ }
+ 
+ /*
+  * This routine is called as a result of a SIGUSR1 signal being
+  * issued.  It prints the status of all the threads.  (Note that
+  * com_err is re-routed to syslog if not in debug mode.)
+  */
+ void signalGetStatus(int code)
+ {
+ 	int i;
+ 	
+ 	/*
+ 	 * We do not get the mutex, just in case some thread is
+ 	 * stuck while holding it.
+ 	 */
+ 
+ 	com_err(NULL, 0, "The latest truncation count is %d", truncation_count);
+ 	for (i = 0; i < num_hosts; i++)
+ 	{
+ 		com_err(NULL, 0,
+ 				"---------- Thread number %d information ----------", i);
+ 		com_err(NULL, 0, "    Hostname        : %s",
+ 					slave_info[i].sl_hostname);
+ 		com_err(NULL, 0, "    Delta file fd   : %d",
+ 					slave_info[i].sl_fd);
+ 		com_err(NULL, 0, "    Latest position : %d",
+ 					slave_info[i].sl_lastPosition);
+ 		com_err(NULL, 0, "    Socket fd       : %d",
+ 					slave_info[i].sl_socket);
+ 		com_err(NULL, 0, "    Current state   : %s",
+ 					slave_info[i].sl_currentState == REPL_STATE_IDLE ? "idle" :
+ 					slave_info[i].sl_currentState == REPL_STATE_PROCESSING ?
+ 					"processing" : "unknown");
+ 		com_err(NULL, 0, "    Truncation vers : %d",
+ 					slave_info[i].sl_lastTruncation);
+ 	}
+ }
+ 
+ 
+ /*
+  * Checks for new unprocessed entries in the delta file.
+  * Returns non-zero if there is work for the thread to do.
+  */
+ int repl_get_work( slave_data *tt, char *buffer, int bufsize, int *bytesread )
+ {
+ 	int rc;
+ 	int workToDo = 0;	   /* Assume no work on entry */
+    
+ 	/* Obtain state update lock */
+ 	if (rc = pthread_mutex_lock(tt->sl_stateUpdateMutex))
+ 	{
+ 		com_err(progname, errno, "%s: failed to obtain mutex (%d)",
+ 			tt->sl_hostname, rc);
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	/* Get a shared lock on the file */
+ 	if (rc = krb5_lock_file(0, tt->sl_fd, KRB5_LOCKMODE_SHARED) )
+ 	{
+ 		com_err(progname, errno,
+ 			"%s: error (%d) obtaining shared lock on delta file",
+ 			tt->sl_hostname, rc);
+ 		return (0);
+ 	}
+ 
+ 	/* Clear the buffer */
+ 	memset(buffer, '\0', bufsize);
+ 
+ 	/* Get current stat information for the file */
+ 	if (fstat(tt->sl_fd, &tt->sl_statinfo))
+ 	{
+ 		com_err(progname, errno, "%s: error obtaining delta file stat info",
+ 			tt->sl_hostname);
+ 	}
+ 	else
+ 	{
+ 		if (tt->sl_statinfo.st_size == 0 ||
+ 			*tt->sl_truncationCount > tt->sl_lastTruncation)
+ 		{
+ 			/* File has been truncated */
+ 			tt->sl_lastPosition = 0;
+ 			tt->sl_lastTruncation = *tt->sl_truncationCount;
+ 			fseek(tt->sl_file, 0, SEEK_SET);
+ 		}
+ 	}
+ 
+ 	if ( fgets(buffer, bufsize, tt->sl_file) != NULL)
+ 	{
+ 		if (buffer[strlen(buffer) - 1] == '\n')
+ 			buffer[strlen(buffer) - 1] = '\0';
+ 		*bytesread = strlen(buffer);
+ 		workToDo = 1;
+ 	}
+ 
+ 	if (workToDo)
+ 		tt->sl_currentState = REPL_STATE_PROCESSING;
+ 	else
+ 		tt->sl_currentState = REPL_STATE_IDLE;
+ 
+ 	/* Release shared lock on the file */
+ 	krb5_lock_file(0, tt->sl_fd, KRB5_LOCKMODE_UNLOCK);
+ 
+ 	/* Release state update lock */
+ 	if (rc = pthread_mutex_unlock(tt->sl_stateUpdateMutex))
+ 	{
+ 		com_err(progname, errno, "%s: failed to release mutex (%d)",
+ 			tt->sl_hostname, rc);
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	if (debug)
+ 		com_err(progname, 0, "%s: There is%s work for this thread to do",
+ 				tt->sl_hostname, workToDo ? "" : " NOT");
+ 	return workToDo;
+ }
+ 
+ /*
+  * Update thread's file position (after receiving ack from slave)
+  */
+ int update_file_position( slave_data *tt, off_t offset )
+ {
+ 	int rc;
+    
+ 	/* Obtain state update lock */
+ 	if (rc = pthread_mutex_lock(tt->sl_stateUpdateMutex))
+ 	{
+ 		com_err(progname, errno, "%s: failed to obtain mutex (%d)",
+ 			tt->sl_hostname, rc);
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	/* Get a shared lock on the file */
+ 	if (rc = krb5_lock_file(0, tt->sl_fd, KRB5_LOCKMODE_SHARED) )
+ 	{
+ 		com_err(progname, errno,
+ 				"%s: error (%d) obtaining shared lock on delta file",
+ 				tt->sl_hostname, rc);
+ 		return (0);
+ 	}
+ 
+ 	/*
+ 	 * If offset is supplied, then we assume that we want to reset back
+ 	 * to the last place where we were, so we fseek to lastPosition.
+ 	 */
+ 	if (offset)
+ 	{
+ 		if (debug)
+ 			com_err(progname, 0, "%s: Resetting file position...",
+ 				tt->sl_hostname);
+ 		if (-1 == fseek(tt->sl_file, tt->sl_lastPosition, SEEK_SET))
+ 			com_err(progname, errno, "%s: error (%d) resetting file position",
+ 				tt->sl_hostname, errno);
+ 	}
+ 
+ 	/* Get the current file position */
+ 	tt->sl_lastPosition = ftell(tt->sl_file);
+ 
+ 	if (debug)
+ 		com_err(progname, 0,
+ 			"%s: lastTrunc %u, lastPosition %u, currentState 0x%08x",
+ 			tt->sl_hostname, tt->sl_lastTruncation,
+ 			tt->sl_lastPosition, tt->sl_currentState);
+ 
+ 	/* Release shared lock on the file */
+ 	krb5_lock_file(0, tt->sl_fd, KRB5_LOCKMODE_UNLOCK);
+ 
+ 	/* Release state update lock */
+ 	if (rc = pthread_mutex_unlock(tt->sl_stateUpdateMutex))
+ 	{
+ 		com_err(progname, errno, "%s: failed to release mutex (%d)",
+ 			tt->sl_hostname, rc);
+ 		pthread_exit((void *) 1);
+ 	}
+ }
+ 
+ /*
+  * Called for initial connection to, and authentication with, a remote
+  * krepd on a slave KDC machine.  Also called to reconnect after a
+  * broken pipe is encountered.  Doesn't return until successfully
+  * connected and authenticated.
+  */
+ void connect_and_authenticate(slave_data *tt,
+ 				krb5_auth_context *auth_contextP,
+ 				krb5_creds **credsPP)
+ {
+ 	char	Errmsg[256];
+ 	krb5_error_code	retval;
+ 
+ 	/*
+ 	 * If we don't have a connection, then keep trying every 15 seconds
+ 	 * until we get a connection.  Then authenticate until it works...
+ 	 */
+ 	if (tt->sl_socket < 0)
+ 	{
+ 		struct timeval sleeptime;
+ 
+ 		com_err(NULL, 0, "Opening connection with %s", tt->sl_hostname);
+ 
+ 		do {
+ 			if (retval = open_connection(tt->sl_hostname, &tt->sl_socket,
+ 							Errmsg))
+ 			{
+ 				com_err(progname, retval, "%s while opening connection to %s",
+ 					Errmsg, tt->sl_hostname);
+ 	
+ 				sleeptime.tv_sec = 15;
+ 				sleeptime.tv_usec = 0;
+ 				select(0, 0, 0, 0, &sleeptime);
+ 			}
+ 		} while (tt->sl_socket < 0);
+ 	
+ 		com_err(NULL, 0, "Authenticating with %s", tt->sl_hostname);
+ 
+ 		while(kerberos_authenticate(tt->sl_context, auth_contextP,
+ 						tt->sl_socket, my_principal, credsPP, tt))
+ 		{
+ 			/* Error messages are printed by routine, wait and try again... */
+ 			sleeptime.tv_sec = 15;
+ 			sleeptime.tv_usec = 0;
+ 			select(0, 0, 0, 0, &sleeptime);
+ 		}
+ 
+ 		/*
+ 		 * Initialize the initial vector. (Only once per connection)
+ 		 */
+ 		if (retval = krb5_auth_con_initivector(tt->sl_context, *auth_contextP)) {
+ 			com_err(progname, retval, "while allocating i_vector (%s)",
+ 				tt->sl_hostname);
+ 		}
+ 
+ 		com_err(NULL, 0, "Successfully connected with %s", tt->sl_hostname);
+ 
+ 	}
+ }
+ 
+ /*
+  * main routine for a thread replicating to a specific slave machine.  There
+  * is one of these threads for each slave machine in the realm.  Each thread
+  * has an individual file pointer reading the delta file so that each thread
+  * can be in a different place in the file.
+  * Loops forever checking for new work to do and sending the changes to
+  * the slave machine that it services..
+  */
+ void * replication_thread_routine(void *parm )
+ {
+ 	slave_data *tt = (slave_data *) parm;	/* tt ==> This Thread */
+ 	int rc;
+ 	char *buffer;
+ 	int bufferSize = KREP_BUFSIZ;
+ 	struct timeval sleeptime;
+ 
+ 	krb5_auth_context auth_context;
+ 	krb5_creds *credsP = &tt->sl_creds;
+ 	krb5_creds **credsPP = &credsP;
+ 
+ 	/* Obtain state update lock */
+ 	if (rc = pthread_mutex_lock(tt->sl_stateUpdateMutex))
+ 	{
+ 		com_err(progname, errno, "%s: failed to obtain state update mutex (%d)",
+ 			tt->sl_hostname, rc);
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ #ifdef POSIX_SIGNALS
+ #error "Not coded to use POSIX signals..."
+ #else
+ 	(void) signal(SIGPIPE, signalBrokenPipe);
+ #endif
+ 
+ 	if (NULL == (buffer = (char *) malloc(bufferSize)))
+ 	{
+ 		com_err(progname, errno, "%s: failed to allocate %d bytes for buffer",
+ 			tt->sl_hostname, bufferSize);
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	if (debug)
+ 		com_err(progname, 0, "%s: Opening file %s for input ...",
+ 			tt->sl_hostname, tt->sl_replfile);
+ 	if ((tt->sl_file = fopen(tt->sl_replfile, "r")) == NULL )
+ 	{
+ 		com_err(progname, errno, "%s: failed to open file %s",
+ 			tt->sl_hostname, tt->sl_replfile);
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	tt->sl_fd = fileno(tt->sl_file);
+ 
+ 	/* Use non-blocking I/O */
+ 	if (-1 == (rc = fcntl(tt->sl_fd, F_SETFL, FNDELAY)))
+ 	{
+ 		com_err(progname, errno,
+ 			"%s: failed to set file %s for non-blocking I/O",
+ 			tt->sl_hostname, tt->sl_replfile);
+ 		pthread_exit((void *) 1);
+ 	}
+ 	if (debug)
+ 		com_err(progname, 0, "%s: file is now open", tt->sl_hostname);
+ 
+ 	/* Release state update lock */
+ 	if (rc = pthread_mutex_unlock(tt->sl_stateUpdateMutex))
+ 	{
+ 		com_err(progname, errno, "%s: failed to release state update mutex (%d)",
+ 			tt->sl_hostname, rc);
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	for (;;) {
+ 		int bytesread;
+ 
+ reconnect:
+ 		connect_and_authenticate(tt, &auth_context, credsPP);
+ 
+ 		/*
+ 		 * repl_check_for_work returns non-zero if
+ 		 * there is new work to do
+ 		 */
+ 		while (repl_get_work(tt, buffer, bufferSize, &bytesread ))
+ 		{
+ 			if (verbose || debug)
+ 			{
+ 				/* Print a readable log message */
+ 
+ 				char namebuff[256];
+ 				char msgbuff[256];
+ 				int numscanned = 0;
+ 
+ 				if (0 == strncmp(buffer, "princ", 5))
+ 				{
+ 					numscanned = sscanf(buffer,
+ 							"%*s\t%*d\t%*d\t%*d\t%*d\t%*d%s\t",
+ 							&namebuff);
+ 					sprintf(msgbuff, "principal '%s'", namebuff);
+ 				}
+ 				else if (0 == strncmp(buffer, "delprinc", 8))
+ 				{
+ 					numscanned = sscanf(buffer, "%*s\t%*d\t%s\t", &namebuff);
+ 					if (1 == numscanned)
+ 						namebuff[strlen(namebuff)-1] = '\0';
+ 					sprintf(msgbuff, "delete principal '%s'", namebuff);
+ 				}
+ 				else if (0 == strncmp(buffer, "policy", 6))
+ 				{
+ 					numscanned = sscanf(buffer, "%*s\t%s\t", &namebuff);
+ 					sprintf(msgbuff, "policy '%s'", namebuff);
+ 				}
+ 				else if (0 == strncmp(buffer, "delpolicy", 9))
+ 				{
+ 					numscanned = sscanf(buffer, "%*s\t%*d\t%s\t", &namebuff);
+ 					if (1 == numscanned)
+ 						namebuff[strlen(namebuff)-1] = '\0';
+ 					sprintf(msgbuff, "delete policy '%s'", namebuff);
+ 				}
+ 				if (numscanned != 1)
+ 					sprintf(msgbuff, "Error scanning record: '%.60s'", buffer);
+ 
+ 				com_err(NULL, 0, "%s: %s", tt->sl_hostname, msgbuff);
+ 			}
+ 
+ 			if (xmit_dbinfo(tt->sl_context, auth_context, &tt->sl_creds,
+ 					tt->sl_socket, buffer, bytesread, tt->sl_hostname))
+ 			{
+ 				/*
+ 				 * It looks like transmission failed, back up our position in
+ 				 * the file so we retry the last record.  Then go back and
+ 				 * reconnect and authenticate with the server...
+ 				 */
+ 
+ 				com_err(NULL, 0,
+ 					"%s: Transmission failed, backing up our "
+ 					"file position and reconnecting...", tt->sl_hostname);
+ 
+ 				update_file_position(tt, -(bytesread+1) );
+ 
+ 				close(tt->sl_socket);
+ 				tt->sl_socket = -1;
+ 				goto reconnect;
+ 			}
+ 			else
+ 			{
+ 				update_file_position(tt, 0);
+ 			}
+ 		}
+ 
+ 		/* Sleep for a while before checking for more work */
+ 		sleeptime.tv_sec = tt->sl_sleeptime;
+ 		sleeptime.tv_usec = 0;
+ 		select(0, 0, 0, 0, &sleeptime);
+ 	}
+ }
+ 
+ /*
+  * One of these threads per krep.  It monitors the status of the slave
+  * threads and the delta file.  If all the slave threads are caught up
+  * to the end of the delta file, then the file is truncated so that it
+  * doesn't grow infinitely.  A mutex is used to protect against a slave
+  * thread's status changing while this thread examines all the slave
+  * threads.  File locking is used to protect against kadmind appending
+  * to the file while we are truncating it.
+  */
+ void * truncation_thread_routine(void *parm )
+ {
+ 	trunc_info *ti = (trunc_info *) parm;
+ 	struct timeval sleeptime;
+ 	char threadname[] = "Truncation";
+ 	struct stat secondStat;
+ 	slave_data *slave;
+ 	int doTruncate;
+ 	int i;
+ 	int rc;
+ 
+ 	sleeptime.tv_sec = ti->tr_sleeptime;
+ 	sleeptime.tv_usec = 0;
+ 	if (debug)
+ 		com_err(progname, 0,
+ 			"%s: running - sleeping for %d seconds before processing",
+ 			threadname, sleeptime.tv_sec);
+ 	select(0, 0, 0, 0, &sleeptime);
+ 
+ 	if (debug) {
+ 		com_err(progname, 0, "%s: beginning processing...", threadname);
+ 		com_err(progname, 0, "%s: Opening file %s ...",
+ 			threadname, ti->tr_replfile);
+ 	}
+ 
+ 	if ((ti->tr_file = fopen(ti->tr_replfile, "r+")) == NULL)
+ 	{
+ 		com_err(progname, errno, "%s: failed to open delta file %s",
+ 			threadname, ti->tr_replfile);
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	ti->tr_fd = fileno(ti->tr_file);
+ 
+ 	if (debug)
+ 		com_err(progname, 0, "%s: file is now open", threadname);
+ 
+ 	for (;;)
+ 	{
+ 		/* Assume that we're not going to truncate */
+ 		doTruncate = 0;
+ 
+ 		/* Obtain state update lock */
+ 		if (rc = pthread_mutex_lock(ti->tr_stateUpdateMutex))
+ 		{
+ 			com_err(progname, errno, "%s: failed to obtain mutex (%d)",
+ 				threadname, rc);
+ 			pthread_exit((void *) 1);
+ 		}
+ 
+ 		/*
+ 		 * If all slave threads are idle and have processed to the current end
+ 		 * of the file, then lock the file (so that krbkdc doesn't update it),
+ 		 * truncate the file and set the flags so that the slave threads know
+ 		 * that it's been truncated
+ 		 */
+ 
+ 		/* Get current stat information for the file */
+ 		if (fstat(ti->tr_fd, &ti->tr_statinfo))
+ 		{
+ 			com_err(progname, errno,
+ 				"%s: error obtaining delta file stat info",
+ 				threadname);
+ 		}
+ 		else
+ 		{
+ 			if (ti->tr_statinfo.st_size != 0)
+ 			{
+ 				doTruncate = 1;
+ 				for (i = 0, slave = ti->tr_slaves;
+ 					 i < ti->tr_numSlaves;
+ 					 i++, slave++)
+ 				{
+ 					if (slave->sl_currentState != REPL_STATE_IDLE ||
+ 						slave->sl_lastPosition != ti->tr_statinfo.st_size ||
+ 						slave->sl_lastTruncation != *ti->tr_truncationCount)
+ 					{
+ 						doTruncate = 0;
+ 						break;
+ 					}
+ 				}
+ 			}
+ 		}
+ 
+ 		if (doTruncate)
+ 		{
+ 			/*
+ 			 * - lock the file
+ 			 * - get another stat to make sure it hasn't
+ 			 *   changed while checking the slave threads
+ 			 * - truncate the file
+ 			 * - set the flags so that slave threads know file
+ 			 *   has been truncated
+ 			 */
+ 
+ 			/* lock the file */
+ 
+ 			if (krb5_lock_file(0, ti->tr_fd, KRB5_LOCKMODE_EXCLUSIVE) )
+ 			{
+ 				com_err(progname, errno,
+ 					"%s: unable to obtain delta file lock, "
+ 					"skipping truncation", threadname);
+ 			}
+ 			else
+ 			{
+ 				if (fstat(ti->tr_fd, &secondStat))
+ 				{
+ 					com_err(progname, errno, "%s: error obtaining delta file "
+ 						"stat info", threadname);
+ 				}
+ 				else
+ 				{
+ 					if (ti->tr_statinfo.st_mtime != secondStat.st_mtime)
+ 					{
+ 						com_err(progname, 0,
+ 							"%s: file changed before I could truncate it",
+ 							threadname);
+ 					}
+ 					else
+ 					{
+ 						if (debug)
+ 							com_err(progname, 0,
+ 								"%s: TRUNCATING FILE !!!!!!!",
+ 								threadname);
+ 
+ 						if ( ftruncate(ti->tr_fd, 0) )
+ 						{
+ 							com_err(progname, errno,
+ 								"%s: could not truncate delta file '%s', "
+ 								"error %d",
+ 								threadname, ti->tr_replfile, errno);
+ 						}
+ 						else
+ 						{
+ 							*ti->tr_truncationCount += 1;
+ 						}
+ 					}
+ 				}
+ 				/* unlock the file */
+ 			krb5_lock_file(0, ti->tr_fd, KRB5_LOCKMODE_UNLOCK);
+ 			}
+ 		}
+ 
+ 		/* Release state update lock */
+ 		if (rc = pthread_mutex_unlock(ti->tr_stateUpdateMutex))
+ 		{
+ 			com_err(progname, errno, "%s: failed to release mutex (%d)",
+ 				threadname, rc);
+ 			pthread_exit((void *) 1);
+ 		}
+ 
+ 		/* Sleep for a while before checking again */
+ 		sleeptime.tv_sec = ti->tr_sleeptime;
+ 		sleeptime.tv_usec = 0;
+ 		if (debug)
+ 			com_err(progname, 0,
+ 				"%s: sleeping for %d seconds before checking again",
+ 				threadname, sleeptime.tv_sec);
+ 		select(0, 0, 0, 0, &sleeptime);
+ 	}
+ 	return ((void *) 0);
+ }
+ #endif	/* UMICH_REPLICATION */
+ 
+ static void usage()
+ {
+ 	com_err(progname, 0, "\nUsage: %s [-r realm] [-f file] [-d] [-n] [-q] [-P port] \n"
+ 				"\t[-s srvtab] [-S slave_delay] [-T trunc_delay] \n\n",
+ 				progname);
+ 	exit(1);
+ }
+ 
+ void
+ main(argc, argv)
+ 	int	argc;
+ 	char	**argv;
+ {
+ 	int		fd, database_fd, database_size;
+ 	krb5_error_code	retval;
+ 	krb5_context	main_context;
+ /*	krb5_auth_context auth_context;		*/
+ 	char		Errmsg[256];
+ #if defined(UMICH_REPLICATION)
+ 	char		**slave_hosts = NULL;
+ 	int		i;
+ 	krb5_data	my_realm;
+ 	int    		rc;
+ 
+ #endif	/* UMICH_REPLICATION */
+ 
+ 	retval = krb5_init_context(&main_context);
+ 	if (retval) {
+ 		com_err(argv[0], retval, "while initializing krb5");
+ 		exit(1);
+ 	}
+ 	PRS(argc, argv);
+ 
+ #ifdef POSIX_SIGNALS
+ #error "Not coded to use POSIX signals..."
+ #else
+ 	(void) signal(SIGUSR1, signalGetStatus);
+ #endif
+ 
+ #if defined(UMICH_REPLICATION)
+ 	
+ 	if (!nofork)
+ 		daemon(0, 0);
+ 	
+ 	/*
+ 	 * If realm was not specified, get our default realm
+ 	 */
+ 	if (!realm) {
+ 		if ((retval = krb5_get_default_realm(main_context, &realm))) {
+ 			com_err(progname, retval,
+ 				"obtaining realm name");
+ 			exit(1);
+ 		}
+ 	}
+ 	if ((my_realm.data = (char *) malloc(strlen(realm)+1)) == (char *) NULL)
+ 	{
+ 		com_err(progname, ENOMEM,
+ 			"allocating memory for realm information");
+ 		exit(1);
+ 	}
+ 	my_realm.magic = KV5M_DATA;
+ 	my_realm.length = strlen(realm);
+ 	strcpy(my_realm.data, realm);
+ 	
+ 	/*
+ 	 * Get a list of the slave servers for the specified
+ 	 * realm (leaving ourself off the list)
+ 	 */
+ 	if (retval = krb5_getslavelist(main_context, &my_realm,
+ 				   &slave_hosts, &num_hosts)) {
+ 		com_err(progname, retval,
+ 			"%s while getting list of slave KDCs", realm);
+ 		exit(1);
+ 	}
+ 
+ 	if (num_hosts > 0)
+ 	{
+ 		/*
+ 		 * Allocate memory for information about each slave server
+ 		 * for use by the thread that will get started for each slave
+ 		 */
+ 		if ((slave_info =
+ 				(slave_data *)malloc(sizeof(slave_data) * num_hosts)) == NULL) {
+ 			com_err(progname, ENOMEM,
+ 				"allocating memory for thread information");
+ 			exit(1);
+ 		}
+ 		memset(slave_info, '\0', sizeof(slave_data) * num_hosts);
+ 	}
+ 
+ 	/*
+ 	 * Initialize and lock a mutex to protect the slave information
+ 	 */
+ 	if (rc = pthread_mutex_init(&repl_stateMutex, pthread_mutexattr_default))
+ 	{
+ 		com_err(progname, errno, "Error %d initializing file mutex", rc);
+ 		exit(1);
+ 	}
+ 
+ 	if (rc = pthread_mutex_lock(&repl_stateMutex))
+ 	{
+ 		com_err(progname, errno,
+ 			"Error %d locking mutex before threads are started!",
+ 			rc);
+ 		exit(1);
+ 	}
+ 
+ 	/*
+ 	 * Initialize and lock a mutex to serialize use of the kerberos library
+ 	 */
+ 	if (rc = pthread_mutex_init(&repl_kerblibMutex, pthread_mutexattr_default))
+ 	{
+ 		com_err(progname, errno, "Error %d initializing kerberos library mutex", rc);
+ 		exit(1);
+ 	}
+ 	if (rc = pthread_mutex_lock(&repl_kerblibMutex))
+ 	{
+ 		com_err(progname, errno,
+ 			"Error %d locking kerberos library mutex while starting threads!",
+ 			rc);
+ 		exit(1);
+ 	}
+ 
+ 	/*
+ 	 * Start a thread to handle updates for each slave
+ 	 */
+ 	for (i = 0; i < num_hosts ; i++)
+ 	{
+ 		krb5_error_code retval;
+ 
+ 		/* Create a separate context for each thread */
+ 		retval = krb5_init_context(&slave_info[i].sl_context);
+ 		if (retval) {
+ 			com_err(argv[0], retval, "while initializing krb5 for thread (%s)",
+ 				slave_hosts[i]);
+ 			exit(1);
+ 		}
+ 		get_tickets(slave_info[i].sl_context, slave_hosts[i], &slave_info[i]);
+ 
+ 		slave_info[i].sl_socket = -1;		/* disconnected */
+ 		slave_info[i].sl_replfile = file;
+ 		slave_info[i].sl_stateUpdateMutex = &repl_stateMutex;
+ 		slave_info[i].sl_kerberosLibMutex = &repl_kerblibMutex;
+ 		slave_info[i].sl_truncationCount = &truncation_count;
+ 		slave_info[i].sl_sleeptime = slaveThreadCheckTime;
+ 		if (!(slave_info[i].sl_hostname = (char *) malloc(50))) {
+ 			com_err(progname, errno, "Allocating storage for slave hostname (%s)",
+ 				slave_hosts[i]);
+ 			exit(1);
+ 		}
+ 		sprintf(slave_info[i].sl_hostname, "%s", slave_hosts[i]);
+ 		if (debug)
+ 			com_err(progname, 0,
+ 				"Creating thread #%d (%s)", i, slave_hosts[i]);
+ 		if (rc = pthread_create(&slave_info[i].sl_id,
+ 					 pthread_attr_default,
+ 					 replication_thread_routine,
+ 					 (void *)(&slave_info[i]) ))
+ 		{
+ 			com_err(progname, errno,
+ 				"error %d creating slave service thread (%s)...",
+ 				rc, slave_info[i].sl_hostname );
+ 			exit(1);
+ 		}
+ 	}
+ 
+ 	/* Release lock serializing kerberos library use */
+ 	if (rc = pthread_mutex_unlock(&repl_kerblibMutex))
+ 	{
+ 		com_err(progname, errno,
+ 			"Error %d unlocking kerberos library mutex while starting threads!",
+ 			rc);
+ 		exit(1);
+ 	}
+ 
+ 	/*
+ 	 * Start an extra thread to handle truncation of the
+ 	 * delta file.
+ 	 */
+ 	t_thread.tr_replfile = file;
+ 	t_thread.tr_stateUpdateMutex = &repl_stateMutex;
+ 	t_thread.tr_numSlaves = num_hosts;
+ 	t_thread.tr_slaves = slave_info;
+ 	t_thread.tr_truncationCount = &truncation_count;
+ 	t_thread.tr_sleeptime = truncThreadCheckTime;
+ 	if (rc = pthread_create(&t_thread.tr_id,
+ 				pthread_attr_default,
+ 				truncation_thread_routine,
+ 				(void *)(&t_thread) ))
+ 	{
+ 		com_err(progname, errno,
+ 			"error %d creating truncation service thread...",
+ 			rc);
+ 		exit(1);
+ 	}
+ 
+ 	/*
+ 	 * Set up to watch for any update thread terminating and attempt
+ 	 * to restart it...
+ 	 */
+ 
+ 	/* BUT FOR NOW ... just wait forever */
+ 	if (debug)
+ 		com_err(progname, 0,
+ 			"Main is waiting 5 seconds before unlocking mutex");
+ 	sleep(5);
+ 
+ 	if (rc = pthread_mutex_unlock(&repl_stateMutex))
+ 	{
+ 		com_err(progname, errno,
+ 			"Error %d unlocking mutex before sleeping", rc);
+ 		exit(1);
+ 	}
+ 	if (debug)
+ 		com_err(progname, 0,
+ 			"Main is now going into infinite wait after unlocking mutex");
+ 
+ 	for (;;)
+ 	{
+ 		sleep(10000);
+ 	}
+ 	
+ 	com_err(progname, 0, "Main thread returned from infinite sleep??");
+ 	exit(0);
+ }
+ 
+ /*
+  * redirects com_err messages to syslog when not in debug mode
+  */
+ static void
+ krep_com_err_proc(whoami, code, fmt, args)
+ 	const char	*whoami;
+ 	long		code;
+ 	const char	*fmt;
+ 	va_list		args;
+ {
+ 	char		error_buf[8096];
+ 
+ 	error_buf[0] = '\0';
+ 	if (fmt)
+ 		vsprintf(error_buf, fmt, args);
+ 	syslog(LOG_ERR, "%s%s%s%s%s", whoami ? whoami : "", whoami ? ": " : "",
+ 			code ? error_message(code) : "", code ? " " : "", error_buf);
+ }
+ 
+ #endif	/* UMICH_REPLICATION */
+ 
+ void PRS(argc, argv)
+ 	int	argc;
+ 	char	**argv;
+ {
+ 	register char	*word, ch;
+ 	
+ 	progname = *argv++;
+ 	while (--argc && (word = *argv++)) {
+ 		if (*word == '-') {
+ 			word++;
+ 			while (word && (ch = *word++)) {
+ 				switch(ch){
+ 				case 'r':
+ 					if (*word)
+ 						realm = word;
+ 					else
+ 						realm = *argv++;
+ 					if (!realm)
+ 						usage();
+ 					word = 0;
+ 					break;
+ 				case 'f':
+ 					if (*word)
+ 						file = word;
+ 					else
+ 						file = *argv++;
+ 					if (!file)
+ 						usage();
+ 					word = 0;
+ 					break;
+ 				case 'd':
+ 					debug++;
+ 					break;
+ 				case 'P':
+ 					if (*word)
+ 						port = htons(atoi(word));
+ 					else
+ 						port = htons(atoi(*argv++));
+ 					if (!port)
+ 						usage();
+ 					word = 0;
+ 					break;
+ 				case 's':
+ 					if (*word)
+ 						srvtab = word;
+ 					else
+ 						srvtab = *argv++;
+ 					if (!srvtab)
+ 						usage();
+ 					word = 0;
+ 					break;
+ #if defined(UMICH_REPLICATION)
+ 				case 'n':
+ 					nofork++;
+ 					break;
+ 				case 'q':
+ 					verbose = 0;
+ 					break;
+ 				case 'S':
+ 					if (*word)
+ 						slaveThreadCheckTime = atoi(word);
+ 					else
+ 						slaveThreadCheckTime = atoi(*argv++);
+ 					if (!slaveThreadCheckTime)
+ 						usage();
+ 					word = 0;
+ 					break;
+ 				case 'T':
+ 					if (*word)
+ 						truncThreadCheckTime = atoi(word);
+ 					else
+ 						truncThreadCheckTime = atoi(*argv++);
+ 					if (!truncThreadCheckTime)
+ 						usage();
+ 					word = 0;
+ 					break;
+ #endif	/* UMICH_REPLICATION */
+ 				default:
+ 					usage();
+ 				}
+ 				
+ 			}
+ 		} else {
+ 			usage();
+ 		}
+ 	}
+ #if defined(UMICH_REPLICATION)
+ 	/*
+ 	 * If not is debug mode, switch com_err reporting to syslog
+ 	 */
+ 	if (! debug) {
+ 		openlog("krep", LOG_PID | LOG_ODELAY, SYSLOG_CLASS);
+ 		set_com_err_hook(krep_com_err_proc);
+ 	}
+ #endif	/* UMICH_REPLICATION */
+ }
+ 
+ void get_tickets(context, slave_host, tt)
+ 	krb5_context context;
+ 	char *slave_host;
+ 	slave_data *tt;
+ {
+ 	char   my_host_name[MAXHOSTNAMELEN];
+ 	char   buf[BUFSIZ];
+ 	char   *cp;
+ 	struct hostent *hp;
+ 	krb5_error_code retval;
+ 	static char tkstring[] = "/tmp/kreptktXXXXXX";
+ 	krb5_keytab keytab = NULL;
+ 
+ 	/*
+ 	 * Figure out what tickets we'll be using to send stuff
+ 	 */
+ 	retval = krb5_sname_to_principal(context, NULL, NULL,
+ 					 KRB5_NT_SRV_HST, &my_principal);
+ 	if (retval) {
+ 		com_err(progname, errno, "while setting client principal name (%s)", slave_host);
+ 		exit(1);
+ 	}
+ 	if (realm) {
+ 		(void) krb5_xfree(krb5_princ_realm(context, my_principal)->data);
+ 		krb5_princ_set_realm_length(context, my_principal, strlen(realm));
+ 		krb5_princ_set_realm_data(context, my_principal, strdup(realm));
+ 	}
+ 
+ 	/*
+ 	 * Initialize cache file which we're going to be using
+ 	 */
+ 	(void) mktemp(tkstring);
+ 	sprintf(buf, "FILE:%s", tkstring);
+ 	if (debug)
+ 		com_err(progname, 0, "%s: Using credentials cache file %s",
+ 			slave_host, buf);
+ 	if (retval = krb5_cc_resolve(context, buf, &tt->sl_ccache)) {
+ 		com_err(progname, retval, "while opening credential cache %s for %s",
+ 			buf, slave_host);
+ 		exit(1);
+ 	}
+ 	if (retval = krb5_cc_initialize(context, tt->sl_ccache, my_principal)) {
+ 		com_err (progname, retval, "when initializing cache %s for %s",
+ 			 buf, slave_host);
+ 		exit(1);
+ 	}
+ 
+ 	/*
+ 	 * Get the tickets we'll need.
+ 	 *
+ 	 * Construct the principal name for the slave host.
+ 	 */
+ 	memset((char *)&tt->sl_creds, 0, sizeof(tt->sl_creds));
+ 	retval = krb5_sname_to_principal(context,
+ 					 slave_host, KREP_SERVICE_NAME,
+ 					 KRB5_NT_SRV_HST, &tt->sl_creds.server);
+ 	if (retval) {
+ 		com_err(progname, errno, "while setting server principal name for %s", slave_host);
+ 		(void) krb5_cc_destroy(context, tt->sl_ccache);
+ 		exit(1);
+ 	}
+ 	if (realm) {
+ 		(void) krb5_xfree(krb5_princ_realm(context, tt->sl_creds.server)->data);
+ 		krb5_princ_set_realm_length(context, tt->sl_creds.server, strlen(realm));
+ 		krb5_princ_set_realm_data(context, tt->sl_creds.server, strdup(realm));
+ 	}
+ 
+ 	/*
+ 	 * Now fill in the client....
+ 	 */
+ 	if (retval = krb5_copy_principal(context, my_principal, &tt->sl_creds.client)) {
+ 		com_err(progname, retval, "While copying client principal for %s", slave_host);
+ 		(void) krb5_cc_destroy(context, tt->sl_ccache);
+ 		exit(1);
+ 	}
+ 	if (srvtab) {
+ 		if (retval = krb5_kt_resolve(context, srvtab, &keytab)) {
+ 			com_err(progname, retval, "while resolving keytab for %s", slave_host);
+ 			(void) krb5_cc_destroy(context, tt->sl_ccache);
+ 			exit(1);
+ 		}
+ 	}
+ 
+ 	retval = krb5_get_in_tkt_with_keytab(context, 0, 0, NULL,
+ 						 NULL, keytab, tt->sl_ccache, &tt->sl_creds, 0);
+ 	if (retval) {
+ 		com_err(progname, retval, "while getting initial ticket for %s", slave_host);
+ 		(void) krb5_cc_destroy(context, tt->sl_ccache);
+ 		exit(1);
+ 	}
+ 
+ 	if (keytab)
+ 		(void) krb5_kt_close(context, keytab);
+ 	
+ 	/*
+ 	 * Now destroy the cache right away --- the credentials we
+ 	 * need will be in tt->sl_creds.
+ 	 */
+ 	if (retval = krb5_cc_destroy(context, tt->sl_ccache)) {
+ 		com_err(progname, retval, "while destroying ticket cache for %s", slave_host);
+ 		exit(1);
+ 	}
+ }
+ 
+ krb5_error_code
+ open_connection(host, fd, Errmsg)
+ 	char	*host;
+ 	int	*fd;
+ 	char	*Errmsg;
+ {
+ 	int	s;
+ 	krb5_error_code	retval;
+ 	
+ 	struct hostent	*hp;
+ 	struct hostent	myhostent;
+ 	struct servent	*sp;
+ 	struct servent	myservent;
+ 	struct sockaddr_in sin;
+ 	size_t		socket_length;
+ 
+ #if defined(__aix42)
+ 	struct hostent_data myhostent_data;
+ 	struct servent_data myservent_data;
+ #endif	/* __aix42 */
+ 
+ #if defined(__aix42)
+ 	memset((void *)&myhostent_data, '\0', sizeof(struct hostent_data));
+ 	if (0 == gethostbyname_r(host, &myhostent, &myhostent_data))
+ 		hp = &myhostent;
+ 	else
+ 		hp = NULL;
+ #else	/* __aix42 */
+ 	hp = gethostbyname(host);
+ #endif	/* __aix42 */
+ 	if (hp == NULL) {
+ 		(void) sprintf(Errmsg, "%s: unknown host", host);
+ 		*fd = -1;
+ 		return(0);
+ 	}
+ 	sin.sin_family = hp->h_addrtype;
+ 	memcpy((char *)&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+ 	if(!port) {
+ #if defined(__aix42)
+ 		memset((void *)&myservent_data, '\0', sizeof(struct servent_data));
+ 		if (0 == getservbyname_r(KREP_SERVICE, "tcp",
+ 					 &myservent, &myservent_data))
+ 			sp = &myservent;
+ 		else
+ 			sp = 0;
+ #else	/* __aix42 */
+ 		sp = getservbyname(KREP_SERVICE, "tcp");
+ #endif	/* __aix42 */
+ 		if (sp == 0) {
+ 			(void) strcpy(Errmsg, KREP_SERVICE);
+ 			(void) strcat(Errmsg, "/tcp: unknown service");
+ 			*fd = -1;
+ 			return(0);
+ 		}
+ 		sin.sin_port = sp->s_port;
+ 	} else
+ 		sin.sin_port = port;
+ 	s = socket(AF_INET, SOCK_STREAM, 0);
+ 	
+ 	if (s < 0) {
+ 		(void) sprintf(Errmsg, "in call to socket");
+ 		return(errno);
+ 	}
+ 	if (connect(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
+ 		retval = errno;
+ 		close(s);
+ 		(void) sprintf(Errmsg, "in call to connect");
+ 		return(retval);
+ 	}
+ 	*fd = s;
+ 
+ 	/*
+ 	 * Set receiver_addr and sender_addr.
+ 	 */
+ 	receiver_addr.addrtype = ADDRTYPE_INET;
+ 	receiver_addr.length = sizeof(sin.sin_addr);
+ 	receiver_addr.contents = (krb5_octet *) malloc(sizeof(sin.sin_addr));
+ 	memcpy((char *) receiver_addr.contents, (char *) &sin.sin_addr,
+ 		   sizeof(sin.sin_addr));
+ 
+ 	socket_length = sizeof(sin);
+ 	if (getsockname(s, (struct sockaddr *)&sin, &socket_length) < 0) {
+ 		retval = errno;
+ 		close(s);
+ 		(void) sprintf(Errmsg, "in call to getsockname");
+ 		return(retval);
+ 	}
+ 	sender_addr.addrtype = ADDRTYPE_INET;
+ 	sender_addr.length = sizeof(sin.sin_addr);
+ 	sender_addr.contents = (krb5_octet *) malloc(sizeof(sin.sin_addr));
+ 	memcpy((char *) sender_addr.contents, (char *) &sin.sin_addr,
+ 		   sizeof(sin.sin_addr));
+ 
+ 	return(0);
+ }
+ 
+ int
+ kerberos_authenticate(context, auth_context, fd, me, new_creds, tt)
+ 	krb5_context context;
+ 	krb5_auth_context *auth_context;
+ 	int	fd;
+ 	krb5_principal me;
+ 	krb5_creds ** new_creds;
+ 	slave_data *tt;
+ {
+ 	krb5_error_code	retval;
+ 	krb5_error	*error = NULL;
+ 	krb5_ap_rep_enc_part	*rep_result;
+ 	int retcode = 0;
+ 	int rc;
+ 
+ 	/* Obtain state update lock */
+ 	if (rc = pthread_mutex_lock(tt->sl_kerberosLibMutex))
+ 	{
+ 		com_err(progname, errno, "%s: failed to obtain kerberos library mutex (%d)",
+ 			tt->sl_hostname, rc);
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	if (retval = krb5_auth_con_init(context, auth_context))
+ 	{
+ 		retcode = 1;
+ 		goto auth_return;
+ 	}
+ 
+ 	krb5_auth_con_setflags(context, *auth_context, 
+ 			   KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+ 
+ 	if (retval = krb5_auth_con_setaddrs(context, *auth_context, &sender_addr,
+ 						&receiver_addr)) {
+ 		com_err(progname, retval, "in krb5_auth_con_setaddrs (%s)", tt->sl_hostname);
+ 		retcode = 1;
+ 		goto auth_return;
+ 	}
+ 
+ 	if (retval = krb5_sendauth(context, auth_context, (void *)&fd, 
+ 				   krep_version, me, tt->sl_creds.server,
+ 				   AP_OPTS_MUTUAL_REQUIRED, NULL, &tt->sl_creds, NULL,
+ 				   &error, &rep_result, new_creds)) {
+ 		com_err(progname, retval, "while authenticating to server (%s)", tt->sl_hostname);
+ 		if (error) {
+ 			if (error->error == KRB_ERR_GENERIC) {
+ 				if (error->text.data)
+ 					com_err(progname, errno,
+ 						"Generic remote error: %s (%s)",
+ 						error->text.data, tt->sl_hostname);
+ 			} else if (error->error) {
+ 				com_err(progname,
+ 					error->error + ERROR_TABLE_BASE_krb5,
+ 					"signalled from server (%s)", tt->sl_hostname);
+ 				if (error->text.data)
+ 					com_err(progname, errno,
+ 						"Error text from server: %s (%s)",
+ 						error->text.data, tt->sl_hostname);
+ 			}
+ 			krb5_free_error(context, error);
+ 		}
+ 		retcode = 1;
+ 	}
+ 	else
+ 	{
+ 		krb5_free_ap_rep_enc_part(context, rep_result);
+ 		retcode = 0;
+ 	}
+ 
+ auth_return:
+ 	/* Release state update lock */
+ 	if (rc = pthread_mutex_unlock(tt->sl_kerberosLibMutex))
+ 	{
+ 		com_err(progname, errno, "%s: failed to obtain kerberos library mutex (%d)",
+ 			tt->sl_hostname, rc);
+ 		pthread_exit((void *) 1);
+ 	}
+ 	return retcode;
+ }
+ 
+ /*
+  * Send over the database information.  We use a similar protocol
+  * to the one used by kprop:
+  *	-	Send a KRB_SAFE message containing the size of the data.
+  *	-	Then send the message, encrypted using KRB_PRIV.
+  *	-	Then we wait for a KRB_SAFE message with the size that the other
+  *			side received and saved.
+  * 
+  * At any point in the protocol, we may send a KRB_ERROR message; this
+  * will abort the entire operation.
+  */
+ int
+ xmit_dbinfo(context, auth_context, my_creds, fd, msg_buff, msg_size, slaveName)
+ 	krb5_context context;
+ 	krb5_auth_context auth_context;
+ 	krb5_creds *my_creds;
+ 	int	fd;
+ 	char	*msg_buff;
+ 	int	msg_size;
+ 	char	*slaveName;
+ {
+ 	krb5_int32	send_size, sent_size, n;
+ 	krb5_data	inbuf, outbuf;
+ 	char		buf[KREP_BUFSIZ];
+ 	krb5_error_code	retval;
+ 	krb5_error	*error;
+ 	
+ 	/*
+ 	 * Send over the size
+ 	 */
+ 
+ 	send_size = htonl(msg_size);
+ 	inbuf.data = (char *) &send_size;
+ 	inbuf.length = sizeof(send_size); /* must be 4, really */
+ 	/* KREP_CKSUMTYPE */
+ 	if (retval = krb5_mk_safe(context, auth_context, &inbuf, 
+ 				  &outbuf, NULL)) {
+ 		com_err(progname, retval, "while encoding message size (%s)", slaveName);
+ 		send_error(context, my_creds, fd,
+ 					"while encoding message size", retval);
+ 		return 1;
+ 	}
+ 	if (retval = krb5_write_message(context, (void *) &fd, &outbuf)) {
+ 		krb5_xfree(outbuf.data);
+ 		com_err(progname, retval, "while sending message size (%s)", slaveName);
+ 		return 1;
+ 	}
+ 	krb5_xfree(outbuf.data);
+ 
+ 	/*
+ 	 * Send over the message....
+ 	 */
+ 
+ 	inbuf.data = msg_buff;
+ 	inbuf.length = msg_size;;
+ 	if (retval = krb5_mk_priv(context, auth_context, &inbuf,
+ 				  &outbuf, NULL)) {
+ 		com_err(progname, retval, "while encoding message block (%s)", slaveName);
+ 		send_error(context, my_creds, fd, buf, retval);
+ 		return 1;
+ 	}
+ 	if (retval = krb5_write_message(context, (void *)&fd,&outbuf)) {
+ 		krb5_xfree(outbuf.data);
+ 		com_err(progname, retval, "while sending message block (%s)", slaveName);
+ 		return 1;
+ 	}
+ 	krb5_xfree(outbuf.data);
+ 
+ 	/*
+ 	 * OK, we've sent the message; now let's wait for a success
+ 	 * indication from the remote end.
+ 	 */
+ 
+ 	if (retval = krb5_read_message(context, (void *) &fd, &inbuf)) {
+ 		com_err(progname, retval,
+ 			"while reading response from server (%s)", slaveName);
+ 		return 1;
+ 	}
+ 
+ 	/*
+ 	 * If we got an error response back from the server, display
+ 	 * the error message
+ 	 */
+ 
+ 	if (krb5_is_krb_error(&inbuf)) {
+ 		if (retval = krb5_rd_error(context, &inbuf, &error)) {
+ 			com_err(progname, retval,
+ 				"while decoding error response from server (%s)", slaveName);
+ 			return 1;
+ 		}
+ 		if (error->error == KRB_ERR_GENERIC) {
+ 			if (error->text.data)
+ 				com_err(progname, errno,
+ 					"Generic remote error: %s (%s)",
+ 					error->text.data, slaveName);
+ 		} else if (error->error) {
+ 			com_err(progname, error->error + ERROR_TABLE_BASE_krb5,
+ 				"signalled from server (%s)", slaveName);
+ 			if (error->text.data)
+ 				com_err(progname, errno,
+ 					"Error text from server: %s (%s)",
+ 					error->text.data, slaveName);
+ 		}
+ 		krb5_free_error(context, error);
+ 		return 1;
+ 	}
+ 
+ 	/*
+ 	 * krepd returns the size of the message that we sent as an
+ 	 * acknowlegment.  If we get back the correct size, that means
+ 	 * that we successfully got the data to the slave and it was
+ 	 * saved to disk there.  The slave is then responsible for
+ 	 * applying the change to the database.
+ 	 */
+ 	if (retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL)) {
+ 		com_err(progname, retval,
+ 			"while decoding final size packet from server (%s)", slaveName);
+ 		krb5_xfree(inbuf.data);
+ 		return 1;
+ 	}
+ 	memcpy((char *)&send_size, outbuf.data, sizeof(send_size));
+ 	send_size = ntohl(send_size);
+ 	if (send_size != msg_size) {
+ 		com_err(progname, 0,
+ 			"Krepd sent message size %d, expecting %d (%s)",
+ 			send_size, msg_size, slaveName);
+ 		krb5_xfree(inbuf.data);
+ 		krb5_xfree(outbuf.data);
+ 		return 1;
+ 	}
+ 	
+ 	krb5_xfree(inbuf.data);
+ 	krb5_xfree(outbuf.data);
+ 	return 0;
+ }
+ 
+ void
+ send_error(context, my_creds, fd, err_text, err_code)
+ 	krb5_context	context;
+ 	krb5_creds	*my_creds;
+ 	int		fd;
+ 	char		*err_text;
+ 	krb5_error_code	err_code;
+ {
+ 	krb5_error	error;
+ 	const char	*text;
+ 	krb5_data	outbuf;
+ 
+ 	memset((char *)&error, 0, sizeof(error));
+ 	krb5_us_timeofday(context, &error.ctime, &error.cusec);
+ 	error.server = my_creds->server;
+ 	error.client = my_principal;
+ 	error.error = err_code - ERROR_TABLE_BASE_krb5;
+ 	if (error.error > 127)
+ 		error.error = KRB_ERR_GENERIC;
+ 	if (err_text)
+ 		text = err_text;
+ 	else
+ 		text = error_message(err_code);
+ 	error.text.length = strlen(text) + 1;
+ 	if (error.text.data = malloc(error.text.length)) {
+ 		strcpy(error.text.data, text);
+ 		if (!krb5_mk_error(context, &error, &outbuf)) {
+ 			(void) krb5_write_message(context, (void *)&fd,&outbuf);
+ 			krb5_xfree(outbuf.data);
+ 		}
+ 		free(error.text.data);
+ 	}
+ }
+ 
Index: krb5-1.0.5UM/src/replication/krep.h
diff -c /dev/null krb5-1.0.5UM/src/replication/krep.h:1.3
*** /dev/null	Thu Sep 16 18:06:36 1999
--- krb5-1.0.5UM/src/replication/krep.h	Mon Jul 27 11:36:41 1998
***************
*** 0 ****
--- 1,125 ----
+ #ifndef _KREP_H_
+ #define _KREP_H_
+ /*
+  * slave/kprop.h
+  *
+  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+  * All Rights Reserved.
+  *
+  * Export of this software from the United States of America may
+  *   require a specific license from the United States Government.
+  *   It is the responsibility of any person or organization contemplating
+  *   export to obtain such a license before exporting.
+  * 
+  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+  * distribute this software and its documentation for any purpose and
+  * without fee is hereby granted, provided that the above copyright
+  * notice appear in all copies and that both that copyright notice and
+  * this permission notice appear in supporting documentation, and that
+  * the name of M.I.T. not be used in advertising or publicity pertaining
+  * to distribution of the software without specific, written prior
+  * permission.  M.I.T. makes no representations about the suitability of
+  * this software for any purpose.  It is provided "as is" without express
+  * or implied warranty.
+  * 
+  *
+  */
+ 
+ /*
+  *  COPYRIGHT    1998
+  *  THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+  *  ALL RIGHTS RESERVED
+  *
+  *  PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+  *  AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+  *  FOR ANY PURPOSE, SO LONG AS NO FEE IS CHARGED, AND SO LONG
+  *  AS THE COPYRIGHT NOTICE ABOVE, THIS GRANT OF PERMISSION,
+  *  AND THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND SO
+  *  LONG AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED
+  *  IN ANY ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR
+  *  DISTRIBUTION OF THIS SOFTWARE WITHOUT SPECIFIC, WRITTEN
+  *  PRIOR AUTHORIZATION.
+  *
+  *  THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+  *  FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+  *  PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+  *  MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+  *  WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+  *  REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+  *  FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+  *  CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+  *  OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+  *  IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+  *  SUCH DAMAGES.
+  */
+ 
+ #define KREP_SERVICE_NAME "host"
+ #define TGT_SERVICE_NAME "krbtgt"
+ #define KREP_SERVICE "krb5_rep"
+ #define KREP_CKSUMTYPE CKSUMTYPE_RSA_MD4_DES
+ 
+ #define KREP_PROT_VERSION "krep5_00"
+ 
+ #define KREP_BUFSIZ 32768
+ 
+ /* Definitions for state information */
+ #define REPL_STATE_IDLE         0x00000001
+ #define REPL_STATE_PROCESSING   0x00000002
+ 
+ /* pathnames are in osconf.h, included via k5-int.h */
+ 
+ /*
+  * This is thread-specific stuff used by the worker threads
+  */
+ typedef struct slave_data {
+     pthread_t   sl_id;              /* thread ID for this thread */
+     char        *sl_hostname;       /* slave hostname this thread services */
+     char        *sl_replfile;       /* name of the delta dump file */
+     pthread_mutex_t     *sl_kerberosLibMutex;   /* pointer to mutex protecting
+                                                    use of kerberos libraries */
+     krb5_context sl_context;        /* context */
+     krb5_creds	sl_creds;           /* credentials with the remote machine */
+     krb5_ccache	sl_ccache;          /* cred cache with the remote machine */
+     pthread_mutex_t     *sl_stateUpdateMutex;   /* pointer to mutex protecting
+                                                    these entries */
+     int         sl_fd;              /* file descriptor for delta dump file */
+     FILE        *sl_file;           /* file ptr for delta dump file */
+     fpos_t      sl_lastPosition;    /* file pos when last stopped processing */
+     int         sl_socket;          /* socket fd connected to slave */
+     int         sl_lastTruncation;  /* last truncation "version" number we know about */
+     int         sl_currentState;    /* processing state (idle or processing) */
+     int         sl_sleeptime;       /* number of secs to sleep while idle */
+     struct stat sl_statinfo;        /* latest file stat info for this thread */
+     int         *sl_truncationCount;    /* latest truncation "version" number */
+ } slave_data;
+ 
+ typedef struct trunc_info {
+     pthread_t   tr_id;              /* thread ID for this thread */
+     char        *tr_replfile;       /* name of the delta dump file */
+     int         tr_fd;              /* file descriptor for delta dump file */
+     FILE        *tr_file;           /* file ptr for delta dump file */
+     int         tr_numSlaves;       /* the number of slave threads to monitor */
+     slave_data  *tr_slaves;         /* pointer to slave data info */
+     int         tr_sleeptime;       /* number of secs between checks */
+     pthread_mutex_t     *tr_stateUpdateMutex;   /* pointer to mutex protecting
+ 						   these entries */
+     struct stat tr_statinfo;        /* latest file stat info */
+     int         *tr_truncationCount;    /* latest trunction "version" number */
+ } trunc_info;
+ 
+ 
+ 
+ /*
+  * The following allow for use of either
+  * "real" POSIX threads or CMA/DCE threads
+  */
+ 
+ #if !defined(_DECTHREADS_)
+ #define pthread_mutexattr_default NULL
+ #define pthread_attr_default      NULL
+ #define pthread_condattr_default  NULL
+ #define pthread_addr_t            void *
+ #endif  /* _DECTHREADS_ */
+ 
+ #endif	/* _KREP_H_ */
Index: krb5-1.0.5UM/src/replication/krepd.M
diff -c /dev/null krb5-1.0.5UM/src/replication/krepd.M:1.2
*** /dev/null	Thu Sep 16 18:06:36 1999
--- krb5-1.0.5UM/src/replication/krepd.M	Mon Apr 27 07:58:16 1998
***************
*** 0 ****
--- 1,158 ----
+ .\" replication/krepd.M
+ .\"
+ .\" Copyright 1992 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.
+ .\" 
+ .\" COPYRIGHT    1998
+ .\" THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ .\" ALL RIGHTS RESERVED
+ .\"
+ .\" PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+ .\" AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+ .\" FOR ANY PURPOSE, SO LONG AS NO FEE IS CHARGED, AND SO LONG
+ .\" AS THE COPYRIGHT NOTICE ABOVE, THIS GRANT OF PERMISSION,
+ .\" AND THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND SO
+ .\" LONG AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED
+ .\" IN ANY ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR
+ .\" DISTRIBUTION OF THIS SOFTWARE WITHOUT SPECIFIC, WRITTEN
+ .\" PRIOR AUTHORIZATION.
+ .\"
+ .\" THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ .\" FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ .\" PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ .\" MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ .\" WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ .\" REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ .\" FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ .\" CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ .\" OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ .\" IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ .\" SUCH DAMAGES.
+ .\"
+ .TH KREPD 8
+ .SH NAME
+ krepd \- Kerberos V5 slave KDC replication server
+ .SH SYNOPSIS
+ .B krep
+ [
+ .B \-r
+ .I realm
+ ] [
+ .B \-f
+ .I slave_delta_file
+ ] [
+ .B \-F
+ .I principal_database
+ ] [
+ .B \-s
+ .I keytab
+ ] [
+ .B \-a
+ .I acl_file_name
+ ] [
+ .B \-d
+ ] [
+ .B \-S
+ ] [
+ .B \-P
+ .I port
+ ]
+ .br
+ .SH DESCRIPTION
+ .I krepd 
+ is the server which accepts connections from the 
+ .IR krep (8)
+ program.  
+ .I krepd 
+ accepts the dumped KDC database records and applies the changes to the
+ database used by
+ .IR krb5kdc (8).
+ Thus, the master Kerberos server can use 
+ .IR krep (8)
+ to replicate its database to the slave slavers.  Upon a successful
+ application of the changes, the slave Kerberos server will have an
+ up-to-date KDC database. 
+ .PP
+ Normally, krepd is invoked out of 
+ .I inetd(8).  
+ This is done by adding a line to the inetd.conf file which looks like
+ this:
+ 
+ krep	stream	tcp	nowait	root	/usr/local/sbin/krepd	krepd
+ 
+ However, krepd can also run as a standalone deamon, if the
+ .B \-S
+ option is turned on.  This is done for debugging purposes.
+ .SH OPTIONS
+ .TP
+ \fB\-r\fP \fIrealm\fP
+ specifies the realm of the master server; by default the realm returned
+ by
+ .IR krb5_default_local_realm (3)
+ is used.
+ .TP
+ \fB\-f\fP \fIfile\fP
+ specifies the filename where the dumped principal database records are
+ to be stored before being applied to the database;
+ by default this file is KREPD_DEFAULT_FILE
+ (normally /usr/local/var/krb5kdc/slave_delta).
+ .TP
+ \fB\-F\fP \fIprincipal_database\fP
+ specifies an alternate name for the principal database used by
+ .IR krb5kdc (8).
+ .TP
+ .B \-S
+ turn on standalone mode.  Normally, krepd is invoked out of
+ .IR inetd (8)
+ so it expects a network connection to be passed to it from
+ .I inetd (8).
+ If the 
+ .B \-S 
+ option is specified, krepd will put itself into the background, and
+ wait for connections to the KREP_SERVICE port (normally krb5_rep).
+ .TP
+ .B \-d
+ turn on debug mode.  In this mode, if the
+ .B \-S 
+ option is selected, 
+ .I krepd
+ will not detach itself from the current job and run in the background.
+ Instead, it will run in the foreground and print out debugging messages
+ during the database replication.
+ .TP
+ .B \-P
+ allow for an alternate port number for
+ .I krepd
+ to listen on. This is only useful if the program is run in standalone
+ mode.
+ .TP
+ \fB\-a\fP \fIacl_file_name\fP
+ specifies an alternate acl file name
+ .TP
+ \fB\-s\fP \fIkeytab\fP
+ specifies the location of the keytab file.
+ .SH FILES
+ .TP "\w'kpropd.acl\ \ 'u"
+ kpropd.acl
+ Access file for
+ .BR krepd .
+ Each entry is a line containing the principal of a host from which the
+ local machine will allow Kerberos database replication via krep.
+ .SH SEE ALSO
+ krep(8), krb5kdc(8), inetd(8)
Index: krb5-1.0.5UM/src/replication/krepd.c
diff -c /dev/null krb5-1.0.5UM/src/replication/krepd.c:1.8
*** /dev/null	Thu Sep 16 18:06:36 1999
--- krb5-1.0.5UM/src/replication/krepd.c	Tue Dec 22 16:46:19 1998
***************
*** 0 ****
--- 1,1299 ----
+ /*
+  * slave/krepd.c
+  *
+  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+  * All Rights Reserved.
+  *
+  * Export of this software from the United States of America may
+  *   require a specific license from the United States Government.
+  *   It is the responsibility of any person or organization contemplating
+  *   export to obtain such a license before exporting.
+  * 
+  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+  * distribute this software and its documentation for any purpose and
+  * without fee is hereby granted, provided that the above copyright
+  * notice appear in all copies and that both that copyright notice and
+  * this permission notice appear in supporting documentation, and that
+  * the name of M.I.T. not be used in advertising or publicity pertaining
+  * to distribution of the software without specific, written prior
+  * permission.  M.I.T. makes no representations about the suitability of
+  * this software for any purpose.  It is provided "as is" without express
+  * or implied warranty.
+  * 
+  */
+ /*
+  *  COPYRIGHT    1998
+  *  THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+  *  ALL RIGHTS RESERVED
+  *
+  *  PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+  *  AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+  *  FOR ANY PURPOSE, SO LONG AS NO FEE IS CHARGED, AND SO LONG
+  *  AS THE COPYRIGHT NOTICE ABOVE, THIS GRANT OF PERMISSION,
+  *  AND THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND SO
+  *  LONG AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED
+  *  IN ANY ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR
+  *  DISTRIBUTION OF THIS SOFTWARE WITHOUT SPECIFIC, WRITTEN
+  *  PRIOR AUTHORIZATION.
+  *
+  *  THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+  *  FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+  *  PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+  *  MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+  *  WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+  *  REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+  *  FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+  *  CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+  *  OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+  *  IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+  *  SUCH DAMAGES.
+ */
+ 
+ #if defined(sun)
+ #define _REENTRANT    /* basic 3-lines for threads */
+ #include <pthread.h>
+ #include <thread.h>
+ #else
+ #include <pthread.h>
+ #endif
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <sys/file.h>
+ #include <signal.h>
+ #include <string.h>
+ #ifndef POSIX_TERMIOS
+ #include <sgtty.h>
+ #endif
+ #include <fcntl.h>
+ #include <sys/types.h>
+ #include <sys/time.h>
+ #include <sys/stat.h>
+ #include <sys/socket.h>
+ #include <sys/wait.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <sys/param.h>
+ #include <netdb.h>
+ #include <syslog.h>
+ 
+ #include "k5-int.h"
+ #include "com_err.h"
+ #include <errno.h>
+ 
+ #include <kadm5/admin.h>
+ #include <kadm5/adb.h>
+ #include "krep.h"
+ 
+ #define SYSLOG_CLASS LOG_DAEMON
+ 
+ static char *krep_version = KREP_PROT_VERSION;
+ 
+ char	*progname;
+ int		debug = 0;
+ int		verbose = 1;
+ char	*srvtab = 0;
+ int		standalone = 0;
+ #if defined(UMICH_REPLICATION)
+ int		nofork = 1;			/* By default, we do not fork */
+ #endif
+ 
+ krb5_principal	server;		/* This is our server principal name */
+ krb5_principal	client;		/* This is who we're talking to */
+ krb5_context krepd_context;
+ krb5_auth_context krepd_auth_context;
+ char	*realm = NULL;		/* Our realm */
+ 
+ osa_adb_policy_t policy_db;
+ kadm5_config_params global_params;
+ 
+ pthread_mutex_t deltaFileMutex;
+ pthread_cond_t deltaFileCond;
+ int signaledToQuit = 0;
+ 
+ /* char deltaFileName[] = "/usr/krb5kdc/slave_delta";		XXX */
+ char *deltaFileName = KREPD_DEFAULT_FILE;
+ 
+ char	*kerb_database = KREPD_DEFAULT_KRB_DB;
+ char	*acl_file_name = KREPD_ACL_FILE;
+ 
+ krb5_address	sender_addr;
+ krb5_address	receiver_addr;
+ short 		port = 0;
+ 
+ void	PRS
+ 	PROTOTYPE((char**));
+ void	do_standalone
+ 	PROTOTYPE((void));
+ void	doit
+ 	PROTOTYPE((int));
+ void	kerberos_authenticate
+ 	PROTOTYPE((krb5_context,
+ 		int,
+ 		krb5_principal *,
+ 		struct sockaddr_in));
+ krb5_boolean authorized_principal
+ 	PROTOTYPE((krb5_context,
+ 		krb5_principal));
+ void	recv_and_store_messages
+ 	PROTOTYPE((krb5_context,
+ 		int));
+ void *	process_messages_and_truncate
+ 	PROTOTYPE((void *));
+ void	load_database
+ 	PROTOTYPE((krb5_context,
+ 		char *,
+ 		char *));
+ void	send_error
+ 	PROTOTYPE((krb5_context,
+ 		int,
+ 		krb5_error_code,
+ 		char	*));
+ void	recv_error
+ 	PROTOTYPE((krb5_context,
+ 		krb5_data *));
+ 
+ static void usage()
+ {
+ 	com_err(progname, 0,
+ #if defined(UMICH_REPLICATION)
+ 		"\nUsage: %s [-r realm] [-s srvtab] [-dkSq] [-f slave_file]\n",
+ #else
+ 		"\nUsage: %s [-r realm] [-s srvtab] [-dSq] [-f slave_file]\n",
+ #endif
+ 		progname);
+ 	com_err(progname, 0, "\t[-F kerberos_db_file ]\n");
+ 	com_err(progname, 0, "\t[-P port] [-a acl_file]\n");
+ 	exit(1);
+ }
+ 
+ void
+ main(argc, argv)
+ 	int	argc;
+ 	char	**argv;
+ {
+ 	PRS(argv);
+ 
+ 	if (standalone)
+ 		do_standalone();
+ 	else
+ 		doit(0);
+ 	exit(0);
+ }
+ 
+ void do_standalone()
+ {
+ 	struct	sockaddr_in	sin, frominet;
+ 	struct servent *sp;
+ 	int	finet, s;
+ 	size_t	fromlen;
+ 	int	ret;
+ 	
+ 	finet = socket(AF_INET, SOCK_STREAM, 0);
+ 	if (finet < 0) {
+ 		com_err(progname, errno, "while obtaining socket");
+ 		exit(1);
+ 	}
+ 	memset((char *) &sin,0, sizeof(sin));
+ 	if(!port) {
+ 		sp = getservbyname(KREP_SERVICE, "tcp");
+ 		if (sp == NULL) {
+ 			com_err(progname, 0, "%s/tcp: unknown service", KREP_SERVICE);
+ 			exit(1);
+ 		}
+ 		sin.sin_port = sp->s_port;
+ 	} else {
+ 		sin.sin_port = port;
+ 	}
+ 	sin.sin_family = AF_INET;
+ 	if ((ret = bind(finet, (struct sockaddr *) &sin, sizeof(sin))) < 0) {
+ 		if (debug || nofork) {
+ 			int on = 1;
+ 			com_err(progname, 0,
+ 				"%s: attempting to rebind socket with SO_REUSEADDR\n",
+ 				progname);
+ 			if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR,
+ 					   (char *)&on, sizeof(on)) < 0)
+ 				com_err(progname, errno, "in setsockopt(SO_REUSEADDR)");
+ 			ret = bind(finet, (struct sockaddr *) &sin, sizeof(sin));
+ 		}
+ 		if (ret < 0) {
+ 			perror("bind");
+ 			com_err(progname, errno, "while binding listener socket");
+ 			exit(1);
+ 		}
+ 	}
+ 	if (!debug && !nofork)
+ 		daemon(1, 0);		
+ #ifdef PID_FILE
+ 	if ((pidfile = fopen(PID_FILE, "w")) != NULL) {
+ 		fprintf(pidfile, "%d\n", getpid());
+ 		fclose(pidfile);
+ 	} else
+ 		com_err(progname, errno,
+ 			"while opening pid file %s for writing", PID_FILE);
+ #endif
+ 	if (listen(finet, 5) < 0) {
+ 		com_err(progname, errno, "in listen call");
+ 		exit(1);
+ 	}
+ 	while (1) {
+ 		int child_pid;
+ 		
+ 		memset((char *)&frominet, 0, sizeof(frominet));
+ 		fromlen = sizeof(frominet);
+ 		s = accept(finet, (struct sockaddr *) &frominet, &fromlen);
+ 
+ 		if (s < 0) {
+ 			if (errno != EINTR)
+ 				com_err(progname, errno,
+ 					"from accept system call");
+ 			continue;
+ 		}
+ 		if (debug || nofork)
+ 			child_pid = 0;
+ 		else
+ 			child_pid = fork();
+ 		switch (child_pid) {
+ 		case -1:
+ 			com_err(progname, errno, "while forking");
+ 			exit(1);
+ 		case 0:
+ 			(void) close(finet);
+ 
+ 			doit(s);
+ 			close(s);
+ 			_exit(0);
+ 		default:
+ 			wait(0);
+ 			close(s);
+ 			
+ 		}
+ 	}
+ }
+ 
+ void doit(fd)
+ 	int	fd;
+ {
+ 	struct sockaddr_in from;
+ 	int on = 1;
+ 	size_t fromlen;
+ 	struct hostent	*hp;
+ #if defined(__aix42)
+ 	struct hostent	myhostent;
+ 	struct hostent_data myhostent_data;
+ #endif
+ 	krb5_error_code	retval;
+ 	int rc;
+ 	pthread_t processThread;
+ 	pthread_addr_t processThreadStatus;
+ 	int exitStatus = 0;
+ 
+ 	/*
+ 	 * Initialize mutex and condition variable
+ 	 */
+ 
+ 	if (rc = pthread_mutex_init(&deltaFileMutex, pthread_mutexattr_default))
+ 	{
+ 		syslog(LOG_ERR, "Error %d initializing deltaFileMutex\n", rc);
+ 		exitStatus++;
+ 		goto closeAndExit;
+ 	}
+ 
+ 	if (rc = pthread_cond_init(&deltaFileCond, pthread_condattr_default))
+ 	{
+ 		syslog(LOG_ERR, "Error %d initializing deltaFileCond\n", rc);
+ 		exitStatus++;
+ 		goto closeAndExit;
+ 	}
+ 
+ 	/*
+ 	 * Lock mutex to synchronize with other thread (make sure
+ 	 * delta file is created before other thread tries to open it)
+ 	 */
+ 
+ 	if (rc = pthread_mutex_lock(&deltaFileMutex))
+ 	{
+ 		syslog(LOG_ERR, "Error %d locking deltaFileMutex before "
+ 						"threads are started!\n", rc);
+ 		exitStatus++;
+ 		goto closeAndExit;
+ 	}
+ 
+ 	/*
+ 	 * Start another thread to process and truncate message file
+ 	 */
+ 
+ 	if (debug > 1)
+ 		com_err(progname, 0,
+ 			"*** Starting thread to run process_messages_and_truncate ***\n");
+ 
+ 	if (rc = pthread_create(&processThread,
+ 							pthread_attr_default,
+ 							process_messages_and_truncate,
+ 							NULL))
+ 	{
+ 		syslog(LOG_ERR, "Error spawning thread to process delta file!\n");
+ 		exitStatus++;
+ 		goto closeAndExit;
+ 	}
+ 
+ 	/*
+ 	 * Find out who we're talking to
+ 	 */
+ 
+ 	fromlen = sizeof (from);
+ 	if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) {
+ 		com_err(progname, errno, "from getpeername\n");
+ 		goto stopAndExit;
+ 	}
+ 	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (caddr_t) &on,
+ 			   sizeof (on)) < 0) {
+ 		com_err(progname, errno,
+ 			"while attempting setsockopt (SO_KEEPALIVE)");
+ 	}
+ 
+ #if defined(__aix42)
+ 	memset((void *)&myhostent_data, '\0', sizeof(struct hostent_data));
+ 	if (0 == gethostbyaddr_r((char *) &(from.sin_addr.s_addr), fromlen,
+ 				AF_INET, &myhostent, &myhostent_data))
+ 		hp = &myhostent;
+ 	else
+ 		hp = NULL;
+ #else
+ 	hp = gethostbyaddr((char *) &(from.sin_addr.s_addr),
+ 						fromlen, AF_INET);
+ #endif
+ 	if (NULL == hp) {
+ 		syslog(LOG_INFO, "Connection from %s",
+ 			   inet_ntoa(from.sin_addr));
+ 		if (debug)
+ 			com_err(progname, 0, "Connection from %s\n",
+ 				   inet_ntoa(from.sin_addr));
+ 	} else {
+ 		syslog(LOG_INFO, "Connection from %s", hp->h_name);
+ 		if (debug)
+ 			com_err(progname, 0, "Connection from %s\n", hp->h_name);
+ 	}
+ 
+ 	/*
+ 	 * Authenticate the peer and validate it is an authorized principal
+ 	 */
+ 
+ 	kerberos_authenticate(krepd_context, fd, &client, from);
+ 	if (!authorized_principal(krepd_context, client)) {
+ 		char	*name;
+ 
+ 		if (retval = krb5_unparse_name(krepd_context, client, &name)) {
+ 			com_err(progname, retval,
+ 				"While unparsing client name");
+ 			goto stopAndExit;
+ 		}
+ 		syslog(LOG_WARNING,
+ 			   "Rejected connection from unauthorized principal %s",
+ 			   name);
+ 		free(name);
+ 		goto stopAndExit;
+ 	}
+ 
+ 	/*
+ 	 * Now go process messages as long as we keep getting them.
+ 	 */
+ 
+ 	recv_and_store_messages(krepd_context, fd);
+ 
+ stopAndExit:
+ 
+ 	/*
+ 	 * Tell the other thread we're going down...
+ 	 */
+ 
+ 	signaledToQuit = 1;
+ 	if (rc = pthread_cond_broadcast(&deltaFileCond))
+ 	{
+ 		syslog(LOG_ERR, "Error from pthread_cond_broadcast "
+ 						"in recv_and_store_messages\n");
+ 	}
+ 	else
+ 	{
+ 
+ 		if (debug)
+ 			com_err(progname, 0,
+ 				"Waiting for the process_messages_and_truncate "
+ 				"thread to end...\n");
+ 
+ 		if (0 != pthread_join(processThread, &processThreadStatus))
+ 		{
+ 			com_err(progname, errno,
+ 					"while joining process_messages thread!\n");
+ 		}
+ 		else
+ 		{
+ 			if (debug)
+ 				com_err(progname, 0,
+ 					"process_messages_and_truncate thread "
+ 					"ended with status %d\n", processThreadStatus);
+ 		}
+ 	}
+ 
+ closeAndExit:
+ 
+ 	/*
+ 	 * Close the socket connected to master
+ 	 */
+ 
+ 	if (close(fd) < 0) {
+ 		com_err(progname, errno,
+ 			"while trying to close database file");
+ 		exitStatus++;
+ 	}
+ 	
+ 	com_err(progname, 0, "Terminating with status %d\n", exitStatus);
+ 	exit(exitStatus);
+ }
+ 
+ static void
+ krepd_com_err_proc(whoami, code, fmt, args)
+ 	const char	*whoami;
+ 	long		code;
+ 	const char	*fmt;
+ 	va_list		args;
+ {
+ 	char	error_buf[8096];
+ 
+ 	error_buf[0] = '\0';
+ 	if (fmt)
+ 		vsprintf(error_buf, fmt, args);
+ 	syslog(LOG_ERR, "%s%s%s%s%s", whoami ? whoami : "", whoami ? ": " : "",
+ 		   code ? error_message(code) : "", code ? " " : "", error_buf);
+ }
+ 
+ void PRS(argv)
+ 	char	**argv;
+ {
+ 	register char	*word, ch;
+ 	char	*cp;
+ 	struct hostent *hp;
+ 	char	my_host_name[MAXHOSTNAMELEN], buf[BUFSIZ];
+ 	krb5_error_code	retval;
+ 	static const char	tmp[] = ".temp";
+ 	
+ 	initialize_adb_error_table();
+ 
+ 	retval = krb5_init_context(&krepd_context);
+ 	if (retval) {
+ 		com_err(argv[0], retval, "while initializing krb5");
+ 		exit(1);
+ 	}
+ 
+ 	progname = *argv++;
+ 	while (word = *argv++) {
+ 		if (*word == '-') {
+ 			word++;
+ 			while (word && (ch = *word++)) {
+ 				switch(ch){
+ 				case 'f':
+ 					if (*word)
+ 						deltaFileName = word;
+ 					else
+ 						deltaFileName = *argv++;
+ 					if (!deltaFileName)
+ 						usage();
+ 					word = 0;
+ 					break;
+ 				case 'F':
+ 					if (*word)
+ 						kerb_database = word;
+ 					else
+ 						kerb_database = *argv++;
+ 					if (!kerb_database)
+ 						usage();
+ 					word = 0;
+ #if defined(UMICH_REPLICATION)
+ 					global_params.dbname = kerb_database;
+ 					global_params.mask |= KADM5_CONFIG_DBNAME;
+ #endif
+ 					break;
+ 				case 'P':
+ 					if (*word)
+ 						port = htons(atoi(word));
+ 					else
+ 						port = htons(atoi(*argv++));
+ 					if (!port)
+ 						usage();
+ 					word = 0;
+ 					break;
+ 				case 'r':
+ 					if (*word)
+ 						realm = word;
+ 					else
+ 						realm = *argv++;
+ 					if (!realm)
+ 						usage();
+ 					word = 0;
+ #if defined(UMICH_REPLICATION)
+ 					global_params.realm = realm;
+ 					global_params.mask |= KADM5_CONFIG_REALM;
+ #endif
+ 					break;
+ 				case 's':
+ 					if (*word)
+ 						srvtab = word;
+ 					else
+ 						srvtab = *argv++;
+ 					if (!srvtab)
+ 						usage();
+ 					word = 0;
+ #if defined(UMICH_REPLICATION)
+ 					global_params.admin_keytab = srvtab;
+ 					global_params.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
+ #endif
+ 					break;
+ 				case 'd':
+ 					debug++;
+ 					break;
+ 				case 'q':
+ 					verbose = 0;
+ 					break;
+ 				case 'S':
+ 					standalone++;
+ 					break;
+ 				case 'a':
+ 					if (*word)
+ 						 acl_file_name = word;
+ 					else
+ 						 acl_file_name = *argv++;
+ 					if (!acl_file_name)
+ 						 usage();
+ 					word = 0;
+ #if defined(UMICH_REPLICATION)
+ 					global_params.acl_file = acl_file_name;
+ 					global_params.mask |= KADM5_CONFIG_ACL_FILE;
+ #endif
+ 					break;
+ #if defined(UMICH_REPLICATION)
+ 				case 'k':
+ 					nofork = 0;
+ 					break;
+ #endif
+ 				default:
+ 					usage();
+ 				}
+ 				
+ 			}
+ 		} else
+ 			/* We don't take any arguments, only options */
+ 			usage();
+ 	}
+ 
+ #if defined(UMICH_REPLICATION)
+ 	if (retval = kadm5_get_config_params(krepd_context, NULL, NULL,
+ 					&global_params, &global_params)) {
+ 		com_err(argv[0], retval, "while retrieving configuration parameters");
+ 		exit(1);
+ 	}
+ #endif
+ 
+ 	/*
+ 	 * Switch com_err reporting to syslog
+ 	 */
+ 	openlog("krepd", LOG_PID | LOG_ODELAY, SYSLOG_CLASS);
+ 	set_com_err_hook(krepd_com_err_proc);
+ 
+ 	/*
+ 	 * Get my hostname, so we can construct my service name
+ 	 */
+ 	retval = krb5_sname_to_principal(krepd_context,
+ 					 NULL, KREP_SERVICE_NAME,
+ 					 KRB5_NT_SRV_HST, &server);
+ 	if (retval) {
+ 		com_err(progname, retval,
+ 			"While trying to construct my service name");
+ 		exit(1);
+ 	}
+ 	if (realm) {
+ 		(void) krb5_xfree(krb5_princ_realm(context, server)->data);
+ 		krb5_princ_set_realm_length(context, server, strlen(realm));
+ 		krb5_princ_set_realm_data(context, server, strdup(realm));
+ 	}
+ }
+ 
+ /*
+  * Figure out who's calling on the other end of the connection....
+  */
+ void
+ kerberos_authenticate(context, fd, clientp, sin)
+ 	krb5_context 	  context;
+ 	int		 	  fd;
+ 	krb5_principal	* clientp;
+ 	struct sockaddr_in	  sin;
+ {
+ 	krb5_error_code	  retval;
+ 	krb5_ticket		* ticket;
+ 	struct sockaddr_in	  r_sin;
+ 	size_t			  sin_length;
+ 	krb5_keytab		  keytab = NULL;
+ 
+ 	/*
+ 	 * Set recv_addr and send_addr
+ 	 */
+ 	sender_addr.addrtype = ADDRTYPE_INET;
+ 	sender_addr.length = sizeof(sin.sin_addr);
+ 	sender_addr.contents = (krb5_octet *) malloc(sizeof(sin.sin_addr));
+ 	memcpy((char *) sender_addr.contents, (char *) &sin.sin_addr,
+ 		   sizeof(sin.sin_addr));
+ 
+ 	sin_length = sizeof(r_sin);
+ 	if (getsockname(fd, (struct sockaddr *) &r_sin, &sin_length)) {
+ 		com_err(progname, errno, "while getting local socket address");
+ 		exit(1);
+ 	}
+ 
+ 	receiver_addr.addrtype = ADDRTYPE_INET;
+ 	receiver_addr.length = sizeof(r_sin.sin_addr);
+ 	receiver_addr.contents = (krb5_octet *) malloc(sizeof(r_sin.sin_addr));
+ 	memcpy((char *) receiver_addr.contents, (char *) &r_sin.sin_addr,
+ 		   sizeof(r_sin.sin_addr));
+ 
+ 	if (debug) {
+ 		char *name;
+ 		if (retval = krb5_unparse_name(context, server, &name)) {
+ 			com_err(progname, retval, "While unparsing client name");
+ 			exit(1);
+ 		}
+ 		com_err(progname, 0, "krb5_recvauth(%d, %s, %s, ...)\n", fd, krep_version, name);
+ 		free(name);
+ 	}
+ 
+ 	if (retval = krb5_auth_con_init(context, &krepd_auth_context)) {
+ 		syslog(LOG_ERR, "Error in krb5_auth_con_init: %s",
+ 				error_message(retval));
+ 		exit(1);
+ 	}
+ 
+ 	if (retval = krb5_auth_con_setflags(context, krepd_auth_context, 
+ 					KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
+ 		syslog(LOG_ERR, "Error in krb5_auth_con_setflags: %s",
+ 			   error_message(retval));
+ 		exit(1);
+ 	}
+ 
+ 	if (retval = krb5_auth_con_setaddrs(context, krepd_auth_context,
+ 						&receiver_addr, &sender_addr)) {
+ 		syslog(LOG_ERR, "Error in krb5_auth_con_setaddrs: %s",
+ 			   error_message(retval));
+ 		exit(1);
+ 	}
+ 
+ 	if (srvtab) {
+ 		if (retval = krb5_kt_resolve(context, srvtab, &keytab)) {
+ 			syslog(LOG_ERR, "Error in krb5_kt_resolve: %s",
+ 					error_message(retval));
+ 			exit(1);
+ 		}
+ 	}
+ 
+ 	if (retval = krb5_recvauth(context, &krepd_auth_context, (void *) &fd,
+ 				   krep_version, server, 0, keytab, &ticket)){
+ 		syslog(LOG_ERR, "Error in krb5_recvauth: %s", error_message(retval));
+ 		exit(1);
+ 	}
+ 
+ 	if (retval = krb5_copy_principal(context, 
+ 					 ticket->enc_part2->client, clientp)) {
+ 		syslog(LOG_ERR, "Error in krb5_copy_prinicpal: %s", 
+ 			   error_message(retval));
+ 		exit(1);
+ 	}
+ 
+ 	if (debug) {
+ 		char * name;
+ 
+ 		if (retval = krb5_unparse_name(context, *clientp, &name)) {
+ 			com_err(progname, retval, "While unparsing client name");
+ 			exit(1);
+ 		}
+ 		com_err(progname, 0, "authenticated client: %s\n", name);
+ 		free(name);
+ 	}
+ 	krb5_free_ticket(context, ticket);
+ }
+ 
+ krb5_boolean
+ authorized_principal(context, p)
+ 	krb5_context context;
+ 	krb5_principal p;
+ {
+ 	char		*name;
+ 	char		buf[1024];
+ 	krb5_error_code	retval;
+ 	FILE		*acl_file;
+ 	int			end;
+ 	
+ 	retval = krb5_unparse_name(context, p, &name);
+ 	if (retval)
+ 	return FALSE;
+ 
+ 	acl_file = fopen(acl_file_name, "r");
+ 	if (!acl_file)
+ 		return FALSE;
+ 
+ 	while (!feof(acl_file)) {
+ 		if (!fgets(buf, sizeof(buf), acl_file))
+ 			break;
+ 		end = strlen(buf) - 1;
+ 		if (buf[end] == '\n')
+ 			buf[end] = '\0';
+ 		if (!strcmp(name, buf)) {
+ 			free(name);
+ 			fclose(acl_file);
+ 			return TRUE;
+ 		}
+ 	}
+ 	free(name);
+ 	fclose(acl_file);
+ 	return FALSE;
+ }
+ 
+ void
+ recv_and_store_messages(krb5_context context, int fd)
+ {
+ 	FILE			*deltaFile;
+ 	int				msg_size;
+ 	int				n;
+ 	krb5_data		inbuf, outbuf, confmsg;
+ 	krb5_error_code	retval;
+ 	int				rc;
+ 
+ 	if (debug > 1)
+ 		com_err(progname, 0, "recv_and_store_messages: entered");
+ 
+ 	/*
+ 	 * Open the file for append or create it
+ 	 */
+ 
+ 	if (NULL == (deltaFile = fopen(deltaFileName, "a+")))
+ 	{
+ 		syslog(LOG_ERR,
+ 				"%s: Error opening deltaFile (%s) for append\n",
+ 				progname, deltaFileName);
+ 		return;
+ 	}
+ 
+ 	/*
+ 	 * With the file safely opened (or created) we can
+ 	 * let the other thread continue
+ 	 */
+ 
+ 	if (rc = pthread_mutex_unlock(&deltaFileMutex))
+ 	{
+ 		syslog(LOG_ERR,
+ 				"%s: error releasing mutex in recv_and_store_messages\n",
+ 				progname);
+ 		goto errorReturn;
+ 	}
+ 
+ 	/*
+ 	 * Initialize the initial vector. (only once per instantiation)
+ 	 */
+ 
+ 	if (retval = krb5_auth_con_initivector(context, krepd_auth_context)) {
+ 		send_error(context, fd, retval, "failed while initializing i_vector");
+ 		com_err(progname, retval, "while initializing i_vector");
+ 		goto errorReturn;
+ 	}
+ 
+ 	for (;;)
+ 	{
+ 		/*
+ 		 * Receive and decode size from client
+ 		 */
+ 
+ 		if (retval = krb5_read_message(context, (void *) &fd, &inbuf)) {
+ 			send_error(context, fd, retval, "while reading message size");
+ 			com_err(progname, retval,
+ 					"while reading size of message from client");
+ 			goto errorReturn;
+ 		}
+ 		if (krb5_is_krb_error(&inbuf))
+ 			recv_error(context, &inbuf);
+ 		if (retval = krb5_rd_safe(context,krepd_auth_context,
+ 								&inbuf,&outbuf,NULL)) {
+ 			krb5_xfree(inbuf.data);
+ 			send_error(context, fd, retval, "while decoding message size");
+ 			com_err(progname, retval,
+ 					"while decoding message size from client");
+ 			goto errorReturn;
+ 		}
+ 		memcpy((char *) &msg_size, outbuf.data, sizeof(msg_size));
+ 		krb5_xfree(inbuf.data);
+ 		krb5_xfree(outbuf.data);
+ 		msg_size = ntohl(msg_size);
+ 		if (debug > 1)
+ 			com_err(progname, 0,
+ 					"recv_and_store_messages: msg_size is %d\n", msg_size);
+ 
+ 		/*
+ 		 * If we got a non-zero length message, process it
+ 		 */
+ 
+ 		if ( msg_size > 0 )
+ 		{
+ 			/*
+ 			 * Read and decode the message with DB info
+ 			 * Cannot put a null into the buffer since it seems
+ 			 * to be the exact size req'd.  So we use "%.*s" to
+ 			 * print and write it...
+ 			 */
+ 
+ 			if (debug > 2)
+ 				com_err(progname, 0,
+ 					"recv_and_store_messages: calling krb5_read_message()\n");
+ 			
+ 			if (retval = krb5_read_message(context, (void *) &fd, &inbuf)) {
+ 				com_err(progname, retval, "while reading database message");
+ 				send_error(context, fd, retval,
+ 							"while reading database message");
+ 				goto errorReturn;
+ 			}
+ 			if (krb5_is_krb_error(&inbuf)) {
+ 				recv_error(context, &inbuf);
+ 			}
+ 			if (retval = krb5_rd_priv(context, krepd_auth_context, &inbuf, 
+ 						  &outbuf, NULL)) {
+ 				krb5_xfree(inbuf.data);
+ 				com_err(progname, retval, "while decoding database message");
+ 				send_error(context, fd, retval,
+ 							"while decoding database message");
+ 				goto errorReturn;
+ 			}
+ 			krb5_xfree(inbuf.data);
+ 
+ 			if (debug > 1)
+ 				com_err(progname, 0, "recv_and_store_messages: got a %d-byte message", msg_size);
+ /*	com_err() has a 1024-byte buffer.  The longer entries created by
+  *	sending the policy info blows out the buffer and causes an error...
+  *				com_err(progname, 0, "recv_and_store_messages: "
+  *								"the message at 0x%08x is\n'%.*s'\n",
+  *						outbuf.data, msg_size, outbuf.data);
+  */
+ 
+ 			/*
+ 			 * Process the record  (write it to the file)
+ 			 */
+ 
+ 			if (debug > 2)
+ 				com_err(progname, 0,
+ 						"recv_and_store_messages: obtaining mutex...\n");
+ 			if (rc = pthread_mutex_lock(&deltaFileMutex))
+ 			{
+ 				syslog(LOG_ERR,
+ 						"Error obtaining mutex in recv_and_store_messages\n");
+ 				goto errorReturn;
+ 			}
+ 
+ 			/* go to the end of the file (in case it was truncated) */
+ 			if (debug > 2)
+ 				com_err(progname, 0, "recv_and_store_messages:"
+ 						" seeking the end of the file...\n");
+ 			fseek(deltaFile, 0, SEEK_END);
+ 
+ 			if (debug > 2)
+ 				com_err(progname, 0, "recv_and_store_messages: "
+ 						"writing and flushing record...\n");
+ 			fprintf(deltaFile, "%.*s\n", msg_size, outbuf.data); 
+ 			fflush(deltaFile);
+ 
+ 			if (debug > 2)
+ 				com_err(progname, 0, "recv_and_store_messages: "
+ 								"calling krb5_xfree() with 0x%08x...\n",
+ 								outbuf.data);
+ 			krb5_xfree(outbuf.data);
+ 
+ 			if (debug > 1)
+ 				com_err(progname, 0, "recv_and_store_messages: "
+ 								"signalling that there is work...\n");
+ 			if (rc = pthread_cond_broadcast(&deltaFileCond))
+ 			{
+ 				syslog(LOG_ERR, "Error from pthread_cond_broadcast "
+ 								"in recv_and_store_messages\n");
+ 				goto errorReturn;
+ 			}
+ 
+ 			if (debug > 2)
+ 				com_err(progname, 0,
+ 						"recv_and_store_messages: releasing mutex...\n");
+ 			if (rc = pthread_mutex_unlock(&deltaFileMutex))
+ 			{
+ 				syslog(LOG_ERR,
+ 						"Error obtaining mutex in recv_and_store_messages\n");
+ 				goto errorReturn;
+ 			}
+ 
+ 			/*
+ 			 * Create acknowledgement message indicating the number
+ 			 * of bytes received and stored
+ 			 */
+ 	
+ 			msg_size = htonl(msg_size);
+ 			inbuf.data = (char *) &msg_size;
+ 			inbuf.length = sizeof(msg_size);
+ 			if (retval = krb5_mk_safe(context, krepd_auth_context, &inbuf,
+ 										&confmsg, NULL)) {
+ 				com_err(progname, retval, "while encoding acknowledgement");
+ 				send_error(context, fd, retval,
+ 							"while encoding acknowledgement");
+ 				goto errorReturn;
+ 			}
+ 
+ 			/*
+ 			 * Send the acknowledgement message
+ 			 */
+ 
+ 			if (debug > 1)
+ 			{
+ 				com_err(progname, 0, "recv_and_store_messages: "
+ 								"calling krb5_write_message() with length %d\n",
+ 								confmsg.length);
+ 			}
+ 			if (retval = krb5_write_message(krepd_context, (void *) &fd,
+ 										&confmsg)) { 
+ 				krb5_xfree(confmsg.data);
+ 				com_err(progname, retval, "while sending acknowledgement");
+ 				goto errorReturn;
+ 			}
+ 			krb5_xfree(confmsg.data);
+ 		}
+ 		else
+ 		{
+ 			/*
+ 			 * When we get a zero-length message we go away...
+ 			 */
+ 
+ 			if (debug)
+ 				com_err(progname, 0, "recv_and_store_messages: "
+ 						"returning because of zero-length msg\n");
+ 			break;		/* out of forever loop */
+ 		}
+ 	}
+ 
+ errorReturn:
+ 
+ 	fclose(deltaFile);
+ }
+ 
+ void * process_messages_and_truncate(void *parm)
+ {
+ 	int rc;
+ 	FILE * deltaFile;
+ 
+ 	if (debug > 1)
+ 		com_err(progname, 0,
+ 				"*** process_messages_and_truncate: thread entered ***\n");
+ 
+ 	/*
+ 	 * Wait here until main thread has the file ready 
+ 	 */
+ 
+ 	if (rc = pthread_mutex_lock(&deltaFileMutex))
+ 	{
+ 		syslog(LOG_ERR, "Error initially obtaining mutex "
+ 						"in process_messages_and_truncate\n");
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	/*
+ 	 * Open the delta file for reading
+ 	 */
+ 
+ 	if (debug > 1)
+ 		com_err(progname, 0, "process_messages_and_truncate: "
+ 						"opening delta file %s...\n", deltaFileName);
+ 
+ 	if (NULL == (deltaFile = fopen(deltaFileName, "r+")))
+ 	{
+ 		syslog(LOG_ERR,
+ 				"Error opening deltaFile (%s) for reading\n", deltaFileName);
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	/*
+ 	 * Release the mutex for now ...
+ 	 */
+ 
+ 	if (rc = pthread_mutex_unlock(&deltaFileMutex))
+ 	{
+ 		syslog(LOG_ERR,
+ 				"Error releasing mutex in process_messages_and_truncate\n");
+ 		pthread_exit((void *) 1);
+ 	}
+ 
+ 	/*
+ 	 * Initialize use of the database
+ 	 */
+ 
+ 	if (debug > 1)
+ 		com_err(progname, 0, "process_messages_and_truncate: "
+ 						"initializing use of the database (%s)...\n",
+ 						global_params.dbname);
+ 
+ 	if (rc = krb5_db_set_name(krepd_context, global_params.dbname))
+ 	{
+ 		com_err(progname, 0,
+ 				"%s: %s while setting database name, aborting\n",
+ 				progname, error_message(rc));
+ 		pthread_exit((void *)1);
+ 	}
+ 	if (rc = krb5_db_init(krepd_context))
+ 	{
+ 		com_err(progname, 0,
+ 				"%s: %s while initializing use of database, aborting\n",
+ 				progname, error_message(rc));
+ 		pthread_exit((void *)1);
+ 	}
+ 
+ 	/*
+ 	 * Initialize use of the policy database ...
+ 	 */
+ 
+ 	if (debug > 1)
+ 		com_err(progname, 0, "process_messages_and_truncate: "
+ 						"initializing use of the policy database (%s)...\n",
+ 						global_params.admin_dbname);
+ 
+ 	if (rc = osa_adb_open_policy(&policy_db, &global_params))
+ 	{
+ 		com_err(progname, 0,
+ 				"%s: %s while initializing use of policy database, aborting\n",
+ 				progname, error_message(rc));
+ 		if (rc = krb5_db_fini(krepd_context))
+ 		{
+ 			com_err(progname, 0, "%s: %s while terminating use of database\n",
+ 					progname, error_message(rc));
+ 		}
+ 		pthread_exit((void *)1);
+ 	}
+ 
+ 	/*
+ 	 * Loop until signaled to quit.  Processes the delta file
+ 	 * applying the changes to the database until it reaches
+ 	 * EOF or encounters an error
+ 	 */
+ 
+ 	if (debug > 1)
+ 		com_err(progname, 0, "process_messages_and_truncate: "
+ 						"entering processing loop ..........\n");
+ 
+ 	while (!signaledToQuit)
+ 	{
+ 		int error = 0;
+ 		int lineno = 0;
+ 
+ 		if (debug > 2)
+ 			com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Calling process_umichrep_record\n");
+ 
+ 		while (! (error = process_umichrep_record(deltaFileName,
+ 												krepd_context,
+ 												deltaFile,
+ 												verbose,
+ 												&lineno,
+ 												policy_db)))
+ 			/* do nothing */
+ 			;
+ 
+ 		if (debug > 2)
+ 			com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Error (%d) from process_umichrep_record\n", error);
+ 
+ 		if (-1 == error)
+ 		{
+ 			if (debug > 2)
+ 				com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Doing EOF processing\n");
+ 
+ 			/* EOF */
+ 			if (rc = pthread_mutex_lock(&deltaFileMutex))
+ 			{
+ 				com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Error locking mutex at EOF\n");
+ 				pthread_exit((void *) 1);
+ 			}
+ 			if (rc = krb5_lock_file(0, fileno(deltaFile),
+ 									KRB5_LOCKMODE_EXCLUSIVE))
+ 			{
+ 				com_err(progname, 0,
+ 						"Error (%d) locking deltaFile at EOF\n", rc);
+ 				pthread_mutex_unlock(&deltaFileMutex);
+ 				pthread_exit((void *) 1);
+ 			}
+ 
+ 			if (debug > 2)
+ 				com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Calling process_umichrep_record after EOF\n");
+ 
+ 			if (-1 == (error =  process_umichrep_record(deltaFileName,
+ 													krepd_context,
+ 													deltaFile,
+ 													verbose,
+ 													&lineno,
+ 													policy_db)))
+ 			{
+ 
+ 				if (debug > 1)
+ 					com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Still EOF, TRUNCATING delta file !!!!!!!\n");
+ 
+ 				/* Still EOF */
+ 				if (ftruncate(fileno(deltaFile), 0))
+ 				{
+ 					com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Error truncating deltaFile!\n");
+ 				}
+ 				else
+ 				{
+ 					lineno = 0;
+ 					fseek(deltaFile, 0, SEEK_SET);
+ 				}
+ 			}
+ 			if (debug > 2)
+ 				com_err(progname, 0, "process_messages_and_truncate: "
+ 							"unlocking file...\n");
+ 
+ 			krb5_lock_file(0, fileno(deltaFile), KRB5_LOCKMODE_UNLOCK);
+ 			if (-1 == error)
+ 			{
+ 				/*
+ 				 * Wait for something to be written to the file
+ 				 */
+ 
+ 				if (debug > 1)
+ 					com_err(progname, 0, "process_messages_and_truncate: "
+ 							"About to wait for more work....\n");
+ 
+ 				if (pthread_cond_wait(&deltaFileCond, &deltaFileMutex))
+ 				{
+ 					com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Error from pthread_cond_wait!?\n");
+ 					sleep(10);
+ 				}
+ 
+ 				if (debug > 1)
+ 					com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Back from pthread_cond_wait....\n");
+ 
+ 			}
+ 			if (debug > 2)
+ 				com_err(progname, 0, "process_messages_and_truncate: "
+ 							"releasing mutex...\n");
+ 
+ 			pthread_mutex_unlock(&deltaFileMutex);
+ 		}
+ 		else
+ 		{
+ 			/* Real error from process_umichrep_record */
+ 			com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Error returned from process_umichrep_record!\n");
+ 			sleep(10);
+ 		}
+ 	}
+ 	
+ 	/*
+ 	 * Close the database and stop logging
+ 	 */
+ 
+ 	if (debug)
+ 		com_err(progname, 0, "process_messages_and_truncate: "
+ 							"Out of the loop, closing up....\n");
+ 
+ 	if (rc = krb5_db_fini(krepd_context))
+ 	{
+ 		com_err(progname, 0, "%s: %s while terminating use of database\n",
+ 				progname, error_message(rc));
+ 	}
+ 
+ 	/*
+ 	 * Close the delta file and exit
+ 	 */
+ 
+ 	fclose(deltaFile);
+ 
+ 	if (debug)
+ 		com_err(progname, 0, "process_messages_and_truncate: Saying adios!\n");
+ 
+ 	pthread_exit((void *) 0);
+ }
+ 
+ 
+ void
+ send_error(context, fd, err_code, err_text)
+ 	krb5_context context;
+ 	int	fd;
+ 	krb5_error_code	err_code;
+ 	char	*err_text;
+ {
+ 	krb5_error	error;
+ 	const char	*text;
+ 	krb5_data	outbuf;
+ 	char		buf[1024];
+ 
+ 	memset((char *)&error, 0, sizeof(error));
+ 	krb5_us_timeofday(context, &error.stime, &error.susec);
+ 	error.server = server;
+ 	error.client = client;
+ 	
+ 	if (err_text)
+ 		text = err_text;
+ 	else
+ 		text = error_message(err_code);
+ 	
+ 	error.error = err_code - ERROR_TABLE_BASE_krb5;
+ 	if (error.error > 127) {
+ 		error.error = KRB_ERR_GENERIC;
+ 		if (err_text) {
+ 			sprintf(buf, "%s %s", error_message(err_code),
+ 				err_text);
+ 			text = buf;
+ 		}
+ 	} 
+ 	error.text.length = strlen(text) + 1;
+ 	if (error.text.data = malloc(error.text.length)) {
+ 		strcpy(error.text.data, text);
+ 		if (!krb5_mk_error(context, &error, &outbuf)) {
+ 			(void) krb5_write_message(context, (void *)&fd,&outbuf);
+ 			krb5_xfree(outbuf.data);
+ 		}
+ 		free(error.text.data);
+ 	}
+ }
+ 
+ void
+ recv_error(context, inbuf)
+ 	krb5_context context;
+ 	krb5_data	*inbuf;
+ {
+ 	krb5_error	*error;
+ 	krb5_error_code	retval;
+ 
+ 	if (retval = krb5_rd_error(context, inbuf, &error)) {
+ 		com_err(progname, retval,
+ 			"while decoding error packet from client");
+ 		exit(1);
+ 	}
+ 	if (error->error == KRB_ERR_GENERIC) {
+ 		if (error->text.data)
+ 			com_err(progname, 0,
+ 				"Generic remote error: %s\n",
+ 				error->text.data);
+ 	} else if (error->error) {
+ 		com_err(progname, error->error + ERROR_TABLE_BASE_krb5,
+ 			"signalled from server");
+ 		if (error->text.data)
+ 			com_err(progname, 0,
+ 				"Error text from client: %s\n",
+ 				error->text.data);
+ 	}
+ 	krb5_free_error(context, error);
+ 	exit(1);
+ }
+ 
