- markus@cvs.openbsd.org 2003/09/23 20:17:11
     [Makefile.in auth1.c auth2.c auth.c auth.h auth-krb5.c canohost.c
     cleanup.c clientloop.c fatal.c gss-serv.c log.c log.h monitor.c monitor.h
     monitor_wrap.c monitor_wrap.h packet.c serverloop.c session.c session.h
     ssh-agent.c sshd.c]
     replace fatal_cleanup() and linked list of fatal callbacks with static
     cleanup_exit() function.  re-refine cleanup_exit() where appropriate,
     allocate sshd's authctxt eary to allow simpler cleanup in sshd.
     tested by many, ok deraadt@
diff --git a/ChangeLog b/ChangeLog
index c782c10..a25c731 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+20031002
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2003/09/23 20:17:11
+     [Makefile.in auth1.c auth2.c auth.c auth.h auth-krb5.c canohost.c
+     cleanup.c clientloop.c fatal.c gss-serv.c log.c log.h monitor.c monitor.h
+     monitor_wrap.c monitor_wrap.h packet.c serverloop.c session.c session.h
+     ssh-agent.c sshd.c]
+     replace fatal_cleanup() and linked list of fatal callbacks with static
+     cleanup_exit() function.  re-refine cleanup_exit() where appropriate,
+     allocate sshd's authctxt eary to allow simpler cleanup in sshd.
+     tested by many, ok deraadt@
+
 20030930
  - (bal) Fix issues in openbsd-compat/realpath.c
 
@@ -1232,4 +1244,4 @@
  - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo.
    Report from murple@murple.net, diagnosis from dtucker@zip.com.au
 
-$Id: ChangeLog,v 1.3044 2003/09/30 23:49:06 mouring Exp $
+$Id: ChangeLog,v 1.3045 2003/10/02 06:12:36 dtucker Exp $
diff --git a/Makefile.in b/Makefile.in
index 4368132..dce12c4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.250 2003/09/22 00:58:56 dtucker Exp $
+# $Id: Makefile.in,v 1.251 2003/10/02 06:12:36 dtucker Exp $
 
 # uncomment if you run a non bourne compatable shell. Ie. csh
 #SHELL = @SH@
@@ -62,8 +62,8 @@
 TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT)
 
 LIBSSH_OBJS=authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o \
-	cipher.o  cipher-aes.o cipher-bf1.o cipher-ctr.o cipher-3des1.o \
-	compat.o compress.o crc32.o deattack.o fatal.o \
+	cipher.o cipher-aes.o cipher-bf1.o cipher-ctr.o cipher-3des1.o \
+	cleanup.o compat.o compress.o crc32.o deattack.o fatal.o \
 	hostfile.o log.o match.o moduli.o mpaux.o nchan.o packet.o \
 	readpass.o rsa.o tildexpand.o ttymodes.o xmalloc.o atomicio.o \
 	key.o dispatch.o kex.o mac.o uuencode.o misc.o \
diff --git a/auth-krb5.c b/auth-krb5.c
index 0aa5195..e31f2eb 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -28,7 +28,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth-krb5.c,v 1.12 2003/08/28 12:54:34 markus Exp $");
+RCSID("$OpenBSD: auth-krb5.c,v 1.13 2003/09/23 20:17:11 markus Exp $");
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -50,7 +50,6 @@
 {
 	Authctxt *authctxt = (Authctxt *)context;
 	krb5_error_code problem;
-	static int cleanup_registered = 0;
 
 	if (authctxt->krb5_ctx == NULL) {
 		problem = krb5_init_context(&authctxt->krb5_ctx);
@@ -58,10 +57,6 @@
 			return (problem);
 		krb5_init_ets(authctxt->krb5_ctx);
 	}
-	if (!cleanup_registered) {
-		fatal_add_cleanup(krb5_cleanup_proc, authctxt);
-		cleanup_registered = 1;
-	}
 	return (0);
 }
 
@@ -205,10 +200,8 @@
 }
 
 void
-krb5_cleanup_proc(void *context)
+krb5_cleanup_proc(Authctxt *authctxt)
 {
-	Authctxt *authctxt = (Authctxt *)context;
-
 	debug("krb5_cleanup_proc called");
 	if (authctxt->krb5_fwd_ccache) {
 		krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
diff --git a/auth.c b/auth.c
index 46e495a..0296728 100644
--- a/auth.c
+++ b/auth.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth.c,v 1.49 2003/08/26 09:58:43 markus Exp $");
+RCSID("$OpenBSD: auth.c,v 1.50 2003/09/23 20:17:11 markus Exp $");
 
 #ifdef HAVE_LOGIN_H
 #include <login.h>
@@ -263,14 +263,6 @@
 	return 1;
 }
 
-Authctxt *
-authctxt_new(void)
-{
-	Authctxt *authctxt = xmalloc(sizeof(*authctxt));
-	memset(authctxt, 0, sizeof(*authctxt));
-	return authctxt;
-}
-
 void
 auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
 {
diff --git a/auth.h b/auth.h
index beaacb8..b081bb5 100644
--- a/auth.h
+++ b/auth.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: auth.h,v 1.46 2003/08/28 12:54:34 markus Exp $	*/
+/*	$OpenBSD: auth.h,v 1.47 2003/09/23 20:17:11 markus Exp $	*/
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -118,15 +118,14 @@
 int	auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *);
 int	auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);
 int	auth_krb5_password(Authctxt *authctxt, const char *password);
