mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-03-14 19:13:02 -05:00

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.
117 lines
3.3 KiB
C
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
|