Two patches for OpenSSH 3.1p1

Peter Eriksson peter at ifm.liu.se
Wed Mar 27 08:21:31 EST 2002


Please find enclosed two patches for OpenSSH 3.1p1.

The first patch solves a problem where sessions will be left "hanging"
when you normally exit from a ssh shell (for example by logging out from
the remote host via "exit" or "logout"). The problem seems to be that sshd
(and some other parts of OpenSSH) doesn't check the return code and errno
from waitpid() for errno == EINTR and thus fails to collect the started
subprocess correctly. This problem occurs atleast on Solaris 2 and UNICOS
systems but it should probably exist on all other SysV based systems...
(It doesn't occur all the time so it can be quite hard to test for).

The other patch adds a "-I" command line option to allow sshd to be
correctly started (and automatically restarted) by "init" (via the
/etc/inittab file) on systems with a SysV-style "init".

It is *not* sufficent to just use the "-D" (no daemon) flag since that
doesn't correctly handle log file output, closing of stdin/stdout/stderr
or the setsid() call to drop the controlling TTY.

Trying to start sshd via inittab and using "-D" will cause sshd to
terminate if the Console connection (for example if using a serial
terminal) gets dropped...

-- 
Peter Eriksson <peter at ifm.liu.se>            Phone:    +46 13  28 2786
Computer Systems Manager/BOFH                Cell/GSM: +46 705 18 2786
Physics Department, Linköping University     Room:     Building F, F203
SE-581 83 Linköping, Sweden                  http://www.ifm.liu.se/~peter
-------------- next part --------------
diff -r -c openssh-3.1p1/entropy.c openssh-3.1p1-peter/entropy.c
*** openssh-3.1p1/entropy.c	Tue Jan 22 11:57:54 2002
--- openssh-3.1p1-peter/entropy.c	Mon Mar 18 22:00:10 2002
***************
*** 110,118 ****
  
  	close(p[0]);
  
! 	if (waitpid(pid, &ret, 0) == -1)
! 	       fatal("Couldn't wait for ssh-rand-helper completion: %s", 
  	           strerror(errno));
  
  	/* We don't mind if the child exits upon a SIGPIPE */
  	if (!WIFEXITED(ret) && 
--- 110,124 ----
  
  	close(p[0]);
  
! 	{
! 	    int code;
! 	    
! 	    while ((code = waitpid(pid, &ret, 0)) == -1 && errno == EINTR)
! 		;
! 	    if (code < 0)
! 		fatal("Couldn't wait for ssh-rand-helper completion: %s", 
  	           strerror(errno));
+ 	}
  
  	/* We don't mind if the child exits upon a SIGPIPE */
  	if (!WIFEXITED(ret) && 
Only in openssh-3.1p1/scard: Ssh.bin
diff -r -c openssh-3.1p1/serverloop.c openssh-3.1p1-peter/serverloop.c
*** openssh-3.1p1/serverloop.c	Fri Feb  8 12:07:17 2002
--- openssh-3.1p1-peter/serverloop.c	Mon Mar 18 22:01:02 2002
***************
*** 673,679 ****
  	/* We no longer want our SIGCHLD handler to be called. */
  	mysignal(SIGCHLD, SIG_DFL);
  
! 	wait_pid = waitpid(-1, &wait_status, 0);
  	if (wait_pid == -1)
  		packet_disconnect("wait: %.100s", strerror(errno));
  	else if (wait_pid != pid)
--- 673,681 ----
  	/* We no longer want our SIGCHLD handler to be called. */
  	mysignal(SIGCHLD, SIG_DFL);
  
! 	while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0 && errno == EINTR)
! 	    ;
! 	
  	if (wait_pid == -1)
  		packet_disconnect("wait: %.100s", strerror(errno));
  	else if (wait_pid != pid)
diff -r -c openssh-3.1p1/sftp-int.c openssh-3.1p1-peter/sftp-int.c
*** openssh-3.1p1/sftp-int.c	Wed Feb 13 04:10:33 2002
--- openssh-3.1p1-peter/sftp-int.c	Mon Mar 18 22:02:38 2002
***************
*** 176,183 ****
  		    strerror(errno));
  		_exit(1);
  	}