-void	krb5_cleanup_proc(void *authctxt);
+void	krb5_cleanup_proc(Authctxt *authctxt);
 #endif /* KRB5 */
 
 #include "auth-pam.h"
 
-Authctxt *do_authentication(void);
-Authctxt *do_authentication2(void);
+void  do_authentication(Authctxt *);
+void  do_authentication2(Authctxt *);
 
-Authctxt *authctxt_new(void);
 void	auth_log(Authctxt *, int, char *, char *);
 void	userauth_finish(Authctxt *, int, char *);
 int	auth_root_allowed(char *);
@@ -149,8 +148,6 @@
 int	verify_response(Authctxt *, const char *);
 void	abandon_challenge_response(Authctxt *);
 
-struct passwd * auth_get_user(void);
-
 char	*expand_filename(const char *, struct passwd *);
 char	*authorized_keys_file(struct passwd *);
 char	*authorized_keys_file2(struct passwd *);
diff --git a/auth1.c b/auth1.c
index dfe944d..38c0bf9 100644
--- a/auth1.c
+++ b/auth1.c
@@ -10,7 +10,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth1.c,v 1.52 2003/08/28 12:54:34 markus Exp $");
+RCSID("$OpenBSD: auth1.c,v 1.53 2003/09/23 20:17:11 markus Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -275,10 +275,9 @@
  * Performs authentication of an incoming connection.  Session key has already
  * been exchanged and encryption is enabled.
  */
-Authctxt *
-do_authentication(void)
+void
+do_authentication(Authctxt *authctxt)
 {
-	Authctxt *authctxt;
 	u_int ulen;
 	char *user, *style = NULL;
 
@@ -292,7 +291,6 @@
 	if ((style = strchr(user, ':')) != NULL)
 		*style++ = '\0';
 
-	authctxt = authctxt_new();
 	authctxt->user = user;
 	authctxt->style = style;
 
@@ -332,6 +330,4 @@
 	packet_start(SSH_SMSG_SUCCESS);
 	packet_send();
 	packet_write_wait();
-
-	return (authctxt);
 }
diff --git a/auth2.c b/auth2.c
index 41e77ef..ef1173f 100644
--- a/auth2.c
+++ b/auth2.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.102 2003/08/26 09:58:43 markus Exp $");
+RCSID("$OpenBSD: auth2.c,v 1.103 2003/09/23 20:17:11 markus Exp $");
 
 #include "ssh2.h"
 #include "xmalloc.h"
@@ -45,8 +45,6 @@
 extern u_char *session_id2;
 extern u_int session_id2_len;
 
-Authctxt *x_authctxt = NULL;
-
 /* methods */
 
 extern Authmethod method_none;
@@ -85,13 +83,9 @@
  * loop until authctxt->success == TRUE
  */
 
-Authctxt *
-do_authentication2(void)
+void
+do_authentication2(Authctxt *authctxt)
 {
-	Authctxt *authctxt = authctxt_new();
-
-	x_authctxt = authctxt;		/*XXX*/
-
 	/* challenge-response is implemented via keyboard interactive */
 	if (options.challenge_response_authentication)
 		options.kbd_interactive_authentication = 1;
@@ -99,8 +93,6 @@
 	dispatch_init(&dispatch_protocol_error);
 	dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
 	dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
-
-	return (authctxt);
 }
 
 static void
@@ -264,14 +256,6 @@
 	}
 }
 
-/* get current user */
-
-struct passwd*
-auth_get_user(void)
-{
-	return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
-}
-
 #define	DELIM	","
 
 static char *
diff --git a/canohost.c b/canohost.c
index 438175f..fca7134 100644
--- a/canohost.c
+++ b/canohost.c
@@ -12,7 +12,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: canohost.c,v 1.37 2003/06/02 09:17:34 markus Exp $");
+RCSID("$OpenBSD: canohost.c,v 1.38 2003/09/23 20:17:11 markus Exp $");
 
 #include "packet.h"
 #include "xmalloc.h"
@@ -40,7 +40,7 @@
 	memset(&from, 0, sizeof(from));
 	if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0) {
 		debug("getpeername failed: %.100s", strerror(errno));
-		fatal_cleanup();
+		cleanup_exit(255);
 	}
 #ifdef IPV4_IN_IPV6
 	if (from.ss_family == AF_INET6) {
@@ -296,7 +296,7 @@
 			canonical_host_ip =
 			    get_peer_ipaddr(packet_get_connection_in());
 			if (canonical_host_ip == NULL)
-				fatal_cleanup();
+				cleanup_exit(255);
 		} else {
 			/* If not on socket, return UNKNOWN. */
 			canonical_host_ip = xstrdup("UNKNOWN");
@@ -336,7 +336,7 @@
 	} else {
 		if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) {
 			debug("getpeername failed: %.100s", strerror(errno));
-			fatal_cleanup();
+			cleanup_exit(255);
 		}
 	}
 
