mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
a864f7bb57
The Telnet proxy system is not a proper network protocol - we have no reliable way to receive communication from the proxy telling us whether a password is even required. However, we _do_ know (a) whether the keywords '%user' or '%pass' appeared in the format string stored in the Conf, and (b) whether we actually had a username or a password to substitute into them. So that's how we know whether to ask for a username or a password: if the format string asks for them and the Conf doesn't provide them, we prompt for them at startup. This involved turning TelnetProxyNegotiator into a coroutine (matching all the other proxy types, but previously, it was the only one simple enough not to need to be one), so that it can wait until a response arrives to that prompt. (And also, as it turned out, so that it can wait until setup is finished before even presenting the prompt!) It also involves having format_telnet_command grow an extra output parameter, in the form of 'unsigned *flags', with which it can communicate back to the caller that a username or password was wanted but not found. The other clients of that function (the local proxy implementations) don't use those flags, but if necessary, they could.
103 lines
2.9 KiB
C
103 lines
2.9 KiB
C
/*
|
|
* uxproxy.c: Unix implementation of platform_new_connection(),
|
|
* supporting an OpenSSH-like proxy command.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "tree234.h"
|
|
#include "putty.h"
|
|
#include "network.h"
|
|
#include "proxy/proxy.h"
|
|
|
|
Socket *platform_new_connection(SockAddr *addr, const char *hostname,
|
|
int port, bool privport,
|
|
bool oobinline, bool nodelay, bool keepalive,
|
|
Plug *plug, Conf *conf)
|
|
{
|
|
char *cmd;
|
|
|
|
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);
|
|
if (outfd == -1) {
|
|
sfree(cmd);
|
|
return new_error_socket_fmt(
|
|
plug, "/dev/null: %s", strerror(errno));
|
|
}
|
|
infd = open(cmd, O_RDONLY);
|
|
if (infd == -1) {
|
|
Socket *toret = new_error_socket_fmt(
|
|
plug, "%s: %s", cmd, strerror(errno));
|
|
sfree(cmd);
|
|
close(outfd);
|
|
return toret;
|
|
}
|
|
sfree(cmd);
|
|
inerrfd = -1;
|
|
}
|
|
|
|
return make_fd_socket(infd, outfd, inerrfd, addr, port, plug);
|
|
}
|