summaryrefslogtreecommitdiffstats
path: root/crypto/openssh/serverloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/serverloop.c')
-rw-r--r--crypto/openssh/serverloop.c72
1 files changed, 49 insertions, 23 deletions
diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c
index 69304b5..77d9dee 100644
--- a/crypto/openssh/serverloop.c
+++ b/crypto/openssh/serverloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.145 2006/10/11 12:38:03 markus Exp $ */
+/* $OpenBSD: serverloop.c,v 1.153 2008/06/30 12:15:39 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -56,6 +56,7 @@
#include <unistd.h>
#include <stdarg.h>
+#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "packet.h"
#include "buffer.h"
@@ -104,7 +105,7 @@ static int connection_in; /* Connection to client (input). */
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 int client_alive_timeouts = 0;
+static int no_more_sessions = 0; /* Disallow further sessions. */
/*
* This SIGCHLD kludge is used to detect when the child exits. The server
@@ -248,7 +249,7 @@ client_alive_check(void)
int channel_id;
/* timeout, check to see how many we have had */
- if (++client_alive_timeouts > options.client_alive_count_max) {
+ if (++keep_alive_timeouts > options.client_alive_count_max) {
logit("Timeout, client not responding.");
cleanup_exit(255);
}
@@ -280,6 +281,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
struct timeval tv, *tvp;
int ret;
int client_alive_scheduled = 0;
+ int program_alive_scheduled = 0;
/*
* if using client_alive, set the max timeout accordingly,
@@ -317,6 +319,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
* the client, try to get some more data from the program.
*/
if (packet_not_very_much_data_to_write()) {
+ program_alive_scheduled = child_terminated;
if (!fdout_eof)
FD_SET(fdout, *readsetp);
if (!fderr_eof)
@@ -362,8 +365,16 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
memset(*writesetp, 0, *nallocp);
if (errno != EINTR)
error("select: %.100s", strerror(errno));
- } else if (ret == 0 && client_alive_scheduled)
- client_alive_check();
+ } else {
+ if (ret == 0 && client_alive_scheduled)
+ client_alive_check();
+ if (!compat20 && program_alive_scheduled && fdin_is_tty) {
+ if (!fdout_eof)
+ FD_SET(fdout, *readsetp);
+ if (!fderr_eof)
+ FD_SET(fderr, *readsetp);
+ }
+ }
notify_done(*readsetp);
}
@@ -389,7 +400,8 @@ process_input(fd_set *readset)
return;
cleanup_exit(255);
} else if (len < 0) {
- if (errno != EINTR && errno != EAGAIN) {
+ if (errno != EINTR && errno != EAGAIN &&
+ errno != EWOULDBLOCK) {
verbose("Read error from remote host "
"%.100s: %.100s",
get_remote_ipaddr(), strerror(errno));
@@ -407,7 +419,8 @@ process_input(fd_set *readset)
if (!fdout_eof && FD_ISSET(fdout, readset)) {
errno = 0;
len = read(fdout, buf, sizeof(buf));
- if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
+ if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+ errno == EWOULDBLOCK) && !child_terminated))) {
/* do nothing */
#ifndef PTY_ZEROREAD
} else if (len <= 0) {
@@ -425,7 +438,8 @@ process_input(fd_set *readset)
if (!fderr_eof && FD_ISSET(fderr, readset)) {
errno = 0;
len = read(fderr, buf, sizeof(buf));
- if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
+ if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+ errno == EWOULDBLOCK) && !child_terminated))) {
/* do nothing */
#ifndef PTY_ZEROREAD
} else if (len <= 0) {
@@ -456,7 +470,8 @@ process_output(fd_set *writeset)
data = buffer_ptr(&stdin_buffer);
dlen = buffer_len(&stdin_buffer);
len = write(fdin, data, dlen);
- if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
+ if (len < 0 &&
+ (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
/* do nothing */
} else if (len <= 0) {
if (fdin != fdout)
@@ -875,7 +890,7 @@ server_input_keep_alive(int type, u_int32_t seq, void *ctxt)
* even if this was generated by something other than
* the bogus CHANNEL_REQUEST we send for keepalives.
*/
- client_alive_timeouts = 0;
+ keep_alive_timeouts = 0;
}
static void
@@ -926,7 +941,6 @@ static Channel *
server_request_direct_tcpip(void)
{
Channel *c;
- int sock;
char *target, *originator;
int target_port, originator_port;
@@ -936,18 +950,16 @@ server_request_direct_tcpip(void)
originator_port = packet_get_int();
packet_check_eom();
- debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
- originator, originator_port, target, target_port);
+ debug("server_request_direct_tcpip: originator %s port %d, target %s "
+ "port %d", originator, originator_port, target, target_port);
/* XXX check permission */
- sock = channel_connect_to(target, target_port);
- xfree(target);
+ c = channel_connect_to(target, target_port,
+ "direct-tcpip", "direct-tcpip");
+
xfree(originator);
- if (sock < 0)
- return NULL;
- c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING,
- sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
- CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1);
+ xfree(target);
+
return c;
}
@@ -988,7 +1000,7 @@ server_request_tun(void)
#if defined(SSH_TUN_FILTER)
if (mode == SSH_TUNMODE_POINTOPOINT)
channel_register_filter(c->self, sys_tun_infilter,
- sys_tun_outfilter);
+ sys_tun_outfilter, NULL, NULL);
#endif
done:
@@ -1004,6 +1016,12 @@ server_request_session(void)
debug("input_session_request");
packet_check_eom();
+
+ if (no_more_sessions) {
+ packet_disconnect("Possible attack: attempt to open a session "
+ "after additional sessions disabled");
+ }
+
/*
* A server session has no fd to read or write until a
* CHANNEL_REQUEST for a shell is made, so we set the type to
@@ -1124,6 +1142,9 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
success = channel_cancel_rport_listener(cancel_address,
cancel_port);
xfree(cancel_address);
+ } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
+ no_more_sessions = 1;
+ success = 1;
}
if (want_reply) {
packet_start(success ?
@@ -1151,7 +1172,11 @@ server_input_channel_req(int type, u_int32_t seq, void *ctxt)
if ((c = channel_lookup(id)) == NULL)
packet_disconnect("server_input_channel_req: "
"unknown channel %d", id);
- if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN)
+ if (!strcmp(rtype, "eow@openssh.com")) {
+ packet_check_eom();
+ chan_rcvd_eow(c);
+ } else if ((c->type == SSH_CHANNEL_LARVAL ||
+ c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
success = session_input_channel_req(c, rtype);
if (reply) {
packet_start(success ?
@@ -1177,8 +1202,9 @@ server_init_dispatch_20(void)
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req);
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
+ dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm);
+ dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm);
/* client_alive */
- dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive);
dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive);
dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive);
/* rekeying */
OpenPOWER on IntegriCloud