diff --git a/cleanup.c b/cleanup.c
new file mode 100644
index 0000000..11d1d4d
--- /dev/null
+++ b/cleanup.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "includes.h"
+RCSID("$OpenBSD: cleanup.c,v 1.1 2003/09/23 20:17:11 markus Exp $");
+
+#include "log.h"
+
+/* default implementation */
+void
+cleanup_exit(int i)
+{
+	_exit(i);
+}
diff --git a/clientloop.c b/clientloop.c
index bc50f0b..d3a32a8 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -59,7 +59,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: clientloop.c,v 1.113 2003/09/19 17:43:35 markus Exp $");
+RCSID("$OpenBSD: clientloop.c,v 1.114 2003/09/23 20:17:11 markus Exp $");
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -1384,14 +1384,9 @@
 
 /* client specific fatal cleanup */
 void
-fatal(const char *fmt,...)
+cleanup_exit(int i)
 {
-	va_list args;
-
-	va_start(args, fmt);
-	do_log(SYSLOG_LEVEL_FATAL, fmt, args);
-	va_end(args);
 	leave_raw_mode();
 	leave_non_blocking();
-	_exit(255);
+	_exit(i);
 }
diff --git a/fatal.c b/fatal.c
index 9e7d160..ae1aaac 100644
--- a/fatal.c
+++ b/fatal.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: fatal.c,v 1.1 2002/02/22 12:20:34 markus Exp $");
+RCSID("$OpenBSD: fatal.c,v 1.2 2003/09/23 20:17:11 markus Exp $");
 
 #include "log.h"
 
@@ -36,5 +36,5 @@
 	va_start(args, fmt);
 	do_log(SYSLOG_LEVEL_FATAL, fmt, args);
 	va_end(args);
-	fatal_cleanup();
+	cleanup_exit(255);
 }
diff --git a/gss-serv.c b/gss-serv.c
index 8fd1d63..6574f97 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: gss-serv.c,v 1.3 2003/08/31 13:31:57 markus Exp $	*/
+/*	$OpenBSD: gss-serv.c,v 1.4 2003/09/23 20:17:11 markus Exp $	*/
 
 /*
  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@@ -232,9 +232,9 @@
 	return (ctx->major);
 }
 
-/* As user - called through fatal cleanup hook */
+/* As user - called on fatal/exit */
 void
-ssh_gssapi_cleanup_creds(void *ignored)
+ssh_gssapi_cleanup_creds(void)
 {
 	if (gssapi_client.store.filename != NULL) {
 		/* Unlink probably isn't sufficient */
@@ -249,8 +249,6 @@
 {
 	if (gssapi_client.mech && gssapi_client.mech->storecreds) {
 		(*gssapi_client.mech->storecreds)(&gssapi_client);
-		if (options.gss_cleanup_creds)
-			fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
 	} else
 		debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
 }
diff --git a/log.c b/log.c
index 9bce255..686a2a4 100644
--- a/log.c
+++ b/log.c
@@ -34,7 +34,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: log.c,v 1.28 2003/05/24 09:02:22 djm Exp $");
+RCSID("$OpenBSD: log.c,v 1.29 2003/09/23 20:17:11 markus Exp $");
 
 #include "log.h"
 #include "xmalloc.h"
@@ -183,83 +183,6 @@
 	va_end(args);
 }
 
-/* Fatal cleanup */
-
-struct fatal_cleanup {
-	struct fatal_cleanup *next;
-	void (*proc) (void *);
-	void *context;
-};
-
-static struct fatal_cleanup *fatal_cleanups = NULL;
-
-/* Registers a cleanup function to be called by fatal() before exiting. */
-
-void
-fatal_add_cleanup(void (*proc) (void *), void *context)
-{
-	struct fatal_cleanup *cu;
-
-	cu = xmalloc(sizeof(*cu));
-	cu->proc = proc;
-	cu->context = context;
-	cu->next = fatal_cleanups;
-	fatal_cleanups = cu;
-}
-
-/* Removes a cleanup frunction to be called at fatal(). */
-
-void
-fatal_remove_cleanup(void (*proc) (void *context), void *context)
-{
-	struct fatal_cleanup **cup, *cu;
-
-	for (cup = &fatal_cleanups; *cup; cup = &cu->next) {
-		cu = *cup;
-		if (cu->proc == proc && cu->context == context) {
-			*cup = cu->next;
-			xfree(cu);
-			return;
-		}
-	}
-	fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx",
-	    (u_long) proc, (u_long) context);
-}
-
-/* Remove all cleanups, to be called after fork() */
-void
-fatal_remove_all_cleanups(void)
-{
-	struct fatal_cleanup *cu, *next_cu;
-
-	for (cu = fatal_cleanups; cu; cu = next_cu) {
-		next_cu = cu->next;
-		xfree(cu);
-	}
-	fatal_cleanups = NULL;
-}
-
-/* Cleanup and exit */
-void
-fatal_cleanup(void)
-{
-	struct fatal_cleanup *cu, *next_cu;
-	static int called = 0;
-
-	if (called)
-		exit(255);
-	called = 1;
-	/* Call cleanup functions. */
-	for (cu = fatal_cleanups; cu; cu = next_cu) {
-		next_cu = cu->next;
-		debug("Calling cleanup 0x%lx(0x%lx)",
-		    (u_long) cu->proc, (u_long) cu->context);
-		(*cu->proc) (cu->context);
-	}
-	exit(255);
-}
-
-
 /*
  * Initialize the log.
  */
