While I was updating our ssh-servers, I rewrote my old patch that adds idletimeout (just like in old ssh1) parameter to openssh. Since reapplying the patch for all new versions of openssh is not fun at all, I would like to have it included in the official openssh, if you consider the patch worthy. Unlike ClientAlive, idletimeout works for both protocol versions. It also works together with ClientAlive (however, the code which prevents clientalive-messages from resetting idletimeout is not foolproof. Foolproof patch would require to add different idletimeout support to different packets, which would be too complex). It adds two time() syscalls to select loop, but only if idletimeout is used in the configuration file. Attached patch (also available from http://www.cs.helsinki.fi/u/jjaakkol/idletimeout.patch ) is against openssh-2.9p2. If you will include it in the official openssh, I would be very happy to also document it. - Jani -------------- next part -------------- diff -ru openssh-2.9p2.orig/CREDITS openssh-2.9p2/CREDITS --- openssh-2.9p2.orig/CREDITS Mon Apr 16 03:41:46 2001 +++ openssh-2.9p2/CREDITS Wed Aug 15 22:00:02 2001 @@ -42,6 +42,7 @@ IWAMURO Motonori <iwa at mmp.fujitsu.co.jp> - bugfixes Jani Hakala <jahakala at cc.jyu.fi> - Patches Jarno Huuskonen <jhuuskon at hytti.uku.fi> - Bugfixes +Jani Jaakkola <jjaakkol at cs.helsinki.fi> - IdleTimeOut Jim Knoble <jmknoble at jmknoble.cx> - Many patches Jonchen (email unknown) - the original author of PAM support of SSH Juergen Keil <jk at tools.de> - scp bugfixing diff -ru openssh-2.9p2.orig/servconf.c openssh-2.9p2/servconf.c --- openssh-2.9p2.orig/servconf.c Wed Apr 25 15:44:15 2001 +++ openssh-2.9p2/servconf.c Wed Aug 15 22:10:23 2001 @@ -102,6 +102,7 @@ options->client_alive_interval = -1; options->client_alive_count_max = -1; options->pam_authentication_via_kbd_int = -1; + options->idletimeout = -1; } void @@ -210,6 +211,8 @@ options->client_alive_count_max = 3; if (options->pam_authentication_via_kbd_int == -1) options->pam_authentication_via_kbd_int = 0; + if (options->idletimeout == -1) + options->idletimeout=0; } /* Keyword tokens. */ @@ -235,7 +238,8 @@ sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups, sBanner, sReverseMappingCheck, sHostbasedAuthentication, sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, - sClientAliveCountMax, sPAMAuthenticationViaKbdInt + sClientAliveCountMax, sPAMAuthenticationViaKbdInt, + sIdleTimeout } ServerOpCodes; /* Textual representation of the tokens. */ @@ -302,6 +306,7 @@ { "clientaliveinterval", sClientAliveInterval }, { "clientalivecountmax", sClientAliveCountMax }, { "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt }, + { "idletimeout", sIdleTimeout }, { NULL, 0 } }; @@ -801,7 +806,28 @@ case sPAMAuthenticationViaKbdInt: intptr = &options->pam_authentication_via_kbd_int; goto parse_flag; - + case sIdleTimeout: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing IdleTimeout argument", + filename,linenum); + options->idletimeout=atoi(arg); + switch(arg[strlen(arg)-1]) { + case 'w': options->idletimeout*=7; + case 'd': options->idletimeout*=24; + case 'h': options->idletimeout*=60; + case 'm': options->idletimeout*=60; + case 's': + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + break; + default: + fatal("%s line %d: Invalid IdleTimeout argument", + filename,linenum); + } + break; + default: fatal("%s line %d: Missing handler for opcode %s (%d)", filename, linenum, arg, opcode); diff -ru openssh-2.9p2.orig/servconf.h openssh-2.9p2/servconf.h --- openssh-2.9p2.orig/servconf.h Wed Apr 25 15:44:16 2001 +++ openssh-2.9p2/servconf.h Wed Aug 15 22:09:33 2001 @@ -125,6 +125,10 @@ * diconnect the session */ int pam_authentication_via_kbd_int; + int idletimeout; /* + * If nonzero, the number of second + * after which idle connections + * will be terminated */ } ServerOptions; /* * Initializes the server options to special values that indicate that they diff -ru openssh-2.9p2.orig/serverloop.c openssh-2.9p2/serverloop.c --- openssh-2.9p2.orig/serverloop.c Sat Apr 14 02:28:03 2001 +++ openssh-2.9p2/serverloop.c Thu Aug 16 14:12:14 2001 @@ -79,7 +79,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 idletime_last=0; /* The last time something happened + * for idletimeout. */ /* * This SIGCHLD kludge is used to detect when the child exits. The server * will exit after that, as soon as forwarded connections have terminated. @@ -193,7 +194,9 @@ struct timeval tv, *tvp; int ret; int client_alive_scheduled = 0; - + /* Secs until idletimeout, zero if no idletimeout */ + int max_time_seconds=0; + /* * if using client_alive, set the max timeout accordingly, * and indicate that this particular timeout was for client @@ -208,6 +211,24 @@ } else client_alive_scheduled = 0; + + if (options.idletimeout>0) { + if (idletime_last==0) { + /* Initialize idletime_last */ + time(&idletime_last); + } + /* Schedule idletimeout if no other timeouts are scheduled. + * Idletimeouts are the longest and it is not a big deal, + * if they are missed by few seconds. */ + if (max_time_milliseconds == 0) { + time_t diff=time(NULL)-idletime_last; + if (diff>=options.idletimeout) + max_time_seconds=1; + else + max_time_seconds=options.idletimeout-diff; + } + } + /* When select fails we restart from here. */ retry_select: @@ -258,10 +279,17 @@ if (child_terminated && packet_not_very_much_data_to_write()) if (max_time_milliseconds == 0 || client_alive_scheduled) max_time_milliseconds = 100; - - if (max_time_milliseconds == 0) - tvp = NULL; - else { + + if (max_time_milliseconds == 0) { + /* Use max_time_seconds only if max_time_milliseconds is + * not set */ + if (max_time_seconds>0) { + tv.tv_sec=max_time_seconds; + tv.tv_usec=0; + tvp=&tv; + } else + tvp = NULL; + } else { tv.tv_sec = max_time_milliseconds / 1000; tv.tv_usec = 1000 * (max_time_milliseconds % 1000); tvp = &tv; @@ -301,7 +329,22 @@ packet_disconnect( "No open channels after timeout!"); } - } + } + + if (options.idletimeout>0) { + /* Reset idletimeout if something happened. + * NOTE: events events happening while there is + * active client_alive_timeouts are ignored. This way + * client_alive messages won't reset idletimeout counter.*/ + if (ret>0 && client_alive_timeouts==0) { + time(&idletime_last); + } + /* Check if idletimeout has happened */ + if (ret==0 && time(NULL)-idletime_last>options.idletimeout) { + packet_disconnect("Idletimeout."); + options.idletimeout=0; + } + } } /*
This is pretty much equiv to idled or the hundreds of other idle testing deamons out there. Except it's more limited. Idled is much nicer for doing such things. It gives you more control the whole process so you can disable it for certian groups of people. Your patch does not so to most people it would be useless. I really don't want to this patch go in. - Ben On Thu, 16 Aug 2001, Jani Jaakkola wrote:> > While I was updating our ssh-servers, I rewrote my old patch that adds > idletimeout (just like in old ssh1) parameter to openssh. Since reapplying > the patch for all new versions of openssh is not fun at all, I would like > to have it included in the official openssh, if you consider the patch > worthy. > > Unlike ClientAlive, idletimeout works for both protocol versions. It also > works together with ClientAlive (however, the code which prevents > clientalive-messages from resetting idletimeout is not foolproof. > Foolproof patch would require to add different idletimeout support to > different packets, which would be too complex). > > It adds two time() syscalls to select loop, but only if idletimeout is > used in the configuration file. > > Attached patch (also available from > http://www.cs.helsinki.fi/u/jjaakkol/idletimeout.patch > ) is against openssh-2.9p2. If you will include it in the > official openssh, I would be very happy to also document it. > > - Jani > >
thanks. here's the patch against current portable CVS with KNF and cleanups. i wonder if this could be shortened by eliminating max_time_seconds and using max_time_milliseconds? i'll also add key file support for idle-timeout later. Index: servconf.h ==================================================================RCS file: /var/cvs/openssh/servconf.h,v retrieving revision 1.38 diff -u -r1.38 servconf.h --- servconf.h 2001/07/04 18:37:21 1.38 +++ servconf.h 2001/08/17 20:24:43 @@ -129,6 +129,11 @@ char *authorized_keys_file; /* File containing public keys */ char *authorized_keys_file2; + long idle_timeout; /* + * If nonzero, the number of seconds + * after which idle connections + * will be terminated + */ int pam_authentication_via_kbd_int; } ServerOptions; Index: servconf.c ==================================================================RCS file: /var/cvs/openssh/servconf.c,v retrieving revision 1.63 diff -u -r1.63 servconf.c --- servconf.c 2001/07/14 02:20:32 1.63 +++ servconf.c 2001/08/17 20:24:47 @@ -105,6 +105,7 @@ options->client_alive_count_max = -1; options->authorized_keys_file = NULL; options->authorized_keys_file2 = NULL; + options->idle_timeout = -1; options->pam_authentication_via_kbd_int = -1; } @@ -218,6 +219,8 @@ options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS; if (options->authorized_keys_file2 == NULL) options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2; + if (options->idle_timeout == -1) + options->idle_timeout = 0; if (options->pam_authentication_via_kbd_int == -1) options->pam_authentication_via_kbd_int = 0; } @@ -249,6 +252,7 @@ sBanner, sReverseMappingCheck, sHostbasedAuthentication, sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, + sIdleTimeout, sPAMAuthenticationViaKbdInt } ServerOpCodes; @@ -320,6 +324,7 @@ { "authorizedkeysfile", sAuthorizedKeysFile }, { "authorizedkeysfile2", sAuthorizedKeysFile2 }, { "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt }, + { "idletimeout", sIdleTimeout }, { NULL, 0 } }; @@ -846,6 +851,10 @@ intptr = &options->pam_authentication_via_kbd_int; goto parse_flag; + case sIdleTimeout: + intptr = &options->idle_timeout; + goto parse_time; + default: fatal("%s line %d: Missing handler for opcode %s (%d)", filename, linenum, arg, opcode); Index: serverloop.c ==================================================================RCS file: /var/cvs/openssh/serverloop.c,v retrieving revision 1.75 diff -u -r1.75 serverloop.c --- serverloop.c 2001/07/26 17:51:50 1.75 +++ serverloop.c 2001/08/17 20:24:53 @@ -80,7 +80,6 @@ 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. */ - /* * This SIGCHLD kludge is used to detect when the child exits. The server * will exit after that, as soon as forwarded connections have terminated. @@ -174,7 +173,11 @@ struct timeval tv, *tvp; int ret; int client_alive_scheduled = 0; - + /* idletimeout last activity time */ + static time_t idletime_last = 0; + /* time until idletimeout, zero if no idletimeout */ + int max_time_seconds = 0; + /* * if using client_alive, set the max timeout accordingly, * and indicate that this particular timeout was for client @@ -189,6 +192,24 @@ max_time_milliseconds = options.client_alive_interval * 1000; } + if (options.idle_timeout > 0) { + if (idletime_last == 0) + time(&idletime_last); /* Initialize */ + + /* + * Schedule idletimeout if no other timeouts are scheduled. + * Idletimeouts are the longest and it is not a big deal + * if they are missed by few seconds. + */ + if (max_time_milliseconds == 0) { + time_t diff = time(NULL) - idletime_last; + if (diff >= options.idle_timeout) + max_time_seconds = 1; + else + max_time_seconds = options.idle_timeout - diff; + } + } + /* When select fails we restart from here. */ retry_select: @@ -239,10 +260,19 @@ if (child_terminated && packet_not_very_much_data_to_write()) if (max_time_milliseconds == 0 || client_alive_scheduled) max_time_milliseconds = 100; - - if (max_time_milliseconds == 0) - tvp = NULL; - else { + + if (max_time_milliseconds == 0) { + /* + * Use max_time_seconds only if max_time_milliseconds is + * not set + */ + if (max_time_seconds > 0) { + tv.tv_sec = max_time_seconds; + tv.tv_usec = 0; + tvp = &tv; + } else + tvp = NULL; + } else { tv.tv_sec = max_time_milliseconds / 1000; tv.tv_usec = 1000 * (max_time_milliseconds % 1000); tvp = &tv; @@ -282,7 +312,22 @@ packet_disconnect( "No open channels after timeout!"); } - } + } + + if (options.idle_timeout > 0) { + /* + * Reset idletimeout if something happened. + * NOTE: events happening while there is + * active client_alive_timeouts are ignored. This way + * client_alive messages won't reset idletimeout counter. + */ + if (ret > 0 && client_alive_timeouts == 0) + time(&idletime_last); + /* Check if idletimeout has happened */ + if (ret == 0 && + time(NULL) - idletime_last > options.idle_timeout) + packet_disconnect("Timeout, idle time exceeded."); + } } /*
On Mon, 20 Aug 2001, Markus Friedl wrote:> but how large is the benefit/line ratio for this patch?Well, in the environment where I am network administrator we must have this functionality, so the amount of extra lines is definetely acceptable. IMHO, this patch is actually more useful than the client alive thing. I guess it could be easily made a configure time option, if the extra amount of bytes is not acceptable for some people. - Jani
In the environment I am working on, I already use an equivalent patch that I sent some time ago for years & would love to have it in the standard delivery ! I could not live without it. -Christophe Jani Jaakkola wrote:> On Mon, 20 Aug 2001, Markus Friedl wrote: > > > but how large is the benefit/line ratio for this patch? > > Well, in the environment where I am network administrator we must > have this functionality, so the amount of extra lines is definetely > acceptable. IMHO, this patch is actually more useful than the client > alive thing. > > I guess it could be easily made a configure time option, if the extra > amount of bytes is not acceptable for some people. > > - Jani-- Christophe Moret mailto:Christophe_Moret at hp.com Hewlett Packard Phone :+33 4 76 14 40 78 5, avenue Raymond Chanas Fax :+33 4 76 14 47 06 38053 GRENOBLE Cedex 09 Mobile:+33 6 72 99 16 51 -------------- next part -------------- A non-text attachment was scrubbed... Name: Christophe_Moret.vcf Type: text/x-vcard Size: 377 bytes Desc: Card for Christophe Moret Url : http://lists.mindrot.org/pipermail/openssh-unix-dev/attachments/20010820/6ab97320/attachment.vcf