*/
#include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.80 2001/01/08 22:03:23 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.89 2001/02/04 15:32:23 stevesk Exp $");
+
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
#include "packet.h"
#include "xmalloc.h"
#include "buffer.h"
#include "uidswap.h"
-#include "readconf.h"
-#include "servconf.h"
-
+#include "log.h"
+#include "misc.h"
#include "channels.h"
#include "nchan.h"
#include "compat.h"
-
-#include "ssh2.h"
-
-#include <openssl/rsa.h>
-#include <openssl/dsa.h>
+#include "canohost.h"
#include "key.h"
#include "authfd.h"
* Maximum file descriptor value used in any of the channels. This is
* updated in channel_allocate.
*/
-static int channel_max_fd_value = 0;
+static int channel_max_fd = 0;
/* Name and directory of socket for authentication agent forwarding. */
static char *channel_forwarded_auth_socket_name = NULL;
/* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */
static int have_hostname_in_open = 0;
+/* AF_UNSPEC or AF_INET or AF_INET6 */
+extern int IPv4or6;
+
/* Sets specific protocol options. */
void
int extusage, int nonblock)
{
/* Update the maximum file descriptor value. */
- if (rfd > channel_max_fd_value)
- channel_max_fd_value = rfd;
- if (wfd > channel_max_fd_value)
- channel_max_fd_value = wfd;
- if (efd > channel_max_fd_value)
- channel_max_fd_value = efd;
+ channel_max_fd = MAX(channel_max_fd, rfd);
+ channel_max_fd = MAX(channel_max_fd, wfd);
+ channel_max_fd = MAX(channel_max_fd, efd);
+
/* XXX set close-on-exec -markus */
c->rfd = rfd;
struct sockaddr addr;
int newsock, newch;
socklen_t addrlen;
- char buf[16384], *remote_hostname;
+ char buf[16384], *remote_ipaddr;
int remote_port;
if (FD_ISSET(c->sock, readset)) {
error("accept: %.100s", strerror(errno));
return;
}
- remote_hostname = get_remote_hostname(newsock);
+ remote_ipaddr = get_peer_ipaddr(newsock);
remote_port = get_peer_port(newsock);
snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
- remote_hostname, remote_port);
+ remote_ipaddr, remote_port);
newch = channel_new("x11",
SSH_CHANNEL_OPENING, newsock, newsock, -1,
packet_put_int(newch);
packet_put_int(c->local_window_max);
packet_put_int(c->local_maxpacket);
- /* originator host and port */
- packet_put_cstring(remote_hostname);
+ /* originator ipaddr and port */
+ packet_put_cstring(remote_ipaddr);
if (datafellows & SSH_BUG_X11FWD) {
debug("ssh2 x11 bug compat mode");
} else {
packet_put_string(buf, strlen(buf));
packet_send();
}
- xfree(remote_hostname);
+ xfree(remote_ipaddr);
}
}
struct sockaddr addr;
int newsock, newch;
socklen_t addrlen;
- char buf[1024], *remote_hostname, *rtype;
+ char buf[1024], *remote_ipaddr, *rtype;
int remote_port;
rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ?
error("accept: %.100s", strerror(errno));
return;
}
- remote_hostname = get_remote_hostname(newsock);
+ remote_ipaddr = get_peer_ipaddr(newsock);
remote_port = get_peer_port(newsock);
snprintf(buf, sizeof buf,
"listen port %d for %.100s port %d, "
"connect from %.200s port %d",
c->listening_port, c->path, c->host_port,
- remote_hostname, remote_port);
+ remote_ipaddr, remote_port);
newch = channel_new(rtype,
SSH_CHANNEL_OPENING, newsock, newsock, -1,
packet_put_int(c->host_port);
}
/* originator host and port */
- packet_put_cstring(remote_hostname);
+ packet_put_cstring(remote_ipaddr);
packet_put_int(remote_port);
packet_send();
} else {
}
packet_send();
}
- xfree(remote_hostname);
+ xfree(remote_ipaddr);
}
}
int err = 0;
int sz = sizeof(err);
c->type = SSH_CHANNEL_OPEN;
- if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, (char *)&err, &sz) < 0) {
+ if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, (char *)&err, &sz) < 0) {
debug("getsockopt SO_ERROR failed");
} else {
if (err == 0) {
}
void
-channel_prepare_select(fd_set * readset, fd_set * writeset)
+channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp)
{
- channel_handler(channel_pre, readset, writeset);
+ int n;
+ u_int sz;
+
+ n = MAX(*maxfdp, channel_max_fd);
+
+ sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
+ if (*readsetp == NULL || n > *maxfdp) {
+ if (*readsetp)
+ xfree(*readsetp);
+ if (*writesetp)
+ xfree(*writesetp);
+ *readsetp = xmalloc(sz);
+ *writesetp = xmalloc(sz);
+ *maxfdp = n;
+ }
+ memset(*readsetp, 0, sz);
+ memset(*writesetp, 0, sz);
+
+ channel_handler(channel_pre, *readsetp, *writesetp);
}
void
channel_handler(channel_post, readset, writeset);
}
-/* If there is data to send to the connection, send some of it now. */
+/* If there is data to send to the connection, enqueue some of it now. */
void
channel_output_poll()
void
channel_input_open_failure(int type, int plen, void *ctxt)
{
- int id;
+ int id, reason;
+ char *msg = NULL, *lang = NULL;
Channel *c;
if (!compat20)
packet_disconnect("Received open failure for "
"non-opening channel %d.", id);
if (compat20) {
- int reason = packet_get_int();
- char *msg = packet_get_string(NULL);
- char *lang = packet_get_string(NULL);
- log("channel_open_failure: %d: reason %d: %s", id, reason, msg);
+ reason = packet_get_int();
+ if (packet_remaining() > 0) {
+ msg = packet_get_string(NULL);
+ lang = packet_get_string(NULL);
+ }
packet_done();
- xfree(msg);
- xfree(lang);
+ log("channel_open_failure: %d: reason %d %s", id,
+ reason, msg ? msg : "<no additional info>");
+ if (msg != NULL)
+ xfree(msg);
+ if (lang != NULL)
+ xfree(lang);
}
/* Free the channel. This will also close the socket. */
channel_free(id);
channel_close_fds(&channels[i]);
}
-/* Returns the maximum file descriptor number used by the channels. */
-
-int
-channel_max_fd()
-{
- return channel_max_fd_value;
-}
-
/* Returns true if any channel is still open. */
int
* Initiate forwarding of connections to local port "port" through the secure
* channel to host:port from remote side.
*/
-void
+int
channel_request_local_forwarding(u_short listen_port, const char *host_to_connect,
u_short port_to_connect, int gateway_ports)
{
- channel_request_forwarding(
+ return channel_request_forwarding(
NULL, listen_port,
host_to_connect, port_to_connect,
gateway_ports, /*remote_fwd*/ 0);
* If 'remote_fwd' is true we have a '-R style' listener for protocol 2
* (SSH_CHANNEL_RPORT_LISTENER).
*/
-void
+int
channel_request_forwarding(
const char *listen_address, u_short listen_port,
const char *host_to_connect, u_short port_to_connect,
const char *host;
struct linger linger;
+ success = 0;
+
if (remote_fwd) {
host = listen_address;
- ctype = SSH_CHANNEL_RPORT_LISTENER;
+ ctype = SSH_CHANNEL_RPORT_LISTENER;
} else {
host = host_to_connect;
ctype =SSH_CHANNEL_PORT_LISTENER;
}
- if (strlen(host) > sizeof(channels[0].path) - 1)
- packet_disconnect("Forward host name too long.");
+ if (strlen(host) > sizeof(channels[0].path) - 1) {
+ error("Forward host name too long.");
+ return success;
+ }
/* XXX listen_address is currently ignored */
/*
if (getaddrinfo(NULL, strport, &hints, &aitop) != 0)
packet_disconnect("getaddrinfo: fatal error");
- success = 0;
for (ai = aitop; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
error("bind: %.100s", strerror(errno));
else
verbose("bind: %.100s", strerror(errno));
-
+
close(sock);
continue;
}
success = 1;
}
if (success == 0)
- packet_disconnect("cannot listen port: %d", listen_port); /*XXX ?disconnect? */
+ error("channel_request_forwarding: cannot listen to port: %d",
+ listen_port);
freeaddrinfo(aitop);
+ return success;
}
/*
error("connect %.100s port %s: %.100s", ntop, strport,
strerror(errno));
close(sock);
- continue; /* fail -- try next */
+ continue; /* fail -- try next */
}
break; /* success */
}
freeaddrinfo(aitop);
if (!ai) {
- error("connect %.100s port %d: failed.", host, host_port);
+ error("connect %.100s port %d: failed.", host, host_port);
return -1;
}
/* success */
break;
#endif
}
+ freeaddrinfo(aitop);
if (num_socks > 0)
break;
}
fatal("gethostname: %.100s", strerror(errno));
#ifdef IPADDR_IN_DISPLAY
- /*
+ /*
* HPUX detects the local hostname in the DISPLAY variable and tries
* to set up a shared memory connection to the server, which it
* incorrectly supposes to be local.
memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
/* Set DISPLAY to <ip address>:screen.display */
- snprintf(display, sizeof(display), "%.50s:%d.%d", inet_ntoa(my_addr),
+ snprintf(display, sizeof(display), "%.50s:%d.%d", inet_ntoa(my_addr),
display_number, screen_number);
}
#else /* IPADDR_IN_DISPLAY */
}
c->dettach_user = NULL;
}
-void
+void
channel_register_filter(int id, channel_filter_fn *fn)
{
Channel *c = channel_lookup(id);