diff --git a/log.h b/log.h
index c366681..e026319 100644
--- a/log.h
+++ b/log.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: log.h,v 1.9 2003/04/08 20:21:28 itojun Exp $	*/
+/*	$OpenBSD: log.h,v 1.10 2003/09/23 20:17:11 markus Exp $	*/
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -61,11 +61,6 @@
 void     debug2(const char *, ...) __attribute__((format(printf, 1, 2)));
 void     debug3(const char *, ...) __attribute__((format(printf, 1, 2)));
 
-void     fatal_cleanup(void);
-void     fatal_add_cleanup(void (*) (void *), void *);
-void     fatal_remove_cleanup(void (*) (void *), void *);
-void     fatal_remove_all_cleanups(void);
-
 void	 do_log(LogLevel, const char *, va_list);
-
+void	 cleanup_exit(int);
 #endif
diff --git a/monitor.c b/monitor.c
index e565647..eaf66f7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -25,7 +25,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: monitor.c,v 1.49 2003/08/28 12:54:34 markus Exp $");
+RCSID("$OpenBSD: monitor.c,v 1.50 2003/09/23 20:17:11 markus Exp $");
 
 #include <openssl/dh.h>
 
@@ -272,14 +272,17 @@
 	}
 }
 
-Authctxt *
-monitor_child_preauth(struct monitor *pmonitor)
+void
+monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
 {
 	struct mon_table *ent;
 	int authenticated = 0;
 
 	debug3("preauth child monitor started");
 
+	authctxt = _authctxt;
+	memset(authctxt, 0, sizeof(*authctxt));
+
 	if (compat20) {
 		mon_dispatch = mon_dispatch_proto20;
 
@@ -292,8 +295,6 @@
 		monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1);
 	}
 
-	authctxt = authctxt_new();
-
 	/* The first few requests do not require asynchronous access */
 	while (!authenticated) {
 		authenticated = monitor_read(pmonitor, mon_dispatch, &ent);
@@ -333,8 +334,6 @@
 	    __func__, authctxt->user);
 
 	mm_get_keystate(pmonitor);
-
-	return (authctxt);
 }
 
 static void
@@ -1185,7 +1184,7 @@
 		if (getpeername(packet_get_connection_in(),
 			(struct sockaddr *) & from, &fromlen) < 0) {
 			debug("getpeername: %.100s", strerror(errno));
-			fatal_cleanup();
+			cleanup_exit(255);
 		}
 	}
 	/* Record that there was a login on that tty from the remote host. */
@@ -1200,7 +1199,6 @@
 	debug3("%s: session %d pid %ld", __func__, s->self, (long)s->pid);
 	if (s->ttyfd != -1) {
 		debug3("%s: tty %s ptyfd %d",  __func__, s->tty, s->ptyfd);
-		fatal_remove_cleanup(session_pty_cleanup2, (void *)s);
 		session_pty_cleanup2(s);
 	}
 	s->used = 0;
@@ -1225,7 +1223,6 @@
 	res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
 	if (res == 0)
 		goto error;
-	fatal_add_cleanup(session_pty_cleanup2, (void *)s);
 	pty_setowner(authctxt->pw, s->tty);
 
 	buffer_put_int(m, 1);
diff --git a/monitor.h b/monitor.h
index 2461156..a153f41 100644
--- a/monitor.h
+++ b/monitor.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: monitor.h,v 1.11 2003/08/28 12:54:34 markus Exp $	*/
+/*	$OpenBSD: monitor.h,v 1.12 2003/09/23 20:17:11 markus Exp $	*/
 
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -76,7 +76,7 @@
 void monitor_sync(struct monitor *);
 
 struct Authctxt;
-struct Authctxt *monitor_child_preauth(struct monitor *);
+void monitor_child_preauth(struct Authctxt *, struct monitor *);
 void monitor_child_postauth(struct monitor *);
 
 struct mon_table;
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 4034d56..99dfc85 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -25,7 +25,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: monitor_wrap.c,v 1.31 2003/08/28 12:54:34 markus Exp $");
+RCSID("$OpenBSD: monitor_wrap.c,v 1.32 2003/09/23 20:17:11 markus Exp $");
 
 #include <openssl/bn.h>
 #include <openssl/dh.h>
@@ -66,6 +66,16 @@
 extern Buffer input, output;
 extern ServerOptions options;
 
