version 1.112, 2001/05/04 14:34:34 |
version 1.113, 2001/05/04 23:47:33 |
|
|
* Pointer to an array containing all allocated channels. The array is |
* Pointer to an array containing all allocated channels. The array is |
* dynamically extended as needed. |
* dynamically extended as needed. |
*/ |
*/ |
static Channel *channels = NULL; |
static Channel **channels = NULL; |
|
|
/* |
/* |
* Size of the channel array. All slots of the array must always be |
* Size of the channel array. All slots of the array must always be |
* initialized (at least the type field); unused slots are marked with type |
* initialized (at least the type field); unused slots set to NULL |
* SSH_CHANNEL_FREE. |
|
*/ |
*/ |
static int channels_alloc = 0; |
static int channels_alloc = 0; |
|
|
/* |
/* |
* Maximum file descriptor value used in any of the channels. This is |
* Maximum file descriptor value used in any of the channels. This is |
* updated in channel_allocate. |
* updated in channel_new. |
*/ |
*/ |
static int channel_max_fd = 0; |
static int channel_max_fd = 0; |
|
|
|
|
channel_lookup(int id) |
channel_lookup(int id) |
{ |
{ |
Channel *c; |
Channel *c; |
|
|
if (id < 0 || id > channels_alloc) { |
if (id < 0 || id > channels_alloc) { |
log("channel_lookup: %d: bad id", id); |
log("channel_lookup: %d: bad id", id); |
return NULL; |
return NULL; |
} |
} |
c = &channels[id]; |
c = channels[id]; |
if (c->type == SSH_CHANNEL_FREE) { |
if (c == NULL) { |
log("channel_lookup: %d: bad id: channel free", id); |
log("channel_lookup: %d: bad id: channel free", id); |
return NULL; |
return NULL; |
} |
} |
|
|
* remote_name to be freed. |
* remote_name to be freed. |
*/ |
*/ |
|
|
int |
Channel * |
channel_new(char *ctype, int type, int rfd, int wfd, int efd, |
channel_new(char *ctype, int type, int rfd, int wfd, int efd, |
int window, int maxpack, int extusage, char *remote_name, int nonblock) |
int window, int maxpack, int extusage, char *remote_name, int nonblock) |
{ |
{ |
|
|
if (channels_alloc == 0) { |
if (channels_alloc == 0) { |
chan_init(); |
chan_init(); |
channels_alloc = 10; |
channels_alloc = 10; |
channels = xmalloc(channels_alloc * sizeof(Channel)); |
channels = xmalloc(channels_alloc * sizeof(Channel *)); |
for (i = 0; i < channels_alloc; i++) |
for (i = 0; i < channels_alloc; i++) |
channels[i].type = SSH_CHANNEL_FREE; |
channels[i] = NULL; |
/* |
/* |
* Kludge: arrange a call to channel_stop_listening if we |
* Kludge: arrange a call to channel_stop_listening if we |
* terminate with fatal(). |
* terminate with fatal(). |
|
|
} |
} |
/* Try to find a free slot where to put the new channel. */ |
/* Try to find a free slot where to put the new channel. */ |
for (found = -1, i = 0; i < channels_alloc; i++) |
for (found = -1, i = 0; i < channels_alloc; i++) |
if (channels[i].type == SSH_CHANNEL_FREE) { |
if (channels[i] == NULL) { |
/* Found a free slot. */ |
/* Found a free slot. */ |
found = i; |
found = i; |
break; |
break; |
|
|
found = channels_alloc; |
found = channels_alloc; |
channels_alloc += 10; |
channels_alloc += 10; |
debug2("channel: expanding %d", channels_alloc); |
debug2("channel: expanding %d", channels_alloc); |
channels = xrealloc(channels, channels_alloc * sizeof(Channel)); |
channels = xrealloc(channels, channels_alloc * sizeof(Channel *)); |
for (i = found; i < channels_alloc; i++) |
for (i = found; i < channels_alloc; i++) |
channels[i].type = SSH_CHANNEL_FREE; |
channels[i] = NULL; |
} |
} |
/* Initialize and return new channel number. */ |
/* Initialize and return new channel. */ |
c = &channels[found]; |
c = channels[found] = xmalloc(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); |
|
|
c->dettach_user = NULL; |
c->dettach_user = NULL; |
c->input_filter = NULL; |
c->input_filter = NULL; |
debug("channel %d: new [%s]", found, remote_name); |
debug("channel %d: new [%s]", found, remote_name); |
return found; |
return c; |
} |
} |
/* old interface XXX */ |
|
int |
|
channel_allocate(int type, int sock, char *remote_name) |
|
{ |
|
return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name, 1); |
|
} |
|
|
|
|
|
/* Close all channel fd/socket. */ |
/* Close all channel fd/socket. */ |
|
|
void |
void |
|
|
/* Free the channel and close its fd/socket. */ |
/* Free the channel and close its fd/socket. */ |
|
|
void |
void |
channel_free(int id) |
channel_free(Channel *c) |
{ |
{ |
Channel *c = channel_lookup(id); |
char *s; |
char *s = channel_open_message(); |
|
|
|
if (c == NULL) |
s = channel_open_message(); |
packet_disconnect("channel free: bad local channel %d", id); |
debug("channel_free: channel %d: status: %s", c->self, s); |
debug("channel_free: channel %d: status: %s", id, s); |
|
xfree(s); |
xfree(s); |
|
|
if (c->dettach_user != NULL) { |
if (c->dettach_user != NULL) { |
debug("channel_free: channel %d: dettaching channel user", id); |
debug("channel_free: channel %d: dettaching channel user", c->self); |
c->dettach_user(c->self, NULL); |
c->dettach_user(c->self, NULL); |
} |
} |
if (c->sock != -1) |
if (c->sock != -1) |
|
|
buffer_free(&c->input); |
buffer_free(&c->input); |
buffer_free(&c->output); |
buffer_free(&c->output); |
buffer_free(&c->extended); |
buffer_free(&c->extended); |
c->type = SSH_CHANNEL_FREE; |
|
if (c->remote_name) { |
if (c->remote_name) { |
xfree(c->remote_name); |
xfree(c->remote_name); |
c->remote_name = NULL; |
c->remote_name = NULL; |
} |
} |
|
channels[c->self] = NULL; |
|
xfree(c); |
} |
} |
|
|
/* |
/* |
|
|
channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) |
channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) |
{ |
{ |
if (buffer_len(&c->output) == 0) |
if (buffer_len(&c->output) == 0) |
channel_free(c->self); |
chan_mark_dead(c); |
else |
else |
FD_SET(c->sock, writeset); |
FD_SET(c->sock, writeset); |
} |
} |
|
|
break; |
break; |
} |
} |
if (ret < 0) { |
if (ret < 0) { |
channel_free(c->self); |
chan_mark_dead(c); |
} else if (ret == 0) { |
} else if (ret == 0) { |
debug2("channel %d: pre_dynamic: need more", c->self); |
debug2("channel %d: pre_dynamic: need more", c->self); |
/* need more */ |
/* need more */ |
|
|
void |
void |
channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) |
channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) |
{ |
{ |
|
Channel *nc; |
struct sockaddr addr; |
struct sockaddr addr; |
int newsock, newch, oldch; |
int newsock; |
socklen_t addrlen; |
socklen_t addrlen; |
char buf[16384], *remote_ipaddr; |
char buf[16384], *remote_ipaddr; |
int remote_port; |
int remote_port; |
|
|
snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", |
snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", |
remote_ipaddr, remote_port); |
remote_ipaddr, remote_port); |
|
|
oldch = c->self; |
nc = channel_new("accepted x11 socket", |
newch = channel_new("x11", |
|
SSH_CHANNEL_OPENING, newsock, newsock, -1, |
SSH_CHANNEL_OPENING, newsock, newsock, -1, |
c->local_window_max, c->local_maxpacket, |
c->local_window_max, c->local_maxpacket, |
0, xstrdup(buf), 1); |
0, xstrdup(buf), 1); |
c = channel_lookup(oldch); |
if (nc == NULL) { |
|
close(newsock); |
|
xfree(remote_ipaddr); |
|
return; |
|
} |
if (compat20) { |
if (compat20) { |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_put_cstring("x11"); |
packet_put_cstring("x11"); |
packet_put_int(newch); |
packet_put_int(nc->self); |
packet_put_int(c->local_window_max); |
packet_put_int(c->local_window_max); |
packet_put_int(c->local_maxpacket); |
packet_put_int(c->local_maxpacket); |
/* originator ipaddr and port */ |
/* originator ipaddr and port */ |
|
|
packet_send(); |
packet_send(); |
} else { |
} else { |
packet_start(SSH_SMSG_X11_OPEN); |
packet_start(SSH_SMSG_X11_OPEN); |
packet_put_int(newch); |
packet_put_int(nc->self); |
if (have_hostname_in_open) |
if (have_hostname_in_open) |
packet_put_string(buf, strlen(buf)); |
packet_put_string(buf, strlen(buf)); |
packet_send(); |
packet_send(); |
|
|
{ |
{ |
Channel *nc; |
Channel *nc; |
struct sockaddr addr; |
struct sockaddr addr; |
int newsock, newch, nextstate, oldch; |
int newsock, nextstate; |
socklen_t addrlen; |
socklen_t addrlen; |
char *rtype; |
char *rtype; |
|
|
|
|
error("accept: %.100s", strerror(errno)); |
error("accept: %.100s", strerror(errno)); |
return; |
return; |
} |
} |
oldch = c->self; |
nc = channel_new(rtype, |
newch = channel_new(rtype, |
|
nextstate, newsock, newsock, -1, |
nextstate, newsock, newsock, -1, |
c->local_window_max, c->local_maxpacket, |
c->local_window_max, c->local_maxpacket, |
0, xstrdup(rtype), 1); |
0, xstrdup(rtype), 1); |
|
|
c = channel_lookup(oldch); |
|
nc = channel_lookup(newch); |
|
if (nc == NULL) { |
if (nc == NULL) { |
error("xxx: no new channel:"); |
error("channel_post_port_listener: no new channel:"); |
|
close(newsock); |
return; |
return; |
} |
} |
nc->listening_port = c->listening_port; |
nc->listening_port = c->listening_port; |
|
|
void |
void |
channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) |
channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) |
{ |
{ |
|
Channel *nc; |
|
int newsock; |
struct sockaddr addr; |
struct sockaddr addr; |
int newsock, newch, oldch; |
|
socklen_t addrlen; |
socklen_t addrlen; |
|
|
if (FD_ISSET(c->sock, readset)) { |
if (FD_ISSET(c->sock, readset)) { |
|
|
error("accept from auth socket: %.100s", strerror(errno)); |
error("accept from auth socket: %.100s", strerror(errno)); |
return; |
return; |
} |
} |
oldch = c->self; |
nc = channel_new("accepted auth socket", |
newch = channel_new("accepted auth socket", |
|
SSH_CHANNEL_OPENING, newsock, newsock, -1, |
SSH_CHANNEL_OPENING, newsock, newsock, -1, |
c->local_window_max, c->local_maxpacket, |
c->local_window_max, c->local_maxpacket, |
0, xstrdup("accepted auth socket"), 1); |
0, xstrdup("accepted auth socket"), 1); |
c = channel_lookup(oldch); |
if (nc == NULL) { |
|
error("channel_post_auth_listener: channel_new failed"); |
|
close(newsock); |
|
} |
if (compat20) { |
if (compat20) { |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_put_cstring("auth-agent@openssh.com"); |
packet_put_cstring("auth-agent@openssh.com"); |
packet_put_int(newch); |
packet_put_int(nc->self); |
packet_put_int(c->local_window_max); |
packet_put_int(c->local_window_max); |
packet_put_int(c->local_maxpacket); |
packet_put_int(c->local_maxpacket); |
} else { |
} else { |
packet_start(SSH_SMSG_AGENT_OPEN); |
packet_start(SSH_SMSG_AGENT_OPEN); |
packet_put_int(newch); |
packet_put_int(nc->self); |
} |
} |
packet_send(); |
packet_send(); |
} |
} |
|
|
c->self, c->rfd, len); |
c->self, c->rfd, len); |
if (c->type != SSH_CHANNEL_OPEN) { |
if (c->type != SSH_CHANNEL_OPEN) { |
debug("channel %d: not open", c->self); |
debug("channel %d: not open", c->self); |
channel_free(c->self); |
chan_mark_dead(c); |
return -1; |
return -1; |
} else if (compat13) { |
} else if (compat13) { |
buffer_consume(&c->output, buffer_len(&c->output)); |
buffer_consume(&c->output, buffer_len(&c->output)); |
|
|
if (len <= 0) { |
if (len <= 0) { |
if (c->type != SSH_CHANNEL_OPEN) { |
if (c->type != SSH_CHANNEL_OPEN) { |
debug("channel %d: not open", c->self); |
debug("channel %d: not open", c->self); |
channel_free(c->self); |
chan_mark_dead(c); |
return -1; |
return -1; |
} else if (compat13) { |
} else if (compat13) { |
buffer_consume(&c->output, buffer_len(&c->output)); |
buffer_consume(&c->output, buffer_len(&c->output)); |
|
|
did_init = 1; |
did_init = 1; |
} |
} |
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
c = &channels[i]; |
c = channels[i]; |
if (c->type == SSH_CHANNEL_FREE) |
if (c == NULL) |
continue; |
continue; |
if (ftab[c->type] == NULL) |
if (ftab[c->type] == NULL) |
continue; |
continue; |
(*ftab[c->type])(c, readset, writeset); |
(*ftab[c->type])(c, readset, writeset); |
c = &channels[i]; /* XXX realloc */ |
|
if (chan_is_dead(c)) { |
if (chan_is_dead(c)) { |
/* |
/* |
* we have to remove the fd's from the select mask |
* we have to remove the fd's from the select mask |
|
|
if (c->extended_usage == CHAN_EXTENDED_WRITE) |
if (c->extended_usage == CHAN_EXTENDED_WRITE) |
FD_CLR(c->efd, writeset); |
FD_CLR(c->efd, writeset); |
} |
} |
channel_free(c->self); |
channel_free(c); |
} |
} |
} |
} |
} |
} |
|
|
Channel *c; |
Channel *c; |
|
|
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
c = &channels[i]; |
|
|
|
|
c = channels[i]; |
|
if (c == NULL) |
|
continue; |
|
|
/* We are only interested in channels that can have buffered incoming data. */ |
/* We are only interested in channels that can have buffered incoming data. */ |
if (compat13) { |
if (compat13) { |
if (c->type != SSH_CHANNEL_OPEN && |
if (c->type != SSH_CHANNEL_OPEN && |
|
|
Channel *c; |
Channel *c; |
|
|
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
c = &channels[i]; |
c = channels[i]; |
if (c->type == SSH_CHANNEL_OPEN) { |
if (c != NULL && c->type == SSH_CHANNEL_OPEN) { |
if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) { |
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)); |
|
|
if (c->type != SSH_CHANNEL_CLOSED) |
if (c->type != SSH_CHANNEL_CLOSED) |
packet_disconnect("Received close confirmation for " |
packet_disconnect("Received close confirmation for " |
"non-closed channel %d (type %d).", id, c->type); |
"non-closed channel %d (type %d).", id, c->type); |
channel_free(c->self); |
channel_free(c); |
} |
} |
|
|
void |
void |
|
|
xfree(lang); |
xfree(lang); |
} |
} |
/* Free the channel. This will also close the socket. */ |
/* Free the channel. This will also close the socket. */ |
channel_free(id); |
channel_free(c); |
} |
} |
|
|
void |
void |
|
|
channel_stop_listening() |
channel_stop_listening() |
{ |
{ |
int i; |
int i; |
|
Channel *c; |
|
|
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
switch (channels[i].type) { |
c = channels[i]; |
case SSH_CHANNEL_AUTH_SOCKET: |
if (c != NULL) { |
close(channels[i].sock); |
switch (c->type) { |
unlink(channels[i].path); |
case SSH_CHANNEL_AUTH_SOCKET: |
channel_free(i); |
close(c->sock); |
break; |
unlink(c->path); |
case SSH_CHANNEL_PORT_LISTENER: |
channel_free(c); |
case SSH_CHANNEL_RPORT_LISTENER: |
break; |
case SSH_CHANNEL_X11_LISTENER: |
case SSH_CHANNEL_PORT_LISTENER: |
close(channels[i].sock); |
case SSH_CHANNEL_RPORT_LISTENER: |
channel_free(i); |
case SSH_CHANNEL_X11_LISTENER: |
break; |
close(c->sock); |
default: |
channel_free(c); |
break; |
break; |
|
default: |
|
break; |
|
} |
} |
} |
} |
} |
} |
} |
|
|
channel_close_all() |
channel_close_all() |
{ |
{ |
int i; |
int i; |
|
|
for (i = 0; i < channels_alloc; i++) |
for (i = 0; i < channels_alloc; i++) |
if (channels[i].type != SSH_CHANNEL_FREE) |
if (channels[i] != NULL) |
channel_close_fds(&channels[i]); |
channel_close_fds(channels[i]); |
} |
} |
|
|
/* Returns true if any channel is still open. */ |
/* Returns true if any channel is still open. */ |
|
|
int |
int |
channel_still_open() |
channel_still_open() |
{ |
{ |
u_int i; |
int i; |
for (i = 0; i < channels_alloc; i++) |
Channel *c; |
switch (channels[i].type) { |
|
case SSH_CHANNEL_FREE: |
for (i = 0; i < channels_alloc; i++) { |
|
c = channels[i]; |
|
if (c == NULL) |
|
continue; |
|
switch (c->type) { |
case SSH_CHANNEL_X11_LISTENER: |
case SSH_CHANNEL_X11_LISTENER: |
case SSH_CHANNEL_PORT_LISTENER: |
case SSH_CHANNEL_PORT_LISTENER: |
case SSH_CHANNEL_RPORT_LISTENER: |
case SSH_CHANNEL_RPORT_LISTENER: |
|
|
fatal("cannot happen: OUT_DRAIN"); |
fatal("cannot happen: OUT_DRAIN"); |
return 1; |
return 1; |
default: |
default: |
fatal("channel_still_open: bad channel type %d", channels[i].type); |
fatal("channel_still_open: bad channel type %d", c->type); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
} |
return 0; |
return 0; |
} |
} |
|
|
|
|
int |
int |
channel_find_open() |
channel_find_open() |
{ |
{ |
u_int i; |
int i; |
for (i = 0; i < channels_alloc; i++) |
Channel *c; |
switch (channels[i].type) { |
|
|
for (i = 0; i < channels_alloc; i++) { |
|
c = channels[i]; |
|
if (c == NULL) |
|
continue; |
|
switch (c->type) { |
case SSH_CHANNEL_CLOSED: |
case SSH_CHANNEL_CLOSED: |
case SSH_CHANNEL_DYNAMIC: |
case SSH_CHANNEL_DYNAMIC: |
case SSH_CHANNEL_FREE: |
|
case SSH_CHANNEL_X11_LISTENER: |
case SSH_CHANNEL_X11_LISTENER: |
case SSH_CHANNEL_PORT_LISTENER: |
case SSH_CHANNEL_PORT_LISTENER: |
case SSH_CHANNEL_RPORT_LISTENER: |
case SSH_CHANNEL_RPORT_LISTENER: |
|
|
fatal("cannot happen: OUT_DRAIN"); |
fatal("cannot happen: OUT_DRAIN"); |
return i; |
return i; |
default: |
default: |
fatal("channel_find_open: bad channel type %d", channels[i].type); |
fatal("channel_find_open: bad channel type %d", c->type); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
} |
return -1; |
return -1; |
} |
} |
|
|
|
|
channel_open_message() |
channel_open_message() |
{ |
{ |
Buffer buffer; |
Buffer buffer; |
|
Channel *c; |
|
char buf[1024], *cp; |
int i; |
int i; |
char buf[512], *cp; |
|
|
|
buffer_init(&buffer); |
buffer_init(&buffer); |
snprintf(buf, sizeof buf, "The following connections are open:\r\n"); |
snprintf(buf, sizeof buf, "The following connections are open:\r\n"); |
buffer_append(&buffer, buf, strlen(buf)); |
buffer_append(&buffer, buf, strlen(buf)); |
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
Channel *c = &channels[i]; |
c = channels[i]; |
|
if (c == NULL) |
|
continue; |
switch (c->type) { |
switch (c->type) { |
case SSH_CHANNEL_FREE: |
|
case SSH_CHANNEL_X11_LISTENER: |
case SSH_CHANNEL_X11_LISTENER: |
case SSH_CHANNEL_PORT_LISTENER: |
case SSH_CHANNEL_PORT_LISTENER: |
case SSH_CHANNEL_RPORT_LISTENER: |
case SSH_CHANNEL_RPORT_LISTENER: |
|
|
const char *host_to_connect, u_short port_to_connect, |
const char *host_to_connect, u_short port_to_connect, |
int gateway_ports, int remote_fwd) |
int gateway_ports, int remote_fwd) |
{ |
{ |
int success, ch, sock, on = 1, ctype; |
Channel *c; |
|
int success, sock, on = 1, ctype; |
struct addrinfo hints, *ai, *aitop; |
struct addrinfo hints, *ai, *aitop; |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
const char *host; |
const char *host; |
|
|
ctype =SSH_CHANNEL_PORT_LISTENER; |
ctype =SSH_CHANNEL_PORT_LISTENER; |
} |
} |
|
|
if (strlen(host) > sizeof(channels[0].path) - 1) { |
if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) { |
error("Forward host name too long."); |
error("Forward host name too long."); |
return success; |
return success; |
} |
} |
|
|
continue; |
continue; |
} |
} |
/* Allocate a channel number for the socket. */ |
/* Allocate a channel number for the socket. */ |
ch = channel_new("port listener", ctype, sock, sock, -1, |
c = channel_new("port listener", ctype, sock, sock, -1, |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
0, xstrdup("port listener"), 1); |
0, xstrdup("port listener"), 1); |
strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); |
if (c == NULL) { |
channels[ch].host_port = port_to_connect; |
error("channel_request_forwarding: channel_new failed"); |
channels[ch].listening_port = listen_port; |
close(sock); |
|
continue; |
|
} |
|
strlcpy(c->path, host, sizeof(c->path)); |
|
c->host_port = port_to_connect; |
|
c->listening_port = listen_port; |
success = 1; |
success = 1; |
} |
} |
if (success == 0) |
if (success == 0) |
|
|
void |
void |
channel_input_port_open(int type, int plen, void *ctxt) |
channel_input_port_open(int type, int plen, void *ctxt) |
{ |
{ |
|
Channel *c = NULL; |
u_short host_port; |
u_short host_port; |
char *host, *originator_string; |
char *host, *originator_string; |
int remote_channel, sock = -1, newch; |
int remote_id, sock = -1; |
|
|
remote_channel = packet_get_int(); |
remote_id = packet_get_int(); |
host = packet_get_string(NULL); |
host = packet_get_string(NULL); |
host_port = packet_get_int(); |
host_port = packet_get_int(); |
|
|
|
|
packet_done(); |
packet_done(); |
sock = channel_connect_to(host, host_port); |
sock = channel_connect_to(host, host_port); |
if (sock != -1) { |
if (sock != -1) { |
newch = channel_allocate(SSH_CHANNEL_CONNECTING, |
c = channel_new("connected socket", |
sock, originator_string); |
SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0, |
channels[newch].remote_id = remote_channel; |
originator_string, 1); |
|
if (c == NULL) { |
|
error("channel_input_port_open: channel_new failed"); |
|
close(sock); |
|
} else { |
|
c->remote_id = remote_id; |
|
} |
|
} |
|
if (c == NULL) { |
|
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
|
packet_put_int(remote_id); |
|
} else { |
/*XXX delay answer? */ |
/*XXX delay answer? */ |
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
packet_put_int(remote_channel); |
packet_put_int(remote_id); |
packet_put_int(newch); |
packet_put_int(c->self); |
packet_send(); |
|
} else { |
|
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
|
packet_put_int(remote_channel); |
|
packet_send(); |
|
} |
} |
|
packet_send(); |
xfree(host); |
xfree(host); |
} |
} |
|
|
|
|
void |
void |
x11_input_open(int type, int plen, void *ctxt) |
x11_input_open(int type, int plen, void *ctxt) |
{ |
{ |
int remote_channel, sock = 0, newch; |
Channel *c = NULL; |
|
int remote_id, sock = 0; |
char *remote_host; |
char *remote_host; |
u_int remote_len; |
|
|
|
/* Get remote channel number. */ |
debug("Received X11 open request."); |
remote_channel = packet_get_int(); |
|
|
|
/* Get remote originator name. */ |
remote_id = packet_get_int(); |
if (have_hostname_in_open) { |
if (have_hostname_in_open) { |
remote_host = packet_get_string(&remote_len); |
remote_host = packet_get_string(NULL); |
remote_len += 4; |
|
} else { |
} else { |
remote_host = xstrdup("unknown (remote did not supply name)"); |
remote_host = xstrdup("unknown (remote did not supply name)"); |
remote_len = 0; |
|
} |
} |
|
packet_done(); |
|
|
debug("Received X11 open request."); |
|
packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN); |
|
|
|
/* Obtain a connection to the real X display. */ |
/* Obtain a connection to the real X display. */ |
sock = x11_connect_display(); |
sock = x11_connect_display(); |
if (sock == -1) { |
if (sock != -1) { |
|
/* Allocate a channel for this connection. */ |
|
c = channel_new("connected x11 socket", |
|
SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0, |
|
remote_host, 1); |
|
if (c == NULL) { |
|
error("x11_input_open: channel_new failed"); |
|
close(sock); |
|
} else { |
|
c->remote_id = remote_id; |
|
} |
|
} |
|
if (c == NULL) { |
/* Send refusal to the remote host. */ |
/* Send refusal to the remote host. */ |
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
packet_put_int(remote_channel); |
packet_put_int(remote_id); |
packet_send(); |
|
} else { |
} else { |
/* Allocate a channel for this connection. */ |
|
newch = channel_allocate( |
|
(x11_saved_proto == NULL) ? |
|
SSH_CHANNEL_OPEN : SSH_CHANNEL_X11_OPEN, |
|
sock, remote_host); |
|
channels[newch].remote_id = remote_channel; |
|
|
|
/* Send a confirmation to the remote host. */ |
/* Send a confirmation to the remote host. */ |
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
packet_put_int(remote_channel); |
packet_put_int(remote_id); |
packet_put_int(newch); |
packet_put_int(c->self); |
packet_send(); |
|
} |
} |
|
packet_send(); |
} |
} |
|
|
/* dummy protocol handler that denies SSH-1 requests (agent/x11) */ |
/* dummy protocol handler that denies SSH-1 requests (agent/x11) */ |
|
|
int |
int |
auth_input_request_forwarding(struct passwd * pw) |
auth_input_request_forwarding(struct passwd * pw) |
{ |
{ |
int sock, newch; |
Channel *nc; |
|
int sock; |
struct sockaddr_un sunaddr; |
struct sockaddr_un sunaddr; |
|
|
if (auth_get_socket_name() != NULL) |
if (auth_get_socket_name() != NULL) |
|
|
packet_disconnect("listen: %.100s", strerror(errno)); |
packet_disconnect("listen: %.100s", strerror(errno)); |
|
|
/* Allocate a channel for the authentication agent socket. */ |
/* Allocate a channel for the authentication agent socket. */ |
newch = channel_new("auth socket", |
nc = channel_new("auth socket", |
SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, |
SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, |
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, |
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, |
0, xstrdup("auth socket"), 1); |
0, xstrdup("auth socket"), 1); |
|
if (nc == NULL) { |
strlcpy(channels[newch].path, channel_forwarded_auth_socket_name, |
error("auth_input_request_forwarding: channel_new failed"); |
sizeof(channels[newch].path)); |
close(sock); |
|
return 0; |
|
} |
|
strlcpy(nc->path, channel_forwarded_auth_socket_name, sizeof(nc->path)); |
return 1; |
return 1; |
} |
} |
|
|
|
|
void |
void |
auth_input_open_request(int type, int plen, void *ctxt) |
auth_input_open_request(int type, int plen, void *ctxt) |
{ |
{ |
int remch, sock, newch; |
Channel *c = NULL; |
|
int remote_id, sock; |
char *dummyname; |
char *dummyname; |
|
|
packet_integrity_check(plen, 4, type); |
packet_integrity_check(plen, 4, type); |
|
|
/* Read the remote channel number from the message. */ |
/* Read the remote channel number from the message. */ |
remch = packet_get_int(); |
remote_id = packet_get_int(); |
|
|
/* |
/* |
* Get a connection to the local authentication agent (this may again |
* Get a connection to the local authentication agent (this may again |
|
|
* because authentication forwarding is only enabled if we have an |
* because authentication forwarding is only enabled if we have an |
* agent. |
* agent. |
*/ |
*/ |
if (sock < 0) { |
if (sock >= 0) { |
|
dummyname = xstrdup("authentication agent connection"); |
|
c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, -1, 0, 0, 0, dummyname, 1); |
|
if (c == NULL) { |
|
error("auth_input_open_request: channel_new failed"); |
|
close(sock); |
|
} else { |
|
c->remote_id = remote_id; |
|
} |
|
} |
|
if (c == NULL) { |
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
packet_put_int(remch); |
packet_put_int(remote_id); |
packet_send(); |
} else { |
return; |
/* Send a confirmation to the remote host. */ |
|
debug("Forwarding authentication connection."); |
|
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
|
packet_put_int(remote_id); |
|
packet_put_int(c->self); |
} |
} |
debug("Forwarding authentication connection."); |
|
|
|
/* |
|
* Dummy host name. This will be freed when the channel is freed; it |
|
* will still be valid in the packet_put_string below since the |
|
* channel cannot yet be freed at that point. |
|
*/ |
|
dummyname = xstrdup("authentication agent connection"); |
|
|
|
newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname); |
|
channels[newch].remote_id = remch; |
|
|
|
/* Send a confirmation to the remote host. */ |
|
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
|
packet_put_int(remch); |
|
packet_put_int(newch); |
|
packet_send(); |
packet_send(); |
} |
} |
|
|