--- cygnus/src/slave/kpropd.c	Tue Jul  1 14:14:30 1997
+++ kerbnet-1.2/slave/kpropd.c	Tue May 27 22:03:41 1997
@@ -32,6 +32,7 @@
 
 #include <stdio.h>
 #include <ctype.h>
+#include <sys/types.h>
 #include <sys/file.h>
 #include <signal.h>
 #include <string.h>
@@ -39,7 +40,6 @@
 #include <sgtty.h>
 #endif
 #include <fcntl.h>
-#include <sys/types.h>
 #include <sys/time.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
@@ -49,7 +49,9 @@
 #include <sys/param.h>
 #include <netdb.h>
 #include <syslog.h>
-
+#ifdef HAS_PROCESS_H
+#include <process.h>
+#endif /* HAS_PROCESS_H */
 #include "k5-int.h"
 #include "com_err.h"
 #include <errno.h>
@@ -64,78 +66,99 @@
 int     debug = 0;
 char	*srvtab = 0;
 int	standalone = 0;
+int 	nodaemon = 0;
+short 	port = 0;
 
-krb5_principal	server;		/* This is our server principal name */
-krb5_principal	client;		/* This is who we're talking to */
-krb5_context kpropd_context;
-krb5_auth_context auth_context;
 char	*realm = NULL;		/* Our realm */
 char	*file = KPROPD_DEFAULT_FILE;
 char	*temp_file_name;
-char	*kdb5_edit = KPROPD_DEFAULT_KDB5_EDIT;
+char	*kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
 char	*kerb_database = KPROPD_DEFAULT_KRB_DB;
+char	*acl_file_name = KPROPD_ACL_FILE;
 
-int		database_fd;
-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((char**,
+	krb5_principal *,
+	krb5_context *));
+int	do_standalone
+	PROTOTYPE((krb5_principal,
+	krb5_context));
+int	doit
+	PROTOTYPE((int,
+	krb5_principal,
+	krb5_context));
+int	kerberos_authenticate
 	PROTOTYPE((krb5_context,
+		   krb5_auth_context *,
 		   int,
 		   krb5_principal *,
+		   krb5_principal,
 		   struct sockaddr_in));
 krb5_boolean authorized_principal
 	PROTOTYPE((krb5_context,
-    		   krb5_principal));
-void	recv_database
+    		   krb5_principal,
+		   char **));
+int	recv_database
 	PROTOTYPE((krb5_context,
+		   krb5_auth_context,
+		   krb5_principal,
+		   krb5_principal,
+		   int,
 		   int,
-		   int));
-void	load_database
+		   krb5_data *));
+int	load_database
 	PROTOTYPE((krb5_context,
     		   char *,
     		   char *));
 void	send_error
 	PROTOTYPE((krb5_context,
+		   krb5_principal,
+		   krb5_principal,
     		   int,
 		   krb5_error_code,
     		   char	*));
-void	recv_error
+int	recv_error
 	PROTOTYPE((krb5_context,
     		   krb5_data *));
 
+void param_usage(FILE *fp)
+{
+	fprintf(fp, "\t[-r realm] [-s srvtab] [-dSn] [-f slave_file]\n");
+	fprintf(stderr, "\t[-F kerberos_db_file ] [-p kdb5_util_pathname]\n");
+	fprintf(stderr, "\t[-P port] [-a acl_file]\n");
+}
+
 static void usage()
 {
-	fprintf(stderr,
-		"\nUsage: %s [-r realm] [-s srvtab] [-dS] [-f slave_file]\n",
-		progname);
-	fprintf(stderr, "\t[-F kerberos_db_file ] [-p kdb5_edit_pathname]\n");
-	fprintf(stderr, "\t[-P port]\n");
-	exit(1);
+  fprintf(stderr, "\nUsage : %s ", progname);
+  param_usage(stderr);
+  exit(1);
 }
 
-void
+int
+#ifdef __CYGWIN32__
+original_main(argc, argv)
+#else /* __CYGWIN32__ */
 main(argc, argv)