+int
+mm_is_monitor(void)
+{
+	/*
+	 * m_pid is only set in the privileged part, and
+	 * points to the unprivileged child.
+	 */
+	return (pmonitor->m_pid > 0);
+}
+
 void
 mm_request_send(int socket, enum monitor_reqtype type, Buffer *m)
 {
@@ -94,7 +104,7 @@
 	res = atomicio(read, socket, buf, sizeof(buf));
 	if (res != sizeof(buf)) {
 		if (res == 0)
-			fatal_cleanup();
+			cleanup_exit(255);
 		fatal("%s: read: %ld", __func__, (long)res);
 	}
 	msg_len = GET_32BIT(buf);
@@ -648,9 +658,8 @@
 }
 
 void
-mm_session_pty_cleanup2(void *session)
+mm_session_pty_cleanup2(Session *s)
 {
-	Session *s = session;
 	Buffer m;
 
 	if (s->ttyfd == -1)
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 5e03345..76c02f1 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: monitor_wrap.h,v 1.11 2003/08/28 12:54:34 markus Exp $	*/
+/*	$OpenBSD: monitor_wrap.h,v 1.12 2003/09/23 20:17:11 markus Exp $	*/
 
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -40,6 +40,7 @@
 struct passwd;
 struct Authctxt;
 
+int mm_is_monitor(void);
 DH *mm_choose_dh(int, int, int);
 int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int);
 void mm_inform_authserv(char *, char *);
@@ -72,9 +73,10 @@
 void mm_sshpam_free_ctx(void *);
 #endif
 
+struct Session;
 void mm_terminate(void);
 int mm_pty_allocate(int *, int *, char *, int);
-void mm_session_pty_cleanup2(void *);
+void mm_session_pty_cleanup2(struct Session *);
 
 /* SSHv1 interfaces */
 void mm_ssh1_session_id(u_char *);
diff --git a/packet.c b/packet.c
index 6e7e574..52b4f66 100644
--- a/packet.c
+++ b/packet.c
@@ -37,7 +37,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: packet.c,v 1.111 2003/09/19 11:33:09 markus Exp $");
+RCSID("$OpenBSD: packet.c,v 1.112 2003/09/23 20:17:11 markus Exp $");
 
 #include "openbsd-compat/sys-queue.h"
 
@@ -868,7 +868,7 @@
 		len = read(connection_in, buf, sizeof(buf));
 		if (len == 0) {
 			logit("Connection closed by %.200s", get_remote_ipaddr());
-			fatal_cleanup();
+			cleanup_exit(255);
 		}
 		if (len < 0)
 			fatal("Read from socket failed: %.100s", strerror(errno));
@@ -1134,7 +1134,7 @@
 				logit("Received disconnect from %s: %u: %.400s",
 				    get_remote_ipaddr(), reason, msg);
 				xfree(msg);
-				fatal_cleanup();
+				cleanup_exit(255);
 				break;
 			case SSH2_MSG_UNIMPLEMENTED:
 				seqnr = packet_get_int();
@@ -1159,7 +1159,7 @@
 				msg = packet_get_string(NULL);
 				logit("Received disconnect from %s: %.400s",
 				    get_remote_ipaddr(), msg);
-				fatal_cleanup();
+				cleanup_exit(255);
 				xfree(msg);
 				break;
 			default:
@@ -1336,7 +1336,7 @@
 
 	/* Close the connection. */
 	packet_close();
-	fatal_cleanup();
+	cleanup_exit(255);
 }
 
 /* Checks if there is any buffered output, and tries to write some of the output. */
diff --git a/serverloop.c b/serverloop.c
index a953902..21656cf 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -35,7 +35,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: serverloop.c,v 1.110 2003/06/24 08:23:46 markus Exp $");
+RCSID("$OpenBSD: serverloop.c,v 1.111 2003/09/23 20:17:11 markus Exp $");
 
 #include "xmalloc.h"
 #include "packet.h"
@@ -60,7 +60,7 @@
 
 /* XXX */
 extern Kex *xxx_kex;
-static Authctxt *xxx_authctxt;
+extern Authctxt *the_authctxt;
 
 static Buffer stdin_buffer;	/* Buffer for stdin data. */
 static Buffer stdout_buffer;	/* Buffer for stdout data. */
@@ -355,13 +355,13 @@
 			connection_closed = 1;
 			if (compat20)
 				return;