! 	if (waitpid(pid, &status, 0) == -1)
  		fatal("Couldn't wait for child: %s", strerror(errno));
  	if (!WIFEXITED(status))
  		error("Shell exited abormally");
  	else if (WEXITSTATUS(status))
--- 176,192 ----
  		    strerror(errno));
  		_exit(1);
  	}
! 	{
! 	    int code;
! 
! 	    
! 	    while ((code = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
! 		;
! 
! 	    if (code < 0)
  		fatal("Couldn't wait for child: %s", strerror(errno));
+ 	}
+ 	
  	if (!WIFEXITED(status))
  		error("Shell exited abormally");
  	else if (WEXITSTATUS(status))
diff -r -c openssh-3.1p1/sftp.c openssh-3.1p1-peter/sftp.c
*** openssh-3.1p1/sftp.c	Wed Feb 13 04:03:57 2002
--- openssh-3.1p1-peter/sftp.c	Mon Mar 18 22:01:49 2002
***************
*** 246,253 ****
  	if (infile != stdin)
  		fclose(infile);
  
! 	if (waitpid(sshpid, NULL, 0) == -1)
  		fatal("Couldn't wait for ssh process: %s", strerror(errno));
  
  	exit(0);
  }
--- 246,261 ----
  	if (infile != stdin)
  		fclose(infile);
  
! 	{
! 	    int code;
! 
! 	    
! 	    while ((code = waitpid(sshpid, NULL, 0)) == -1 && errno == EINTR)
! 		;
! 
! 	    if (code < 0)
  		fatal("Couldn't wait for ssh process: %s", strerror(errno));
+ 	}
  
  	exit(0);
  }
diff -r -c openssh-3.1p1/ssh-rand-helper.c openssh-3.1p1-peter/ssh-rand-helper.c
*** openssh-3.1p1/ssh-rand-helper.c	Sun Feb 10 08:32:30 2002
--- openssh-3.1p1-peter/ssh-rand-helper.c	Mon Mar 18 22:04:34 2002
***************
*** 389,398 ****
  
  	debug3("Time elapsed: %d msec", msec_elapsed);
  
! 	if (waitpid(pid, &status, 0) == -1) {
  	       error("Couldn't wait for child '%s' completion: %s",
  	           src->cmdstring, strerror(errno));
  		return 0.0;
  	}
  
  	RAND_add(&status, sizeof(&status), 0.0);
--- 389,406 ----
  
  	debug3("Time elapsed: %d msec", msec_elapsed);
  