+#endif /* __CYGWIN32__ */
 	int	argc;
 	char	**argv;
 {
-	PRS(argv);
+	krb5_principal	server = 0;		/* This is our server principal name */
+	krb5_context kpropd_context = 0;
+
+	PRS(argv, &server, &kpropd_context);
 
 	if (standalone)
-		do_standalone();
+		return do_standalone(server, kpropd_context);
 	else
-		doit(0);
-	exit(0);
+		return doit(0, server, kpropd_context); 
 }
 
-void do_standalone()
+int do_standalone(server, kpropd_context)
+	krb5_principal	server;
+	krb5_context	kpropd_context;
 {
 	struct	sockaddr_in	sin, frominet;
 	struct servent *sp;
@@ -145,16 +168,15 @@
 	finet = socket(AF_INET, SOCK_STREAM, 0);
 	if (finet < 0) {
 		com_err(progname, errno, "while obtaining socket");
-		exit(1);
+		return(1);
 	}
 	memset((char *) &sin,0, sizeof(sin));
 	if(!port) {
 		sp = getservbyname(KPROP_SERVICE, "tcp");
-		if (sp == NULL) {
-			com_err(progname, 0, "%s/tcp: unknown service", KPROP_SERVICE);
-			exit(1);
-		}
-		sin.sin_port = sp->s_port;
+                if (sp == NULL)
+                  sin.sin_port = htons(DEFAULT_KPROP_PORT);
+                else
+                  sin.sin_port = sp->s_port;
 	} else {
 		sin.sin_port = port;
 	}
@@ -173,10 +195,10 @@
 	    if (ret < 0) {
 		perror("bind");
 		com_err(progname, errno, "while binding listener socket");
-		exit(1);
+		return(1);
 	    }
 	}
-	if (!debug)
+	if (!debug && !nodaemon)
 		daemon(1, 0);	    
 #ifdef PID_FILE
 	if ((pidfile = fopen(PID_FILE, "w")) != NULL) {
@@ -188,11 +210,9 @@
 #endif
 	if (listen(finet, 5) < 0) {
 		com_err(progname, errno, "in listen call");
-		exit(1);
+		return(1);
 	}
 	while (1) {
-		int child_pid;
-	    
 		memset((char *)&frominet, 0, sizeof(frominet));
 		fromlen = sizeof(frominet);
 		s = accept(finet, (struct sockaddr *) &frominet, &fromlen);
@@ -203,43 +223,45 @@
 					"from accept system call");
 			continue;
 		}
-		if (debug)
-			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);
-			
-		}
+		doit(s, server, kpropd_context);
+		close(s);
 	}
+	return 0;
 }
 
-void doit(fd)
+int doit(fd, server, kpropd_context)
 	int	fd;
