summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 918c843b..80140019 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,15 @@
- Sync with OpenBSD glob.c, strlcat.c and vis.c changes
- Cygwin sftp/sftp-server binary mode patch from Corinna Vinschen
<vinschen@redhat.com>
+ - OpenBSD CVS Sync
+ - 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@
20010413
- OpenBSD CVS Sync
@@ -5054,4 +5063,4 @@
- Wrote replacements for strlcpy and mkdtemp
- Released 1.0pre1
-$Id: ChangeLog,v 1.1109 2001/04/13 14:28:42 djm Exp $
+$Id: ChangeLog,v 1.1110 2001/04/13 23:28:01 mouring Exp $
diff --git a/channels.c b/channels.c
index a1aa937a..f4f2c494 100644
--- a/channels.c
+++ b/channels.c
@@ -40,7 +40,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.106 2001/04/11 13:56:13 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.107 2001/04/13 22:46:52 beck Exp $");
#include <openssl/rsa.h>
#include <openssl/dsa.h>
@@ -1843,6 +1843,41 @@ channel_still_open()
return 0;
}
+/* Returns the id of an open channel suitable for keepaliving */
+
+int
+channel_find_open()
+{
+ u_int i;
+ for (i = 0; i < channels_alloc; i++)
+ switch (channels[i].type) {
+ case SSH_CHANNEL_CLOSED:
+ continue;
+ case SSH_CHANNEL_LARVAL:
+ case SSH_CHANNEL_DYNAMIC:
+ case SSH_CHANNEL_AUTH_SOCKET:
+ case SSH_CHANNEL_CONNECTING: /* XXX ??? */
+ case SSH_CHANNEL_FREE:
+ case SSH_CHANNEL_X11_LISTENER:
+ case SSH_CHANNEL_PORT_LISTENER:
+ case SSH_CHANNEL_RPORT_LISTENER:
+ case SSH_CHANNEL_OPENING:
+ case SSH_CHANNEL_OPEN:
+ case SSH_CHANNEL_X11_OPEN:
+ return i;
+ case SSH_CHANNEL_INPUT_DRAINING:
+ case SSH_CHANNEL_OUTPUT_DRAINING:
+ if (!compat13)
+ fatal("cannot happen: OUT_DRAIN");
+ return i;
+ default:
+ fatal("channel_find_open: bad channel type %d", channels[i].type);
+ /* NOTREACHED */
+ }
+ return -1;
+}
+
+
/*
* Returns a message describing the currently open forwarded connections,
* suitable for sending to the client. The message contains crlf pairs for
diff --git a/channels.h b/channels.h
index 23e6ece8..bf70a8f2 100644
--- a/channels.h
+++ b/channels.h
@@ -32,7 +32,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* RCSID("$OpenBSD: channels.h,v 1.30 2001/04/07 08:55:17 markus Exp $"); */
+/* RCSID("$OpenBSD: channels.h,v 1.31 2001/04/13 22:46:53 beck Exp $"); */
#ifndef CHANNELS_H
#define CHANNELS_H
@@ -307,4 +307,6 @@ int channel_connect_to(const char *host, u_short host_port);
int channel_connect_by_listen_adress(u_short listen_port);
int x11_connect_display(void);
+int channel_find_open(void);
+
#endif
diff --git a/servconf.c b/servconf.c
index f3d5068c..f978c632 100644
--- a/servconf.c
+++ b/servconf.c
@@ -10,7 +10,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.76 2001/04/12 20:09:37 stevesk Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.77 2001/04/13 22:46:53 beck Exp $");
#ifdef KRB4
#include <krb.h>
@@ -99,6 +99,8 @@ initialize_server_options(ServerOptions *options)
options->max_startups = -1;
options->banner = NULL;
options->reverse_mapping_check = -1;
+ options->client_alive_interval = -1;
+ options->client_alive_count_max = -1;
}
void
@@ -201,6 +203,10 @@ fill_default_server_options(ServerOptions *options)
options->max_startups_begin = options->max_startups;
if (options->reverse_mapping_check == -1)
options->reverse_mapping_check = 0;
+ if (options->client_alive_interval == -1)
+ options->client_alive_interval = 0;
+ if (options->client_alive_count_max == -1)
+ options->client_alive_count_max = 3;
}
/* Keyword tokens. */
@@ -225,7 +231,8 @@ typedef enum {
sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
sBanner, sReverseMappingCheck, sHostbasedAuthentication,
- sHostbasedUsesNameFromPacketOnly
+ sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
+ sClientAliveCountMax
} ServerOpCodes;
/* Textual representation of the tokens. */
@@ -289,6 +296,8 @@ static struct {
{ "maxstartups", sMaxStartups },
{ "banner", sBanner },
{ "reversemappingcheck", sReverseMappingCheck },
+ { "clientaliveinterval", sClientAliveInterval },
+ { "clientalivecountmax", sClientAliveCountMax },
{ NULL, 0 }
};
@@ -792,7 +801,12 @@ parse_flag:
case sBanner:
charptr = &options->banner;
goto parse_filename;
-
+ case sClientAliveInterval:
+ intptr = &options->client_alive_interval;
+ goto parse_int;
+ case sClientAliveCountMax:
+ intptr = &options->client_alive_count_max;
+ goto parse_int;
default:
fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
filename, linenum, arg, opcode);
diff --git a/servconf.h b/servconf.h
index 9b3a60f0..4c02c0f5 100644
--- a/servconf.h
+++ b/servconf.h
@@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* RCSID("$OpenBSD: servconf.h,v 1.40 2001/04/12 19:15:25 markus Exp $"); */
+/* RCSID("$OpenBSD: servconf.h,v 1.41 2001/04/13 22:46:53 beck Exp $"); */
#ifndef SERVCONF_H
#define SERVCONF_H
@@ -115,6 +115,15 @@ typedef struct {
int max_startups;
char *banner; /* SSH-2 banner message */
int reverse_mapping_check; /* cross-check ip and dns */
+ int client_alive_interval; /*
+ * poke the client this often to
+ * see if it's still there
+ */
+ int client_alive_count_max; /*
+ *If the client is unresponsive
+ * for this many intervals, above
+ * diconnect the session
+ */
} ServerOptions;
/*
diff --git a/serverloop.c b/serverloop.c
index d6b360d9..5a5b1e37 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -35,7 +35,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: serverloop.c,v 1.60 2001/04/05 23:39:20 markus Exp $");
+RCSID("$OpenBSD: serverloop.c,v 1.61 2001/04/13 22:46:54 beck Exp $");
#include "xmalloc.h"
#include "packet.h"
@@ -91,6 +91,8 @@ static volatile int child_wait_status; /* Status from wait(). */
void server_init_dispatch(void);
+int client_alive_timeouts = 0;
+
void
sigchld_handler(int sig)
{
@@ -190,6 +192,21 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
{
struct timeval tv, *tvp;
int ret;
+ int client_alive_scheduled = 0;
+
+ /*
+ * if using client_alive, set the max timeout accordingly,
+ * and indicate that this particular timeout was for client
+ * alive by setting the client_alive_scheduled flag.
+ *
+ * this could be randomized somewhat to make traffic
+ * analysis more difficult, but we're not doing it yet.
+ */
+ if (max_time_milliseconds == 0 && options.client_alive_interval) {
+ client_alive_scheduled = 1;
+ max_time_milliseconds = options.client_alive_interval * 1000;
+ } else
+ client_alive_scheduled = 0;
/* When select fails we restart from here. */
retry_select:
@@ -239,7 +256,7 @@ retry_select:
* from it, then read as much as is available and exit.
*/
if (child_terminated && packet_not_very_much_data_to_write())
- if (max_time_milliseconds == 0)
+ if (max_time_milliseconds == 0 || client_alive_scheduled)
max_time_milliseconds = 100;
if (max_time_milliseconds == 0)
@@ -255,12 +272,36 @@ retry_select:
/* Wait for something to happen, or the timeout to expire. */
ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
- if (ret < 0) {
+ if (ret == -1) {
if (errno != EINTR)
error("select: %.100s", strerror(errno));
else
goto retry_select;
}
+ if (ret == 0 && client_alive_scheduled) {
+ /* timeout, check to see how many we have had */
+ client_alive_timeouts++;
+
+ if (client_alive_timeouts > options.client_alive_count_max ) {
+ packet_disconnect(
+ "Timeout, your session not responding.");
+ } else {
+ /*
+ * send a bogus channel request with "wantreply"
+ * we should get back a failure
+ */
+ int id;
+
+ id = channel_find_open();
+ if (id != -1) {
+ channel_request_start(id,
+ "keepalive@openssh.com", 1);
+ packet_send();
+ } else
+ packet_disconnect(
+ "No open channels after timeout!");
+ }
+ }
}
/*
@@ -701,6 +742,19 @@ server_loop2(void)
}
void
+server_input_channel_failure(int type, int plen, void *ctxt)
+{
+ debug("Got CHANNEL_FAILURE for keepalive");
+ /*
+ * reset timeout, since we got a sane answer from the client.
+ * even if this was generated by something other than
+ * the bogus CHANNEL_REQUEST we send for keepalives.
+ */
+ client_alive_timeouts = 0;
+}
+
+
+void
server_input_stdin_data(int type, int plen, void *ctxt)
{
char *data;
@@ -912,7 +966,8 @@ server_init_dispatch_20(void)
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
-
+ /* client_alive */
+ dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure);
/* rekeying */
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
@@ -949,3 +1004,4 @@ server_init_dispatch(void)
else
server_init_dispatch_15();
}
+
diff --git a/sshd.8 b/sshd.8
index da95eaef..887cc3ba 100644
--- a/sshd.8
+++ b/sshd.8
@@ -34,7 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $OpenBSD: sshd.8,v 1.114 2001/04/11 16:25:31 lebel Exp $
+.\" $OpenBSD: sshd.8,v 1.115 2001/04/13 22:46:54 beck Exp $
.Dd September 25, 1999
.Dt SSHD 8
.Os
@@ -363,6 +363,31 @@ Specifies whether
should check for new mail for interactive logins.
The default is
.Dq no .
+.It Cm ClientAliveInterval
+Sets a timeout interval in seconds after which if no data has been received
+from the client,
+.Nm
+will send a message through the encrypted
+channel to request a response from the client. This may only be
+used on a server supporting only protocol version 2. The default
+is 0, indicating that these messages will not be sent to the client.
+.It Cm ClientAliveCountMax
+Sets the number of client alive messages (see above) which may be
+sent without
+.Nm
+receiving any messages back from the client. If this threshold is
+reached while client alive messages are being sent,
+.Nm
+will disconnect the client, terminating the session. It is important
+to note that the use of client alive messages is very different from
+Keepalive (below). The client alive messages are sent through the
+encrypted channel and therefore will not be spoofable. The TCP keepalive
+option enable by Keepalive is spoofable. You want to use the client
+alive mechanism when you are basing something important on
+clients having an active connection to the server.
+ The default is value is 3. If you set ClientAliveInterval
+(above) to 15, and leave this value at the default, unresponsive ssh clients
+will be disconnected after approximately 45 seconds.
.It Cm DenyGroups
This keyword can be followed by a number of group names, separated
by spaces.