version 1.50, 2000/04/16 16:40:43 |
version 1.51, 2000/04/28 08:10:20 |
|
|
/* Max len of agent socket */ |
/* Max len of agent socket */ |
#define MAX_SOCKET_NAME 100 |
#define MAX_SOCKET_NAME 100 |
|
|
/* default buffer for tcp-fwd-channel */ |
/* default window/packet sizes for tcp/x11-fwd-channel */ |
#define CHAN_WINDOW_DEFAULT (8*1024) |
#define CHAN_TCP_WINDOW_DEFAULT (8*1024) |
#define CHAN_PACKET_DEFAULT (CHAN_WINDOW_DEFAULT/2) |
#define CHAN_TCP_PACKET_DEFAULT (CHAN_TCP_WINDOW_DEFAULT/2) |
|
#define CHAN_X11_WINDOW_DEFAULT (4*1024) |
|
#define CHAN_X11_PACKET_DEFAULT (CHAN_X11_WINDOW_DEFAULT/2) |
|
|
/* |
/* |
* Pointer to an array containing all allocated channels. The array is |
* Pointer to an array containing all allocated channels. The array is |
|
|
c->self = found; |
c->self = found; |
c->type = type; |
c->type = type; |
c->ctype = ctype; |
c->ctype = ctype; |
c->local_window = window; |
|
c->local_window_max = window; |
|
c->local_consumed = 0; |
|
c->local_maxpacket = maxpack; |
|
c->remote_window = 0; |
|
c->remote_maxpacket = 0; |
|
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->efd = efd; |
c->efd = efd; |
c->extended_usage = extended_usage; |
c->extended_usage = extended_usage; |
|
c->local_window = window; |
|
c->local_window_max = window; |
|
c->local_consumed = 0; |
|
c->local_maxpacket = maxpack; |
c->remote_id = -1; |
c->remote_id = -1; |
c->remote_name = remote_name; |
c->remote_name = remote_name; |
c->remote_window = 0; |
c->remote_window = 0; |
|
|
* state until the first packet has been completely read. The authentication |
* state until the first packet has been completely read. The authentication |
* data in that packet is then substituted by the real data if it matches the |
* data in that packet is then substituted by the real data if it matches the |
* fake data, and the channel is put into normal mode. |
* fake data, and the channel is put into normal mode. |
|
* XXX All this happens at the client side. |
*/ |
*/ |
int |
int |
x11_open_helper(Channel *c) |
x11_open_helper(Channel *c) |
|
|
} |
} |
|
|
void |
void |
channel_pre_x11_open_15(Channel *c, fd_set * readset, fd_set * writeset) |
channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) |
{ |
{ |
int ret = x11_open_helper(c); |
int ret = x11_open_helper(c); |
if (ret == 1) { |
if (ret == 1) { |
|
|
channel_pre_open_15(c, readset, writeset); |
channel_pre_open_15(c, readset, writeset); |
} else if (ret == -1) { |
} else if (ret == -1) { |
debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); |
debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); |
chan_read_failed(c); |
chan_read_failed(c); /** force close? */ |
chan_write_failed(c); |
chan_write_failed(c); |
debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); |
debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); |
} |
} |
|
|
int newsock, newch; |
int newsock, newch; |
socklen_t addrlen; |
socklen_t addrlen; |
char buf[16384], *remote_hostname; |
char buf[16384], *remote_hostname; |
|
int remote_port; |
|
|
if (FD_ISSET(c->sock, readset)) { |
if (FD_ISSET(c->sock, readset)) { |
debug("X11 connection requested."); |
debug("X11 connection requested."); |
|
|
return; |
return; |
} |
} |
remote_hostname = get_remote_hostname(newsock); |
remote_hostname = get_remote_hostname(newsock); |
|
remote_port = get_peer_port(newsock); |
snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", |
snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", |
remote_hostname, get_peer_port(newsock)); |
remote_hostname, remote_port); |
|
|
|
newch = channel_new("x11", |
|
SSH_CHANNEL_OPENING, newsock, newsock, -1, |
|
c->local_window_max, c->local_maxpacket, |
|
0, xstrdup(buf)); |
|
if (compat20) { |
|
packet_start(SSH2_MSG_CHANNEL_OPEN); |
|
packet_put_cstring("x11"); |
|
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); |
|
packet_put_int(remote_port); |
|
packet_send(); |
|
} else { |
|
packet_start(SSH_SMSG_X11_OPEN); |
|
packet_put_int(newch); |
|
if (have_hostname_in_open) |
|
packet_put_string(buf, strlen(buf)); |
|
packet_send(); |
|
} |
xfree(remote_hostname); |
xfree(remote_hostname); |
newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, |
|
xstrdup(buf)); |
|
packet_start(SSH_SMSG_X11_OPEN); |
|
packet_put_int(newch); |
|
if (have_hostname_in_open) |
|
packet_put_string(buf, strlen(buf)); |
|
packet_send(); |
|
} |
} |
} |
} |
|
|
|
|
FD_ISSET(c->rfd, readset)) { |
FD_ISSET(c->rfd, readset)) { |
len = read(c->rfd, buf, sizeof(buf)); |
len = read(c->rfd, buf, sizeof(buf)); |
if (len <= 0) { |
if (len <= 0) { |
debug("channel %d: read<0 rfd %d len %d", |
debug("channel %d: read<=0 rfd %d len %d", |
c->self, c->rfd, len); |
c->self, c->rfd, len); |
if (compat13) { |
if (compat13) { |
buffer_consume(&c->output, buffer_len(&c->output)); |
buffer_consume(&c->output, buffer_len(&c->output)); |
|
|
channel_handler_init_20(void) |
channel_handler_init_20(void) |
{ |
{ |
channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; |
channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; |
|
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; |
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; |
|
channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; |
|
|
channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2; |
channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2; |
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; |
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; |
|
channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; |
} |
} |
|
|
void |
void |
|
|
channel_handler_init_15(void) |
channel_handler_init_15(void) |
{ |
{ |
channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_15; |
channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_15; |
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open_15; |
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; |
channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
|
|
ch = channel_new( |
ch = channel_new( |
"port listener", SSH_CHANNEL_PORT_LISTENER, |
"port listener", SSH_CHANNEL_PORT_LISTENER, |
sock, sock, -1, |
sock, sock, -1, |
CHAN_WINDOW_DEFAULT, CHAN_PACKET_DEFAULT, |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
0, xstrdup("port listener")); |
0, xstrdup("port listener")); |
strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); |
strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); |
channels[ch].host_port = host_port; |
channels[ch].host_port = host_port; |
|
|
/* Allocate a channel for each socket. */ |
/* Allocate a channel for each socket. */ |
for (n = 0; n < num_socks; n++) { |
for (n = 0; n < num_socks; n++) { |
sock = socks[n]; |
sock = socks[n]; |
(void) channel_allocate(SSH_CHANNEL_X11_LISTENER, sock, |
(void) channel_new("x11 listener", |
xstrdup("X11 inet listener")); |
SSH_CHANNEL_X11_LISTENER, sock, sock, -1, |
|
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, |
|
0, xstrdup("X11 inet listener")); |
} |
} |
|
|
/* Return a suitable value for the DISPLAY environment variable. */ |
/* Return a suitable value for the DISPLAY environment variable. */ |
|
|
return -1; |
return -1; |
} |
} |
|
|
|
int |
/* |
x11_connect_display(void) |
* This is called when SSH_SMSG_X11_OPEN is received. The packet contains |
|
* the remote channel number. We should do whatever we want, and respond |
|
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. |
|
*/ |
|
|
|
void |
|
x11_input_open(int type, int plen) |
|
{ |
{ |
int remote_channel, display_number, sock = 0, newch; |
int display_number, sock = 0; |
const char *display; |
const char *display; |
char buf[1024], *cp, *remote_host; |
char buf[1024], *cp; |
unsigned int remote_len; |
|
struct addrinfo hints, *ai, *aitop; |
struct addrinfo hints, *ai, *aitop; |
char strport[NI_MAXSERV]; |
char strport[NI_MAXSERV]; |
int gaierr; |
int gaierr; |
|
|
/* Get remote channel number. */ |
|
remote_channel = packet_get_int(); |
|
|
|
/* Get remote originator name. */ |
|
if (have_hostname_in_open) { |
|
remote_host = packet_get_string(&remote_len); |
|
remote_len += 4; |
|
} else { |
|
remote_host = xstrdup("unknown (remote did not supply name)"); |
|
remote_len = 0; |
|
} |
|
|
|
debug("Received X11 open request."); |
|
packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN); |
|
|
|
/* Try to open a socket for the local X server. */ |
/* Try to open a socket for the local X server. */ |
display = getenv("DISPLAY"); |
display = getenv("DISPLAY"); |
if (!display) { |
if (!display) { |
error("DISPLAY not set."); |
error("DISPLAY not set."); |
goto fail; |
return -1; |
} |
} |
/* |
/* |
* Now we decode the value of the DISPLAY variable and make a |
* Now we decode the value of the DISPLAY variable and make a |
|
|
if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) { |
if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) { |
error("Could not parse display number from DISPLAY: %.100s", |
error("Could not parse display number from DISPLAY: %.100s", |
display); |
display); |
goto fail; |
return -1; |
} |
} |
/* Create a socket. */ |
/* Create a socket. */ |
sock = connect_local_xsocket(display_number); |
sock = connect_local_xsocket(display_number); |
if (sock < 0) |
if (sock < 0) |
goto fail; |
return -1; |
|
|
/* OK, we now have a connection to the display. */ |
/* OK, we now have a connection to the display. */ |
goto success; |
return sock; |
} |
} |
/* |
/* |
* Connect to an inet socket. The DISPLAY value is supposedly |
* Connect to an inet socket. The DISPLAY value is supposedly |
|
|
cp = strchr(buf, ':'); |
cp = strchr(buf, ':'); |
if (!cp) { |
if (!cp) { |
error("Could not find ':' in DISPLAY: %.100s", display); |
error("Could not find ':' in DISPLAY: %.100s", display); |
goto fail; |
return -1; |
} |
} |
*cp = 0; |
*cp = 0; |
/* buf now contains the host name. But first we parse the display number. */ |
/* buf now contains the host name. But first we parse the display number. */ |
if (sscanf(cp + 1, "%d", &display_number) != 1) { |
if (sscanf(cp + 1, "%d", &display_number) != 1) { |
error("Could not parse display number from DISPLAY: %.100s", |
error("Could not parse display number from DISPLAY: %.100s", |
display); |
display); |
goto fail; |
return -1; |
} |
} |
|
|
/* Look up the host address */ |
/* Look up the host address */ |
|
|
snprintf(strport, sizeof strport, "%d", 6000 + display_number); |
snprintf(strport, sizeof strport, "%d", 6000 + display_number); |
if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { |
if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { |
error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr)); |
error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr)); |
goto fail; |
return -1; |
} |
} |
for (ai = aitop; ai; ai = ai->ai_next) { |
for (ai = aitop; ai; ai = ai->ai_next) { |
/* Create a socket. */ |
/* Create a socket. */ |
|
|
if (!ai) { |
if (!ai) { |
error("connect %.100s port %d: %.100s", buf, 6000 + display_number, |
error("connect %.100s port %d: %.100s", buf, 6000 + display_number, |
strerror(errno)); |
strerror(errno)); |
goto fail; |
return -1; |
} |
} |
success: |
return sock; |
/* We have successfully obtained a connection to the real X display. */ |
} |
|
|
/* Allocate a channel for this connection. */ |
/* |
if (x11_saved_proto == NULL) |
* This is called when SSH_SMSG_X11_OPEN is received. The packet contains |
newch = channel_allocate(SSH_CHANNEL_OPEN, sock, remote_host); |
* the remote channel number. We should do whatever we want, and respond |
else |
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. |
newch = channel_allocate(SSH_CHANNEL_X11_OPEN, sock, remote_host); |
*/ |
channels[newch].remote_id = remote_channel; |
|
|
|
/* Send a confirmation to the remote host. */ |
void |
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
x11_input_open(int type, int plen) |
packet_put_int(remote_channel); |
{ |
packet_put_int(newch); |
int remote_channel, sock = 0, newch; |
packet_send(); |
char *remote_host; |
|
unsigned int remote_len; |
|
|
return; |
/* Get remote channel number. */ |
|
remote_channel = packet_get_int(); |
|
|
fail: |
/* Get remote originator name. */ |
/* Send refusal to the remote host. */ |
if (have_hostname_in_open) { |
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
remote_host = packet_get_string(&remote_len); |
packet_put_int(remote_channel); |
remote_len += 4; |
packet_send(); |
} else { |
|
remote_host = xstrdup("unknown (remote did not supply name)"); |
|
remote_len = 0; |
|
} |
|
|
|
debug("Received X11 open request."); |
|
packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN); |
|
|
|
/* Obtain a connection to the real X display. */ |
|
sock = x11_connect_display(); |
|
if (sock == -1) { |
|
/* Send refusal to the remote host. */ |
|
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
|
packet_put_int(remote_channel); |
|
packet_send(); |
|
} 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. */ |
|
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
|
packet_put_int(remote_channel); |
|
packet_put_int(newch); |
|
packet_send(); |
|
} |
} |
} |
|
|
/* |
/* |
|
|
*/ |
*/ |
|
|
void |
void |
x11_request_forwarding_with_spoofing(const char *proto, const char *data) |
x11_request_forwarding_with_spoofing(int client_session_id, |
|
const char *proto, const char *data) |
{ |
{ |
unsigned int data_len = (unsigned int) strlen(data) / 2; |
unsigned int data_len = (unsigned int) strlen(data) / 2; |
unsigned int i, value; |
unsigned int i, value; |
|
|
sprintf(new_data + 2 * i, "%02x", (unsigned char) x11_fake_data[i]); |
sprintf(new_data + 2 * i, "%02x", (unsigned char) x11_fake_data[i]); |
|
|
/* Send the request packet. */ |
/* Send the request packet. */ |
packet_start(SSH_CMSG_X11_REQUEST_FORWARDING); |
if (compat20) { |
packet_put_string(proto, strlen(proto)); |
channel_request_start(client_session_id, "x11-req", 0); |
packet_put_string(new_data, strlen(new_data)); |
packet_put_char(0); /* XXX bool single connection */ |
|
} else { |
|
packet_start(SSH_CMSG_X11_REQUEST_FORWARDING); |
|
} |
|
packet_put_cstring(proto); |
|
packet_put_cstring(new_data); |
packet_put_int(screen_number); |
packet_put_int(screen_number); |
packet_send(); |
packet_send(); |
packet_write_wait(); |
packet_write_wait(); |
|
|
} |
} |
|
|
void |
void |
channel_open(int id) |
channel_start_open(int id) |
{ |
{ |
Channel *c = channel_lookup(id); |
Channel *c = channel_lookup(id); |
if (c == NULL) { |
if (c == NULL) { |
log("channel_open: %d: bad id", id); |
log("channel_open: %d: bad id", id); |
return; |
return; |
} |
} |
|
debug("send channel open %d", id); |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_start(SSH2_MSG_CHANNEL_OPEN); |
packet_put_cstring(c->ctype); |
packet_put_cstring(c->ctype); |
packet_put_int(c->self); |
packet_put_int(c->self); |
packet_put_int(c->local_window); |
packet_put_int(c->local_window); |
packet_put_int(c->local_maxpacket); |
packet_put_int(c->local_maxpacket); |
|
} |
|
void |
|
channel_open(int id) |
|
{ |
|
/* XXX REMOVE ME */ |
|
channel_start_open(id); |
packet_send(); |
packet_send(); |
debug("channel open %d", id); |
|
} |
} |
void |
void |
channel_request(int id, char *service, int wantconfirm) |
channel_request(int id, char *service, int wantconfirm) |