diff --git a/portfwd.c b/portfwd.c index b14458b9..e3e63e39 100644 --- a/portfwd.c +++ b/portfwd.c @@ -15,10 +15,10 @@ #define TRUE 1 #endif -struct PFwdPrivate { +struct PortForwarding { const struct plug_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ - void *c; /* (channel) data used by ssh.c */ + struct ssh_channel *c; /* channel structure held by ssh.c */ void *backhandle; /* instance of SSH backend itself */ /* Note that backhandle need not be filled in if c is non-NULL */ Socket s; @@ -27,8 +27,8 @@ struct PFwdPrivate { /* * `dynamic' does double duty. It's set to 0 for an ordinary * forwarded port, and nonzero for SOCKS-style dynamic port - * forwarding; but it also represents the state of the SOCKS - * exchange. + * forwarding; but the nonzero values are also a state machine + * tracking where the SOCKS exchange has got to. */ int dynamic; /* @@ -52,24 +52,57 @@ struct PFwdPrivate { int buflen; }; -static struct PFwdPrivate *new_portfwd_private(void) +struct PortListener { + const struct plug_function_table *fn; + /* the above variable absolutely *must* be the first in this structure */ + void *backhandle; /* instance of SSH backend itself */ + Socket s; + /* + * `dynamic' is set to 0 for an ordinary forwarded port, and + * nonzero for SOCKS-style dynamic port forwarding. + */ + int dynamic; + /* + * `hostname' and `port' are the real hostname and port, for + * ordinary forwardings. + */ + char *hostname; + int port; +}; + +static struct PortForwarding *new_portfwd_state(void) { - struct PFwdPrivate *pr = snew(struct PFwdPrivate); - pr->hostname = NULL; - pr->socksbuf = NULL; - pr->sockslen = pr->sockssize = 0; - pr->buffer = NULL; - return pr; + struct PortForwarding *pf = snew(struct PortForwarding); + pf->hostname = NULL; + pf->socksbuf = NULL; + pf->sockslen = pf->sockssize = 0; + pf->buffer = NULL; + return pf; } -static void free_portfwd_private(struct PFwdPrivate *pr) +static void free_portfwd_state(struct PortForwarding *pf) { - if (!pr) + if (!pf) return; - sfree(pr->hostname); - sfree(pr->socksbuf); - sfree(pr->buffer); - sfree(pr); + sfree(pf->hostname); + sfree(pf->socksbuf); + sfree(pf->buffer); + sfree(pf); +} + +static struct PortListener *new_portlistener_state(void) +{ + struct PortListener *pl = snew(struct PortListener); + pl->hostname = NULL; + return pl; +} + +static void free_portlistener_state(struct PortListener *pl) +{ + if (!pl) + return; + sfree(pl->hostname); + sfree(pl); } static void pfd_log(Plug plug, int type, SockAddr addr, int port, @@ -78,17 +111,23 @@ static void pfd_log(Plug plug, int type, SockAddr addr, int port, /* we have to dump these since we have no interface to logging.c */ } +static void pfl_log(Plug plug, int type, SockAddr addr, int port, + const char *error_msg, int error_code) +{ + /* we have to dump these since we have no interface to logging.c */ +} + static int pfd_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { - struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; + struct PortForwarding *pf = (struct PortForwarding *) plug; if (error_msg) { /* * Socket error. Slam the connection instantly shut. */ - if (pr->c) { - sshfwd_unclean_close(pr->c, error_msg); + if (pf->c) { + sshfwd_unclean_close(pf->c, error_msg); } else { /* * We might not have an SSH channel, if a socket error @@ -96,64 +135,72 @@ static int pfd_closing(Plug plug, const char *error_msg, int error_code, * clean ourself up without sshfwd_unclean_close's call * back to pfd_close. */ - pfd_close(pr->s); + pfd_close(pf); } } else { /* * Ordinary EOF received on socket. Send an EOF on the SSH * channel. */ - if (pr->c) - sshfwd_write_eof(pr->c); + if (pf->c) + sshfwd_write_eof(pf->c); } return 1; } +static int pfl_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) +{ + struct PortListener *pl = (struct PortListener *) plug; + pfl_terminate(pl); + return 1; +} + static int pfd_receive(Plug plug, int urgent, char *data, int len) { - struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; - if (pr->dynamic) { + struct PortForwarding *pf = (struct PortForwarding *) plug; + if (pf->dynamic) { while (len--) { - if (pr->sockslen >= pr->sockssize) { - pr->sockssize = pr->sockslen * 5 / 4 + 256; - pr->socksbuf = sresize(pr->socksbuf, pr->sockssize, char); + if (pf->sockslen >= pf->sockssize) { + pf->sockssize = pf->sockslen * 5 / 4 + 256; + pf->socksbuf = sresize(pf->socksbuf, pf->sockssize, char); } - pr->socksbuf[pr->sockslen++] = *data++; + pf->socksbuf[pf->sockslen++] = *data++; /* * Now check what's in the buffer to see if it's a * valid and complete message in the SOCKS exchange. */ - if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 4) && - pr->socksbuf[0] == 4) { + if ((pf->dynamic == 1 || (pf->dynamic >> 12) == 4) && + pf->socksbuf[0] == 4) { /* * SOCKS 4. */ - if (pr->dynamic == 1) - pr->dynamic = 0x4000; - if (pr->sockslen < 2) + if (pf->dynamic == 1) + pf->dynamic = 0x4000; + if (pf->sockslen < 2) continue; /* don't have command code yet */ - if (pr->socksbuf[1] != 1) { + if (pf->socksbuf[1] != 1) { /* Not CONNECT. */ /* Send back a SOCKS 4 error before closing. */ char data[8]; memset(data, 0, sizeof(data)); data[1] = 91; /* generic `request rejected' */ - sk_write(pr->s, data, 8); - pfd_close(pr->s); + sk_write(pf->s, data, 8); + pfd_close(pf); return 1; } - if (pr->sockslen <= 8) + if (pf->sockslen <= 8) continue; /* haven't started user/hostname */ - if (pr->socksbuf[pr->sockslen-1] != 0) + if (pf->socksbuf[pf->sockslen-1] != 0) continue; /* haven't _finished_ user/hostname */ /* * Now we have a full SOCKS 4 request. Check it to * see if it's a SOCKS 4A request. */ - if (pr->socksbuf[4] == 0 && pr->socksbuf[5] == 0 && - pr->socksbuf[6] == 0 && pr->socksbuf[7] != 0) { + if (pf->socksbuf[4] == 0 && pf->socksbuf[5] == 0 && + pf->socksbuf[6] == 0 && pf->socksbuf[7] != 0) { /* * It's SOCKS 4A. So if we haven't yet * collected the host name, we should continue @@ -161,19 +208,19 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) * have, we can go ahead. */ int len; - if (pr->dynamic == 0x4000) { - pr->dynamic = 0x4001; - pr->sockslen = 8; /* reset buffer to overwrite name */ + if (pf->dynamic == 0x4000) { + pf->dynamic = 0x4001; + pf->sockslen = 8; /* reset buffer to overwrite name */ continue; } - pr->socksbuf[0] = 0; /* reply version code */ - pr->socksbuf[1] = 90; /* request granted */ - sk_write(pr->s, pr->socksbuf, 8); - len = pr->sockslen - 8; - pr->port = GET_16BIT_MSB_FIRST(pr->socksbuf+2); - pr->hostname = snewn(len+1, char); - pr->hostname[len] = '\0'; - memcpy(pr->hostname, pr->socksbuf + 8, len); + pf->socksbuf[0] = 0; /* reply version code */ + pf->socksbuf[1] = 90; /* request granted */ + sk_write(pf->s, pf->socksbuf, 8); + len = pf->sockslen - 8; + pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+2); + pf->hostname = snewn(len+1, char); + pf->hostname[len] = '\0'; + memcpy(pf->hostname, pf->socksbuf + 8, len); goto connect; } else { /* @@ -181,52 +228,52 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) * the IP address into the hostname string and * then just go. */ - pr->socksbuf[0] = 0; /* reply version code */ - pr->socksbuf[1] = 90; /* request granted */ - sk_write(pr->s, pr->socksbuf, 8); - pr->port = GET_16BIT_MSB_FIRST(pr->socksbuf+2); - pr->hostname = dupprintf("%d.%d.%d.%d", - (unsigned char)pr->socksbuf[4], - (unsigned char)pr->socksbuf[5], - (unsigned char)pr->socksbuf[6], - (unsigned char)pr->socksbuf[7]); + pf->socksbuf[0] = 0; /* reply version code */ + pf->socksbuf[1] = 90; /* request granted */ + sk_write(pf->s, pf->socksbuf, 8); + pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+2); + pf->hostname = dupprintf("%d.%d.%d.%d", + (unsigned char)pf->socksbuf[4], + (unsigned char)pf->socksbuf[5], + (unsigned char)pf->socksbuf[6], + (unsigned char)pf->socksbuf[7]); goto connect; } } - if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 5) && - pr->socksbuf[0] == 5) { + if ((pf->dynamic == 1 || (pf->dynamic >> 12) == 5) && + pf->socksbuf[0] == 5) { /* * SOCKS 5. */ - if (pr->dynamic == 1) - pr->dynamic = 0x5000; + if (pf->dynamic == 1) + pf->dynamic = 0x5000; - if (pr->dynamic == 0x5000) { + if (pf->dynamic == 0x5000) { int i, method; char data[2]; /* * We're receiving a set of method identifiers. */ - if (pr->sockslen < 2) + if (pf->sockslen < 2) continue; /* no method count yet */ - if (pr->sockslen < 2 + (unsigned char)pr->socksbuf[1]) + if (pf->sockslen < 2 + (unsigned char)pf->socksbuf[1]) continue; /* no methods yet */ method = 0xFF; /* invalid */ - for (i = 0; i < (unsigned char)pr->socksbuf[1]; i++) - if (pr->socksbuf[2+i] == 0) { + for (i = 0; i < (unsigned char)pf->socksbuf[1]; i++) + if (pf->socksbuf[2+i] == 0) { method = 0;/* no auth */ break; } data[0] = 5; data[1] = method; - sk_write(pr->s, data, 2); - pr->dynamic = 0x5001; - pr->sockslen = 0; /* re-empty the buffer */ + sk_write(pf->s, data, 2); + pf->dynamic = 0x5001; + pf->sockslen = 0; /* re-empty the buffer */ continue; } - if (pr->dynamic == 0x5001) { + if (pf->dynamic == 0x5001) { /* * We're receiving a SOCKS request. */ @@ -244,50 +291,50 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) reply[0] = 5; /* VER */ reply[3] = 1; /* ATYP = 1 (IPv4, 0.0.0.0:0) */ - if (pr->sockslen < 6) continue; - atype = (unsigned char)pr->socksbuf[3]; + if (pf->sockslen < 6) continue; + atype = (unsigned char)pf->socksbuf[3]; if (atype == 1) /* IPv4 address */ alen = 4; if (atype == 4) /* IPv6 address */ alen = 16; if (atype == 3) /* domain name has leading length */ - alen = 1 + (unsigned char)pr->socksbuf[4]; - if (pr->sockslen < 6 + alen) continue; - if (pr->socksbuf[1] != 1 || pr->socksbuf[2] != 0) { + alen = 1 + (unsigned char)pf->socksbuf[4]; + if (pf->sockslen < 6 + alen) continue; + if (pf->socksbuf[1] != 1 || pf->socksbuf[2] != 0) { /* Not CONNECT or reserved field nonzero - error */ reply[1] = 1; /* generic failure */ - sk_write(pr->s, (char *) reply, lenof(reply)); - pfd_close(pr->s); + sk_write(pf->s, (char *) reply, lenof(reply)); + pfd_close(pf); return 1; } /* * Now we have a viable connect request. Switch * on atype. */ - pr->port = GET_16BIT_MSB_FIRST(pr->socksbuf+4+alen); + pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+4+alen); if (atype == 1) { /* REP=0 (success) already */ - sk_write(pr->s, (char *) reply, lenof(reply)); - pr->hostname = dupprintf("%d.%d.%d.%d", - (unsigned char)pr->socksbuf[4], - (unsigned char)pr->socksbuf[5], - (unsigned char)pr->socksbuf[6], - (unsigned char)pr->socksbuf[7]); + sk_write(pf->s, (char *) reply, lenof(reply)); + pf->hostname = dupprintf("%d.%d.%d.%d", + (unsigned char)pf->socksbuf[4], + (unsigned char)pf->socksbuf[5], + (unsigned char)pf->socksbuf[6], + (unsigned char)pf->socksbuf[7]); goto connect; } else if (atype == 3) { /* REP=0 (success) already */ - sk_write(pr->s, (char *) reply, lenof(reply)); - pr->hostname = snewn(alen, char); - pr->hostname[alen-1] = '\0'; - memcpy(pr->hostname, pr->socksbuf + 5, alen-1); + sk_write(pf->s, (char *) reply, lenof(reply)); + pf->hostname = snewn(alen, char); + pf->hostname[alen-1] = '\0'; + memcpy(pf->hostname, pf->socksbuf + 5, alen-1); goto connect; } else { /* * Unknown address type. (FIXME: support IPv6!) */ reply[1] = 8; /* atype not supported */ - sk_write(pr->s, (char *) reply, lenof(reply)); - pfd_close(pr->s); + sk_write(pf->s, (char *) reply, lenof(reply)); + pfd_close(pf); return 1; } } @@ -299,7 +346,7 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) * sensible interpretation of what's in our buffer. So * close the connection rudely. */ - pfd_close(pr->s); + pfd_close(pf); return 1; } return 1; @@ -309,39 +356,39 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) * connection. */ connect: - sfree(pr->socksbuf); - pr->socksbuf = NULL; + sfree(pf->socksbuf); + pf->socksbuf = NULL; /* * Freeze the socket until the SSH server confirms the * connection. */ - sk_set_frozen(pr->s, 1); + sk_set_frozen(pf->s, 1); - pr->c = new_sock_channel(pr->backhandle, pr->s); - if (pr->c == NULL) { - pfd_close(pr->s); + pf->c = new_sock_channel(pf->backhandle, pf); + if (pf->c == NULL) { + pfd_close(pf); return 1; } else { /* asks to forward to the specified host/port for this */ - ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding"); + ssh_send_port_open(pf->c, pf->hostname, pf->port, "forwarding"); } - pr->dynamic = 0; + pf->dynamic = 0; /* * If there's any data remaining in our current buffer, * save it to be sent on pfd_confirm(). */ if (len > 0) { - pr->buffer = snewn(len, char); - memcpy(pr->buffer, data, len); - pr->buflen = len; + pf->buffer = snewn(len, char); + memcpy(pf->buffer, data, len); + pf->buflen = len; } } - if (pr->ready) { - if (sshfwd_write(pr->c, data, len) > 0) { - pr->throttled = 1; - sk_set_frozen(pr->s, 1); + if (pf->ready) { + if (sshfwd_write(pf->c, data, len) > 0) { + pf->throttled = 1; + sk_set_frozen(pf->s, 1); } } return 1; @@ -349,17 +396,21 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len) static void pfd_sent(Plug plug, int bufsize) { - struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; + struct PortForwarding *pf = (struct PortForwarding *) plug; - if (pr->c) - sshfwd_unthrottle(pr->c, bufsize); + if (pf->c) + sshfwd_unthrottle(pf->c, bufsize); } /* - * Called when receiving a PORT OPEN from the server + * Called when receiving a PORT OPEN from the server to make a + * connection to a destination host. + * + * On success, returns NULL and fills in *pf_ret. On error, returns a + * dynamically allocated error message string. */ -const char *pfd_newconnect(Socket *s, char *hostname, int port, - void *c, Conf *conf, int addressfamily) +char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port, + void *c, Conf *conf, int addressfamily) { static const struct plug_function_table fn_table = { pfd_log, @@ -372,38 +423,41 @@ const char *pfd_newconnect(Socket *s, char *hostname, int port, SockAddr addr; const char *err; char *dummy_realhost; - struct PFwdPrivate *pr; + struct PortForwarding *pf; /* * Try to find host. */ addr = name_lookup(hostname, port, &dummy_realhost, conf, addressfamily); if ((err = sk_addr_error(addr)) != NULL) { + char *err_ret = dupstr(err); sk_addr_free(addr); sfree(dummy_realhost); - return err; + return err_ret; } /* * Open socket. */ - pr = new_portfwd_private(); - pr->fn = &fn_table; - pr->throttled = pr->throttle_override = 0; - pr->ready = 1; - pr->c = c; - pr->backhandle = NULL; /* we shouldn't need this */ - pr->dynamic = 0; + pf = *pf_ret = new_portfwd_state(); + pf->fn = &fn_table; + pf->throttled = pf->throttle_override = 0; + pf->ready = 1; + pf->c = c; + pf->backhandle = NULL; /* we shouldn't need this */ + pf->dynamic = 0; - pr->s = *s = new_connection(addr, dummy_realhost, port, - 0, 1, 0, 0, (Plug) pr, conf); + pf->s = new_connection(addr, dummy_realhost, port, + 0, 1, 0, 0, (Plug) pf, conf); sfree(dummy_realhost); - if ((err = sk_socket_error(*s)) != NULL) { - free_portfwd_private(pr); - return err; + if ((err = sk_socket_error(pf->s)) != NULL) { + char *err_ret = dupstr(err); + sk_close(pf->s); + free_portfwd_state(pf); + *pf_ret = NULL; + return err_ret; } - sk_set_private_ptr(*s, pr); return NULL; } @@ -411,7 +465,7 @@ const char *pfd_newconnect(Socket *s, char *hostname, int port, called when someone connects to the local port */ -static int pfd_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) +static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) { static const struct plug_function_table fn_table = { pfd_log, @@ -420,44 +474,43 @@ static int pfd_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) pfd_sent, NULL }; - struct PFwdPrivate *pr, *org; + struct PortForwarding *pf; + struct PortListener *pl; Socket s; const char *err; - org = (struct PFwdPrivate *)p; - pr = new_portfwd_private(); - pr->fn = &fn_table; + pl = (struct PortListener *)p; + pf = new_portfwd_state(); + pf->fn = &fn_table; - pr->c = NULL; - pr->backhandle = org->backhandle; + pf->c = NULL; + pf->backhandle = pl->backhandle; - pr->s = s = constructor(ctx, (Plug) pr); + pf->s = s = constructor(ctx, (Plug) pf); if ((err = sk_socket_error(s)) != NULL) { - free_portfwd_private(pr); + free_portfwd_state(pf); return err != NULL; } - sk_set_private_ptr(s, pr); + pf->throttled = pf->throttle_override = 0; + pf->ready = 0; - pr->throttled = pr->throttle_override = 0; - pr->ready = 0; - - if (org->dynamic) { - pr->dynamic = 1; - pr->port = 0; /* "hostname" buffer is so far empty */ + if (pl->dynamic) { + pf->dynamic = 1; + pf->port = 0; /* "hostname" buffer is so far empty */ sk_set_frozen(s, 0); /* we want to receive SOCKS _now_! */ } else { - pr->dynamic = 0; - pr->hostname = dupstr(org->hostname); - pr->port = org->port; - pr->c = new_sock_channel(org->backhandle, s); + pf->dynamic = 0; + pf->hostname = dupstr(pl->hostname); + pf->port = pl->port; + pf->c = new_sock_channel(pl->backhandle, pf); - if (pr->c == NULL) { - free_portfwd_private(pr); + if (pf->c == NULL) { + free_portfwd_state(pf); return 1; } else { /* asks to forward to the specified host/port for this */ - ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding"); + ssh_send_port_open(pf->c, pf->hostname, pf->port, "forwarding"); } } @@ -465,129 +518,119 @@ static int pfd_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) } -/* Add a new forwarding from port -> desthost:destport - sets up a listener on the local machine on (srcaddr:)port +/* + * Add a new port-forwarding listener from srcaddr:port -> desthost:destport. + * + * On success, returns NULL and fills in *pl_ret. On error, returns a + * dynamically allocated error message string. */ -const char *pfd_addforward(char *desthost, int destport, char *srcaddr, - int port, void *backhandle, Conf *conf, - void **sockdata, int address_family) +char *pfl_listen(char *desthost, int destport, char *srcaddr, + int port, void *backhandle, Conf *conf, + struct PortListener **pl_ret, int address_family) { static const struct plug_function_table fn_table = { - pfd_log, - pfd_closing, - pfd_receive, /* should not happen... */ - pfd_sent, /* also should not happen */ - pfd_accepting + pfl_log, + pfl_closing, + NULL, /* recv */ + NULL, /* send */ + pfl_accepting }; const char *err; - struct PFwdPrivate *pr; - Socket s; + struct PortListener *pl; /* * Open socket. */ - pr = new_portfwd_private(); - pr->fn = &fn_table; - pr->c = NULL; + pl = *pl_ret = new_portlistener_state(); + pl->fn = &fn_table; if (desthost) { - pr->hostname = dupstr(desthost); - pr->port = destport; - pr->dynamic = 0; + pl->hostname = dupstr(desthost); + pl->port = destport; + pl->dynamic = 0; } else - pr->dynamic = 1; - pr->throttled = pr->throttle_override = 0; - pr->ready = 0; - pr->backhandle = backhandle; + pl->dynamic = 1; + pl->backhandle = backhandle; - pr->s = s = new_listener(srcaddr, port, (Plug) pr, - !conf_get_int(conf, CONF_lport_acceptall), - conf, address_family); - if ((err = sk_socket_error(s)) != NULL) { - free_portfwd_private(pr); - return err; + pl->s = new_listener(srcaddr, port, (Plug) pl, + !conf_get_int(conf, CONF_lport_acceptall), + conf, address_family); + if ((err = sk_socket_error(pl->s)) != NULL) { + char *err_ret = dupstr(err); + sk_close(pl->s); + free_portlistener_state(pl); + *pl_ret = NULL; + return err_ret; } - sk_set_private_ptr(s, pr); - - *sockdata = (void *)s; - return NULL; } -void pfd_close(Socket s) +void pfd_close(struct PortForwarding *pf) { - struct PFwdPrivate *pr; - - if (!s) + if (!pf) return; - pr = (struct PFwdPrivate *) sk_get_private_ptr(s); - - free_portfwd_private(pr); - - sk_close(s); + sk_close(pf->s); + free_portfwd_state(pf); } /* * Terminate a listener. */ -void pfd_terminate(void *sv) +void pfl_terminate(struct PortListener *pl) { - pfd_close((Socket)sv); + if (!pl) + return; + + sk_close(pl->s); + free_portlistener_state(pl); } -void pfd_unthrottle(Socket s) +void pfd_unthrottle(struct PortForwarding *pf) { - struct PFwdPrivate *pr; - if (!s) + if (!pf) return; - pr = (struct PFwdPrivate *) sk_get_private_ptr(s); - pr->throttled = 0; - sk_set_frozen(s, pr->throttled || pr->throttle_override); + pf->throttled = 0; + sk_set_frozen(pf->s, pf->throttled || pf->throttle_override); } -void pfd_override_throttle(Socket s, int enable) +void pfd_override_throttle(struct PortForwarding *pf, int enable) { - struct PFwdPrivate *pr; - if (!s) + if (!pf) return; - pr = (struct PFwdPrivate *) sk_get_private_ptr(s); - pr->throttle_override = enable; - sk_set_frozen(s, pr->throttled || pr->throttle_override); + pf->throttle_override = enable; + sk_set_frozen(pf->s, pf->throttled || pf->throttle_override); } /* * Called to send data down the raw connection. */ -int pfd_send(Socket s, char *data, int len) +int pfd_send(struct PortForwarding *pf, char *data, int len) { - if (s == NULL) + if (pf == NULL) return 0; - return sk_write(s, data, len); + return sk_write(pf->s, data, len); } -void pfd_send_eof(Socket s) +void pfd_send_eof(struct PortForwarding *pf) { - sk_write_eof(s); + sk_write_eof(pf->s); } -void pfd_confirm(Socket s) +void pfd_confirm(struct PortForwarding *pf) { - struct PFwdPrivate *pr; - - if (s == NULL) + if (pf == NULL) return; - pr = (struct PFwdPrivate *) sk_get_private_ptr(s); - pr->ready = 1; - sk_set_frozen(s, 0); - sk_write(s, NULL, 0); - if (pr->buffer) { - sshfwd_write(pr->c, pr->buffer, pr->buflen); - sfree(pr->buffer); - pr->buffer = NULL; + pf->ready = 1; + sk_set_frozen(pf->s, 0); + sk_write(pf->s, NULL, 0); + if (pf->buffer) { + sshfwd_write(pf->c, pf->buffer, pf->buflen); + sfree(pf->buffer); + pf->buffer = NULL; } } diff --git a/ssh.c b/ssh.c index 0983f7d3..fa9bc745 100644 --- a/ssh.c +++ b/ssh.c @@ -544,10 +544,10 @@ struct ssh_channel { int outstanding_requests; } a; struct ssh_x11_channel { - Socket s; + struct X11Connection *xconn; } x11; struct ssh_pfd_channel { - Socket s; + struct PortForwarding *pf; } pfd; } u; }; @@ -613,7 +613,7 @@ struct ssh_portfwd { char *sserv, *dserv; struct ssh_rportfwd *remote; int addressfamily; - void *local; + struct PortListener *local; }; #define free_portfwd(pf) ( \ ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \ @@ -3005,11 +3005,11 @@ static int ssh_do_close(Ssh ssh, int notify_exit) while (NULL != (c = index234(ssh->channels, 0))) { switch (c->type) { case CHAN_X11: - x11_close(c->u.x11.s); + x11_close(c->u.x11.xconn); break; case CHAN_SOCKDATA: case CHAN_SOCKDATA_DORMANT: - pfd_close(c->u.pfd.s); + pfd_close(c->u.pfd.pf); break; } del234(ssh->channels, c); /* moving next one to index 0 */ @@ -3027,7 +3027,7 @@ static int ssh_do_close(Ssh ssh, int notify_exit) while (NULL != (pf = index234(ssh->portfwds, 0))) { /* Dispose of any listening socket. */ if (pf->local) - pfd_terminate(pf->local); + pfl_terminate(pf->local); del234(ssh->portfwds, pf); /* moving next one to index 0 */ free_portfwd(pf); } @@ -3238,13 +3238,13 @@ static void ssh_throttle_all(Ssh ssh, int enable, int bufsize) */ break; case CHAN_X11: - x11_override_throttle(c->u.x11.s, enable); + x11_override_throttle(c->u.x11.xconn, enable); break; case CHAN_AGENT: /* Agent channels require no buffer management. */ break; case CHAN_SOCKDATA: - pfd_override_throttle(c->u.pfd.s, enable); + pfd_override_throttle(c->u.pfd.pf, enable); break; } } @@ -4376,13 +4376,13 @@ void sshfwd_unclean_close(struct ssh_channel *c, const char *err) switch (c->type) { case CHAN_X11: - x11_close(c->u.x11.s); + x11_close(c->u.x11.xconn); logeventf(ssh, "Forwarded X11 connection terminated due to local " "error: %s", err); break; case CHAN_SOCKDATA: case CHAN_SOCKDATA_DORMANT: - pfd_close(c->u.pfd.s); + pfd_close(c->u.pfd.pf); logeventf(ssh, "Forwarded port closed due to local error: %s", err); break; } @@ -4720,7 +4720,7 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) del234(ssh->rportfwds, rpf); free_rportfwd(rpf); } else if (epf->local) { - pfd_terminate(epf->local); + pfl_terminate(epf->local); } delpos234(ssh->portfwds, i); @@ -4753,29 +4753,31 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) } if (epf->type == 'L') { - const char *err = pfd_addforward(epf->daddr, epf->dport, - epf->saddr, epf->sport, - ssh, conf, - &epf->local, - epf->addressfamily); + char *err = pfl_listen(epf->daddr, epf->dport, + epf->saddr, epf->sport, + ssh, conf, &epf->local, + epf->addressfamily); logeventf(ssh, "Local %sport %s forwarding to %s%s%s", epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", sportdesc, dportdesc, err ? " failed: " : "", err ? err : ""); + if (err) + sfree(err); } else if (epf->type == 'D') { - const char *err = pfd_addforward(NULL, -1, - epf->saddr, epf->sport, - ssh, conf, - &epf->local, - epf->addressfamily); + char *err = pfl_listen(NULL, -1, epf->saddr, epf->sport, + ssh, conf, &epf->local, + epf->addressfamily); logeventf(ssh, "Local %sport %s SOCKS dynamic forwarding%s%s", epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", sportdesc, err ? " failed: " : "", err ? err : ""); + + if (err) + sfree(err); } else { struct ssh_rportfwd *pf; @@ -4875,12 +4877,15 @@ static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin) PKT_INT, remoteid, PKT_END); logevent("Rejected X11 connect request"); } else { + char *err; + c = snew(struct ssh_channel); c->ssh = ssh; - if (x11_init(&c->u.x11.s, ssh->x11disp, c, - NULL, -1, ssh->conf) != NULL) { - logevent("Opening X11 forward connection failed"); + if ((err = x11_init(&c->u.x11.xconn, ssh->x11disp, c, + NULL, -1, ssh->conf)) != NULL) { + logeventf(ssh, "Opening X11 forward connection failed: %s", err); + sfree(err); sfree(c); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, PKT_INT, remoteid, PKT_END); @@ -4942,7 +4947,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin) int remoteid; int hostsize, port; char *host; - const char *e; + char *err; remoteid = ssh_pkt_getuint32(pktin); ssh_pkt_getstring(pktin, &host, &hostsize); @@ -4963,10 +4968,11 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin) logeventf(ssh, "Received remote port open request for %s:%d", pf.dhost, port); - e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port, - c, ssh->conf, pfp->pfrec->addressfamily); - if (e != NULL) { - logeventf(ssh, "Port open failed: %s", e); + err = pfd_connect(&c->u.pfd.pf, pf.dhost, port, + c, ssh->conf, pfp->pfrec->addressfamily); + if (err != NULL) { + logeventf(ssh, "Port open failed: %s", err); + sfree(err); sfree(c); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, PKT_INT, remoteid, PKT_END); @@ -5001,7 +5007,7 @@ static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) c->halfopen = FALSE; c->type = CHAN_SOCKDATA; c->throttling_conn = 0; - pfd_confirm(c->u.pfd.s); + pfd_confirm(c->u.pfd.pf); } if (c && c->pending_eof) { @@ -5023,7 +5029,7 @@ static void ssh1_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) c = find234(ssh->channels, &remoteid, ssh_channelfind); if (c && c->type == CHAN_SOCKDATA_DORMANT) { logevent("Forwarded connection refused by server"); - pfd_close(c->u.pfd.s); + pfd_close(c->u.pfd.pf); del234(ssh->channels, c); sfree(c); } @@ -5049,14 +5055,14 @@ static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin) switch (c->type) { case CHAN_X11: - if (c->u.x11.s) - x11_send_eof(c->u.x11.s); + if (c->u.x11.xconn) + x11_send_eof(c->u.x11.xconn); else send_close = TRUE; break; case CHAN_SOCKDATA: - if (c->u.pfd.s) - pfd_send_eof(c->u.pfd.s); + if (c->u.pfd.pf) + pfd_send_eof(c->u.pfd.pf); else send_close = TRUE; break; @@ -5115,10 +5121,10 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin) int bufsize = 0; switch (c->type) { case CHAN_X11: - bufsize = x11_send(c->u.x11.s, p, len); + bufsize = x11_send(c->u.x11.xconn, p, len); break; case CHAN_SOCKDATA: - bufsize = pfd_send(c->u.pfd.s, p, len); + bufsize = pfd_send(c->u.pfd.pf, p, len); break; case CHAN_AGENT: /* Data for an agent message. Buffer it. */ @@ -6660,14 +6666,14 @@ static void ssh2_try_send_and_unthrottle(Ssh ssh, struct ssh_channel *c) * notification since it will be polled */ break; case CHAN_X11: - x11_unthrottle(c->u.x11.s); + x11_unthrottle(c->u.x11.xconn); break; case CHAN_AGENT: /* agent sockets are request/response and need no * buffer management */ break; case CHAN_SOCKDATA: - pfd_unthrottle(c->u.pfd.s); + pfd_unthrottle(c->u.pfd.pf); break; } } @@ -6930,10 +6936,10 @@ static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin) data, length); break; case CHAN_X11: - bufsize = x11_send(c->u.x11.s, data, length); + bufsize = x11_send(c->u.x11.xconn, data, length); break; case CHAN_SOCKDATA: - bufsize = pfd_send(c->u.pfd.s, data, length); + bufsize = pfd_send(c->u.pfd.pf, data, length); break; case CHAN_AGENT: while (length > 0) { @@ -7021,16 +7027,16 @@ static void ssh_channel_destroy(struct ssh_channel *c) update_specials_menu(ssh->frontend); break; case CHAN_X11: - if (c->u.x11.s != NULL) - x11_close(c->u.x11.s); + if (c->u.x11.xconn != NULL) + x11_close(c->u.x11.xconn); logevent("Forwarded X11 connection terminated"); break; case CHAN_AGENT: sfree(c->u.a.message); break; case CHAN_SOCKDATA: - if (c->u.pfd.s != NULL) - pfd_close(c->u.pfd.s); + if (c->u.pfd.pf != NULL) + pfd_close(c->u.pfd.pf); logevent("Forwarded port closed"); break; } @@ -7112,14 +7118,14 @@ static void ssh2_channel_got_eof(struct ssh_channel *c) c->closes |= CLOSES_RCVD_EOF; if (c->type == CHAN_X11) { - x11_send_eof(c->u.x11.s); + x11_send_eof(c->u.x11.xconn); } else if (c->type == CHAN_AGENT) { if (c->u.a.outstanding_requests == 0) { /* Manufacture an outgoing EOF in response to the incoming one. */ sshfwd_write_eof(c); } } else if (c->type == CHAN_SOCKDATA) { - pfd_send_eof(c->u.pfd.s); + pfd_send_eof(c->u.pfd.pf); } else if (c->type == CHAN_MAINSESSION) { Ssh ssh = c->ssh; @@ -7182,10 +7188,10 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin) ssh->send_ok = 0; /* stop trying to read from stdin */ break; case CHAN_X11: - x11_override_throttle(c->u.x11.s, 1); + x11_override_throttle(c->u.x11.xconn, 1); break; case CHAN_SOCKDATA: - pfd_override_throttle(c->u.pfd.s, 1); + pfd_override_throttle(c->u.pfd.pf, 1); break; } @@ -7228,8 +7234,8 @@ static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) if (c->type == CHAN_SOCKDATA_DORMANT) { c->type = CHAN_SOCKDATA; - if (c->u.pfd.s) - pfd_confirm(c->u.pfd.s); + if (c->u.pfd.pf) + pfd_confirm(c->u.pfd.pf); } else if (c->type == CHAN_ZOMBIE) { /* * This case can occur if a local socket error occurred @@ -7285,7 +7291,7 @@ static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]", reasons[reason_code], reason_length, reason_string); - pfd_close(c->u.pfd.s); + pfd_close(c->u.pfd.pf); } else if (c->type == CHAN_ZOMBIE) { /* * This case can occur if a local socket error occurred @@ -7536,7 +7542,7 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) if (typelen == 3 && !memcmp(type, "x11", 3)) { char *addrstr; - const char *x11err; + char *x11err; ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen); addrstr = snewn(peeraddrlen+1, char); @@ -7549,9 +7555,10 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) if (!ssh->X11_fwd_enabled) error = "X11 forwarding is not enabled"; - else if ((x11err = x11_init(&c->u.x11.s, ssh->x11disp, c, + else if ((x11err = x11_init(&c->u.x11.xconn, ssh->x11disp, c, addrstr, peerport, ssh->conf)) != NULL) { logeventf(ssh, "Local X11 connection failed: %s", x11err); + sfree(x11err); error = "Unable to open an X11 connection"; } else { logevent("Opening X11 forward connection succeeded"); @@ -7577,15 +7584,16 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) if (realpf == NULL) { error = "Remote port is not recognised"; } else { - const char *e = pfd_newconnect(&c->u.pfd.s, - realpf->dhost, - realpf->dport, c, - ssh->conf, - realpf->pfrec->addressfamily); + char *err = pfd_connect(&c->u.pfd.pf, + realpf->dhost, + realpf->dport, c, + ssh->conf, + realpf->pfrec->addressfamily); logeventf(ssh, "Attempting to forward remote port to " "%s:%d", realpf->dhost, realpf->dport); - if (e != NULL) { - logeventf(ssh, "Port open failed: %s", e); + if (err != NULL) { + logeventf(ssh, "Port open failed: %s", err); + sfree(err); error = "Port open failed"; } else { logevent("Forwarded port opened successfully"); @@ -9909,13 +9917,13 @@ static void ssh_free(void *handle) while ((c = delpos234(ssh->channels, 0)) != NULL) { switch (c->type) { case CHAN_X11: - if (c->u.x11.s != NULL) - x11_close(c->u.x11.s); + if (c->u.x11.xconn != NULL) + x11_close(c->u.x11.xconn); break; case CHAN_SOCKDATA: case CHAN_SOCKDATA_DORMANT: - if (c->u.pfd.s != NULL) - pfd_close(c->u.pfd.s); + if (c->u.pfd.pf != NULL) + pfd_close(c->u.pfd.pf); break; } if (ssh->version == 2) { @@ -10288,7 +10296,7 @@ static void ssh_special(void *handle, Telnet_Special code) } } -void *new_sock_channel(void *handle, Socket s) +void *new_sock_channel(void *handle, struct PortForwarding *pf) { Ssh ssh = (Ssh) handle; struct ssh_channel *c; @@ -10298,7 +10306,7 @@ void *new_sock_channel(void *handle, Socket s) ssh2_channel_init(c); c->halfopen = TRUE; c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */ - c->u.pfd.s = s; + c->u.pfd.pf = pf; add234(ssh->channels, c); return c; } diff --git a/ssh.h b/ssh.h index 9404e824..b900738e 100644 --- a/ssh.h +++ b/ssh.h @@ -330,24 +330,27 @@ void random_add_heavynoise(void *noise, int length); void logevent(void *, const char *); +struct PortForwarding; + /* Allocate and register a new channel for port forwarding */ -void *new_sock_channel(void *handle, Socket s); +void *new_sock_channel(void *handle, struct PortForwarding *pf); void ssh_send_port_open(void *channel, char *hostname, int port, char *org); /* Exports from portfwd.c */ -extern const char *pfd_newconnect(Socket * s, char *hostname, int port, - void *c, Conf *conf, int addressfamily); +extern char *pfd_connect(struct PortForwarding **pf, char *hostname, int port, + void *c, Conf *conf, int addressfamily); +extern void pfd_close(struct PortForwarding *); +extern int pfd_send(struct PortForwarding *, char *data, int len); +extern void pfd_send_eof(struct PortForwarding *); +extern void pfd_confirm(struct PortForwarding *); +extern void pfd_unthrottle(struct PortForwarding *); +extern void pfd_override_throttle(struct PortForwarding *, int enable); +struct PortListener; /* desthost == NULL indicates dynamic (SOCKS) port forwarding */ -extern const char *pfd_addforward(char *desthost, int destport, char *srcaddr, - int port, void *backhandle, Conf *conf, - void **sockdata, int address_family); -extern void pfd_close(Socket s); -extern void pfd_terminate(void *sockdata); -extern int pfd_send(Socket s, char *data, int len); -extern void pfd_send_eof(Socket s); -extern void pfd_confirm(Socket s); -extern void pfd_unthrottle(Socket s); -extern void pfd_override_throttle(Socket s, int enable); +extern char *pfl_listen(char *desthost, int destport, char *srcaddr, + int port, void *backhandle, Conf *conf, + struct PortListener **pl, int address_family); +extern void pfl_terminate(struct PortListener *); /* Exports from x11fwd.c */ enum { @@ -396,13 +399,14 @@ struct X11Display { extern struct X11Display *x11_setup_display(char *display, int authtype, Conf *); void x11_free_display(struct X11Display *disp); -extern const char *x11_init(Socket *, struct X11Display *, void *, - const char *, int, Conf *); -extern void x11_close(Socket); -extern int x11_send(Socket, char *, int); -extern void x11_send_eof(Socket s); -extern void x11_unthrottle(Socket s); -extern void x11_override_throttle(Socket s, int enable); +struct X11Connection; /* opaque outside x11fwd.c */ +extern char *x11_init(struct X11Connection **, struct X11Display *, + void *, const char *, int, Conf *); +extern void x11_close(struct X11Connection *); +extern int x11_send(struct X11Connection *, char *, int); +extern void x11_send_eof(struct X11Connection *s); +extern void x11_unthrottle(struct X11Connection *s); +extern void x11_override_throttle(struct X11Connection *s, int enable); char *x11_display(const char *display); /* Platform-dependent X11 functions */ extern void platform_get_x11_auth(struct X11Display *display, Conf *); diff --git a/x11fwd.c b/x11fwd.c index ba729d18..7f4b06c4 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -26,7 +26,7 @@ struct XDMSeen { unsigned char clientid[6]; }; -struct X11Private { +struct X11Connection { const struct plug_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ unsigned char firstpkt[12]; /* first X data packet */ @@ -38,7 +38,7 @@ struct X11Private { int throttled, throttle_override; unsigned long peer_ip; int peer_port; - void *c; /* data used by ssh.c */ + struct ssh_channel *c; /* channel structure held by ssh.c */ Socket s; }; @@ -504,20 +504,20 @@ static void x11_log(Plug p, int type, SockAddr addr, int port, static int x11_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { - struct X11Private *pr = (struct X11Private *) plug; + struct X11Connection *xconn = (struct X11Connection *) plug; if (error_msg) { /* * Socket error. Slam the connection instantly shut. */ - sshfwd_unclean_close(pr->c, error_msg); + sshfwd_unclean_close(xconn->c, error_msg); } else { /* * Ordinary EOF received on socket. Send an EOF on the SSH * channel. */ - if (pr->c) - sshfwd_write_eof(pr->c); + if (xconn->c) + sshfwd_write_eof(xconn->c); } return 1; @@ -525,11 +525,11 @@ static int x11_closing(Plug plug, const char *error_msg, int error_code, static int x11_receive(Plug plug, int urgent, char *data, int len) { - struct X11Private *pr = (struct X11Private *) plug; + struct X11Connection *xconn = (struct X11Connection *) plug; - if (sshfwd_write(pr->c, data, len) > 0) { - pr->throttled = 1; - sk_set_frozen(pr->s, 1); + if (sshfwd_write(xconn->c, data, len) > 0) { + xconn->throttled = 1; + sk_set_frozen(xconn->s, 1); } return 1; @@ -537,9 +537,9 @@ static int x11_receive(Plug plug, int urgent, char *data, int len) static void x11_sent(Plug plug, int bufsize) { - struct X11Private *pr = (struct X11Private *) plug; + struct X11Connection *xconn = (struct X11Connection *) plug; - sshfwd_unthrottle(pr->c, bufsize); + sshfwd_unthrottle(xconn->c, bufsize); } /* @@ -563,11 +563,12 @@ int x11_get_screen_number(char *display) /* * Called to set up the raw connection. * - * Returns an error message, or NULL on success. - * also, fills the SocketsStructure + * On success, returns NULL and fills in *xconnret. On error, returns + * a dynamically allocated error message string. */ -extern const char *x11_init(Socket *s, struct X11Display *disp, void *c, - const char *peeraddr, int peerport, Conf *conf) +extern char *x11_init(struct X11Connection **xconnret, + struct X11Display *disp, void *c, + const char *peeraddr, int peerport, Conf *conf) { static const struct plug_function_table fn_table = { x11_log, @@ -578,26 +579,29 @@ extern const char *x11_init(Socket *s, struct X11Display *disp, void *c, }; const char *err; - struct X11Private *pr; + struct X11Connection *xconn; /* * Open socket. */ - pr = snew(struct X11Private); - pr->fn = &fn_table; - pr->auth_protocol = NULL; - pr->disp = disp; - pr->verified = 0; - pr->data_read = 0; - pr->throttled = pr->throttle_override = 0; - pr->c = c; + xconn = *xconnret = snew(struct X11Connection); + xconn->fn = &fn_table; + xconn->auth_protocol = NULL; + xconn->disp = disp; + xconn->verified = 0; + xconn->data_read = 0; + xconn->throttled = xconn->throttle_override = 0; + xconn->c = c; - pr->s = *s = new_connection(sk_addr_dup(disp->addr), - disp->realhost, disp->port, - 0, 1, 0, 0, (Plug) pr, conf); - if ((err = sk_socket_error(*s)) != NULL) { - sfree(pr); - return err; + xconn->s = new_connection(sk_addr_dup(disp->addr), + disp->realhost, disp->port, + 0, 1, 0, 0, (Plug) xconn, conf); + if ((err = sk_socket_error(xconn->s)) != NULL) { + char *err_ret = dupstr(err); + sk_close(xconn->s); + sfree(xconn); + *xconnret = NULL; + return err_ret; } /* @@ -607,109 +611,102 @@ extern const char *x11_init(Socket *s, struct X11Display *disp, void *c, int i[4]; if (peeraddr && 4 == sscanf(peeraddr, "%d.%d.%d.%d", i+0, i+1, i+2, i+3)) { - pr->peer_ip = (i[0] << 24) | (i[1] << 16) | (i[2] << 8) | i[3]; - pr->peer_port = peerport; + xconn->peer_ip = (i[0] << 24) | (i[1] << 16) | (i[2] << 8) | i[3]; + xconn->peer_port = peerport; } else { - pr->peer_ip = 0; - pr->peer_port = -1; + xconn->peer_ip = 0; + xconn->peer_port = -1; } } - sk_set_private_ptr(*s, pr); return NULL; } -void x11_close(Socket s) +void x11_close(struct X11Connection *xconn) { - struct X11Private *pr; - if (!s) + if (!xconn) return; - pr = (struct X11Private *) sk_get_private_ptr(s); - if (pr->auth_protocol) { - sfree(pr->auth_protocol); - sfree(pr->auth_data); + + if (xconn->auth_protocol) { + sfree(xconn->auth_protocol); + sfree(xconn->auth_data); } - sfree(pr); - - sk_close(s); + sk_close(xconn->s); + sfree(xconn); } -void x11_unthrottle(Socket s) +void x11_unthrottle(struct X11Connection *xconn) { - struct X11Private *pr; - if (!s) + if (!xconn) return; - pr = (struct X11Private *) sk_get_private_ptr(s); - pr->throttled = 0; - sk_set_frozen(s, pr->throttled || pr->throttle_override); + xconn->throttled = 0; + sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override); } -void x11_override_throttle(Socket s, int enable) +void x11_override_throttle(struct X11Connection *xconn, int enable) { - struct X11Private *pr; - if (!s) + if (!xconn) return; - pr = (struct X11Private *) sk_get_private_ptr(s); - pr->throttle_override = enable; - sk_set_frozen(s, pr->throttled || pr->throttle_override); + xconn->throttle_override = enable; + sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override); } /* * Called to send data down the raw connection. */ -int x11_send(Socket s, char *data, int len) +int x11_send(struct X11Connection *xconn, char *data, int len) { - struct X11Private *pr; - if (!s) + if (!xconn) return 0; - pr = (struct X11Private *) sk_get_private_ptr(s); /* * Read the first packet. */ - while (len > 0 && pr->data_read < 12) - pr->firstpkt[pr->data_read++] = (unsigned char) (len--, *data++); - if (pr->data_read < 12) + while (len > 0 && xconn->data_read < 12) + xconn->firstpkt[xconn->data_read++] = (unsigned char) (len--, *data++); + if (xconn->data_read < 12) return 0; /* * If we have not allocated the auth_protocol and auth_data * strings, do so now. */ - if (!pr->auth_protocol) { - pr->auth_plen = GET_16BIT(pr->firstpkt[0], pr->firstpkt + 6); - pr->auth_dlen = GET_16BIT(pr->firstpkt[0], pr->firstpkt + 8); - pr->auth_psize = (pr->auth_plen + 3) & ~3; - pr->auth_dsize = (pr->auth_dlen + 3) & ~3; + if (!xconn->auth_protocol) { + xconn->auth_plen = GET_16BIT(xconn->firstpkt[0], xconn->firstpkt + 6); + xconn->auth_dlen = GET_16BIT(xconn->firstpkt[0], xconn->firstpkt + 8); + xconn->auth_psize = (xconn->auth_plen + 3) & ~3; + xconn->auth_dsize = (xconn->auth_dlen + 3) & ~3; /* Leave room for a terminating zero, to make our lives easier. */ - pr->auth_protocol = snewn(pr->auth_psize + 1, char); - pr->auth_data = snewn(pr->auth_dsize, unsigned char); + xconn->auth_protocol = snewn(xconn->auth_psize + 1, char); + xconn->auth_data = snewn(xconn->auth_dsize, unsigned char); } /* * Read the auth_protocol and auth_data strings. */ - while (len > 0 && pr->data_read < 12 + pr->auth_psize) - pr->auth_protocol[pr->data_read++ - 12] = (len--, *data++); - while (len > 0 && pr->data_read < 12 + pr->auth_psize + pr->auth_dsize) - pr->auth_data[pr->data_read++ - 12 - - pr->auth_psize] = (unsigned char) (len--, *data++); - if (pr->data_read < 12 + pr->auth_psize + pr->auth_dsize) + while (len > 0 && + xconn->data_read < 12 + xconn->auth_psize) + xconn->auth_protocol[xconn->data_read++ - 12] = (len--, *data++); + while (len > 0 && + xconn->data_read < 12 + xconn->auth_psize + xconn->auth_dsize) + xconn->auth_data[xconn->data_read++ - 12 - + xconn->auth_psize] = (unsigned char) (len--, *data++); + if (xconn->data_read < 12 + xconn->auth_psize + xconn->auth_dsize) return 0; /* * If we haven't verified the authorisation, do so now. */ - if (!pr->verified) { + if (!xconn->verified) { char *err; - pr->auth_protocol[pr->auth_plen] = '\0'; /* ASCIZ */ - err = x11_verify(pr->peer_ip, pr->peer_port, - pr->disp, pr->auth_protocol, - pr->auth_data, pr->auth_dlen); + xconn->auth_protocol[xconn->auth_plen] = '\0'; /* ASCIZ */ + err = x11_verify(xconn->peer_ip, xconn->peer_port, + xconn->disp, xconn->auth_protocol, + xconn->auth_data, xconn->auth_dlen); /* * If authorisation failed, construct and send an error @@ -726,12 +723,12 @@ int x11_send(Socket s, char *data, int len) msgsize = (msglen + 3) & ~3; reply[0] = 0; /* failure */ reply[1] = msglen; /* length of reason string */ - memcpy(reply + 2, pr->firstpkt + 2, 4); /* major/minor proto vsn */ - PUT_16BIT(pr->firstpkt[0], reply + 6, msgsize >> 2);/* data len */ + memcpy(reply + 2, xconn->firstpkt + 2, 4); /* major/minor proto vsn */ + PUT_16BIT(xconn->firstpkt[0], reply + 6, msgsize >> 2);/* data len */ memset(reply + 8, 0, msgsize); memcpy(reply + 8, message, msglen); - sshfwd_write(pr->c, (char *)reply, 8 + msgsize); - sshfwd_write_eof(pr->c); + sshfwd_write(xconn->c, (char *)reply, 8 + msgsize); + sshfwd_write_eof(xconn->c); sfree(reply); sfree(message); return 0; @@ -745,59 +742,59 @@ int x11_send(Socket s, char *data, int len) { char realauthdata[64]; int realauthlen = 0; - int authstrlen = strlen(x11_authnames[pr->disp->localauthproto]); + int authstrlen = strlen(x11_authnames[xconn->disp->localauthproto]); int buflen = 0; /* initialise to placate optimiser */ static const char zeroes[4] = { 0,0,0,0 }; void *buf; - if (pr->disp->localauthproto == X11_MIT) { - assert(pr->disp->localauthdatalen <= lenof(realauthdata)); - realauthlen = pr->disp->localauthdatalen; - memcpy(realauthdata, pr->disp->localauthdata, realauthlen); - } else if (pr->disp->localauthproto == X11_XDM && - pr->disp->localauthdatalen == 16 && - ((buf = sk_getxdmdata(s, &buflen))!=0)) { + if (xconn->disp->localauthproto == X11_MIT) { + assert(xconn->disp->localauthdatalen <= lenof(realauthdata)); + realauthlen = xconn->disp->localauthdatalen; + memcpy(realauthdata, xconn->disp->localauthdata, realauthlen); + } else if (xconn->disp->localauthproto == X11_XDM && + xconn->disp->localauthdatalen == 16 && + ((buf = sk_getxdmdata(xconn->s, &buflen))!=0)) { time_t t; realauthlen = (buflen+12+7) & ~7; assert(realauthlen <= lenof(realauthdata)); memset(realauthdata, 0, realauthlen); - memcpy(realauthdata, pr->disp->localauthdata, 8); + memcpy(realauthdata, xconn->disp->localauthdata, 8); memcpy(realauthdata+8, buf, buflen); t = time(NULL); PUT_32BIT_MSB_FIRST(realauthdata+8+buflen, t); - des_encrypt_xdmauth(pr->disp->localauthdata+9, + des_encrypt_xdmauth(xconn->disp->localauthdata+9, (unsigned char *)realauthdata, realauthlen); sfree(buf); } /* implement other auth methods here if required */ - PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 6, authstrlen); - PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 8, realauthlen); + PUT_16BIT(xconn->firstpkt[0], xconn->firstpkt + 6, authstrlen); + PUT_16BIT(xconn->firstpkt[0], xconn->firstpkt + 8, realauthlen); - sk_write(s, (char *)pr->firstpkt, 12); + sk_write(xconn->s, (char *)xconn->firstpkt, 12); if (authstrlen) { - sk_write(s, x11_authnames[pr->disp->localauthproto], + sk_write(xconn->s, x11_authnames[xconn->disp->localauthproto], authstrlen); - sk_write(s, zeroes, 3 & (-authstrlen)); + sk_write(xconn->s, zeroes, 3 & (-authstrlen)); } if (realauthlen) { - sk_write(s, realauthdata, realauthlen); - sk_write(s, zeroes, 3 & (-realauthlen)); + sk_write(xconn->s, realauthdata, realauthlen); + sk_write(xconn->s, zeroes, 3 & (-realauthlen)); } } - pr->verified = 1; + xconn->verified = 1; } /* * After initialisation, just copy data simply. */ - return sk_write(s, data, len); + return sk_write(xconn->s, data, len); } -void x11_send_eof(Socket s) +void x11_send_eof(struct X11Connection *xconn) { - sk_write_eof(s); + sk_write_eof(xconn->s); }