+	krb5_principal	server;
+	krb5_context	kpropd_context;
 {
 	struct sockaddr_in from;
 	int on = 1, fromlen;
 	struct hostent	*hp;
 	krb5_error_code	retval;
+	krb5_data confmsg;
+	krb5_auth_context auth_context;
+	krb5_principal	client;		/* This is who we're talking to */
 	int lock_fd;
+	int database_fd;
 	int omask;
-
+	char	*name;
+	int ret = 1;
+	
+	/*
+	 * Set the resources so we can clean up on error.
+	 */
+	lock_fd = -1;
+	database_fd = -1;
+	confmsg.data = 0;
+	auth_context = 0;
+	client = 0;
+	name = 0;
+	
 	fromlen = sizeof (from);
 	if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) {
 		fprintf(stderr, "%s: ", progname);
 		perror("getpeername");
-		exit(1);
+		goto cleanup;
 	}
 	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (caddr_t) &on,
 		       sizeof (on)) < 0) {
@@ -263,63 +285,123 @@
 	/*
 	 * Now do the authentication
 	 */
-	kerberos_authenticate(kpropd_context, fd, &client, from);
-	if (!authorized_principal(kpropd_context, client)) {
-		char	*name;
-
-		if (retval = krb5_unparse_name(kpropd_context, client, &name)) {
-			com_err(progname, retval,
-				"While unparsing client name");
-			exit(1);
+	if(kerberos_authenticate(kpropd_context, &auth_context, fd, &client, server, from)!=0) {
+		goto cleanup;
+	}
+		
+	if (!authorized_principal(kpropd_context, client, &name)) {
+		if(name == 0) {
+			if (retval = krb5_unparse_name(kpropd_context, client, &name)) {
+				com_err(progname, retval,
+					"While unparsing client name");
+				goto cleanup;
+			}
 		}
 		syslog(LOG_WARNING,
 		       "Rejected connection from unauthorized principal %s",
 		       name);
-		free(name);
-		exit(1);
+		goto cleanup;
 	}
 	omask = umask(077);
-	lock_fd = open(temp_file_name, O_RDWR|O_CREAT, 0600);
+	lock_fd = open(temp_file_name, O_RDWR|O_CREAT|O_BINARY, 0600);
 	(void) umask(omask);
 	retval = krb5_lock_file(kpropd_context, lock_fd, 
 				KRB5_LOCKMODE_EXCLUSIVE|KRB5_LOCKMODE_DONTBLOCK);
 	if (retval) {
-	    com_err(progname, retval, "while trying to lock '%s'",
+		com_err(progname, retval, "while trying to lock '%s'",
 		    temp_file_name);
-	    exit(1);
+		goto cleanup;
 	}
+
+	/* We only open database_fd here to truncate the file. */
 	if ((database_fd = open(temp_file_name,
-				O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
+				O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600)) < 0) {
 		com_err(progname, errno,
 			"while opening database file, '%s'",
 			temp_file_name);
-		exit(1);
+		goto cleanup;
 	}
-	recv_database(kpropd_context, fd, database_fd);
-	if (close(fd) < 0) {
-		com_err(progname, errno,
-			"while trying to close database file");
-		exit(1);
+	close(database_fd);
+	database_fd = -1; /* So we don't close twice. */
+
+	if(recv_database(kpropd_context, auth_context, server, client, fd, lock_fd, &confmsg) != 0) {
+		goto cleanup;
 	}
+
+#ifdef __CYGWIN32__
+	/* 
+	 * Cygwin32 needs some braindead code here, as it can't rename
+	 * a file with a lock on it. We are adding a race condition,
+	 * but hopefully this part of the code will go away when
+	 * Cygwin32 gets fixed.
+	 */
+	close(lock_fd);
+	lock_fd = -1;
+#endif /* __CYGWIN32__ */
+	
 	if (rename(temp_file_name, file)) {
 		com_err(progname, errno, "While renaming %s to %s",
 			temp_file_name, file);
-		exit(1);
+		goto cleanup;
 	}
+
+#ifdef __CYGWIN32__
+	lock_fd = open(file, O_RDWR|O_BINARY);
+#endif /* __CYGWIN32__ */
+
 	retval = krb5_lock_file(kpropd_context, lock_fd, KRB5_LOCKMODE_SHARED);
 	if (retval) {
-	    com_err(progname, retval, "while downgrading lock on '%s'",
+		com_err(progname, retval, "while downgrading lock on '%s'",
 		    temp_file_name);
-	    exit(1);
+		goto cleanup;
+	}
+	if(load_database(kpropd_context, kdb5_util, file)!=0) {
+		goto cleanup;
 	}
-	load_database(kpropd_context, kdb5_edit, file);
+
 	retval = krb5_lock_file(kpropd_context, lock_fd, KRB5_LOCKMODE_UNLOCK);
 	if (retval) {
-	    com_err(progname, retval, "while unlocking '%s'", temp_file_name);
-	    exit(1);
+		com_err(progname, retval, "while unlocking '%s'", temp_file_name);
+		goto cleanup;
 	}
 	(void)close(lock_fd);
-	exit(0);
+	lock_fd = -1;
+
+	/*
+	 * Send the acknowledgement message generated in
+	 * recv_database.
+	 */
+	if (retval = krb5_write_message(kpropd_context, (void *) &fd,
+					&confmsg)) { 
+		com_err(progname, retval,
+			"while sending # of received bytes");
+		goto cleanup;
+	}
+
+	/*
+	 * Log a message to say propagation was successful.
+	 */
+	syslog( LOG_INFO, "Successful database propagation from principal %s, host %s",
+		name ? name : "Unknown!!",
+		hp ? hp->h_name : inet_ntoa(from.sin_addr));
+		
+	ret = 0;
+
+cleanup:
+
+	if(lock_fd != -1)
+		close(lock_fd);
+	if(database_fd != -1)
+		close(database_fd);
+	if(confmsg.data != 0)
+		krb5_xfree(confmsg.data);
+	if(auth_context != 0)
+		krb5_auth_con_free(kpropd_context, auth_context);
+	if(client != 0)
+		krb5_free_principal(kpropd_context, client);
+	if(name != 0)
+		free(name);
+	return ret;
 }
 
 static void
@@ -338,8 +420,10 @@
 	       code ? error_message(code) : "", code ? " " : "", error_buf);
 }
 
-void PRS(argv)
+void PRS(argv, serverp, kpropd_contextp)
 	char	**argv;
+	krb5_principal *serverp;
+	krb5_context *kpropd_contextp;
 {
 	register char	*word, ch;
 	char	*cp;
@@ -347,9 +431,9 @@
 	char	my_host_name[MAXHOSTNAMELEN], buf[BUFSIZ];
 	krb5_error_code	retval;
 	static const char	tmp[] = ".temp";
-	
-	krb5_init_context(&kpropd_context);
-	krb5_init_ets(kpropd_context);
+
+	krb5_init_context(kpropd_contextp);
+	krb5_init_ets(*kpropd_contextp);
 
 	progname = *argv++;
 	while (word = *argv++) {
@@ -377,10 +461,10 @@
 					break;
 				case 'p':
 					if (*word)
-						kdb5_edit = word;
+						kdb5_util = word;
 					else
-						kdb5_edit = *argv++;
-					if (!kdb5_edit)
+						kdb5_util = *argv++;
+					if (!kdb5_util)
 						usage();
 					word = 0;
 					break;
@@ -417,6 +501,20 @@
 				case 'S':
 					standalone++;
 					break;
+				case 'n':
+					nodaemon++;
+					/* nodaemon implies standalone. */
+					standalone++;
+					break;
+				case 'a':
+					if (*word)
+					     acl_file_name = word;
+					else
+					     acl_file_name = *argv++;
+					if (!acl_file_name)
+					     usage();
+					word = 0;
+					break;
 				default:
 					usage();
 				}
@@ -426,6 +524,7 @@
 			/* We don't take any arguments, only options */
 			usage();
 	}
+
 	/*
 	 * If not in debug mode, switch com_err reporting to syslog
 	 */
@@ -433,17 +532,19 @@
 	    openlog("kpropd", LOG_PID | LOG_ODELAY, SYSLOG_CLASS);
 	    set_com_err_hook(kpropd_com_err_proc);
 	}
+
 	/*
 	 * Get my hostname, so we can construct my service name
 	 */
-	retval = krb5_sname_to_principal(kpropd_context,
+	retval = krb5_sname_to_principal(*kpropd_contextp,
 					 NULL, KPROP_SERVICE_NAME,
-					 KRB5_NT_SRV_HST, &server);
+					 KRB5_NT_SRV_HST, serverp);
 	if (retval) {
 		com_err(progname, retval,
 			"While trying to construct my service name");
 		exit(1);
 	}
+
 	/*
 	 * Construct the name of the temporary file.
 	 */
@@ -460,19 +561,24 @@
 /*
  * Figure out who's calling on the other end of the connection....
  */
-void
-kerberos_authenticate(context, fd, clientp, sin)
+int
+kerberos_authenticate(context, auth_contextp, fd, clientp, server, sin)
     krb5_context 	  context;
+    krb5_auth_context 	  *auth_contextp;
     int		 	  fd;
     krb5_principal	* clientp;
+    krb5_principal	  server;
     struct sockaddr_in	  sin;
 {
     krb5_error_code	  retval;
-    krb5_ticket		* ticket;
+    krb5_ticket		* ticket = 0;
     struct sockaddr_in	  r_sin;
     int			  sin_length;
+    krb5_address	sender_addr;
+    krb5_address	receiver_addr;
     krb5_keytab		  keytab = NULL;
-
+    int ret = 1;
+    
     /*
      * Set recv_addr and send_addr
      */
@@ -485,7 +591,7 @@
     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);
+	goto cleanup;
     }
 
     receiver_addr.addrtype = ADDRTYPE_INET;
@@ -497,50 +603,50 @@
     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, retval, "While unparsing server name");
