The attached patch fixes a problem building openssh-4.5p1-20061109.src.rpm with_watchdog=yes. It isn't as pretty as Ralf's, but it works.
Bill -- INTERNET: [EMAIL PROTECTED] Bill Campbell; Celestial Software LLC URL: http://www.celestial.com/ PO Box 820; 6641 E. Mercer Way Voice: (206) 236-1676 Mercer Island, WA 98040-0820 Fax: (206) 232-9186 Intellectually, teachers fall between education theorists and bright cocker spaniels. (Probably closer to the education theorists. The AKC has been doing wonders with spaniels.) If you think I'm kidding look at the GREs for education majors, whose scores are the lowest of all fields, and remember that these are the smart ones. -- http://www.FredOnEverything.net
--- serverloop.c.orig 2008-07-04 06:10:49.000000000 -0700 +++ serverloop.c 2008-11-14 16:41:50.968100073 -0800 @@ -105,6 +105,8 @@ static int connection_out; /* Connection to client (output). */ static int connection_closed = 0; /* Connection to client closed. */ static u_int buffer_high; /* "Soft" max buffer size. */ +static time_t idle_time_last; /* Last time of packet receipt. */ +static int child_forced_to_terminate; /* The child will be killed by sshd. */ static int no_more_sessions = 0; /* Disallow further sessions. */ /* @@ -280,6 +282,7 @@ { struct timeval tv, *tvp; int ret; + int watchdog_timeout = 0; int client_alive_scheduled = 0; int program_alive_scheduled = 0; @@ -349,6 +352,19 @@ if (max_time_milliseconds == 0 || client_alive_scheduled) max_time_milliseconds = 100; + /* When the watchdog is needed, set the maximum length + * of timeout to 0.25sec. + */ + watchdog_timeout = options.watchdog_timeout; + if (!compat20 && options.watchdog_timeout1 > 0){ + watchdog_timeout = options.watchdog_timeout1; + } + if (watchdog_timeout > 0) { + if (max_time_milliseconds == 0 || max_time_milliseconds > 250) { + max_time_milliseconds = 250; + } + } + if (max_time_milliseconds == 0) tvp = NULL; else { @@ -376,6 +392,23 @@ } } + /* + * Watchdog timer: + * If the input channel has been silent for more than the specified + * time, try to kill the child process(es) to protect server resources. + */ + if (watchdog_timeout > 0) { + if (FD_ISSET(connection_in,*readsetp)) { + /* Update the time of last data receipt. */ + idle_time_last = time(NULL); + /* fputs("*",stderr); */ + } + if (!child_terminated && \ + (time(NULL) - idle_time_last) > watchdog_timeout) { + child_forced_to_terminate = 1; + } + } + notify_done(*readsetp); } @@ -556,7 +589,9 @@ u_int max_time_milliseconds; u_int previous_stdout_buffer_bytes; u_int stdout_buffer_bytes; - int type; + int type, i; + + child_forced_to_terminate = 0; debug("Entering interactive session."); @@ -623,6 +658,8 @@ server_init_dispatch(); + idle_time_last = time(NULL); + /* Main loop of the server for the interactive session mode. */ for (;;) { @@ -703,6 +740,9 @@ cleanup_exit(255); } + /* Break, if watchdog timeout occured. */ + if (child_forced_to_terminate) break; + /* Process any channel events. */ channel_after_select(readset, writeset); @@ -712,6 +752,24 @@ /* Process output to the client and to program stdin. */ process_output(writeset); } + + /* + * If the child should be terminated due to + * watchdog timeout, send kill signal to the child. + */ + if (child_forced_to_terminate) { + /* We won't have pid=0. However, for safety... */ + if ( pid != 0 ){ + kill(pid, SIGHUP); + for (i=0 ; i<5 ; i++){ + sleep(1); + if (child_terminated) break; + } + if (i>=5) kill(pid, SIGKILL); + logit("Warning: Command has been killed due to watchdog timeout."); + } + } + if (readset) xfree(readset); if (writeset) @@ -720,7 +778,9 @@ /* Cleanup and termination code. */ /* Wait until all output has been sent to the client. */ - drain_output(); + if (!child_forced_to_terminate) { + drain_output(); + } debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.", stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes); @@ -748,6 +808,12 @@ /* We no longer want our SIGCHLD handler to be called. */ mysignal(SIGCHLD, SIG_DFL); + /* If the child has been terminated, free the session and exit here. */ + if (child_forced_to_terminate) { + session_destroy_all(NULL); + return; + } + while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0) if (errno != EINTR) packet_disconnect("wait: %.100s", strerror(errno)); @@ -821,6 +887,7 @@ mysignal(SIGCHLD, sigchld_handler); child_terminated = 0; + child_forced_to_terminate = 0; connection_in = packet_get_connection_in(); connection_out = packet_get_connection_out(); @@ -837,6 +904,8 @@ server_init_dispatch(); + idle_time_last = time(NULL); + for (;;) { process_buffered_input_packets(); @@ -853,6 +922,12 @@ cleanup_exit(255); } + /* Terminate child processes, if watchdog timeout occured. */ + if (child_forced_to_terminate){ + packet_disconnect("Command has been killed due to watchdog timeout."); + logit("Warning: Command has been killed due to watchdog timeout."); + } + collect_children(); if (!rekeying) { channel_after_select(readset, writeset);