summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2008-07-22 19:45:18 +0000
committerColin Watson <cjwatson@debian.org>2008-07-22 19:45:18 +0000
commit137d76ba65883aa8143af1fcad83b57e7badef0c (patch)
treef426e804bb5248ceafedfab7bb78ae6e6752942c /channels.c
parentdac7d049dad31f5f84d421d4eb628a7e13f977d7 (diff)
parentef94e5613d37bcbf880f21ee6094e4b1c7683a4c (diff)
* New upstream release (closes: #474301). Important changes not previously
backported to 4.7p1: - 4.9/4.9p1 (http://www.openssh.com/txt/release-4.9): + Added chroot(2) support for sshd(8), controlled by a new option "ChrootDirectory" (closes: #139047, LP: #24777). + Linked sftp-server(8) into sshd(8). The internal sftp server is used when the command "internal-sftp" is specified in a Subsystem or ForceCommand declaration. When used with ChrootDirectory, the internal sftp server requires no special configuration of files inside the chroot environment. + Added a protocol extension method "posix-rename@openssh.com" for sftp-server(8) to perform POSIX atomic rename() operations; sftp(1) prefers this if available (closes: #308561). + Removed the fixed limit of 100 file handles in sftp-server(8). + ssh(8) will now skip generation of SSH protocol 1 ephemeral server keys when in inetd mode and protocol 2 connections are negotiated. This speeds up protocol 2 connections to inetd-mode servers that also allow Protocol 1. + Accept the PermitRootLogin directive in a sshd_config(5) Match block. Allows for, e.g. permitting root only from the local network. + Reworked sftp(1) argument splitting and escaping to be more internally consistent (i.e. between sftp commands) and more consistent with sh(1). Please note that this will change the interpretation of some quoted strings, especially those with embedded backslash escape sequences. + Support "Banner=none" in sshd_config(5) to disable sending of a pre-login banner (e.g. in a Match block). + ssh(1) ProxyCommands are now executed with $SHELL rather than /bin/sh. + ssh(1)'s ConnectTimeout option is now applied to both the TCP connection and the SSH banner exchange (previously it just covered the TCP connection). This allows callers of ssh(1) to better detect and deal with stuck servers that accept a TCP connection but don't progress the protocol, and also makes ConnectTimeout useful for connections via a ProxyCommand. + scp(1) incorrectly reported "stalled" on slow copies (closes: #140828). + scp(1) date underflow for timestamps before epoch. + ssh(1) used the obsolete SIG DNS RRtype for host keys in DNS, instead of the current standard RRSIG. + Correctly drain ACKs when a sftp(1) upload write fails midway, avoids a fatal() exit from what should be a recoverable condition. + Fixed ssh-keygen(1) selective host key hashing (i.e. "ssh-keygen -HF hostname") to not include any IP address in the data to be hashed. + Make ssh(1) skip listening on the IPv6 wildcard address when a binding address of 0.0.0.0 is used against an old SSH server that does not support the RFC4254 syntax for wildcard bind addresses. + Enable IPV6_V6ONLY socket option on sshd(8) listen socket, as is already done for X11/TCP forwarding sockets (closes: #439661). + Fix FD leak that could hang a ssh(1) connection multiplexing master. + Make ssh(1) -q option documentation consistent with reality. + Fixed sshd(8) PAM support not calling pam_session_close(), or failing to call it with root privileges (closes: #372680). + Fix activation of OpenSSL engine support when requested in configure (LP: #119295). - 5.1/5.1p1 (http://www.openssh.com/txt/release-5.1): + Introduce experimental SSH Fingerprint ASCII Visualisation to ssh(1) and ssh-keygen(1). Visual fingerprint display is controlled by a new ssh_config(5) option "VisualHostKey". The intent is to render SSH host keys in a visual form that is amenable to easy recall and rejection of changed host keys. + sshd_config(5) now supports CIDR address/masklen matching in "Match address" blocks, with a fallback to classic wildcard matching. + sshd(8) now supports CIDR matching in ~/.ssh/authorized_keys from="..." restrictions, also with a fallback to classic wildcard matching. + Added an extended test mode (-T) to sshd(8) to request that it write its effective configuration to stdout and exit. Extended test mode also supports the specification of connection parameters (username, source address and hostname) to test the application of sshd_config(5) Match rules. + ssh(1) now prints the number of bytes transferred and the overall connection throughput for SSH protocol 2 sessions when in verbose mode (previously these statistics were displayed for protocol 1 connections only). + sftp-server(8) now supports extension methods statvfs@openssh.com and fstatvfs@openssh.com that implement statvfs(2)-like operations. + sftp(1) now has a "df" command to the sftp client that uses the statvfs@openssh.com to produce a df(1)-like display of filesystem space and inode utilisation (requires statvfs@openssh.com support on the server). + Added a MaxSessions option to sshd_config(5) to allow control of the number of multiplexed sessions supported over a single TCP connection. This allows increasing the number of allowed sessions above the previous default of 10, disabling connection multiplexing (MaxSessions=1) or disallowing login/shell/subsystem sessions entirely (MaxSessions=0). + Added a no-more-sessions@openssh.com global request extension that is sent from ssh(1) to sshd(8) when the client knows that it will never request another session (i.e. when session multiplexing is disabled). This allows a server to disallow further session requests and terminate the session in cases where the client has been hijacked. + ssh-keygen(1) now supports the use of the -l option in combination with -F to search for a host in ~/.ssh/known_hosts and display its fingerprint. + ssh-keyscan(1) now defaults to "rsa" (protocol 2) keys, instead of "rsa1". + Added an AllowAgentForwarding option to sshd_config(8) to control whether authentication agent forwarding is permitted. Note that this is a loose control, as a client may install their own unofficial forwarder. + ssh(1) and sshd(8): avoid unnecessary malloc/copy/free when receiving network data, resulting in a ~10% speedup. + ssh(1) and sshd(8) will now try additional addresses when connecting to a port forward destination whose DNS name resolves to more than one address. The previous behaviour was to try the only first address and give up if that failed. + ssh(1) and sshd(8) now support signalling that channels are half-closed for writing, through a channel protocol extension notification "eow@openssh.com". This allows propagation of closed file descriptors, so that commands such as "ssh -2 localhost od /bin/ls | true" do not send unnecessary data over the wire. + sshd(8): increased the default size of ssh protocol 1 ephemeral keys from 768 to 1024 bits. + When ssh(1) has been requested to fork after authentication ("ssh -f") with ExitOnForwardFailure enabled, delay the fork until after replies for any -R forwards have been seen. Allows for robust detection of -R forward failure when using -f. + "Match group" blocks in sshd_config(5) now support negation of groups. E.g. "Match group staff,!guests". + sftp(1) and sftp-server(8) now allow chmod-like operations to set set[ug]id/sticky bits. + The MaxAuthTries option is now permitted in sshd_config(5) match blocks. + Multiplexed ssh(1) sessions now support a subset of the ~ escapes that are available to a primary connection. + ssh(1) connection multiplexing will now fall back to creating a new connection in most error cases (closes: #352830). + Make ssh(1) deal more gracefully with channel requests that fail. Previously it would optimistically assume that requests would always succeed, which could cause hangs if they did not (e.g. when the server runs out of file descriptors). + ssh(1) now reports multiplexing errors via the multiplex slave's stderr where possible (subject to LogLevel in the mux master). + Prevent sshd(8) from erroneously applying public key restrictions leaned from ~/.ssh/authorized_keys to other authentication methods when public key authentication subsequently fails (LP: #161047). + Fixed an UMAC alignment problem that manifested on Itanium platforms.
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c344
1 files changed, 229 insertions, 115 deletions
diff --git a/channels.c b/channels.c
index 900ab848f..c293eadf1 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.270 2007/06/25 08:20:03 dtucker Exp $ */ 1/* $OpenBSD: channels.c,v 1.286 2008/07/16 11:52:19 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -61,6 +61,7 @@
61#include <unistd.h> 61#include <unistd.h>
62#include <stdarg.h> 62#include <stdarg.h>
63 63
64#include "openbsd-compat/sys-queue.h"
64#include "xmalloc.h" 65#include "xmalloc.h"
65#include "ssh.h" 66#include "ssh.h"
66#include "ssh1.h" 67#include "ssh1.h"
@@ -164,6 +165,10 @@ static int IPv4or6 = AF_UNSPEC;
164/* helper */ 165/* helper */
165static void port_open_helper(Channel *c, char *rtype); 166static void port_open_helper(Channel *c, char *rtype);
166 167
168/* non-blocking connect helpers */
169static int connect_next(struct channel_connect *);
170static void channel_connect_ctx_free(struct channel_connect *);
171
167/* -- channel core */ 172/* -- channel core */
168 173
169Channel * 174Channel *
@@ -216,7 +221,7 @@ channel_lookup(int id)
216 */ 221 */
217static void 222static void
218channel_register_fds(Channel *c, int rfd, int wfd, int efd, 223channel_register_fds(Channel *c, int rfd, int wfd, int efd,
219 int extusage, int nonblock) 224 int extusage, int nonblock, int is_tty)
220{ 225{
221 /* Update the maximum file descriptor value. */ 226 /* Update the maximum file descriptor value. */
222 channel_max_fd = MAX(channel_max_fd, rfd); 227 channel_max_fd = MAX(channel_max_fd, rfd);
@@ -232,18 +237,9 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd,
232 c->efd = efd; 237 c->efd = efd;
233 c->extended_usage = extusage; 238 c->extended_usage = extusage;
234 239
235 /* XXX ugly hack: nonblock is only set by the server */ 240 if ((c->isatty = is_tty) != 0)
236 if (nonblock && isatty(c->rfd)) {
237 debug2("channel %d: rfd %d isatty", c->self, c->rfd); 241 debug2("channel %d: rfd %d isatty", c->self, c->rfd);
238 c->isatty = 1; 242 c->wfd_isatty = is_tty || isatty(c->wfd);
239 if (!isatty(c->wfd)) {
240 error("channel %d: wfd %d is not a tty?",
241 c->self, c->wfd);
242 }
243 } else {
244 c->isatty = 0;
245 }
246 c->wfd_isatty = isatty(c->wfd);
247 243
248 /* enable nonblocking mode */ 244 /* enable nonblocking mode */
249 if (nonblock) { 245 if (nonblock) {
@@ -303,7 +299,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
303 c->ostate = CHAN_OUTPUT_OPEN; 299 c->ostate = CHAN_OUTPUT_OPEN;
304 c->istate = CHAN_INPUT_OPEN; 300 c->istate = CHAN_INPUT_OPEN;
305 c->flags = 0; 301 c->flags = 0;
306 channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); 302 channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
307 c->self = found; 303 c->self = found;
308 c->type = type; 304 c->type = type;
309 c->ctype = ctype; 305 c->ctype = ctype;
@@ -319,10 +315,13 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
319 c->single_connection = 0; 315 c->single_connection = 0;
320 c->detach_user = NULL; 316 c->detach_user = NULL;
321 c->detach_close = 0; 317 c->detach_close = 0;
322 c->confirm = NULL; 318 c->open_confirm = NULL;
323 c->confirm_ctx = NULL; 319 c->open_confirm_ctx = NULL;
324 c->input_filter = NULL; 320 c->input_filter = NULL;
325 c->output_filter = NULL; 321 c->output_filter = NULL;
322 c->filter_ctx = NULL;
323 c->filter_cleanup = NULL;
324 TAILQ_INIT(&c->status_confirms);
326 debug("channel %d: new [%s]", found, remote_name); 325 debug("channel %d: new [%s]", found, remote_name);
327 return c; 326 return c;
328} 327}
@@ -379,6 +378,7 @@ channel_free(Channel *c)
379{ 378{
380 char *s; 379 char *s;
381 u_int i, n; 380 u_int i, n;
381 struct channel_confirm *cc;
382 382
383 for (n = 0, i = 0; i < channels_alloc; i++) 383 for (n = 0, i = 0; i < channels_alloc; i++)
384 if (channels[i]) 384 if (channels[i])
@@ -402,6 +402,15 @@ channel_free(Channel *c)
402 xfree(c->remote_name); 402 xfree(c->remote_name);
403 c->remote_name = NULL; 403 c->remote_name = NULL;
404 } 404 }
405 while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
406 if (cc->abandon_cb != NULL)
407 cc->abandon_cb(c, cc->ctx);
408 TAILQ_REMOVE(&c->status_confirms, cc, entry);
409 bzero(cc, sizeof(*cc));
410 xfree(cc);
411 }
412 if (c->filter_cleanup != NULL && c->filter_ctx != NULL)
413 c->filter_cleanup(c->self, c->filter_ctx);
405 channels[c->self] = NULL; 414 channels[c->self] = NULL;
406 xfree(c); 415 xfree(c);
407} 416}
@@ -660,16 +669,33 @@ channel_request_start(int id, char *service, int wantconfirm)
660} 669}
661 670
662void 671void
663channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) 672channel_register_status_confirm(int id, channel_confirm_cb *cb,
673 channel_confirm_abandon_cb *abandon_cb, void *ctx)
674{
675 struct channel_confirm *cc;
676 Channel *c;
677
678 if ((c = channel_lookup(id)) == NULL)
679 fatal("channel_register_expect: %d: bad id", id);
680
681 cc = xmalloc(sizeof(*cc));
682 cc->cb = cb;
683 cc->abandon_cb = abandon_cb;
684 cc->ctx = ctx;
685 TAILQ_INSERT_TAIL(&c->status_confirms, cc, entry);
686}
687
688void
689channel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx)
664{ 690{
665 Channel *c = channel_lookup(id); 691 Channel *c = channel_lookup(id);
666 692
667 if (c == NULL) { 693 if (c == NULL) {
668 logit("channel_register_comfirm: %d: bad id", id); 694 logit("channel_register_open_comfirm: %d: bad id", id);
669 return; 695 return;
670 } 696 }
671 c->confirm = fn; 697 c->open_confirm = fn;
672 c->confirm_ctx = ctx; 698 c->open_confirm_ctx = ctx;
673} 699}
674 700
675void 701void
@@ -700,7 +726,7 @@ channel_cancel_cleanup(int id)
700 726
701void 727void
702channel_register_filter(int id, channel_infilter_fn *ifn, 728channel_register_filter(int id, channel_infilter_fn *ifn,
703 channel_outfilter_fn *ofn) 729 channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx)
704{ 730{
705 Channel *c = channel_lookup(id); 731 Channel *c = channel_lookup(id);
706 732
@@ -710,17 +736,19 @@ channel_register_filter(int id, channel_infilter_fn *ifn,
710 } 736 }
711 c->input_filter = ifn; 737 c->input_filter = ifn;
712 c->output_filter = ofn; 738 c->output_filter = ofn;
739 c->filter_ctx = ctx;
740 c->filter_cleanup = cfn;
713} 741}
714 742
715void 743void
716channel_set_fds(int id, int rfd, int wfd, int efd, 744channel_set_fds(int id, int rfd, int wfd, int efd,
717 int extusage, int nonblock, u_int window_max) 745 int extusage, int nonblock, int is_tty, u_int window_max)
718{ 746{
719 Channel *c = channel_lookup(id); 747 Channel *c = channel_lookup(id);
720 748
721 if (c == NULL || c->type != SSH_CHANNEL_LARVAL) 749 if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
722 fatal("channel_activate for non-larval channel %d.", id); 750 fatal("channel_activate for non-larval channel %d.", id);
723 channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); 751 channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, is_tty);
724 c->type = SSH_CHANNEL_OPEN; 752 c->type = SSH_CHANNEL_OPEN;
725 c->local_window = c->local_window_max = window_max; 753 c->local_window = c->local_window_max = window_max;
726 packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); 754 packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
@@ -788,7 +816,8 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
788 } 816 }
789 } 817 }
790 /** XXX check close conditions, too */ 818 /** XXX check close conditions, too */
791 if (compat20 && c->efd != -1) { 819 if (compat20 && c->efd != -1 &&
820 !(c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED)) {
792 if (c->extended_usage == CHAN_EXTENDED_WRITE && 821 if (c->extended_usage == CHAN_EXTENDED_WRITE &&
793 buffer_len(&c->extended) > 0) 822 buffer_len(&c->extended) > 0)
794 FD_SET(c->efd, writeset); 823 FD_SET(c->efd, writeset);
@@ -1181,7 +1210,7 @@ static void
1181channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset) 1210channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
1182{ 1211{
1183 Channel *nc; 1212 Channel *nc;
1184 struct sockaddr addr; 1213 struct sockaddr_storage addr;
1185 int newsock; 1214 int newsock;
1186 socklen_t addrlen; 1215 socklen_t addrlen;
1187 char buf[16384], *remote_ipaddr; 1216 char buf[16384], *remote_ipaddr;
@@ -1190,7 +1219,7 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
1190 if (FD_ISSET(c->sock, readset)) { 1219 if (FD_ISSET(c->sock, readset)) {
1191 debug("X11 connection requested."); 1220 debug("X11 connection requested.");
1192 addrlen = sizeof(addr); 1221 addrlen = sizeof(addr);
1193 newsock = accept(c->sock, &addr, &addrlen); 1222 newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
1194 if (c->single_connection) { 1223 if (c->single_connection) {
1195 debug2("single_connection: closing X11 listener."); 1224 debug2("single_connection: closing X11 listener.");
1196 channel_close_fd(&c->sock); 1225 channel_close_fd(&c->sock);
@@ -1307,7 +1336,7 @@ static void
1307channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset) 1336channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
1308{ 1337{
1309 Channel *nc; 1338 Channel *nc;
1310 struct sockaddr addr; 1339 struct sockaddr_storage addr;
1311 int newsock, nextstate; 1340 int newsock, nextstate;
1312 socklen_t addrlen; 1341 socklen_t addrlen;
1313 char *rtype; 1342 char *rtype;
@@ -1331,7 +1360,7 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
1331 } 1360 }
1332 1361
1333 addrlen = sizeof(addr); 1362 addrlen = sizeof(addr);
1334 newsock = accept(c->sock, &addr, &addrlen); 1363 newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
1335 if (newsock < 0) { 1364 if (newsock < 0) {
1336 error("accept: %.100s", strerror(errno)); 1365 error("accept: %.100s", strerror(errno));
1337 return; 1366 return;
@@ -1366,12 +1395,12 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
1366{ 1395{
1367 Channel *nc; 1396 Channel *nc;
1368 int newsock; 1397 int newsock;
1369 struct sockaddr addr; 1398 struct sockaddr_storage addr;
1370 socklen_t addrlen; 1399 socklen_t addrlen;
1371 1400
1372 if (FD_ISSET(c->sock, readset)) { 1401 if (FD_ISSET(c->sock, readset)) {
1373 addrlen = sizeof(addr); 1402 addrlen = sizeof(addr);
1374 newsock = accept(c->sock, &addr, &addrlen); 1403 newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
1375 if (newsock < 0) { 1404 if (newsock < 0) {
1376 error("accept from auth socket: %.100s", strerror(errno)); 1405 error("accept from auth socket: %.100s", strerror(errno));
1377 return; 1406 return;
@@ -1398,7 +1427,7 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
1398static void 1427static void
1399channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset) 1428channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
1400{ 1429{
1401 int err = 0; 1430 int err = 0, sock;
1402 socklen_t sz = sizeof(err); 1431 socklen_t sz = sizeof(err);
1403 1432
1404 if (FD_ISSET(c->sock, writeset)) { 1433 if (FD_ISSET(c->sock, writeset)) {
@@ -1407,7 +1436,9 @@ channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
1407 error("getsockopt SO_ERROR failed"); 1436 error("getsockopt SO_ERROR failed");
1408 } 1437 }
1409 if (err == 0) { 1438 if (err == 0) {
1410 debug("channel %d: connected", c->self); 1439 debug("channel %d: connected to %s port %d",
1440 c->self, c->connect_ctx.host, c->connect_ctx.port);
1441 channel_connect_ctx_free(&c->connect_ctx);
1411 c->type = SSH_CHANNEL_OPEN; 1442 c->type = SSH_CHANNEL_OPEN;
1412 if (compat20) { 1443 if (compat20) {
1413 packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); 1444 packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
@@ -1421,8 +1452,19 @@ channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
1421 packet_put_int(c->self); 1452 packet_put_int(c->self);
1422 } 1453 }
1423 } else { 1454 } else {
1424 debug("channel %d: not connected: %s", 1455 debug("channel %d: connection failed: %s",
1425 c->self, strerror(err)); 1456 c->self, strerror(err));
1457 /* Try next address, if any */
1458 if ((sock = connect_next(&c->connect_ctx)) > 0) {
1459 close(c->sock);
1460 c->sock = c->rfd = c->wfd = sock;
1461 channel_max_fd = channel_find_maxfd();
1462 return;
1463 }
1464 /* Exhausted all addresses */
1465 error("connect_to %.100s port %d: failed.",
1466 c->connect_ctx.host, c->connect_ctx.port);
1467 channel_connect_ctx_free(&c->connect_ctx);
1426 if (compat20) { 1468 if (compat20) {
1427 packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); 1469 packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
1428 packet_put_int(c->remote_id); 1470 packet_put_int(c->remote_id);
@@ -1452,7 +1494,8 @@ channel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset)
1452 if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) { 1494 if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) {
1453 errno = 0; 1495 errno = 0;
1454 len = read(c->rfd, buf, sizeof(buf)); 1496 len = read(c->rfd, buf, sizeof(buf));
1455 if (len < 0 && (errno == EINTR || (errno == EAGAIN && !force))) 1497 if (len < 0 && (errno == EINTR ||
1498 ((errno == EAGAIN || errno == EWOULDBLOCK) && !force)))
1456 return 1; 1499 return 1;
1457#ifndef PTY_ZEROREAD 1500#ifndef PTY_ZEROREAD
1458 if (len <= 0) { 1501 if (len <= 0) {
@@ -1523,7 +1566,8 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
1523 c->local_consumed += dlen + 4; 1566 c->local_consumed += dlen + 4;
1524 len = write(c->wfd, buf, dlen); 1567 len = write(c->wfd, buf, dlen);
1525 xfree(data); 1568 xfree(data);
1526 if (len < 0 && (errno == EINTR || errno == EAGAIN)) 1569 if (len < 0 && (errno == EINTR || errno == EAGAIN ||
1570 errno == EWOULDBLOCK))
1527 return 1; 1571 return 1;
1528 if (len <= 0) { 1572 if (len <= 0) {
1529 if (c->type != SSH_CHANNEL_OPEN) 1573 if (c->type != SSH_CHANNEL_OPEN)
@@ -1541,7 +1585,8 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
1541#endif 1585#endif
1542 1586
1543 len = write(c->wfd, buf, dlen); 1587 len = write(c->wfd, buf, dlen);
1544 if (len < 0 && (errno == EINTR || errno == EAGAIN)) 1588 if (len < 0 &&
1589 (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
1545 return 1; 1590 return 1;
1546 if (len <= 0) { 1591 if (len <= 0) {
1547 if (c->type != SSH_CHANNEL_OPEN) { 1592 if (c->type != SSH_CHANNEL_OPEN) {
@@ -1593,7 +1638,8 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
1593 buffer_len(&c->extended)); 1638 buffer_len(&c->extended));
1594 debug2("channel %d: written %d to efd %d", 1639 debug2("channel %d: written %d to efd %d",
1595 c->self, len, c->efd); 1640 c->self, len, c->efd);
1596 if (len < 0 && (errno == EINTR || errno == EAGAIN)) 1641 if (len < 0 && (errno == EINTR || errno == EAGAIN ||
1642 errno == EWOULDBLOCK))
1597 return 1; 1643 return 1;
1598 if (len <= 0) { 1644 if (len <= 0) {
1599 debug2("channel %d: closing write-efd %d", 1645 debug2("channel %d: closing write-efd %d",
@@ -1608,8 +1654,8 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
1608 len = read(c->efd, buf, sizeof(buf)); 1654 len = read(c->efd, buf, sizeof(buf));
1609 debug2("channel %d: read %d from efd %d", 1655 debug2("channel %d: read %d from efd %d",
1610 c->self, len, c->efd); 1656 c->self, len, c->efd);
1611 if (len < 0 && (errno == EINTR || 1657 if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
1612 (errno == EAGAIN && !c->detach_close))) 1658 errno == EWOULDBLOCK) && !c->detach_close)))
1613 return 1; 1659 return 1;
1614 if (len <= 0) { 1660 if (len <= 0) {
1615 debug2("channel %d: closing read-efd %d", 1661 debug2("channel %d: closing read-efd %d",
@@ -1633,7 +1679,8 @@ channel_handle_ctl(Channel *c, fd_set *readset, fd_set *writeset)
1633 /* Monitor control fd to detect if the slave client exits */ 1679 /* Monitor control fd to detect if the slave client exits */
1634 if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) { 1680 if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) {
1635 len = read(c->ctl_fd, buf, sizeof(buf)); 1681 len = read(c->ctl_fd, buf, sizeof(buf));
1636 if (len < 0 && (errno == EINTR || errno == EAGAIN)) 1682 if (len < 0 &&
1683 (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
1637 return 1; 1684 return 1;
1638 if (len <= 0) { 1685 if (len <= 0) {
1639 debug2("channel %d: ctl read<=0", c->self); 1686 debug2("channel %d: ctl read<=0", c->self);
@@ -2012,7 +2059,7 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
2012 return; 2059 return;
2013 2060
2014 /* Get the data. */ 2061 /* Get the data. */
2015 data = packet_get_string(&data_len); 2062 data = packet_get_string_ptr(&data_len);
2016 2063
2017 /* 2064 /*
2018 * Ignore data for protocol > 1.3 if output end is no longer open. 2065 * Ignore data for protocol > 1.3 if output end is no longer open.
@@ -2026,7 +2073,6 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
2026 c->local_window -= data_len; 2073 c->local_window -= data_len;
2027 c->local_consumed += data_len; 2074 c->local_consumed += data_len;
2028 } 2075 }
2029 xfree(data);
2030 return; 2076 return;
2031 } 2077 }
2032 2078
@@ -2038,17 +2084,15 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
2038 if (data_len > c->local_window) { 2084 if (data_len > c->local_window) {
2039 logit("channel %d: rcvd too much data %d, win %d", 2085 logit("channel %d: rcvd too much data %d, win %d",
2040 c->self, data_len, c->local_window); 2086 c->self, data_len, c->local_window);
2041 xfree(data);
2042 return; 2087 return;
2043 } 2088 }
2044 c->local_window -= data_len; 2089 c->local_window -= data_len;
2045 } 2090 }
2046 packet_check_eom();
2047 if (c->datagram) 2091 if (c->datagram)
2048 buffer_put_string(&c->output, data, data_len); 2092 buffer_put_string(&c->output, data, data_len);
2049 else 2093 else
2050 buffer_append(&c->output, data, data_len); 2094 buffer_append(&c->output, data, data_len);
2051 xfree(data); 2095 packet_check_eom();
2052} 2096}
2053 2097
2054/* ARGSUSED */ 2098/* ARGSUSED */
@@ -2212,9 +2256,9 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
2212 if (compat20) { 2256 if (compat20) {
2213 c->remote_window = packet_get_int(); 2257 c->remote_window = packet_get_int();
2214 c->remote_maxpacket = packet_get_int(); 2258 c->remote_maxpacket = packet_get_int();
2215 if (c->confirm) { 2259 if (c->open_confirm) {
2216 debug2("callback start"); 2260 debug2("callback start");
2217 c->confirm(c->self, c->confirm_ctx); 2261 c->open_confirm(c->self, c->open_confirm_ctx);
2218 debug2("callback done"); 2262 debug2("callback done");
2219 } 2263 }
2220 debug2("channel %d: open confirm rwindow %u rmax %u", c->self, 2264 debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
@@ -2303,7 +2347,7 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
2303 Channel *c = NULL; 2347 Channel *c = NULL;
2304 u_short host_port; 2348 u_short host_port;
2305 char *host, *originator_string; 2349 char *host, *originator_string;
2306 int remote_id, sock = -1; 2350 int remote_id;
2307 2351
2308 remote_id = packet_get_int(); 2352 remote_id = packet_get_int();
2309 host = packet_get_string(NULL); 2353 host = packet_get_string(NULL);
@@ -2315,22 +2359,46 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
2315 originator_string = xstrdup("unknown (remote did not supply name)"); 2359 originator_string = xstrdup("unknown (remote did not supply name)");
2316 } 2360 }
2317 packet_check_eom(); 2361 packet_check_eom();
2318 sock = channel_connect_to(host, host_port); 2362 c = channel_connect_to(host, host_port,
2319 if (sock != -1) { 2363 "connected socket", originator_string);
2320 c = channel_new("connected socket",
2321 SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0,
2322 originator_string, 1);
2323 c->remote_id = remote_id;
2324 }
2325 xfree(originator_string); 2364 xfree(originator_string);
2365 xfree(host);
2326 if (c == NULL) { 2366 if (c == NULL) {
2327 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 2367 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
2328 packet_put_int(remote_id); 2368 packet_put_int(remote_id);
2329 packet_send(); 2369 packet_send();
2330 } 2370 } else
2331 xfree(host); 2371 c->remote_id = remote_id;
2332} 2372}
2333 2373
2374/* ARGSUSED */
2375void
2376channel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
2377{
2378 Channel *c;
2379 struct channel_confirm *cc;
2380 int remote_id;
2381
2382 /* Reset keepalive timeout */
2383 keep_alive_timeouts = 0;
2384
2385 remote_id = packet_get_int();
2386 packet_check_eom();
2387
2388 debug2("channel_input_confirm: type %d id %d", type, remote_id);
2389
2390 if ((c = channel_lookup(remote_id)) == NULL) {
2391 logit("channel_input_success_failure: %d: unknown", remote_id);
2392 return;
2393 }
2394 ;
2395 if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
2396 return;
2397 cc->cb(type, c, cc->ctx);
2398 TAILQ_REMOVE(&c->status_confirms, cc, entry);
2399 bzero(cc, sizeof(*cc));
2400 xfree(cc);
2401}
2334 2402
2335/* -- tcp forwarding */ 2403/* -- tcp forwarding */
2336 2404
@@ -2385,7 +2453,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
2385 wildcard = 1; 2453 wildcard = 1;
2386 } else if (gateway_ports || is_client) { 2454 } else if (gateway_ports || is_client) {
2387 if (((datafellows & SSH_OLD_FORWARD_ADDR) && 2455 if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2388 strcmp(listen_addr, "0.0.0.0") == 0) || 2456 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2389 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || 2457 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2390 (!is_client && gateway_ports == 1)) 2458 (!is_client && gateway_ports == 1))
2391 wildcard = 1; 2459 wildcard = 1;
@@ -2409,10 +2477,11 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
2409 if (addr == NULL) { 2477 if (addr == NULL) {
2410 /* This really shouldn't happen */ 2478 /* This really shouldn't happen */
2411 packet_disconnect("getaddrinfo: fatal error: %s", 2479 packet_disconnect("getaddrinfo: fatal error: %s",
2412 gai_strerror(r)); 2480 ssh_gai_strerror(r));
2413 } else { 2481 } else {
2414 error("channel_setup_fwd_listener: " 2482 error("channel_setup_fwd_listener: "
2415 "getaddrinfo(%.64s): %s", addr, gai_strerror(r)); 2483 "getaddrinfo(%.64s): %s", addr,
2484 ssh_gai_strerror(r));
2416 } 2485 }
2417 return 0; 2486 return 0;
2418 } 2487 }
@@ -2717,35 +2786,37 @@ channel_clear_adm_permitted_opens(void)
2717 num_adm_permitted_opens = 0; 2786 num_adm_permitted_opens = 0;
2718} 2787}
2719 2788
2720/* return socket to remote host, port */ 2789void
2790channel_print_adm_permitted_opens(void)
2791{
2792 int i;
2793
2794 for (i = 0; i < num_adm_permitted_opens; i++)
2795 if (permitted_adm_opens[i].host_to_connect != NULL)
2796 printf(" %s:%d", permitted_adm_opens[i].host_to_connect,
2797 permitted_adm_opens[i].port_to_connect);
2798}
2799
2800/* Try to start non-blocking connect to next host in cctx list */
2721static int 2801static int
2722connect_to(const char *host, u_short port) 2802connect_next(struct channel_connect *cctx)
2723{ 2803{
2724 struct addrinfo hints, *ai, *aitop; 2804 int sock, saved_errno;
2725 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 2805 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
2726 int gaierr;
2727 int sock = -1;
2728 2806
2729 memset(&hints, 0, sizeof(hints)); 2807 for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
2730 hints.ai_family = IPv4or6; 2808 if (cctx->ai->ai_family != AF_INET &&
2731 hints.ai_socktype = SOCK_STREAM; 2809 cctx->ai->ai_family != AF_INET6)
2732 snprintf(strport, sizeof strport, "%d", port);
2733 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
2734 error("connect_to %.100s: unknown host (%s)", host,
2735 gai_strerror(gaierr));
2736 return -1;
2737 }
2738 for (ai = aitop; ai; ai = ai->ai_next) {
2739 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
2740 continue; 2810 continue;
2741 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 2811 if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
2742 strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 2812 ntop, sizeof(ntop), strport, sizeof(strport),
2743 error("connect_to: getnameinfo failed"); 2813 NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
2814 error("connect_next: getnameinfo failed");
2744 continue; 2815 continue;
2745 } 2816 }
2746 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 2817 if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
2747 if (sock < 0) { 2818 cctx->ai->ai_protocol)) == -1) {
2748 if (ai->ai_next == NULL) 2819 if (cctx->ai->ai_next == NULL)
2749 error("socket: %.100s", strerror(errno)); 2820 error("socket: %.100s", strerror(errno));
2750 else 2821 else
2751 verbose("socket: %.100s", strerror(errno)); 2822 verbose("socket: %.100s", strerror(errno));
@@ -2753,45 +2824,95 @@ connect_to(const char *host, u_short port)
2753 } 2824 }
2754 if (set_nonblock(sock) == -1) 2825 if (set_nonblock(sock) == -1)
2755 fatal("%s: set_nonblock(%d)", __func__, sock); 2826 fatal("%s: set_nonblock(%d)", __func__, sock);
2756 if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && 2827 if (connect(sock, cctx->ai->ai_addr,
2757 errno != EINPROGRESS) { 2828 cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) {
2758 error("connect_to %.100s port %s: %.100s", ntop, strport, 2829 debug("connect_next: host %.100s ([%.100s]:%s): "
2830 "%.100s", cctx->host, ntop, strport,
2759 strerror(errno)); 2831 strerror(errno));
2832 saved_errno = errno;
2760 close(sock); 2833 close(sock);
2834 errno = saved_errno;
2761 continue; /* fail -- try next */ 2835 continue; /* fail -- try next */
2762 } 2836 }
2763 break; /* success */ 2837 debug("connect_next: host %.100s ([%.100s]:%s) "
2838 "in progress, fd=%d", cctx->host, ntop, strport, sock);
2839 cctx->ai = cctx->ai->ai_next;
2840 set_nodelay(sock);
2841 return sock;
2842 }
2843 return -1;
2844}
2764 2845
2846static void
2847channel_connect_ctx_free(struct channel_connect *cctx)
2848{
2849 xfree(cctx->host);
2850 if (cctx->aitop)
2851 freeaddrinfo(cctx->aitop);
2852 bzero(cctx, sizeof(*cctx));
2853 cctx->host = NULL;
2854 cctx->ai = cctx->aitop = NULL;
2855}
2856
2857/* Return CONNECTING channel to remote host, port */
2858static Channel *
2859connect_to(const char *host, u_short port, char *ctype, char *rname)
2860{
2861 struct addrinfo hints;
2862 int gaierr;
2863 int sock = -1;
2864 char strport[NI_MAXSERV];
2865 struct channel_connect cctx;
2866 Channel *c;
2867
2868 memset(&cctx, 0, sizeof(cctx));
2869 memset(&hints, 0, sizeof(hints));
2870 hints.ai_family = IPv4or6;
2871 hints.ai_socktype = SOCK_STREAM;
2872 snprintf(strport, sizeof strport, "%d", port);
2873 if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) {
2874 error("connect_to %.100s: unknown host (%s)", host,
2875 ssh_gai_strerror(gaierr));
2876 return NULL;
2765 } 2877 }
2766 freeaddrinfo(aitop); 2878
2767 if (!ai) { 2879 cctx.host = xstrdup(host);
2768 error("connect_to %.100s port %d: failed.", host, port); 2880 cctx.port = port;
2769 return -1; 2881 cctx.ai = cctx.aitop;
2882
2883 if ((sock = connect_next(&cctx)) == -1) {
2884 error("connect to %.100s port %d failed: %s",
2885 host, port, strerror(errno));
2886 channel_connect_ctx_free(&cctx);
2887 return NULL;
2770 } 2888 }
2771 /* success */ 2889 c = channel_new(ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
2772 set_nodelay(sock); 2890 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
2773 return sock; 2891 c->connect_ctx = cctx;
2892 return c;
2774} 2893}
2775 2894
2776int 2895Channel *
2777channel_connect_by_listen_address(u_short listen_port) 2896channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname)
2778{ 2897{
2779 int i; 2898 int i;
2780 2899
2781 for (i = 0; i < num_permitted_opens; i++) 2900 for (i = 0; i < num_permitted_opens; i++) {
2782 if (permitted_opens[i].host_to_connect != NULL && 2901 if (permitted_opens[i].host_to_connect != NULL &&
2783 permitted_opens[i].listen_port == listen_port) 2902 permitted_opens[i].listen_port == listen_port) {
2784 return connect_to( 2903 return connect_to(
2785 permitted_opens[i].host_to_connect, 2904 permitted_opens[i].host_to_connect,
2786 permitted_opens[i].port_to_connect); 2905 permitted_opens[i].port_to_connect, ctype, rname);
2906 }
2907 }
2787 error("WARNING: Server requests forwarding for unknown listen_port %d", 2908 error("WARNING: Server requests forwarding for unknown listen_port %d",
2788 listen_port); 2909 listen_port);
2789 return -1; 2910 return NULL;
2790} 2911}
2791 2912
2792/* Check if connecting to that port is permitted and connect. */ 2913/* Check if connecting to that port is permitted and connect. */
2793int 2914Channel *
2794channel_connect_to(const char *host, u_short port) 2915channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
2795{ 2916{
2796 int i, permit, permit_adm = 1; 2917 int i, permit, permit_adm = 1;
2797 2918
@@ -2817,9 +2938,9 @@ channel_connect_to(const char *host, u_short port)
2817 if (!permit || !permit_adm) { 2938 if (!permit || !permit_adm) {
2818 logit("Received request to connect to host %.100s port %d, " 2939 logit("Received request to connect to host %.100s port %d, "
2819 "but the request was denied.", host, port); 2940 "but the request was denied.", host, port);
2820 return -1; 2941 return NULL;
2821 } 2942 }
2822 return connect_to(host, port); 2943 return connect_to(host, port, ctype, rname);
2823} 2944}
2824 2945
2825void 2946void
@@ -2874,7 +2995,7 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
2874 hints.ai_socktype = SOCK_STREAM; 2995 hints.ai_socktype = SOCK_STREAM;
2875 snprintf(strport, sizeof strport, "%d", port); 2996 snprintf(strport, sizeof strport, "%d", port);
2876 if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) { 2997 if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
2877 error("getaddrinfo: %.100s", gai_strerror(gaierr)); 2998 error("getaddrinfo: %.100s", ssh_gai_strerror(gaierr));
2878 return -1; 2999 return -1;
2879 } 3000 }
2880 for (ai = aitop; ai; ai = ai->ai_next) { 3001 for (ai = aitop; ai; ai = ai->ai_next) {
@@ -2904,7 +3025,8 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
2904 error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno)); 3025 error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno));
2905 } 3026 }
2906#endif 3027#endif
2907 channel_set_reuseaddr(sock); 3028 if (x11_use_localhost)
3029 channel_set_reuseaddr(sock);
2908 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 3030 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
2909 debug2("bind port %d: %.100s", port, strerror(errno)); 3031 debug2("bind port %d: %.100s", port, strerror(errno));
2910 close(sock); 3032 close(sock);
@@ -2916,17 +3038,8 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
2916 break; 3038 break;
2917 } 3039 }
2918 socks[num_socks++] = sock; 3040 socks[num_socks++] = sock;
2919#ifndef DONT_TRY_OTHER_AF
2920 if (num_socks == NUM_SOCKS) 3041 if (num_socks == NUM_SOCKS)
2921 break; 3042 break;
2922#else
2923 if (x11_use_localhost) {
2924 if (num_socks == NUM_SOCKS)
2925 break;
2926 } else {
2927 break;
2928 }
2929#endif
2930 } 3043 }
2931 freeaddrinfo(aitop); 3044 freeaddrinfo(aitop);
2932 if (num_socks > 0) 3045 if (num_socks > 0)
@@ -3048,7 +3161,8 @@ x11_connect_display(void)
3048 hints.ai_socktype = SOCK_STREAM; 3161 hints.ai_socktype = SOCK_STREAM;
3049 snprintf(strport, sizeof strport, "%u", 6000 + display_number); 3162 snprintf(strport, sizeof strport, "%u", 6000 + display_number);
3050 if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { 3163 if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
3051 error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr)); 3164 error("%.100s: unknown host. (%s)", buf,
3165 ssh_gai_strerror(gaierr));
3052 return -1; 3166 return -1;
3053 } 3167 }
3054 for (ai = aitop; ai; ai = ai->ai_next) { 3168 for (ai = aitop; ai; ai = ai->ai_next) {