+	    goto cleanup;
 	}
 	printf("krb5_recvauth(%d, %s, %s, ...)\n", fd, kprop_version, name);
 	free(name);
     }
 
-    if (retval = krb5_auth_con_init(context, &auth_context)) {
+    if (retval = krb5_auth_con_init(context, auth_contextp)) {
 	syslog(LOG_ERR, "Error in krb5_auth_con_ini: %s",error_message(retval));
-    	exit(1);
+    	goto cleanup;
     }
 
-    if (retval = krb5_auth_con_setflags(context, auth_context, 
+    if (retval = krb5_auth_con_setflags(context, *auth_contextp, 
 					KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
 	syslog(LOG_ERR, "Error in krb5_auth_con_setflags: %s",
 	       error_message(retval));
-	exit(1);
+	goto cleanup;
     }
 
-    if (retval = krb5_auth_con_setaddrs(context, auth_context, &receiver_addr,
+    if (retval = krb5_auth_con_setaddrs(context, *auth_contextp, &receiver_addr,
 				        &sender_addr)) {
 	syslog(LOG_ERR, "Error in krb5_auth_con_setaddrs: %s",
 	       error_message(retval));
-	exit(1);
+	goto cleanup;
     }
 
     if (srvtab) {
 	if (retval = krb5_kt_resolve(context, srvtab, &keytab)) {
 	  syslog(LOG_ERR, "Error in krb5_kt_resolve: %s", error_message(retval));
-	  exit(1);
+	  goto cleanup;
 	}
     }
 
-    if (retval = krb5_recvauth(context, &auth_context, (void *) &fd,
+    if (retval = krb5_recvauth(context, auth_contextp, (void *) &fd,
 			       kprop_version, server, 0, keytab, &ticket)){
 	syslog(LOG_ERR, "Error in krb5_recvauth: %s", error_message(retval));
-	exit(1);
+	goto cleanup;
     }
 
     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);
+	goto cleanup;
     }
 
     if (debug) {
@@ -548,32 +654,47 @@
 
 	if (retval = krb5_unparse_name(context, *clientp, &name)) {
 	    com_err(progname, retval, "While unparsing client name");
-	    exit(1);
+	    return(1);
 	}
 	printf("authenticated client: %s\n", name);
 	free(name);
     }
-    krb5_free_ticket(context, ticket);
+    ret = 0;
+
+cleanup:
+
+    if(keytab != 0)
+    	krb5_kt_close( context, keytab);
+    if(ticket != 0)
+        krb5_free_ticket(context, ticket);
+    return ret;
 }
 
 krb5_boolean
-authorized_principal(context, p)
+authorized_principal(context, p, name)
     krb5_context context;
     krb5_principal p;
+    char **name;
 {
-    char		*name;
     char		buf[1024];
     krb5_error_code	retval;
     FILE		*acl_file;
     int			end;
     
-    retval = krb5_unparse_name(context, p, &name);
-    if (retval)
+    *name = 0;
+    retval = krb5_unparse_name(context, p, name);
+    if (retval) {
+    	*name = 0;
 	return FALSE;
+    }
 
-    acl_file = fopen(KPROPD_ACL_FILE, "r");
-    if (!acl_file)
+    acl_file = fopen(acl_file_name, "r");
+    if (!acl_file) {
+	syslog(LOG_ERR, "Cannot open kpropd acl file %s", acl_file_name);
+    	if(debug)
+    	    fprintf(stderr, "Cannot open kpropd acl file %s\n", acl_file_name);
 	return FALSE;
+    }
 
     while (!feof(acl_file)) {
 	if (!fgets(buf, sizeof(buf), acl_file))
@@ -581,60 +702,72 @@
 	end = strlen(buf) - 1;
 	if (buf[end] == '\n')
 	    buf[end] = '\0';
-	if (!strcmp(name, buf)) {
-	    free(name);
+	if (!strcmp(*name, buf)) {
 	    fclose(acl_file);
 	    return TRUE;
 	}
     }
-    free(name);
     fclose(acl_file);
     return FALSE;
 }
 
-void
-recv_database(context, fd, database_fd)
+int
+recv_database(context, auth_context, server, client, fd, database_fd, confmsg)
     krb5_context context;
+    krb5_auth_context auth_context;
+    krb5_principal server;
+    krb5_principal client;
     int	fd;
     int	database_fd;
+    krb5_data *confmsg;
 {
 	int	database_size;
 	int	received_size, n;
 	char		buf[1024];
 	krb5_data	inbuf, outbuf;
 	krb5_error_code	retval;
+	int ret = 1;
 
 	/*
+	 * Setup for cleanup.
+ 	 */
+	inbuf.data = 0;
+	outbuf.data = 0;
+	
+	/*
 	 * Receive and decode size from client
 	 */
 	if (retval = krb5_read_message(context, (void *) &fd, &inbuf)) {
-		send_error(context, fd, retval, "while reading database size");
+		send_error(context, server, client, fd, retval, "while reading database size");
 		com_err(progname, retval,
 			"while reading size of database from client");
-		exit(1);
+		goto cleanup;
 	}
-	if (krb5_is_krb_error(&inbuf))
+	if (krb5_is_krb_error(&inbuf)) {
 		recv_error(context, &inbuf);
+		goto cleanup;
+	}
 	if (retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL)) {
-		send_error(context, fd, retval, "while decoding database size");
-		krb5_xfree(inbuf.data);
+		send_error(context, server, client, fd, retval, "while decoding database size");
 		com_err(progname, retval,
 			"while decoding database size from client");
-		exit(1);
+		goto cleanup;
 	}
 	memcpy((char *) &database_size, outbuf.data, sizeof(database_size));
 	krb5_xfree(inbuf.data);
 	krb5_xfree(outbuf.data);
+	inbuf.data = 0;
+	outbuf.data = 0;
 	database_size = ntohl(database_size);
 
-    /*
-     * Initialize the initial vector.
-     */
-    if (retval = krb5_auth_con_initivector(context, auth_context)) {
-	send_error(context, fd, retval, "failed while initializing i_vector");
-	com_err(progname, retval, "while initializing i_vector");
-	exit(1);
-    }
+	/*
+	 * Initialize the initial vector.
+	 */
+	if (retval = krb5_auth_con_initivector(context, auth_context)) {
+		send_error(context, server, client, fd, retval, "failed while initializing i_vector");
+		com_err(progname, retval, "while initializing i_vector");
+		goto cleanup;
+    	}
 
 	/*
 	 * Now start receiving the database from the net
@@ -646,34 +779,39 @@
 				"while reading database block starting at offset %d",
 				received_size);
 			com_err(progname, retval, buf);
-			send_error(context, fd, retval, buf);
-			exit(1);
+			send_error(context, server, client, fd, retval, buf);
+			goto cleanup;
 		}
-		if (krb5_is_krb_error(&inbuf))
+		if (krb5_is_krb_error(&inbuf)) {
 			recv_error(context, &inbuf);
+			goto cleanup;
+		}
 		if (retval = krb5_rd_priv(context, auth_context, &inbuf, 
 					  &outbuf, NULL)) {
 			sprintf(buf,
 				"while decoding database block starting at offset %d",
 				received_size);
 			com_err(progname, retval, buf);
-			send_error(context, fd, retval, buf);
-			krb5_xfree(inbuf.data);
-			exit(1);
+			send_error(context, server, client, fd, retval, buf);
+			goto cleanup;
 		}
 		n = write(database_fd, outbuf.data, outbuf.length);
 		krb5_xfree(inbuf.data);
 		krb5_xfree(outbuf.data);
+		inbuf.data = 0;
+		outbuf.data = 0;
 		if (n < 0) {
 			sprintf(buf,
 				"while writing database block starting at offset %d",
 				received_size);
-			send_error(context, fd, errno, buf);
+			send_error(context, server, client, fd, errno, buf);
+			goto cleanup;
 		} else if (n != outbuf.length) {
 			sprintf(buf,
 				"incomplete write while writing database block starting at \noffset %d (%d written, %d expected)",
 				received_size, n, outbuf.length);
-			send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
+			send_error(context, server, client, fd, KRB5KRB_ERR_GENERIC, buf);
+			goto cleanup;
 		}
 		received_size += outbuf.length;
 	}
@@ -684,34 +822,42 @@
 		sprintf(buf,
 			"Received %d bytes, expected %d bytes for database file",
 			received_size, database_size);
-		send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
+		send_error(context, server, client, fd, KRB5KRB_ERR_GENERIC, buf);
+		goto cleanup;
 	}
 	/*
-	 * Send over acknowledgement of number of bytes receieved.
+	 * Create message acknowledging number of bytes received, but
+	 * don't send it until kdb5_util returns successfully.
 	 */
 	database_size = htonl(database_size);
 	inbuf.data = (char *) &database_size;
 	inbuf.length = sizeof(database_size);
-	if (retval = krb5_mk_safe(context,auth_context,&inbuf,&outbuf,NULL)) {
+	if (retval = krb5_mk_safe(context,auth_context,&inbuf,confmsg,NULL)) {
+		inbuf.data = 0;
 		com_err(progname, retval,
 			"while encoding # of receieved bytes");
-		send_error(context, fd, retval,
+		send_error(context, server, client, fd, retval,
 			   "while encoding # of received bytes");
-		exit(1);
+		goto cleanup;
 	}
-	if (retval = krb5_write_message(context, (void *) &fd, &outbuf)) {
+	inbuf.data = 0;
+	ret = 0;
+
+cleanup:
+
+	if(inbuf.data != 0)
+		krb5_xfree(inbuf.data);
+	if(outbuf.data != 0)
 		krb5_xfree(outbuf.data);
-		com_err(progname, retval,
-			"while sending # of receeived bytes");
-		exit(1);
-	}
-	krb5_xfree(outbuf.data);
+	return ret;	
 }
 
 
 void
-send_error(context, fd, err_code, err_text)
+send_error(context, server, client, fd, err_code, err_text)
     krb5_context context;
+    krb5_principal server;
+    krb5_principal client;
     int	fd;
     krb5_error_code	err_code;
     char	*err_text;
@@ -751,7 +897,7 @@
 	}
 }
 
-void
+int
 recv_error(context, inbuf)
     krb5_context context;
     krb5_data	*inbuf;
@@ -762,7 +908,7 @@
 	if (retval = krb5_rd_error(context, inbuf, &error)) {
 		com_err(progname, retval,
 			"while decoding error packet from client");
-		exit(1);
+		return(1);
 	}
 	if (error->error == KRB_ERR_GENERIC) {
 		if (error->text.data)
@@ -778,20 +924,21 @@
 				error->text.data);
 	}
 	krb5_free_error(context, error);
-	exit(1);
+	return(1);
 }
 
-void
-load_database(context, kdb5_edit, database_file_name)
+int
+load_database(context, kdb5_util, database_file_name)
     krb5_context context;
-    char *kdb5_edit;
+    char *kdb5_util;
     char *database_file_name;
 {
 	static char	*edit_av[10];
 	int	error_ret, save_stderr;
 	int	child_pid;
 	int 	count;
-
+	char	*log_file_name;
+	int	log_fd;
 	/* <sys/param.h> has been included, so BSD will be defined on
 	   BSD systems */
 #if BSD > 0 && BSD <= 43
@@ -802,46 +949,58 @@
 #else
 	int	waitb;
 #endif
-	char	request[1024];
 	krb5_error_code	retval;
 
+#define ERREXT ".load_log"
+
+	log_file_name = malloc(strlen(database_file_name)+strlen(ERREXT)+1);
+	if (!log_file_name)
+		return 1; /* ENOMEM */
+	strcpy(log_file_name, database_file_name);
+	strcat(log_file_name, ERREXT);
+
+
 	if (debug)
-		printf("calling krb5_edit to load database\n");
+		printf("calling kdb5_util to load database\n");
 
-	sprintf(request, "load_db %s %s", database_file_name, kerb_database);
-	
-	edit_av[0] = kdb5_edit;
+	edit_av[0] = kdb5_util;
 	count = 1;
 	if (realm) {
 		edit_av[count++] = "-r";	
 		edit_av[count++] = realm;	
 	}
-	edit_av[count++] = "-R";	
-	edit_av[count++] = request;
+	edit_av[count++] = "load";
+	edit_av[count++] = "-d";
+	edit_av[count++] = kerb_database;
+	edit_av[count++] = database_file_name;
 	edit_av[count++] = NULL;
 
+#ifndef __CYGWIN32__
 	switch(child_pid = fork()) {
 	case -1:
 		com_err(progname, errno, "while trying to fork %s",
-			kdb5_edit);
-		exit(1);
+			kdb5_util);
+		free(log_file_name);
+		return(1);
 	case 0:
 		if (!debug) {
 			save_stderr = dup(2);
 			close(0);
 			close(1);
 			close(2);
-			open("/dev/null", O_RDWR);
+			log_fd = open(log_file_name, O_RDWR);
+			if (log_fd < 0) 
+			  open("/dev/null", O_RDWR);
 			dup(0);
 			dup(0);
 		}
 
-		execv(kdb5_edit, edit_av);
+		execv(kdb5_util, edit_av);
 		retval = errno;
 		if (!debug)
 			dup2(save_stderr, 2);
 		com_err(progname, retval, "while trying to exec %s",
-			kdb5_edit);
+			kdb5_util);
 		_exit(1);
 		/*NOTREACHED*/
 	default:
@@ -849,15 +1008,46 @@
 		    printf("Child PID is %d\n", child_pid);
 		if (wait(&waitb) < 0) {
 			com_err(progname, errno, "while waiting for %s",
-				kdb5_edit);
-			exit(1);
+				kdb5_util);
+			free(log_file_name);
+			return(1);
 		}
 	}
 	
 	if (error_ret = WEXITSTATUS(waitb)) {
+#else /* __CYGWIN32__ */
+	{
+	    int save_stdout, save_stdin;
+	    save_stdin = dup(0);
+	    save_stdout = dup(1);
+	    save_stderr = dup(2);
+
+	    /*
+	     * Setup the log file to be 0,1,2.
+	     */
+	    log_fd = open(log_file_name, O_RDWR|O_CREAT|O_TRUNC);
+	    if (log_fd < 0) 
+	        log_fd = open("/dev/null", O_RDWR);
+	    dup2(log_fd,0);
+	    dup2(log_fd,1);
+	    dup2(log_fd,2);
+	    close(log_fd);
+	    error_ret = spawnv( _P_WAIT, kdb5_util, edit_av);
+	    dup2(save_stdin, 0);
+	    dup2(save_stdout,1);
+	    dup2(save_stderr,2);
+	    close(save_stdin);
+	    close(save_stdout);
+	    close(save_stderr);
+	}
+	if(error_ret != 0) {
+#endif /* __CYGWIN32__ */
 		com_err(progname, 0, "%s returned a bad exit status (%d)",
-			kdb5_edit, error_ret);
-		exit(1);
+			kdb5_util, error_ret);
+		free(log_file_name);
+		return(1);
 	}
-	return;
+
+	free(log_file_name);
+	return(0);
 }
