1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-03-14 19:13:02 -05:00
Simon Tatham c1ddacf78f 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.
2021-12-22 15:45:41 +00:00

117 lines
3.3 KiB
C

/*
* Network proxy abstraction in PuTTY
*
* A proxy layer, if necessary, wedges itself between the
* network code and the higher level backend.
*
* Supported proxies: HTTP CONNECT, generic telnet, SOCKS 4 & 5
*/
#ifndef PUTTY_PROXY_H
#define PUTTY_PROXY_H
typedef struct ProxySocket ProxySocket;
typedef struct ProxyNegotiator ProxyNegotiator;
typedef struct ProxyNegotiatorVT ProxyNegotiatorVT;
struct ProxySocket {
const char *error;
Socket *sub_socket;
Plug *plug;
SockAddr *remote_addr;
int remote_port;
bufchain pending_output_data;
bufchain pending_oob_output_data;
bufchain pending_input_data;
bool pending_eof;
bool freeze; /* should we freeze the underlying socket when
* we are done with the proxy negotiation? this
* simply caches the value of sk_set_frozen calls.
*/
ProxyNegotiator *pn; /* non-NULL if still negotiating */
bufchain output_from_negotiator;
/* configuration, used to look up proxy settings */
Conf *conf;
/* for interaction with the Seat */
Interactor *clientitr;
LogPolicy *clientlp;
Seat *clientseat;
Socket sock;
Plug plugimpl;
Interactor interactor;
};
struct ProxyNegotiator {
const ProxyNegotiatorVT *vt;
/* Standard fields for any ProxyNegotiator. new() and free() don't
* have to set these up; that's done centrally, to save duplication. */
ProxySocket *ps;
bufchain *input;
bufchain_sink output[1];
Interactor *itr; /* NULL if we are not able to interact with the user */
/* Set to report success during proxy negotiation. */
bool done;
/* Set to report an error during proxy negotiation. The main
* ProxySocket will free it, and will then guarantee never to call
* process_queue again. */
char *error;
/* Set to report user abort during proxy negotiation. */
bool aborted;
};
struct ProxyNegotiatorVT {
ProxyNegotiator *(*new)(const ProxyNegotiatorVT *);
void (*process_queue)(ProxyNegotiator *);
void (*free)(ProxyNegotiator *);
const char *type;
};
static inline ProxyNegotiator *proxy_negotiator_new(
const ProxyNegotiatorVT *vt)
{ return vt->new(vt); }
static inline void proxy_negotiator_process_queue(ProxyNegotiator *pn)
{ pn->vt->process_queue(pn); }
static inline void proxy_negotiator_free(ProxyNegotiator *pn)
{ pn->vt->free(pn); }
extern const ProxyNegotiatorVT http_proxy_negotiator_vt;
extern const ProxyNegotiatorVT socks4_proxy_negotiator_vt;
extern const ProxyNegotiatorVT socks5_proxy_negotiator_vt;
extern const ProxyNegotiatorVT telnet_proxy_negotiator_vt;
/*
* Centralised function to allow ProxyNegotiators to get hold of a
* prompts_t.
*/
prompts_t *proxy_new_prompts(ProxySocket *ps);
/*
* This may be reused by local-command proxies on individual
* platforms.
*/
#define TELNET_CMD_MISSING_USERNAME 0x0001
#define TELNET_CMD_MISSING_PASSWORD 0x0002
char *format_telnet_command(SockAddr *addr, int port, Conf *conf,
unsigned *flags_out);
DeferredSocketOpener *local_proxy_opener(
SockAddr *addr, int port, Plug *plug, Conf *conf, Interactor *itr);
void local_proxy_opener_set_socket(DeferredSocketOpener *opener,
Socket *socket);
char *platform_setup_local_proxy(Socket *socket, const char *cmd);
#include "cproxy.h"
#endif