- djm@cvs.openbsd.org 2010/08/12 21:49:44
     [ssh.c]
     close any extra file descriptors inherited from parent at start and
     reopen stdin/stdout to /dev/null when forking for ControlPersist.

     prevents tools that fork and run a captive ssh for communication from
     failing to exit when the ssh completes while they wait for these fds to
     close. The inherited fds may persist arbitrarily long if a background
     mux master has been started by ControlPersist. cvs and scp were effected
     by this.

     "please commit" markus@
diff --git a/ssh.c b/ssh.c
index ab37c20..4419f76 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.345 2010/08/04 05:42:47 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.346 2010/08/12 21:49:44 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -238,6 +238,12 @@
 	init_rng();
 
 	/*
+	 * Discard other fds that are hanging around. These can cause problem
+	 * with backgrounded ssh processes started by ControlPersist.
+	 */
+	closefrom(STDERR_FILENO + 1);
+
+	/*
 	 * Save the original real uid.  It will be needed later (uid-swapping
 	 * may clobber the real uid).
 	 */
@@ -898,6 +904,7 @@
 control_persist_detach(void)
 {
 	pid_t pid;
+	int devnull;
 
 	debug("%s: backgrounding master process", __func__);
 
@@ -924,6 +931,16 @@
 		/* muxclient() doesn't return on success. */
  		fatal("Failed to connect to new control master");
  	}
+	if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
+		error("%s: open(\"/dev/null\"): %s", __func__,
+		    strerror(errno));
+	} else {
+		if (dup2(devnull, STDIN_FILENO) == -1 ||
+		    dup2(devnull, STDOUT_FILENO) == -1)
+			error("%s: dup2: %s", __func__, strerror(errno));
+		if (devnull > STDERR_FILENO)
+			close(devnull);
+	}
 }
 
 /* Do fork() after authentication. Used by "ssh -f" */