From 0edafb21b50772bc9e245b7d140aba43875c443d Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 26 Aug 2006 10:20:16 +0000 Subject: [PATCH] ProxyCommand support for Windows, using the new winhandl.c API. Seems a bit clunky when I actually try to use it - not sure why - but I think all the actual functionality is there. git-svn-id: svn://svn.tartarus.org/sgt/putty@6806 cda61777-01e9-0310-a592-d414129be87e --- Recipe | 3 +- windows/wincfg.c | 38 ++++++++++ windows/winproxy.c | 213 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 windows/winproxy.c diff --git a/Recipe b/Recipe index 7aa0d071..779995fe 100644 --- a/Recipe +++ b/Recipe @@ -244,7 +244,8 @@ SFTP = sftp int64 logging # Miscellaneous objects appearing in all the network utilities (not # Pageant or PuTTYgen). MISC = timing misc version settings tree234 proxy -WINMISC = MISC winstore winnet winhandl cmdline windefs winmisc pproxy wintime +WINMISC = MISC winstore winnet winhandl cmdline windefs winmisc winproxy + + wintime UXMISC = MISC uxstore uxsel uxnet cmdline uxmisc uxproxy time OSXMISC = MISC uxstore uxsel osxsel uxnet uxmisc uxproxy time MACMISC = MISC macstore macnet mtcpnet otnet macmisc macabout pproxy diff --git a/windows/wincfg.c b/windows/wincfg.c index 29201f4c..6a970a75 100644 --- a/windows/wincfg.c +++ b/windows/wincfg.c @@ -333,4 +333,42 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, HELPCTX(behaviour_altenter), dlg_stdcheckbox_handler, I(offsetof(Config,fullscreenonaltenter))); + + /* + * Windows supports a local-command proxy. This also means we + * must adjust the text on the `Telnet command' control. + */ + if (!midsession) { + int i; + s = ctrl_getset(b, "Connection/Proxy", "basics", NULL); + for (i = 0; i < s->ncontrols; i++) { + c = s->ctrls[i]; + if (c->generic.type == CTRL_RADIO && + c->generic.context.i == offsetof(Config, proxy_type)) { + assert(c->generic.handler == dlg_stdradiobutton_handler); + c->radio.nbuttons++; + c->radio.buttons = + sresize(c->radio.buttons, c->radio.nbuttons, char *); + c->radio.buttons[c->radio.nbuttons-1] = + dupstr("Local"); + c->radio.buttondata = + sresize(c->radio.buttondata, c->radio.nbuttons, intorptr); + c->radio.buttondata[c->radio.nbuttons-1] = I(PROXY_CMD); + break; + } + } + + for (i = 0; i < s->ncontrols; i++) { + c = s->ctrls[i]; + if (c->generic.type == CTRL_EDITBOX && + c->generic.context.i == + offsetof(Config, proxy_telnet_command)) { + assert(c->generic.handler == dlg_stdeditbox_handler); + sfree(c->generic.label); + c->generic.label = dupstr("Telnet command, or local" + " proxy command"); + break; + } + } + } } diff --git a/windows/winproxy.c b/windows/winproxy.c new file mode 100644 index 00000000..329cb893 --- /dev/null +++ b/windows/winproxy.c @@ -0,0 +1,213 @@ +/* + * winproxy.c: Windows implementation of platform_new_connection(), + * supporting an OpenSSH-like proxy command via the winhandl.c + * mechanism. + */ + +#include +#include + +#define DEFINE_PLUG_METHOD_MACROS +#include "tree234.h" +#include "putty.h" +#include "network.h" +#include "proxy.h" + +typedef struct Socket_localproxy_tag *Local_Proxy_Socket; + +struct Socket_localproxy_tag { + const struct socket_function_table *fn; + /* the above variable absolutely *must* be the first in this structure */ + + HANDLE to_cmd_H, from_cmd_H; + struct handle *to_cmd_h, *from_cmd_h; + + char *error; + + Plug plug; + + void *privptr; +}; + +int localproxy_gotdata(struct handle *h, void *data, int len) +{ + Local_Proxy_Socket ps = (Local_Proxy_Socket) handle_get_privdata(h); + + if (len < 0) { + return plug_closing(ps->plug, "Read error from local proxy command", + 0, 0); + } else if (len == 0) { + return plug_closing(ps->plug, NULL, 0, 0); + } else { + return plug_receive(ps->plug, 1, data, len); + } +} + +void localproxy_sentdata(struct handle *h, int new_backlog) +{ + Local_Proxy_Socket ps = (Local_Proxy_Socket) handle_get_privdata(h); + + plug_sent(ps->plug, new_backlog); +} + +static Plug sk_localproxy_plug (Socket s, Plug p) +{ + Local_Proxy_Socket ps = (Local_Proxy_Socket) s; + Plug ret = ps->plug; + if (p) + ps->plug = p; + return ret; +} + +static void sk_localproxy_close (Socket s) +{ + Local_Proxy_Socket ps = (Local_Proxy_Socket) s; + + handle_free(ps->to_cmd_h); + handle_free(ps->from_cmd_h); + CloseHandle(ps->to_cmd_H); + CloseHandle(ps->from_cmd_H); + + sfree(ps); +} + +static int sk_localproxy_write (Socket s, const char *data, int len) +{ + Local_Proxy_Socket ps = (Local_Proxy_Socket) s; + + return handle_write(ps->to_cmd_h, data, len); +} + +static int sk_localproxy_write_oob(Socket s, const char *data, int len) +{ + /* + * oob data is treated as inband; nasty, but nothing really + * better we can do + */ + return sk_localproxy_write(s, data, len); +} + +static void sk_localproxy_flush(Socket s) +{ + /* Local_Proxy_Socket ps = (Local_Proxy_Socket) s; */ + /* do nothing */ +} + +static void sk_localproxy_set_private_ptr(Socket s, void *ptr) +{ + Local_Proxy_Socket ps = (Local_Proxy_Socket) s; + ps->privptr = ptr; +} + +static void *sk_localproxy_get_private_ptr(Socket s) +{ + Local_Proxy_Socket ps = (Local_Proxy_Socket) s; + return ps->privptr; +} + +static void sk_localproxy_set_frozen(Socket s, int is_frozen) +{ + Local_Proxy_Socket ps = (Local_Proxy_Socket) s; + + /* + * FIXME + */ +} + +static const char *sk_localproxy_socket_error(Socket s) +{ + Local_Proxy_Socket ps = (Local_Proxy_Socket) s; + return ps->error; +} + +Socket platform_new_connection(SockAddr addr, char *hostname, + int port, int privport, + int oobinline, int nodelay, int keepalive, + Plug plug, const Config *cfg) +{ + char *cmd; + + static const struct socket_function_table socket_fn_table = { + sk_localproxy_plug, + sk_localproxy_close, + sk_localproxy_write, + sk_localproxy_write_oob, + sk_localproxy_flush, + sk_localproxy_set_private_ptr, + sk_localproxy_get_private_ptr, + sk_localproxy_set_frozen, + sk_localproxy_socket_error + }; + + Local_Proxy_Socket ret; + HANDLE us_to_cmd, us_from_cmd, cmd_to_us, cmd_from_us; + SECURITY_ATTRIBUTES sa; + STARTUPINFO si; + PROCESS_INFORMATION pi; + + if (cfg->proxy_type != PROXY_CMD) + return NULL; + + cmd = format_telnet_command(addr, port, cfg); + + { + char *msg = dupprintf("Starting local proxy command: %s", cmd); + /* We're allowed to pass NULL here, because we're part of the Windows + * front end so we know logevent doesn't expect any data. */ + logevent(NULL, msg); + sfree(msg); + } + + ret = snew(struct Socket_localproxy_tag); + ret->fn = &socket_fn_table; + ret->plug = plug; + ret->error = NULL; + + /* + * Create the pipes to the proxy command, and spawn the proxy + * command process. + */ + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; /* default */ + sa.bInheritHandle = TRUE; + if (!CreatePipe(&us_from_cmd, &cmd_to_us, &sa, 0)) { + ret->error = dupprintf("Unable to create pipes for proxy command"); + return (Socket)ret; + } + + if (!CreatePipe(&cmd_from_us, &us_to_cmd, &sa, 0)) { + CloseHandle(us_from_cmd); + CloseHandle(cmd_to_us); + ret->error = dupprintf("Unable to create pipes for proxy command"); + return (Socket)ret; + } + + si.cb = sizeof(si); + si.lpReserved = NULL; + si.lpDesktop = NULL; + si.lpTitle = NULL; + si.dwFlags = STARTF_USESTDHANDLES; + si.cbReserved2 = 0; + si.lpReserved2 = NULL; + si.hStdInput = cmd_from_us; + si.hStdOutput = cmd_to_us; + si.hStdError = NULL; + CreateProcess(NULL, cmd, NULL, NULL, TRUE, + CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS, + NULL, NULL, &si, &pi); + + CloseHandle(cmd_from_us); + CloseHandle(cmd_to_us); + + ret->to_cmd_H = us_to_cmd; + ret->from_cmd_H = us_from_cmd; + + ret->from_cmd_h = handle_input_new(ret->from_cmd_H, localproxy_gotdata, ret); + ret->to_cmd_h = handle_output_new(ret->to_cmd_H, + localproxy_sentdata, ret); + + /* We are responsible for this and don't need it any more */ + sk_addr_free(addr); + + return (Socket) ret; +} -- 2.11.0