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);

Reply via email to