-/* $OpenBSD: serverloop.c,v 1.148 2008/02/22 20:44:02 dtucker 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
#include <unistd.h>
#include <stdarg.h>
+#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "packet.h"
#include "buffer.h"
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 no_more_sessions = 0; /* Disallow further sessions. */
/*
* This SIGCHLD kludge is used to detect when the child exits. The server
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));
if (!fdout_eof && FD_ISSET(fdout, readset)) {
errno = 0;
len = read(fdout, buf, sizeof(buf));
- if (len < 0 && (errno == EINTR ||
- (errno == EAGAIN && !child_terminated))) {
+ if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+ errno == EWOULDBLOCK) && !child_terminated))) {
/* do nothing */
#ifndef PTY_ZEROREAD
} else if (len <= 0) {
if (!fderr_eof && FD_ISSET(fderr, readset)) {
errno = 0;
len = read(fderr, buf, sizeof(buf));
- if (len < 0 && (errno == EINTR ||
- (errno == EAGAIN && !child_terminated))) {
+ if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+ errno == EWOULDBLOCK) && !child_terminated))) {
/* do nothing */
#ifndef PTY_ZEROREAD
} else if (len <= 0) {
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)
server_request_direct_tcpip(void)
{
Channel *c;
- int sock;
char *target, *originator;
int target_port, originator_port;
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;
- if (options.hpn_disabled)
- c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING,
- sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
- CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1);
- else
- c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING,
- sock, sock, -1, options.hpn_buffer_size,
- CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1);
+ xfree(target);
+
return c;
}
#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:
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
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 ?
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 ?
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 */