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.
116 lines
3.2 KiB
C
116 lines
3.2 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);
|
|
|
|
/*
|
|
* These are implemented in cproxy.c or nocproxy.c, depending on
|
|
* whether encrypted proxy authentication is available.
|
|
*/
|
|
extern const bool socks5_chap_available;
|
|
strbuf *chap_response(ptrlen challenge, ptrlen password);
|
|
|
|
#endif
|