-			fatal_cleanup();
+			cleanup_exit(255);
 		} else if (len < 0) {
 			if (errno != EINTR && errno != EAGAIN) {
 				verbose("Read error from remote host "
 				    "%.100s: %.100s",
 				    get_remote_ipaddr(), strerror(errno));
-				fatal_cleanup();
+				cleanup_exit(255);
 			}
 		} else {
 			/* Buffer any received data. */
@@ -756,8 +756,6 @@
 	max_fd = MAX(connection_in, connection_out);
 	max_fd = MAX(max_fd, notify_pipe[0]);
 
-	xxx_authctxt = authctxt;
-
 	server_init_dispatch();
 
 	for (;;) {
@@ -900,7 +898,7 @@
 	c = channel_new(ctype, SSH_CHANNEL_LARVAL,
 	    -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
 	    0, "server-session", 1);
-	if (session_open(xxx_authctxt, c->self) != 1) {
+	if (session_open(the_authctxt, c->self) != 1) {
 		debug("session open failed, free channel %d", c->self);
 		channel_free(c);
 		return NULL;
@@ -974,7 +972,7 @@
 		char *listen_address;
 		u_short listen_port;
 
-		pw = auth_get_user();
+		pw = the_authctxt->pw;
 		if (pw == NULL)
 			fatal("server_input_global_request: no user");
 		listen_address = packet_get_string(NULL);
diff --git a/session.c b/session.c
index 2898ac5..647be40 100644
--- a/session.c
+++ b/session.c
@@ -33,7 +33,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.164 2003/09/18 08:49:45 markus Exp $");
+RCSID("$OpenBSD: session.c,v 1.165 2003/09/23 20:17:11 markus Exp $");
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -66,7 +66,7 @@
 
 Session *session_new(void);
 void	session_set_fds(Session *, int, int, int);
-void	session_pty_cleanup(void *);
+void	session_pty_cleanup(Session *);
 void	session_proctitle(Session *);
 int	session_setup_x11fwd(Session *);
 void	do_exec_pty(Session *, const char *);
@@ -106,6 +106,8 @@
 login_cap_t *lc;
 #endif
 
+static int is_child = 0;
+
 /* Name and directory of socket for authentication agent forwarding. */
 static char *auth_sock_name = NULL;
 static char *auth_sock_dir = NULL;
@@ -113,10 +115,8 @@
 /* removes the agent forwarding socket */
 
 static void
-auth_sock_cleanup_proc(void *_pw)
+auth_sock_cleanup_proc(struct passwd *pw)
 {
-	struct passwd *pw = _pw;
-
 	if (auth_sock_name != NULL) {
 		temporarily_use_uid(pw);
 		unlink(auth_sock_name);
@@ -160,9 +160,6 @@
 	snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld",
 		 auth_sock_dir, (long) getpid());
 
-	/* delete agent socket on fatal() */
-	fatal_add_cleanup(auth_sock_cleanup_proc, pw);
-
 	/* Create the socket. */
 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
 	if (sock < 0)
@@ -217,13 +214,7 @@
 	else
 		do_authenticated1(authctxt);
 
-	/* remove agent socket */
-	if (auth_sock_name != NULL)
-		auth_sock_cleanup_proc(authctxt->pw);
-#ifdef KRB5
-	if (options.kerberos_ticket_cleanup)
-		krb5_cleanup_proc(authctxt);
-#endif
+	do_cleanup(authctxt);
 }
 
 /*
@@ -405,7 +396,7 @@
 
 	/* Fork the child. */
 	if ((pid = fork()) == 0) {
-		fatal_remove_all_cleanups();
+		is_child = 1;
 
 		/* Child.  Reinitialize the log since the pid has changed. */
 		log_init(__progname, options.log_level, options.log_facility, log_stderr);
@@ -531,7 +522,7 @@
 
 	/* Fork the child. */
 	if ((pid = fork()) == 0) {
-		fatal_remove_all_cleanups();
+		is_child = 1;
 
 		/* Child.  Reinitialize the log because the pid has changed. */
 		log_init(__progname, options.log_level, options.log_facility, log_stderr);
@@ -627,7 +618,7 @@
 		if (getpeername(packet_get_connection_in(),
 		    (struct sockaddr *) & from, &fromlen) < 0) {
 			debug("getpeername: %.100s", strerror(errno));
-			fatal_cleanup();
+			cleanup_exit(255);
 		}
 	}
 
@@ -687,7 +678,7 @@
 		if (getpeername(packet_get_connection_in(),
 		    (struct sockaddr *) & from, &fromlen) < 0) {
 			debug("getpeername: %.100s", strerror(errno));
-			fatal_cleanup();
+			cleanup_exit(255);
 		}
 	}
 
@@ -1178,7 +1169,7 @@
 		if (debug_flag) {
 			fprintf(stderr,
 			    "Running %.500s remove %.100s\n",
-  			    options.xauth_location, s->auth_display);
+			    options.xauth_location, s->auth_display);
 			fprintf(stderr,
 			    "%.500s add %.100s %.100s %.100s\n",
 			    options.xauth_location, s->auth_display,
@@ -1663,11 +1654,6 @@
 		n_bytes = packet_remaining();
 	tty_parse_modes(s->ttyfd, &n_bytes);
 
-	/*
-	 * Add a cleanup function to clear the utmp entry and record logout
-	 * time in case we call fatal() (e.g., the connection gets closed).
-	 */
-	fatal_add_cleanup(session_pty_cleanup, (void *)s);
 	if (!use_privsep)
 		pty_setowner(s->pw, s->tty);
 
@@ -1849,10 +1835,8 @@
  * (e.g., due to a dropped connection).
  */
 void
-session_pty_cleanup2(void *session)
+session_pty_cleanup2(Session *s)
 {
-	Session *s = session;
-
 	if (s == NULL) {
 		error("session_pty_cleanup: no session");
 		return;
@@ -1883,9 +1867,9 @@
 }
 
 void
-session_pty_cleanup(void *session)
+session_pty_cleanup(Session *s)
 {
-	PRIVSEP(session_pty_cleanup2(session));
+	PRIVSEP(session_pty_cleanup2(s));
 }
 
 static char *
@@ -1958,10 +1942,8 @@
 session_close(Session *s)
 {
 	debug("session_close: session %d pid %ld", s->self, (long)s->pid);
-	if (s->ttyfd != -1) {
-		fatal_remove_cleanup(session_pty_cleanup, (void *)s);
+	if (s->ttyfd != -1)
 		session_pty_cleanup(s);
-	}
 	if (s->term)
 		xfree(s->term);
 	if (s->display)
@@ -2010,10 +1992,8 @@
 		 * delay detach of session, but release pty, since
 		 * the fd's to the child are already closed
 		 */
-		if (s->ttyfd != -1) {
-			fatal_remove_cleanup(session_pty_cleanup, (void *)s);
+		if (s->ttyfd != -1)
 			session_pty_cleanup(s);
-		}
 		return;
 	}
 	/* detach by removing callback */
@@ -2154,8 +2134,44 @@
 do_authenticated2(Authctxt *authctxt)
 {
 	server_loop2(authctxt);
-#if defined(GSSAPI)
-	if (options.gss_cleanup_creds)
-		ssh_gssapi_cleanup_creds(NULL);
+}
+
+void
+do_cleanup(Authctxt *authctxt)
+{
+	static int called = 0;
+
+	debug("do_cleanup");
+
+	/* no cleanup if we're in the child for login shell */
+	if (is_child)
+		return;
+
+	/* avoid double cleanup */
+	if (called)
+		return;
+	called = 1;
+
+	if (authctxt == NULL)
+		return;
+#ifdef KRB5
+	if (options.kerberos_ticket_cleanup &&
+	    authctxt->krb5_ctx)
+		krb5_cleanup_proc(authctxt);
 #endif
+
+#ifdef GSSAPI
+	if (compat20 && options.gss_cleanup_creds)
+		ssh_gssapi_cleanup_creds();
+#endif
+
+	/* remove agent socket */
+	auth_sock_cleanup_proc(authctxt->pw);
+
+	/*
+	 * Cleanup ptys/utmp only if privsep is disabled,
+	 * or if running in monitor.
+	 */
+	if (!use_privsep || mm_is_monitor())
+		session_destroy_all(session_pty_cleanup2);
 }
diff --git a/session.h b/session.h
index 525e47f..405b8fe 100644
--- a/session.h
+++ b/session.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: session.h,v 1.20 2003/08/22 10:56:09 markus Exp $	*/
+/*	$OpenBSD: session.h,v 1.21 2003/09/23 20:17:11 markus Exp $	*/
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -56,13 +56,14 @@
 };
 
 void	 do_authenticated(Authctxt *);
+void	 do_cleanup(Authctxt *);
 
 int	 session_open(Authctxt *, int);
 int	 session_input_channel_req(Channel *, const char *);
 void	 session_close_by_pid(pid_t, int);
 void	 session_close_by_channel(int, void *);
 void	 session_destroy_all(void (*)(Session *));
-void	 session_pty_cleanup2(void *);
+void	 session_pty_cleanup2(Session *);
 
 Session	*session_new(void);
 Session	*session_by_tty(char *);
diff --git a/ssh-agent.c b/ssh-agent.c
index 28a39a9..0fe8772 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -35,7 +35,7 @@
 
 #include "includes.h"
 #include "openbsd-compat/sys-queue.h"
-RCSID("$OpenBSD: ssh-agent.c,v 1.113 2003/09/19 11:29:40 markus Exp $");
+RCSID("$OpenBSD: ssh-agent.c,v 1.114 2003/09/23 20:17:11 markus Exp $");
 
 #include <openssl/evp.h>
 #include <openssl/md5.h>
@@ -957,7 +957,7 @@
 		rmdir(socket_dir);
 }
 
-static void
+void
 cleanup_exit(int i)
 {
 	cleanup_socket();
@@ -971,17 +971,6 @@
 	_exit(2);
 }
 
-void
-fatal(const char *fmt,...)
-{
-	va_list args;
-	va_start(args, fmt);
-	do_log(SYSLOG_LEVEL_FATAL, fmt, args);
-	va_end(args);
-	cleanup_socket();
-	_exit(255);
-}
-
 static void
 check_parent_exists(int sig)
 {
diff --git a/sshd.c b/sshd.c
index 4b3ff0d..5c27112 100644
--- a/sshd.c
+++ b/sshd.c
@@ -42,7 +42,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.277 2003/09/19 11:33:09 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.278 2003/09/23 20:17:11 markus Exp $");
 
 #include <openssl/dh.h>
 #include <openssl/bn.h>
@@ -204,6 +204,9 @@
 /* message to be displayed after login */
 Buffer loginmsg;
 
+/* global authentication context */
+Authctxt *the_authctxt = NULL;
+
 /* Prototypes for various functions defined later in this file. */
 void destroy_sensitive_data(void);
 void demote_sensitive_data(void);
@@ -375,7 +378,7 @@
 	    strlen(server_version_string))
 	    != strlen(server_version_string)) {
 		logit("Could not write ident string to %s", get_remote_ipaddr());
-		fatal_cleanup();
+		cleanup_exit(255);
 	}
 
 	/* Read other sides version identification. */
@@ -384,7 +387,7 @@
 		if (atomicio(read, sock_in, &buf[i], 1) != 1) {
 			logit("Did not receive identification string from %s",
 			    get_remote_ipaddr());
-			fatal_cleanup();
+			cleanup_exit(255);
 		}
 		if (buf[i] == '\r') {
 			buf[i] = 0;
@@ -414,7 +417,7 @@
 		close(sock_out);
 		logit("Bad protocol version identification '%.100s' from %s",
 		    client_version_string, get_remote_ipaddr());
-		fatal_cleanup();
+		cleanup_exit(255);
 	}
 	debug("Client protocol version %d.%d; client software version %.100s",
 	    remote_major, remote_minor, remote_version);
@@ -424,13 +427,13 @@
 	if (datafellows & SSH_BUG_PROBE) {
 		logit("probed from %s with %s.  Don't panic.",
 		    get_remote_ipaddr(), client_version_string);
-		fatal_cleanup();
+		cleanup_exit(255);
 	}
 
 	if (datafellows & SSH_BUG_SCANNER) {
 		logit("scanned from %s with %s.  Don't panic.",
 		    get_remote_ipaddr(), client_version_string);
-		fatal_cleanup();
+		cleanup_exit(255);
 	}
 
 	mismatch = 0;
@@ -476,7 +479,7 @@
 		logit("Protocol major versions differ for %s: %.200s vs. %.200s",
 		    get_remote_ipaddr(),
 		    server_version_string, client_version_string);
-		fatal_cleanup();
+		cleanup_exit(255);
 	}
 }
 
@@ -571,10 +574,9 @@
 #endif
 }
 
