version 1.195, 2003/09/16 21:02:40 |
version 1.195.2.2, 2004/08/19 22:37:30 |
|
|
* 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 set to NULL |
* initialized (at least the type field); unused slots set to NULL |
*/ |
*/ |
static int channels_alloc = 0; |
static u_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 |
|
|
{ |
{ |
Channel *c; |
Channel *c; |
|
|
if (id < 0 || id >= channels_alloc) { |
if (id < 0 || (u_int)id >= channels_alloc) { |
logit("channel_lookup: %d: bad id", id); |
logit("channel_lookup: %d: bad id", id); |
return NULL; |
return NULL; |
} |
} |
|
|
c->rfd = rfd; |
c->rfd = rfd; |
c->wfd = wfd; |
c->wfd = wfd; |
c->sock = (rfd == wfd) ? rfd : -1; |
c->sock = (rfd == wfd) ? rfd : -1; |
|
c->ctl_fd = -1; /* XXX: set elsewhere */ |
c->efd = efd; |
c->efd = efd; |
c->extended_usage = extusage; |
c->extended_usage = extusage; |
|
|
|
|
channel_new(char *ctype, int type, int rfd, int wfd, int efd, |
channel_new(char *ctype, int type, int rfd, int wfd, int efd, |
u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) |
u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) |
{ |
{ |
int i, found; |
int found; |
|
u_int i; |
Channel *c; |
Channel *c; |
|
|
/* Do initial allocation if this is the first call. */ |
/* Do initial allocation if this is the first call. */ |
|
|
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] = NULL; |
channels[i] = NULL; |
fatal_add_cleanup((void (*) (void *)) channel_free_all, NULL); |
|
} |
} |
/* 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] == NULL) { |
if (channels[i] == NULL) { |
/* Found a free slot. */ |
/* Found a free slot. */ |
found = i; |
found = (int)i; |
break; |
break; |
} |
} |
if (found == -1) { |
if (found < 0) { |
/* There are no free slots. Take last+1 slot and expand the array. */ |
/* There are no free slots. Take last+1 slot and expand the array. */ |
found = channels_alloc; |
found = channels_alloc; |
if (channels_alloc > 10000) |
if (channels_alloc > 10000) |
|
|
c->single_connection = 0; |
c->single_connection = 0; |
c->detach_user = NULL; |
c->detach_user = NULL; |
c->confirm = NULL; |
c->confirm = NULL; |
|
c->confirm_ctx = 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 c; |
return c; |
|
|
static int |
static int |
channel_find_maxfd(void) |
channel_find_maxfd(void) |
{ |
{ |
int i, max = 0; |
u_int i; |
|
int max = 0; |
Channel *c; |
Channel *c; |
|
|
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
|
|
static void |
static void |
channel_close_fds(Channel *c) |
channel_close_fds(Channel *c) |
{ |
{ |
debug3("channel %d: close_fds r %d w %d e %d", |
debug3("channel %d: close_fds r %d w %d e %d c %d", |
c->self, c->rfd, c->wfd, c->efd); |
c->self, c->rfd, c->wfd, c->efd, c->ctl_fd); |
|
|
channel_close_fd(&c->sock); |
channel_close_fd(&c->sock); |
|
channel_close_fd(&c->ctl_fd); |
channel_close_fd(&c->rfd); |
channel_close_fd(&c->rfd); |
channel_close_fd(&c->wfd); |
channel_close_fd(&c->wfd); |
channel_close_fd(&c->efd); |
channel_close_fd(&c->efd); |
|
|
channel_free(Channel *c) |
channel_free(Channel *c) |
{ |
{ |
char *s; |
char *s; |
int i, n; |
u_int i, n; |
|
|
for (n = 0, i = 0; i < channels_alloc; i++) |
for (n = 0, i = 0; i < channels_alloc; i++) |
if (channels[i]) |
if (channels[i]) |
n++; |
n++; |
debug("channel %d: free: %s, nchannels %d", c->self, |
debug("channel %d: free: %s, nchannels %u", c->self, |
c->remote_name ? c->remote_name : "???", n); |
c->remote_name ? c->remote_name : "???", n); |
|
|
s = channel_open_message(); |
s = channel_open_message(); |
|
|
|
|
if (c->sock != -1) |
if (c->sock != -1) |
shutdown(c->sock, SHUT_RDWR); |
shutdown(c->sock, SHUT_RDWR); |
|
if (c->ctl_fd != -1) |
|
shutdown(c->ctl_fd, SHUT_RDWR); |
channel_close_fds(c); |
channel_close_fds(c); |
buffer_free(&c->input); |
buffer_free(&c->input); |
buffer_free(&c->output); |
buffer_free(&c->output); |
|
|
void |
void |
channel_free_all(void) |
channel_free_all(void) |
{ |
{ |
int i; |
u_int i; |
|
|
for (i = 0; i < channels_alloc; i++) |
for (i = 0; i < channels_alloc; i++) |
if (channels[i] != NULL) |
if (channels[i] != NULL) |
|
|
void |
void |
channel_close_all(void) |
channel_close_all(void) |
{ |
{ |
int i; |
u_int i; |
|
|
for (i = 0; i < channels_alloc; i++) |
for (i = 0; i < channels_alloc; i++) |
if (channels[i] != NULL) |
if (channels[i] != NULL) |
|
|
void |
void |
channel_stop_listening(void) |
channel_stop_listening(void) |
{ |
{ |
int i; |
u_int i; |
Channel *c; |
Channel *c; |
|
|
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
|
|
int |
int |
channel_still_open(void) |
channel_still_open(void) |
{ |
{ |
int i; |
u_int i; |
Channel *c; |
Channel *c; |
|
|
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
|
|
int |
int |
channel_find_open(void) |
channel_find_open(void) |
{ |
{ |
int i; |
u_int i; |
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) |
if (c == NULL || c->remote_id < 0) |
continue; |
continue; |
switch (c->type) { |
switch (c->type) { |
case SSH_CHANNEL_CLOSED: |
case SSH_CHANNEL_CLOSED: |
|
|
Buffer buffer; |
Buffer buffer; |
Channel *c; |
Channel *c; |
char buf[1024], *cp; |
char buf[1024], *cp; |
int i; |
u_int i; |
|
|
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"); |
|
|
case SSH_CHANNEL_X11_OPEN: |
case SSH_CHANNEL_X11_OPEN: |
case SSH_CHANNEL_INPUT_DRAINING: |
case SSH_CHANNEL_INPUT_DRAINING: |
case SSH_CHANNEL_OUTPUT_DRAINING: |
case SSH_CHANNEL_OUTPUT_DRAINING: |
snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n", |
snprintf(buf, sizeof buf, |
|
" #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cfd %d)\r\n", |
c->self, c->remote_name, |
c->self, c->remote_name, |
c->type, c->remote_id, |
c->type, c->remote_id, |
c->istate, buffer_len(&c->input), |
c->istate, buffer_len(&c->input), |
c->ostate, buffer_len(&c->output), |
c->ostate, buffer_len(&c->output), |
c->rfd, c->wfd); |
c->rfd, c->wfd, c->ctl_fd); |
buffer_append(&buffer, buf, strlen(buf)); |
buffer_append(&buffer, buf, strlen(buf)); |
continue; |
continue; |
default: |
default: |
|
|
logit("channel_request_start: %d: unknown channel id", id); |
logit("channel_request_start: %d: unknown channel id", id); |
return; |
return; |
} |
} |
debug2("channel %d: request %s", id, service) ; |
debug2("channel %d: request %s confirm %d", id, service, wantconfirm); |
packet_start(SSH2_MSG_CHANNEL_REQUEST); |
packet_start(SSH2_MSG_CHANNEL_REQUEST); |
packet_put_int(c->remote_id); |
packet_put_int(c->remote_id); |
packet_put_cstring(service); |
packet_put_cstring(service); |
packet_put_char(wantconfirm); |
packet_put_char(wantconfirm); |
} |
} |
void |
void |
channel_register_confirm(int id, channel_callback_fn *fn) |
channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) |
{ |
{ |
Channel *c = channel_lookup(id); |
Channel *c = channel_lookup(id); |
|
|
|
|
return; |
return; |
} |
} |
c->confirm = fn; |
c->confirm = fn; |
|
c->confirm_ctx = ctx; |
} |
} |
void |
void |
channel_register_cleanup(int id, channel_callback_fn *fn) |
channel_register_cleanup(int id, channel_callback_fn *fn) |
|
|
buffer_len(&c->extended) < c->remote_window) |
buffer_len(&c->extended) < c->remote_window) |
FD_SET(c->efd, readset); |
FD_SET(c->efd, readset); |
} |
} |
|
/* XXX: What about efd? races? */ |
|
if (compat20 && c->ctl_fd != -1 && |
|
c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN) |
|
FD_SET(c->ctl_fd, readset); |
} |
} |
|
|
static void |
static void |
|
|
have = buffer_len(&c->input); |
have = buffer_len(&c->input); |
if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { |
if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { |
/* format: ver | nmethods | methods */ |
/* format: ver | nmethods | methods */ |
if (have < 2) |
if (have < 2) |
return 0; |
return 0; |
nmethods = p[1]; |
nmethods = p[1]; |
if (have < nmethods + 2) |
if (have < nmethods + 2) |
|
|
buffer_get(&c->input, (char *)&dest_port, 2); |
buffer_get(&c->input, (char *)&dest_port, 2); |
dest_addr[addrlen] = '\0'; |
dest_addr[addrlen] = '\0'; |
if (s5_req.atyp == SSH_SOCKS5_DOMAIN) |
if (s5_req.atyp == SSH_SOCKS5_DOMAIN) |
strlcpy(c->path, dest_addr, sizeof(c->path)); |
strlcpy(c->path, (char *)dest_addr, sizeof(c->path)); |
else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL) |
else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL) |
return -1; |
return -1; |
c->host_port = ntohs(dest_port); |
c->host_port = ntohs(dest_port); |
|
|
debug2("channel %d: dynamic request: socks5 host %s port %u command %u", |
debug2("channel %d: dynamic request: socks5 host %s port %u command %u", |
c->self, c->path, c->host_port, s5_req.command); |
c->self, c->path, c->host_port, s5_req.command); |
|
|
|
|
return 1; |
return 1; |
} |
} |
static int |
static int |
|
channel_handle_ctl(Channel *c, fd_set * readset, fd_set * writeset) |
|
{ |
|
char buf[16]; |
|
int len; |
|
|
|
/* Monitor control fd to detect if the slave client exits */ |
|
if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) { |
|
len = read(c->ctl_fd, buf, sizeof(buf)); |
|
if (len < 0 && (errno == EINTR || errno == EAGAIN)) |
|
return 1; |
|
if (len <= 0) { |
|
debug2("channel %d: ctl read<=0", c->self); |
|
if (c->type != SSH_CHANNEL_OPEN) { |
|
debug2("channel %d: not open", c->self); |
|
chan_mark_dead(c); |
|
return -1; |
|
} else { |
|
chan_read_failed(c); |
|
chan_write_failed(c); |
|
} |
|
return -1; |
|
} else |
|
fatal("%s: unexpected data on ctl fd", __func__); |
|
} |
|
return 1; |
|
} |
|
static int |
channel_check_window(Channel *c) |
channel_check_window(Channel *c) |
{ |
{ |
if (c->type == SSH_CHANNEL_OPEN && |
if (c->type == SSH_CHANNEL_OPEN && |
|
|
if (!compat20) |
if (!compat20) |
return; |
return; |
channel_handle_efd(c, readset, writeset); |
channel_handle_efd(c, readset, writeset); |
|
channel_handle_ctl(c, readset, writeset); |
channel_check_window(c); |
channel_check_window(c); |
} |
} |
|
|
|
|
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; |
int i; |
u_int i; |
Channel *c; |
Channel *c; |
|
|
if (!did_init) { |
if (!did_init) { |
|
|
*/ |
*/ |
void |
void |
channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, |
channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, |
int *nallocp, int rekeying) |
u_int *nallocp, int rekeying) |
{ |
{ |
int n; |
u_int n, sz; |
u_int sz; |
|
|
|
n = MAX(*maxfdp, channel_max_fd); |
n = MAX(*maxfdp, channel_max_fd); |
|
|
|
|
channel_output_poll(void) |
channel_output_poll(void) |
{ |
{ |
Channel *c; |
Channel *c; |
int i; |
u_int i, len; |
u_int len; |
|
|
|
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
c = channels[i]; |
c = channels[i]; |
|
|
c->type != SSH_CHANNEL_X11_OPEN) |
c->type != SSH_CHANNEL_X11_OPEN) |
return; |
return; |
|
|
/* same for protocol 1.5 if output end is no longer open */ |
|
if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) |
|
return; |
|
|
|
/* Get the data. */ |
/* Get the data. */ |
data = packet_get_string(&data_len); |
data = packet_get_string(&data_len); |
|
|
|
/* |
|
* Ignore data for protocol > 1.3 if output end is no longer open. |
|
* For protocol 2 the sending side is reducing its window as it sends |
|
* data, so we must 'fake' consumption of the data in order to ensure |
|
* that window updates are sent back. Otherwise the connection might |
|
* deadlock. |
|
*/ |
|
if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) { |
|
if (compat20) { |
|
c->local_window -= data_len; |
|
c->local_consumed += data_len; |
|
} |
|
xfree(data); |
|
return; |
|
} |
|
|
if (compat20) { |
if (compat20) { |
if (data_len > c->local_maxpacket) { |
if (data_len > c->local_maxpacket) { |
logit("channel %d: rcvd big packet %d, maxpack %d", |
logit("channel %d: rcvd big packet %d, maxpack %d", |
|
|
c->remote_maxpacket = packet_get_int(); |
c->remote_maxpacket = packet_get_int(); |
if (c->confirm) { |
if (c->confirm) { |
debug2("callback start"); |
debug2("callback start"); |
c->confirm(c->self, NULL); |
c->confirm(c->self, c->confirm_ctx); |
debug2("callback done"); |
debug2("callback done"); |
} |
} |
debug2("channel %d: open confirm rwindow %u rmax %u", c->self, |
debug2("channel %d: open confirm rwindow %u rmax %u", c->self, |
|
|
continue; |
continue; |
} |
} |
/* Start listening for connections on the socket. */ |
/* Start listening for connections on the socket. */ |
if (listen(sock, 5) < 0) { |
if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { |
error("listen: %.100s", strerror(errno)); |
error("listen: %.100s", strerror(errno)); |
close(sock); |
close(sock); |
continue; |
continue; |
|
|
return success; |
return success; |
} |
} |
|
|
|
int |
|
channel_cancel_rport_listener(const char *host, u_short port) |
|
{ |
|
u_int i; |
|
int found = 0; |
|
|
|
for(i = 0; i < channels_alloc; i++) { |
|
Channel *c = channels[i]; |
|
|
|
if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && |
|
strncmp(c->path, host, sizeof(c->path)) == 0 && |
|
c->listening_port == port) { |
|
debug2("%s: close clannel %d", __func__, i); |
|
channel_free(c); |
|
found = 1; |
|
} |
|
} |
|
|
|
return (found); |
|
} |
|
|
/* protocol local port fwd, used by ssh (and sshd in v1) */ |
/* protocol local port fwd, used by ssh (and sshd in v1) */ |
int |
int |
channel_setup_local_fwd_listener(u_short listen_port, |
channel_setup_local_fwd_listener(u_short listen_port, |
|
|
} |
} |
|
|
/* |
/* |
|
* Request cancellation of remote forwarding of connection host:port from |
|
* local side. |
|
*/ |
|
void |
|
channel_request_rforward_cancel(u_short port) |
|
{ |
|
int i; |
|
const char *address_to_bind = "0.0.0.0"; |
|
|
|
if (!compat20) |
|
return; |
|
|
|
for (i = 0; i < num_permitted_opens; i++) { |
|
if (permitted_opens[i].host_to_connect != NULL && |
|
permitted_opens[i].listen_port == port) |
|
break; |
|
} |
|
if (i >= num_permitted_opens) { |
|
debug("%s: requested forward not found", __func__); |
|
return; |
|
} |
|
packet_start(SSH2_MSG_GLOBAL_REQUEST); |
|
packet_put_cstring("cancel-tcpip-forward"); |
|
packet_put_char(0); |
|
packet_put_cstring(address_to_bind); |
|
packet_put_int(port); |
|
packet_send(); |
|
|
|
permitted_opens[i].listen_port = 0; |
|
permitted_opens[i].port_to_connect = 0; |
|
free(permitted_opens[i].host_to_connect); |
|
permitted_opens[i].host_to_connect = NULL; |
|
} |
|
|
|
/* |
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates |
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates |
* listening for the port, and sends back a success reply (or disconnect |
* listening for the port, and sends back a success reply (or disconnect |
* message if there was an error). This never returns if there was an error. |
* message if there was an error). This never returns if there was an error. |
|
|
int i; |
int i; |
|
|
for (i = 0; i < num_permitted_opens; i++) |
for (i = 0; i < num_permitted_opens; i++) |
xfree(permitted_opens[i].host_to_connect); |
if (permitted_opens[i].host_to_connect != NULL) |
|
xfree(permitted_opens[i].host_to_connect); |
num_permitted_opens = 0; |
num_permitted_opens = 0; |
|
|
} |
} |
|
|
verbose("socket: %.100s", strerror(errno)); |
verbose("socket: %.100s", strerror(errno)); |
continue; |
continue; |
} |
} |
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) |
if (set_nonblock(sock) == -1) |
fatal("connect_to: F_SETFL: %s", strerror(errno)); |
fatal("%s: set_nonblock(%d)", __func__, sock); |
if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && |
if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && |
errno != EINPROGRESS) { |
errno != EINPROGRESS) { |
error("connect_to %.100s port %s: %.100s", ntop, strport, |
error("connect_to %.100s port %s: %.100s", ntop, strport, |
|
|
int i; |
int i; |
|
|
for (i = 0; i < num_permitted_opens; i++) |
for (i = 0; i < num_permitted_opens; i++) |
if (permitted_opens[i].listen_port == listen_port) |
if (permitted_opens[i].host_to_connect != NULL && |
|
permitted_opens[i].listen_port == listen_port) |
return connect_to( |
return connect_to( |
permitted_opens[i].host_to_connect, |
permitted_opens[i].host_to_connect, |
permitted_opens[i].port_to_connect); |
permitted_opens[i].port_to_connect); |
|
|
permit = all_opens_permitted; |
permit = all_opens_permitted; |
if (!permit) { |
if (!permit) { |
for (i = 0; i < num_permitted_opens; i++) |
for (i = 0; i < num_permitted_opens; i++) |
if (permitted_opens[i].port_to_connect == port && |
if (permitted_opens[i].host_to_connect != NULL && |
|
permitted_opens[i].port_to_connect == port && |
strcmp(permitted_opens[i].host_to_connect, host) == 0) |
strcmp(permitted_opens[i].host_to_connect, host) == 0) |
permit = 1; |
permit = 1; |
|
|
|
|
return connect_to(host, port); |
return connect_to(host, port); |
} |
} |
|
|
|
void |
|
channel_send_window_changes(void) |
|
{ |
|
u_int i; |
|
struct winsize ws; |
|
|
|
for (i = 0; i < channels_alloc; i++) { |
|
if (channels[i] == NULL || |
|
channels[i]->type != SSH_CHANNEL_OPEN) |
|
continue; |
|
if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0) |
|
continue; |
|
channel_request_start(i, "window-change", 0); |
|
packet_put_int(ws.ws_col); |
|
packet_put_int(ws.ws_row); |
|
packet_put_int(ws.ws_xpixel); |
|
packet_put_int(ws.ws_ypixel); |
|
packet_send(); |
|
} |
|
} |
|
|
/* -- X11 forwarding */ |
/* -- X11 forwarding */ |
|
|
/* |
/* |
|
|
ai->ai_protocol); |
ai->ai_protocol); |
if (sock < 0) { |
if (sock < 0) { |
error("socket: %.100s", strerror(errno)); |
error("socket: %.100s", strerror(errno)); |
|
freeaddrinfo(aitop); |
return -1; |
return -1; |
} |
} |
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
|
|
/* Start listening for connections on the socket. */ |
/* Start listening for connections on the socket. */ |
for (n = 0; n < num_socks; n++) { |
for (n = 0; n < num_socks; n++) { |
sock = socks[n]; |
sock = socks[n]; |
if (listen(sock, 5) < 0) { |
if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { |
error("listen: %.100s", strerror(errno)); |
error("listen: %.100s", strerror(errno)); |
close(sock); |
close(sock); |
return -1; |
return -1; |
|
|
char *new_data; |
char *new_data; |
int screen_number; |
int screen_number; |
const char *cp; |
const char *cp; |
u_int32_t rand = 0; |
u_int32_t rnd = 0; |
|
|
cp = getenv("DISPLAY"); |
cp = getenv("DISPLAY"); |
if (cp) |
if (cp) |
|
|
if (sscanf(data + 2 * i, "%2x", &value) != 1) |
if (sscanf(data + 2 * i, "%2x", &value) != 1) |
fatal("x11_request_forwarding: bad authentication data: %.100s", data); |
fatal("x11_request_forwarding: bad authentication data: %.100s", data); |
if (i % 4 == 0) |
if (i % 4 == 0) |
rand = arc4random(); |
rnd = arc4random(); |
x11_saved_data[i] = value; |
x11_saved_data[i] = value; |
x11_fake_data[i] = rand & 0xff; |
x11_fake_data[i] = rnd & 0xff; |
rand >>= 8; |
rnd >>= 8; |
} |
} |
x11_saved_data_len = data_len; |
x11_saved_data_len = data_len; |
x11_fake_data_len = data_len; |
x11_fake_data_len = data_len; |
|
|
packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); |
packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); |
packet_send(); |
packet_send(); |
packet_write_wait(); |
packet_write_wait(); |
} |
|
|
|
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */ |
|
|
|
void |
|
auth_input_open_request(int type, u_int32_t seq, void *ctxt) |
|
{ |
|
Channel *c = NULL; |
|
int remote_id, sock; |
|
|
|
/* Read the remote channel number from the message. */ |
|
remote_id = packet_get_int(); |
|
packet_check_eom(); |
|
|
|
/* |
|
* Get a connection to the local authentication agent (this may again |
|
* get forwarded). |
|
*/ |
|
sock = ssh_get_authentication_socket(); |
|
|
|
/* |
|
* If we could not connect the agent, send an error message back to |
|
* the server. This should never happen unless the agent dies, |
|
* because authentication forwarding is only enabled if we have an |
|
* agent. |
|
*/ |
|
if (sock >= 0) { |
|
c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, |
|
-1, 0, 0, 0, "authentication agent connection", 1); |
|
c->remote_id = remote_id; |
|
c->force_drain = 1; |
|
} |
|
if (c == NULL) { |
|
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
|
packet_put_int(remote_id); |
|
} else { |
|
/* 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); |
|
} |
|
packet_send(); |
|
} |
} |