! 	{
! 	    int code;
! 	    
! 	    while ((code = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
! 		;
! 	    
! 	    if (code < 0)
! 	    {
  	       error("Couldn't wait for child '%s' completion: %s",
  	           src->cmdstring, strerror(errno));
  		return 0.0;
+ 	    }
  	}
  
  	RAND_add(&status, sizeof(&status), 0.0);
diff -r -c openssh-3.1p1/sshd.c openssh-3.1p1-peter/sshd.c
*** openssh-3.1p1/sshd.c	Tue Mar  5 02:31:30 2002
--- openssh-3.1p1-peter/sshd.c	Mon Mar 18 22:03:37 2002
***************
*** 264,273 ****
  main_sigchld_handler(int sig)
  {
  	int save_errno = errno;
! 	int status;
  
! 	while (waitpid(-1, &status, WNOHANG) > 0)
! 		;
  
  	signal(SIGCHLD, main_sigchld_handler);
  	errno = save_errno;
--- 264,274 ----
  main_sigchld_handler(int sig)
  {
  	int save_errno = errno;
! 	int status, code;
  
! 	
! 	while ((code = waitpid(-1, &status, WNOHANG)) < 0 && errno == EINTR || code > 0)
! 	    ;
  
  	signal(SIGCHLD, main_sigchld_handler);
  	errno = save_errno;
-------------- next part --------------
diff -r -c openssh-3.1p1/sshd.c openssh-3.1p1-peter/sshd.c
*** openssh-3.1p1/sshd.c	Tue Mar  5 02:31:30 2002
--- openssh-3.1p1-peter/sshd.c	Tue Mar 26 20:59:06 2002
***************
*** 120,125 ****
--- 120,128 ----
  /* Flag indicating that the daemon is being started from inetd. */
  int inetd_flag = 0;
  
+ /* Flag indicating that the daemon is being started from init (/etc/inittab). */
+ int init_flag = 0;
+ 
  /* Flag indicating that sshd should not detach and become a daemon. */
  int no_daemon_flag = 0;
  
***************
*** 608,614 ****
  	initialize_server_options(&options);
  
  	/* Parse command-line arguments. */
! 	while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:o:dDeiqtQ46")) != -1) {
  		switch (opt) {
  		case '4':
  			IPv4or6 = AF_INET;
--- 612,618 ----
  	initialize_server_options(&options);
  
  	/* Parse command-line arguments. */
! 	while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:o:dDeiIqtQ46")) != -1) {
  		switch (opt) {
  		case '4':
  			IPv4or6 = AF_INET;
***************
*** 636,641 ****
--- 640,648 ----
  		case 'e':
  			log_stderr = 1;
  			break;
+ 		case 'I':
+ 		        init_flag = 1;
+ 			break;
  		case 'i':
  			inetd_flag = 1;
  			break;
***************
*** 706,719 ****
  
  	/*
  	 * Force logging to stderr until we have loaded the private host
! 	 * key (unless started from inetd)
  	 */
  	log_init(__progname,
  	    options.log_level == SYSLOG_LEVEL_NOT_SET ?
  	    SYSLOG_LEVEL_INFO : options.log_level,
  	    options.log_facility == SYSLOG_FACILITY_NOT_SET ?
  	    SYSLOG_FACILITY_AUTH : options.log_facility,
! 	    !inetd_flag);
  
  #ifdef _CRAY
  	/* Cray can define user privs drop all prives now!
--- 713,726 ----
  
  	/*
  	 * Force logging to stderr until we have loaded the private host
! 	 * key (unless started from inetd or init)
  	 */
  	log_init(__progname,
  	    options.log_level == SYSLOG_LEVEL_NOT_SET ?
  	    SYSLOG_LEVEL_INFO : options.log_level,
  	    options.log_facility == SYSLOG_FACILITY_NOT_SET ?
  	    SYSLOG_FACILITY_AUTH : options.log_facility,
! 	    !inetd_flag && !init_flag);
  
  #ifdef _CRAY
  	/* Cray can define user privs drop all prives now!
***************
*** 814,820 ****
  #endif
  
  	/* Initialize the log (it is reinitialized below in case we forked). */
! 	if (debug_flag && !inetd_flag)
  		log_stderr = 1;
  	log_init(__progname, options.log_level, options.log_facility, log_stderr);
  
--- 821,827 ----
  #endif
  
  	/* Initialize the log (it is reinitialized below in case we forked). */
! 	if (debug_flag && !inetd_flag && !init_flag)
  		log_stderr = 1;
  	log_init(__progname, options.log_level, options.log_facility, log_stderr);
  
***************
*** 827,834 ****
  #ifdef TIOCNOTTY
  		int fd;
  #endif /* TIOCNOTTY */
! 		if (daemon(0, 0) < 0)
  			fatal("daemon() failed: %.200s", strerror(errno));
  
  		/* Disconnect from the controlling tty. */
  #ifdef TIOCNOTTY
--- 834,862 ----
  #ifdef TIOCNOTTY
  		int fd;
  #endif /* TIOCNOTTY */
! 
! 		if (!init_flag)
! 		{
! 		    if (daemon(0, 0) < 0)
  			fatal("daemon() failed: %.200s", strerror(errno));
+ 		}
+ 		else
+ 		{
+ 		    signal(SIGTTOU, SIG_IGN);
+ 		    signal(SIGTTIN, SIG_IGN);
+ 
+ 		    (void) setsid();
+ 		    (void) chdir("/");
+ 		    
+ 		    if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1)
+ 		    {
+ 			(void)dup2(fd, STDIN_FILENO);
+ 			(void)dup2(fd, STDOUT_FILENO);
+ 			(void)dup2(fd, STDERR_FILENO);
+ 			if (fd > 2)
+ 			    (void)close (fd);
+ 		    }
+ 		}
  
  		/* Disconnect from the controlling tty. */
  #ifdef TIOCNOTTY


More information about the openssh-unix-dev mailing list