summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Lindstrom <mouring@eviladmin.org>2001-04-13 23:28:01 +0000
committerBen Lindstrom <mouring@eviladmin.org>2001-04-13 23:28:01 +0000
commit5744dc421d035c701b6660a58bed0d038c211375 (patch)
treea7c8df98b56a37c9be2fb3e33893e90424a85379
parent402b3319456c1f0da0822319c3813c68e155726d (diff)
- beck@cvs.openbsd.org 2001/04/13 22:46:54
[channels.c channels.h servconf.c servconf.h serverloop.c sshd.8] Add options ClientAliveInterval and ClientAliveCountMax to sshd. This gives the ability to do a "keepalive" via the encrypted channel which can't be spoofed (unlike TCP keepalives). Useful for when you want to use ssh connections to authenticate people for something, and know relatively quickly when they are no longer authenticated. Disabled by default (of course). ok markus@
-rw-r--r--ChangeLog11
-rw-r--r--channels.c37
-rw-r--r--channels.h4
-rw-r--r--servconf.c20
-rw-r--r--servconf.h11
-rw-r--r--serverloop.c64
-rw-r--r--sshd.827
7 files changed, 162 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index 918c843bb..80140019f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,15 @@
2 - Sync with OpenBSD glob.c, strlcat.c and vis.c changes 2 - Sync with OpenBSD glob.c, strlcat.c and vis.c changes
3 - Cygwin sftp/sftp-server binary mode patch from Corinna Vinschen 3 - Cygwin sftp/sftp-server binary mode patch from Corinna Vinschen
4 <vinschen@redhat.com> 4 <vinschen@redhat.com>
5 - OpenBSD CVS Sync
6 - beck@cvs.openbsd.org 2001/04/13 22:46:54
7 [channels.c channels.h servconf.c servconf.h serverloop.c sshd.8]
8 Add options ClientAliveInterval and ClientAliveCountMax to sshd.
9 This gives the ability to do a "keepalive" via the encrypted channel
10 which can't be spoofed (unlike TCP keepalives). Useful for when you want
11 to use ssh connections to authenticate people for something, and know
12 relatively quickly when they are no longer authenticated. Disabled
13 by default (of course). ok markus@
5 14
620010413 1520010413
7 - OpenBSD CVS Sync 16 - OpenBSD CVS Sync
@@ -5054,4 +5063,4 @@
5054 - Wrote replacements for strlcpy and mkdtemp 5063 - Wrote replacements for strlcpy and mkdtemp
5055 - Released 1.0pre1 5064 - Released 1.0pre1
5056 5065
5057$Id: ChangeLog,v 1.1109 2001/04/13 14:28:42 djm Exp $ 5066$Id: ChangeLog,v 1.1110 2001/04/13 23:28:01 mouring Exp $
diff --git a/channels.c b/channels.c
index a1aa937ae..f4f2c4942 100644
--- a/channels.c
+++ b/channels.c
@@ -40,7 +40,7 @@
40 */ 40 */
41 41
42#include "includes.h" 42#include "includes.h"
43RCSID("$OpenBSD: channels.c,v 1.106 2001/04/11 13:56:13 markus Exp $"); 43RCSID("$OpenBSD: channels.c,v 1.107 2001/04/13 22:46:52 beck Exp $");
44 44
45#include <openssl/rsa.h> 45#include <openssl/rsa.h>
46#include <openssl/dsa.h> 46#include <openssl/dsa.h>
@@ -1843,6 +1843,41 @@ channel_still_open()
1843 return 0; 1843 return 0;
1844} 1844}
1845 1845
1846/* Returns the id of an open channel suitable for keepaliving */
1847
1848int
1849channel_find_open()
1850{
1851 u_int i;
1852 for (i = 0; i < channels_alloc; i++)
1853 switch (channels[i].type) {
1854 case SSH_CHANNEL_CLOSED:
1855 continue;
1856 case SSH_CHANNEL_LARVAL:
1857 case SSH_CHANNEL_DYNAMIC:
1858 case SSH_CHANNEL_AUTH_SOCKET:
1859 case SSH_CHANNEL_CONNECTING: /* XXX ??? */
1860 case SSH_CHANNEL_FREE:
1861 case SSH_CHANNEL_X11_LISTENER:
1862 case SSH_CHANNEL_PORT_LISTENER:
1863 case SSH_CHANNEL_RPORT_LISTENER:
1864 case SSH_CHANNEL_OPENING:
1865 case SSH_CHANNEL_OPEN:
1866 case SSH_CHANNEL_X11_OPEN:
1867 return i;
1868 case SSH_CHANNEL_INPUT_DRAINING:
1869 case SSH_CHANNEL_OUTPUT_DRAINING:
1870 if (!compat13)
1871 fatal("cannot happen: OUT_DRAIN");
1872 return i;
1873 default:
1874 fatal("channel_find_open: bad channel type %d", channels[i].type);
1875 /* NOTREACHED */
1876 }
1877 return -1;
1878}
1879
1880
1846/* 1881/*
1847 * Returns a message describing the currently open forwarded connections, 1882 * Returns a message describing the currently open forwarded connections,
1848 * suitable for sending to the client. The message contains crlf pairs for 1883 * suitable for sending to the client. The message contains crlf pairs for
diff --git a/channels.h b/channels.h
index 23e6ece83..bf70a8f21 100644
--- a/channels.h
+++ b/channels.h
@@ -32,7 +32,7 @@
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */ 34 */
35/* RCSID("$OpenBSD: channels.h,v 1.30 2001/04/07 08:55:17 markus Exp $"); */ 35/* RCSID("$OpenBSD: channels.h,v 1.31 2001/04/13 22:46:53 beck Exp $"); */
36 36
37#ifndef CHANNELS_H 37#ifndef CHANNELS_H
38#define CHANNELS_H 38#define CHANNELS_H
@@ -307,4 +307,6 @@ int channel_connect_to(const char *host, u_short host_port);
307int channel_connect_by_listen_adress(u_short listen_port); 307int channel_connect_by_listen_adress(u_short listen_port);
308int x11_connect_display(void); 308int x11_connect_display(void);
309 309
310int channel_find_open(void);
311
310#endif 312#endif
diff --git a/servconf.c b/servconf.c
index f3d5068c0..f978c632b 100644
--- a/servconf.c
+++ b/servconf.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12#include "includes.h" 12#include "includes.h"
13RCSID("$OpenBSD: servconf.c,v 1.76 2001/04/12 20:09:37 stevesk Exp $"); 13RCSID("$OpenBSD: servconf.c,v 1.77 2001/04/13 22:46:53 beck Exp $");
14 14
15#ifdef KRB4 15#ifdef KRB4
16#include <krb.h> 16#include <krb.h>
@@ -99,6 +99,8 @@ initialize_server_options(ServerOptions *options)
99 options->max_startups = -1; 99 options->max_startups = -1;
100 options->banner = NULL; 100 options->banner = NULL;
101 options->reverse_mapping_check = -1; 101 options->reverse_mapping_check = -1;
102 options->client_alive_interval = -1;
103 options->client_alive_count_max = -1;
102} 104}
103 105
104void 106void
@@ -201,6 +203,10 @@ fill_default_server_options(ServerOptions *options)
201 options->max_startups_begin = options->max_startups; 203 options->max_startups_begin = options->max_startups;
202 if (options->reverse_mapping_check == -1) 204 if (options->reverse_mapping_check == -1)
203 options->reverse_mapping_check = 0; 205 options->reverse_mapping_check = 0;
206 if (options->client_alive_interval == -1)
207 options->client_alive_interval = 0;
208 if (options->client_alive_count_max == -1)
209 options->client_alive_count_max = 3;
204} 210}
205 211
206/* Keyword tokens. */ 212/* Keyword tokens. */
@@ -225,7 +231,8 @@ typedef enum {
225 sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, 231 sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
226 sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups, 232 sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
227 sBanner, sReverseMappingCheck, sHostbasedAuthentication, 233 sBanner, sReverseMappingCheck, sHostbasedAuthentication,
228 sHostbasedUsesNameFromPacketOnly 234 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
235 sClientAliveCountMax
229} ServerOpCodes; 236} ServerOpCodes;
230 237
231/* Textual representation of the tokens. */ 238/* Textual representation of the tokens. */
@@ -289,6 +296,8 @@ static struct {
289 { "maxstartups", sMaxStartups }, 296 { "maxstartups", sMaxStartups },
290 { "banner", sBanner }, 297 { "banner", sBanner },
291 { "reversemappingcheck", sReverseMappingCheck }, 298 { "reversemappingcheck", sReverseMappingCheck },
299 { "clientaliveinterval", sClientAliveInterval },
300 { "clientalivecountmax", sClientAliveCountMax },
292 { NULL, 0 } 301 { NULL, 0 }
293}; 302};
294 303
@@ -792,7 +801,12 @@ parse_flag:
792 case sBanner: 801 case sBanner:
793 charptr = &options->banner; 802 charptr = &options->banner;
794 goto parse_filename; 803 goto parse_filename;
795 804 case sClientAliveInterval:
805 intptr = &options->client_alive_interval;
806 goto parse_int;
807 case sClientAliveCountMax:
808 intptr = &options->client_alive_count_max;
809 goto parse_int;
796 default: 810 default:
797 fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n", 811 fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
798 filename, linenum, arg, opcode); 812 filename, linenum, arg, opcode);
diff --git a/servconf.h b/servconf.h
index 9b3a60f08..4c02c0f52 100644
--- a/servconf.h
+++ b/servconf.h
@@ -11,7 +11,7 @@
11 * called by a name other than "ssh" or "Secure Shell". 11 * called by a name other than "ssh" or "Secure Shell".
12 */ 12 */
13 13
14/* RCSID("$OpenBSD: servconf.h,v 1.40 2001/04/12 19:15:25 markus Exp $"); */ 14/* RCSID("$OpenBSD: servconf.h,v 1.41 2001/04/13 22:46:53 beck Exp $"); */
15 15
16#ifndef SERVCONF_H 16#ifndef SERVCONF_H
17#define SERVCONF_H 17#define SERVCONF_H
@@ -115,6 +115,15 @@ typedef struct {
115 int max_startups; 115 int max_startups;
116 char *banner; /* SSH-2 banner message */ 116 char *banner; /* SSH-2 banner message */
117 int reverse_mapping_check; /* cross-check ip and dns */ 117 int reverse_mapping_check; /* cross-check ip and dns */
118 int client_alive_interval; /*
119 * poke the client this often to
120 * see if it's still there
121 */
122 int client_alive_count_max; /*
123 *If the client is unresponsive
124 * for this many intervals, above
125 * diconnect the session
126 */
118 127
119} ServerOptions; 128} ServerOptions;
120/* 129/*
diff --git a/serverloop.c b/serverloop.c
index d6b360d9a..5a5b1e37f 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -35,7 +35,7 @@
35 */ 35 */
36 36
37#include "includes.h" 37#include "includes.h"
38RCSID("$OpenBSD: serverloop.c,v 1.60 2001/04/05 23:39:20 markus Exp $"); 38RCSID("$OpenBSD: serverloop.c,v 1.61 2001/04/13 22:46:54 beck Exp $");
39 39
40#include "xmalloc.h" 40#include "xmalloc.h"
41#include "packet.h" 41#include "packet.h"
@@ -91,6 +91,8 @@ static volatile int child_wait_status; /* Status from wait(). */
91 91
92void server_init_dispatch(void); 92void server_init_dispatch(void);
93 93
94int client_alive_timeouts = 0;
95
94void 96void
95sigchld_handler(int sig) 97sigchld_handler(int sig)
96{ 98{
@@ -190,6 +192,21 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
190{ 192{
191 struct timeval tv, *tvp; 193 struct timeval tv, *tvp;
192 int ret; 194 int ret;
195 int client_alive_scheduled = 0;
196
197 /*
198 * if using client_alive, set the max timeout accordingly,
199 * and indicate that this particular timeout was for client
200 * alive by setting the client_alive_scheduled flag.
201 *
202 * this could be randomized somewhat to make traffic
203 * analysis more difficult, but we're not doing it yet.
204 */
205 if (max_time_milliseconds == 0 && options.client_alive_interval) {
206 client_alive_scheduled = 1;
207 max_time_milliseconds = options.client_alive_interval * 1000;
208 } else
209 client_alive_scheduled = 0;
193 210
194 /* When select fails we restart from here. */ 211 /* When select fails we restart from here. */
195retry_select: 212retry_select:
@@ -239,7 +256,7 @@ retry_select:
239 * from it, then read as much as is available and exit. 256 * from it, then read as much as is available and exit.
240 */ 257 */
241 if (child_terminated && packet_not_very_much_data_to_write()) 258 if (child_terminated && packet_not_very_much_data_to_write())
242 if (max_time_milliseconds == 0) 259 if (max_time_milliseconds == 0 || client_alive_scheduled)
243 max_time_milliseconds = 100; 260 max_time_milliseconds = 100;
244 261
245 if (max_time_milliseconds == 0) 262 if (max_time_milliseconds == 0)
@@ -255,12 +272,36 @@ retry_select:
255 /* Wait for something to happen, or the timeout to expire. */ 272 /* Wait for something to happen, or the timeout to expire. */
256 ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); 273 ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
257 274
258 if (ret < 0) { 275 if (ret == -1) {
259 if (errno != EINTR) 276 if (errno != EINTR)
260 error("select: %.100s", strerror(errno)); 277 error("select: %.100s", strerror(errno));
261 else 278 else
262 goto retry_select; 279 goto retry_select;
263 } 280 }
281 if (ret == 0 && client_alive_scheduled) {
282 /* timeout, check to see how many we have had */
283 client_alive_timeouts++;
284
285 if (client_alive_timeouts > options.client_alive_count_max ) {
286 packet_disconnect(
287 "Timeout, your session not responding.");
288 } else {
289 /*
290 * send a bogus channel request with "wantreply"
291 * we should get back a failure
292 */
293 int id;
294
295 id = channel_find_open();
296 if (id != -1) {
297 channel_request_start(id,
298 "keepalive@openssh.com", 1);
299 packet_send();
300 } else
301 packet_disconnect(
302 "No open channels after timeout!");
303 }
304 }
264} 305}
265 306
266/* 307/*
@@ -701,6 +742,19 @@ server_loop2(void)
701} 742}
702 743
703void 744void
745server_input_channel_failure(int type, int plen, void *ctxt)
746{
747 debug("Got CHANNEL_FAILURE for keepalive");
748 /*
749 * reset timeout, since we got a sane answer from the client.
750 * even if this was generated by something other than
751 * the bogus CHANNEL_REQUEST we send for keepalives.
752 */
753 client_alive_timeouts = 0;
754}
755
756
757void
704server_input_stdin_data(int type, int plen, void *ctxt) 758server_input_stdin_data(int type, int plen, void *ctxt)
705{ 759{
706 char *data; 760 char *data;
@@ -912,7 +966,8 @@ server_init_dispatch_20(void)
912 dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request); 966 dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
913 dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); 967 dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
914 dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); 968 dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
915 969 /* client_alive */
970 dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure);
916 /* rekeying */ 971 /* rekeying */
917 dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 972 dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
918} 973}
@@ -949,3 +1004,4 @@ server_init_dispatch(void)
949 else 1004 else
950 server_init_dispatch_15(); 1005 server_init_dispatch_15();
951} 1006}
1007
diff --git a/sshd.8 b/sshd.8
index da95eaef7..887cc3ba3 100644
--- a/sshd.8
+++ b/sshd.8
@@ -34,7 +34,7 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: sshd.8,v 1.114 2001/04/11 16:25:31 lebel Exp $ 37.\" $OpenBSD: sshd.8,v 1.115 2001/04/13 22:46:54 beck Exp $
38.Dd September 25, 1999 38.Dd September 25, 1999
39.Dt SSHD 8 39.Dt SSHD 8
40.Os 40.Os
@@ -363,6 +363,31 @@ Specifies whether
363should check for new mail for interactive logins. 363should check for new mail for interactive logins.
364The default is 364The default is
365.Dq no . 365.Dq no .
366.It Cm ClientAliveInterval
367Sets a timeout interval in seconds after which if no data has been received
368from the client,
369.Nm
370will send a message through the encrypted
371channel to request a response from the client. This may only be
372used on a server supporting only protocol version 2. The default
373is 0, indicating that these messages will not be sent to the client.
374.It Cm ClientAliveCountMax
375Sets the number of client alive messages (see above) which may be
376sent without
377.Nm
378receiving any messages back from the client. If this threshold is
379reached while client alive messages are being sent,
380.Nm
381will disconnect the client, terminating the session. It is important
382to note that the use of client alive messages is very different from
383Keepalive (below). The client alive messages are sent through the
384encrypted channel and therefore will not be spoofable. The TCP keepalive
385option enable by Keepalive is spoofable. You want to use the client
386alive mechanism when you are basing something important on
387clients having an active connection to the server.
388 The default is value is 3. If you set ClientAliveInterval
389(above) to 15, and leave this value at the default, unresponsive ssh clients
390will be disconnected after approximately 45 seconds.
366.It Cm DenyGroups 391.It Cm DenyGroups
367This keyword can be followed by a number of group names, separated 392This keyword can be followed by a number of group names, separated
368by spaces. 393by spaces.