version 1.109.2.3, 2001/09/27 19:03:54 |
version 1.109.2.4, 2001/11/15 00:15:19 |
|
|
static char *auth_sock_dir = NULL; |
static char *auth_sock_dir = NULL; |
|
|
/* AF_UNSPEC or AF_INET or AF_INET6 */ |
/* AF_UNSPEC or AF_INET or AF_INET6 */ |
extern int IPv4or6; |
static int IPv4or6 = AF_UNSPEC; |
|
|
/* helper */ |
/* helper */ |
static void port_open_helper(Channel *c, char *rtype); |
static void port_open_helper(Channel *c, char *rtype); |
|
|
} |
} |
/* Initialize and return new channel. */ |
/* Initialize and return new channel. */ |
c = channels[found] = xmalloc(sizeof(Channel)); |
c = channels[found] = xmalloc(sizeof(Channel)); |
|
memset(c, 0, sizeof(Channel)); |
buffer_init(&c->input); |
buffer_init(&c->input); |
buffer_init(&c->output); |
buffer_init(&c->output); |
buffer_init(&c->extended); |
buffer_init(&c->extended); |
|
|
debug3("channel_free: status: %s", s); |
debug3("channel_free: status: %s", s); |
xfree(s); |
xfree(s); |
|
|
if (c->detach_user != NULL) { |
|
debug("channel_free: channel %d: detaching channel user", c->self); |
|
c->detach_user(c->self, NULL); |
|
} |
|
if (c->sock != -1) |
if (c->sock != -1) |
shutdown(c->sock, SHUT_RDWR); |
shutdown(c->sock, SHUT_RDWR); |
channel_close_fds(c); |
channel_close_fds(c); |
|
|
channel_free(channels[i]); |
channel_free(channels[i]); |
} |
} |
|
|
void |
|
channel_detach_all(void) |
|
{ |
|
int i; |
|
Channel *c; |
|
|
|
for (i = 0; i < channels_alloc; i++) { |
|
c = channels[i]; |
|
if (c != NULL && c->detach_user != NULL) { |
|
debug("channel_detach_all: channel %d", c->self); |
|
c->detach_user(c->self, NULL); |
|
c->detach_user = NULL; |
|
} |
|
} |
|
} |
|
|
|
/* |
/* |
* Closes the sockets/fds of all channels. This is used to close extra file |
* Closes the sockets/fds of all channels. This is used to close extra file |
* descriptors after a fork. |
* descriptors after a fork. |
|
|
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
c = channels[i]; |
c = channels[i]; |
if (c != NULL && c->type == SSH_CHANNEL_OPEN) { |
if (c != NULL && c->type == SSH_CHANNEL_OPEN) { |
if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) { |
#if 0 |
|
if (!compat20 && |
|
buffer_len(&c->input) > packet_get_maxsize()) { |
debug("channel %d: big input buffer %d", |
debug("channel %d: big input buffer %d", |
c->self, buffer_len(&c->input)); |
c->self, buffer_len(&c->input)); |
return 0; |
return 0; |
} |
} |
|
#endif |
if (buffer_len(&c->output) > packet_get_maxsize()) { |
if (buffer_len(&c->output) > packet_get_maxsize()) { |
debug("channel %d: big output buffer %d", |
debug("channel %d: big output buffer %d > %d", |
c->self, buffer_len(&c->output)); |
c->self, buffer_len(&c->output), |
|
packet_get_maxsize()); |
return 0; |
return 0; |
} |
} |
} |
} |
|
|
int have, ret; |
int have, ret; |
|
|
have = buffer_len(&c->input); |
have = buffer_len(&c->input); |
|
c->delayed = 0; |
debug2("channel %d: pre_dynamic: have %d", c->self, have); |
debug2("channel %d: pre_dynamic: have %d", c->self, have); |
/* buffer_dump(&c->input); */ |
/* buffer_dump(&c->input); */ |
/* check if the fixed size part of the packet is in buffer. */ |
/* check if the fixed size part of the packet is in buffer. */ |
|
|
"to %.100s port %d requested.", |
"to %.100s port %d requested.", |
c->listening_port, c->path, c->host_port); |
c->listening_port, c->path, c->host_port); |
|
|
rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ? |
if (c->type == SSH_CHANNEL_RPORT_LISTENER) { |
"forwarded-tcpip" : "direct-tcpip"; |
nextstate = SSH_CHANNEL_OPENING; |
nextstate = (c->host_port == 0 && |
rtype = "forwarded-tcpip"; |
c->type != SSH_CHANNEL_RPORT_LISTENER) ? |
} else { |
SSH_CHANNEL_DYNAMIC : SSH_CHANNEL_OPENING; |
if (c->host_port == 0) { |
|
nextstate = SSH_CHANNEL_DYNAMIC; |
|
rtype = "dynamic-tcpip"; |
|
} else { |
|
nextstate = SSH_CHANNEL_OPENING; |
|
rtype = "direct-tcpip"; |
|
} |
|
} |
|
|
addrlen = sizeof(addr); |
addrlen = sizeof(addr); |
newsock = accept(c->sock, &addr, &addrlen); |
newsock = accept(c->sock, &addr, &addrlen); |
|
|
nc->host_port = c->host_port; |
nc->host_port = c->host_port; |
strlcpy(nc->path, c->path, sizeof(nc->path)); |
strlcpy(nc->path, c->path, sizeof(nc->path)); |
|
|
if (nextstate != SSH_CHANNEL_DYNAMIC) |
if (nextstate == SSH_CHANNEL_DYNAMIC) { |
|
/* |
|
* do not call the channel_post handler until |
|
* this flag has been reset by a pre-handler. |
|
* otherwise the FD_ISSET calls might overflow |
|
*/ |
|
nc->delayed = 1; |
|
} else { |
port_open_helper(nc, rtype); |
port_open_helper(nc, rtype); |
|
} |
} |
} |
} |
} |
|
|
|
|
static void |
static void |
channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset) |
channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset) |
{ |
{ |
|
if (c->delayed) |
|
return; |
channel_handle_rfd(c, readset, writeset); |
channel_handle_rfd(c, readset, writeset); |
channel_handle_wfd(c, readset, writeset); |
channel_handle_wfd(c, readset, writeset); |
} |
} |
|
|
static void |
static void |
channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset) |
channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset) |
{ |
{ |
|
if (c->delayed) |
|
return; |
channel_handle_rfd(c, readset, writeset); |
channel_handle_rfd(c, readset, writeset); |
channel_handle_wfd(c, readset, writeset); |
channel_handle_wfd(c, readset, writeset); |
channel_handle_efd(c, readset, writeset); |
channel_handle_efd(c, readset, writeset); |
|
|
channel_handler_init_15(); |
channel_handler_init_15(); |
} |
} |
|
|
|
/* gc dead channels */ |
static void |
static void |
|
channel_garbage_collect(Channel *c) |
|
{ |
|
if (c == NULL) |
|
return; |
|
if (c->detach_user != NULL) { |
|
if (!chan_is_dead(c, 0)) |
|
return; |
|
debug("channel %d: gc: notify user", c->self); |
|
c->detach_user(c->self, NULL); |
|
/* if we still have a callback */ |
|
if (c->detach_user != NULL) |
|
return; |
|
debug("channel %d: gc: user detached", c->self); |
|
} |
|
if (!chan_is_dead(c, 1)) |
|
return; |
|
debug("channel %d: garbage collecting", c->self); |
|
channel_free(c); |
|
} |
|
|
|
static void |
channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) |
channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) |
{ |
{ |
static int did_init = 0; |
static int did_init = 0; |
|
|
continue; |
continue; |
if (ftab[c->type] != NULL) |
if (ftab[c->type] != NULL) |
(*ftab[c->type])(c, readset, writeset); |
(*ftab[c->type])(c, readset, writeset); |
if (chan_is_dead(c)) { |
channel_garbage_collect(c); |
/* |
|
* we have to remove the fd's from the select mask |
|
* before the channels are free'd and the fd's are |
|
* closed |
|
*/ |
|
if (c->wfd != -1) |
|
FD_CLR(c->wfd, writeset); |
|
if (c->rfd != -1) |
|
FD_CLR(c->rfd, readset); |
|
if (c->efd != -1) { |
|
if (c->extended_usage == CHAN_EXTENDED_READ) |
|
FD_CLR(c->efd, readset); |
|
if (c->extended_usage == CHAN_EXTENDED_WRITE) |
|
FD_CLR(c->efd, writeset); |
|
} |
|
channel_free(c); |
|
} |
|
} |
} |
} |
} |
|
|
|
|
if (compat20 && |
if (compat20 && |
(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { |
(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { |
/* XXX is this true? */ |
/* XXX is this true? */ |
debug2("channel %d: no data after CLOSE", c->self); |
debug3("channel %d: will not send data after close", c->self); |
continue; |
continue; |
} |
} |
|
|
|
|
|
|
|
|
/* -- tcp forwarding */ |
/* -- tcp forwarding */ |
|
|
|
void |
|
channel_set_af(int af) |
|
{ |
|
IPv4or6 = af; |
|
} |
|
|
/* |
/* |
* Initiate forwarding of connections to local port "port" through the secure |
* Initiate forwarding of connections to local port "port" through the secure |