1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-01 11:32:48 -05:00

Rewrite local-proxy system to allow interactive prompts.

This fills in the remaining gap in the interactive prompt rework of
the proxy system in general. If you used the Telnet proxy with a
command containing %user or %pass, and hadn't filled in those
variables in the PuTTY config, then proxy/telnet.c would prompt you at
run time to enter the proxy auth details. But the local proxy command,
which uses the same format_telnet_command function, would not do that.
Now it does!

I've implemented this by moving the formatting of the proxy command
into a new module proxy/local.c, shared between both the Unix and
Windows local-proxy implementations. That module implements a
DeferredSocketOpener, which constructs the proxy command (prompting
first if necessary), and once it's constructed, hands it to a
per-platform function platform_setup_local_proxy().

So each platform-specific proxy function, instead of starting a
subprocess there and then and passing its details to make_fd_socket or
make_handle_socket, now returns a _deferred_ version of one of those
sockets, with the DeferredSocketOpener being the thing in
proxy/local.c. When that calls back to platform_setup_local_proxy(),
we actually start the subprocess and pass the resulting fds/handles to
the deferred socket to un-defer it.

A side effect of the rewrite is that when proxy commands are logged in
the Event Log, they now get the same amenities as in the Telnet proxy
type: the proxy password is sanitised out, and any difficult
characters are escaped.
This commit is contained in:
Simon Tatham
2021-12-22 12:03:28 +00:00
parent ca70b1285d
commit c1ddacf78f
5 changed files with 363 additions and 98 deletions

View File

@ -14,79 +14,73 @@
#include "network.h"
#include "proxy/proxy.h"
char *platform_setup_local_proxy(Socket *socket, const char *cmd)
{
/*
* Create the pipes to the proxy command, and spawn the proxy
* command process.
*/
int to_cmd_pipe[2], from_cmd_pipe[2], cmd_err_pipe[2];
if (pipe(to_cmd_pipe) < 0 ||
pipe(from_cmd_pipe) < 0 ||
pipe(cmd_err_pipe) < 0) {
return dupprintf("pipe: %s", strerror(errno));
}
cloexec(to_cmd_pipe[1]);
cloexec(from_cmd_pipe[0]);
cloexec(cmd_err_pipe[0]);
int pid = fork();
if (pid == 0) {
close(0);
close(1);
dup2(to_cmd_pipe[0], 0);
dup2(from_cmd_pipe[1], 1);
close(to_cmd_pipe[0]);
close(from_cmd_pipe[1]);
dup2(cmd_err_pipe[1], 2);
noncloexec(0);
noncloexec(1);
execl("/bin/sh", "sh", "-c", cmd, (void *)NULL);
_exit(255);
}
if (pid < 0) {
return dupprintf("fork: %s", strerror(errno));
}
close(to_cmd_pipe[0]);
close(from_cmd_pipe[1]);
close(cmd_err_pipe[1]);
setup_fd_socket(socket, from_cmd_pipe[0], to_cmd_pipe[1], cmd_err_pipe[0]);
return NULL;
}
Socket *platform_new_connection(SockAddr *addr, const char *hostname,
int port, bool privport,
bool oobinline, bool nodelay, bool keepalive,
Plug *plug, Conf *conf, Interactor *itr)
{
char *cmd;
switch (conf_get_int(conf, CONF_proxy_type)) {
case PROXY_CMD: {
DeferredSocketOpener *opener = local_proxy_opener(
addr, port, plug, conf, itr);
Socket *socket = make_deferred_fd_socket(opener, addr, port, plug);
local_proxy_opener_set_socket(opener, socket);
return socket;
}
int to_cmd_pipe[2], from_cmd_pipe[2], cmd_err_pipe[2], pid, proxytype;
int infd, outfd, inerrfd;
proxytype = conf_get_int(conf, CONF_proxy_type);
if (proxytype != PROXY_CMD && proxytype != PROXY_FUZZ)
return NULL;
if (proxytype == PROXY_CMD) {
cmd = format_telnet_command(addr, port, conf, NULL);
{
char *logmsg = dupprintf("Starting local proxy command: %s", cmd);
plug_log(plug, PLUGLOG_PROXY_MSG, NULL, 0, logmsg, 0);
sfree(logmsg);
}
/*
* Create the pipes to the proxy command, and spawn the proxy
* command process.
*/
if (pipe(to_cmd_pipe) < 0 ||
pipe(from_cmd_pipe) < 0 ||
pipe(cmd_err_pipe) < 0) {
sfree(cmd);
return new_error_socket_fmt(plug, "pipe: %s", strerror(errno));
}
cloexec(to_cmd_pipe[1]);
cloexec(from_cmd_pipe[0]);
cloexec(cmd_err_pipe[0]);
pid = fork();
if (pid == 0) {
close(0);
close(1);
dup2(to_cmd_pipe[0], 0);
dup2(from_cmd_pipe[1], 1);
close(to_cmd_pipe[0]);
close(from_cmd_pipe[1]);
dup2(cmd_err_pipe[1], 2);
noncloexec(0);
noncloexec(1);
execl("/bin/sh", "sh", "-c", cmd, (void *)NULL);
_exit(255);
}
sfree(cmd);
if (pid < 0)
return new_error_socket_fmt(plug, "fork: %s", strerror(errno));
close(to_cmd_pipe[0]);
close(from_cmd_pipe[1]);
close(cmd_err_pipe[1]);
outfd = to_cmd_pipe[1];
infd = from_cmd_pipe[0];
inerrfd = cmd_err_pipe[0];
} else {
cmd = format_telnet_command(addr, port, conf, NULL);
outfd = open("/dev/null", O_WRONLY);
case PROXY_FUZZ: {
char *cmd = format_telnet_command(addr, port, conf, NULL);
int outfd = open("/dev/null", O_WRONLY);
if (outfd == -1) {
sfree(cmd);
return new_error_socket_fmt(
plug, "/dev/null: %s", strerror(errno));
}
infd = open(cmd, O_RDONLY);
int infd = open(cmd, O_RDONLY);
if (infd == -1) {
Socket *toret = new_error_socket_fmt(
plug, "%s: %s", cmd, strerror(errno));
@ -95,8 +89,10 @@ Socket *platform_new_connection(SockAddr *addr, const char *hostname,
return toret;
}
sfree(cmd);
inerrfd = -1;
}
return make_fd_socket(infd, outfd, -1, addr, port, plug);
}
return make_fd_socket(infd, outfd, inerrfd, addr, port, plug);
default:
return NULL;
}
}