-static Authctxt *
-privsep_preauth(void)
+static int
+privsep_preauth(Authctxt *authctxt)
 {
-	Authctxt *authctxt = NULL;
 	int status;
 	pid_t pid;
 
@@ -590,7 +592,7 @@
 		debug2("Network child is on pid %ld", (long)pid);
 
 		close(pmonitor->m_recvfd);
-		authctxt = monitor_child_preauth(pmonitor);
+		monitor_child_preauth(authctxt, pmonitor);
 		close(pmonitor->m_sendfd);
 
 		/* Sync memory */
@@ -600,7 +602,7 @@
 		while (waitpid(pid, &status, 0) < 0)
 			if (errno != EINTR)
 				break;
-		return (authctxt);
+		return (1);
 	} else {
 		/* child */
 
@@ -611,17 +613,12 @@
 			privsep_preauth_child();
 		setproctitle("%s", "[net]");
 	}
-	return (NULL);
+	return (0);
 }
 
 static void
 privsep_postauth(Authctxt *authctxt)
 {
-	extern Authctxt *x_authctxt;
-
-	/* XXX - Remote port forwarding */
-	x_authctxt = authctxt;
-
 #ifdef DISABLE_FD_PASSING
 	if (1) {
 #else
@@ -804,8 +801,8 @@
 	int listen_sock, maxfd;
 	int startup_p[2];
 	int startups = 0;
-	Authctxt *authctxt;
 	Key *key;
+	Authctxt *authctxt;
 	int ret, key_used = 0;
 
 #ifdef HAVE_SECUREWARE
@@ -1460,18 +1457,25 @@
         /* prepare buffers to collect authentication messages */
 	buffer_init(&loginmsg);
 
+	/* allocate authentication context */
+	authctxt = xmalloc(sizeof(*authctxt));
+	memset(authctxt, 0, sizeof(*authctxt));
+
+	/* XXX global for cleanup, access from other modules */
+	the_authctxt = authctxt;
+
 	if (use_privsep)
-		if ((authctxt = privsep_preauth()) != NULL)
+		if (privsep_preauth(authctxt) == 1)
 			goto authenticated;
 
 	/* perform the key exchange */
 	/* authenticate user and start session */
 	if (compat20) {
 		do_ssh2_kex();
-		authctxt = do_authentication2();
+		do_authentication2(authctxt);
 	} else {
 		do_ssh1_kex();
-		authctxt = do_authentication();
+		do_authentication(authctxt);
 	}
 	/*
 	 * If we use privilege separation, the unprivileged child transfers
@@ -1494,7 +1498,7 @@
 			destroy_sensitive_data();
 	}
 
-	/* Perform session preparation. */
+	/* Start session. */
 	do_authenticated(authctxt);
 
 	/* The connection has been terminated. */
@@ -1787,3 +1791,12 @@
 #endif
 	debug("KEX done");
 }
+
+/* server specific fatal cleanup */
+void
+cleanup_exit(int i)
+{
+	if (the_authctxt)
+		do_cleanup(the_authctxt);
+	_exit(i);
+}