mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 09:27:59 +00:00
sshproxy: borrow a Seat for host key and crypto dialogs.
This puts the previous commit's framework to practical use. Now the main new_connection() passes its Seat ** through to the SshProxy setup function, which (if the stars align) will actually use it: stash it, return a TempSeat wrapper on it for the main backend to use in the interim, and pass through the GUI dialog prompts for host key confirmation and weak-crypto warnings. This is unfinished at the UI end: those dialog prompts will now need to be much clearer about which SSH server they're talking to (since now there could be two involved), and I haven't made that change yet. I haven't attempted to deal with get_userpass_input yet, though. That's much harder, and I'm still working on it.
This commit is contained in:
parent
6d272ee007
commit
b1d01cd3c7
@ -161,7 +161,7 @@ Socket *sshproxy_new_connection(SockAddr *addr, const char *hostname,
|
|||||||
int port, bool privport,
|
int port, bool privport,
|
||||||
bool oobinline, bool nodelay, bool keepalive,
|
bool oobinline, bool nodelay, bool keepalive,
|
||||||
Plug *plug, Conf *conf,
|
Plug *plug, Conf *conf,
|
||||||
LogPolicy *clientlp);
|
LogPolicy *clientlp, Seat **clientseat);
|
||||||
|
|
||||||
/* socket functions */
|
/* socket functions */
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ Socket *sshproxy_new_connection(SockAddr *addr, const char *hostname,
|
|||||||
int port, bool privport,
|
int port, bool privport,
|
||||||
bool oobinline, bool nodelay, bool keepalive,
|
bool oobinline, bool nodelay, bool keepalive,
|
||||||
Plug *plug, Conf *conf,
|
Plug *plug, Conf *conf,
|
||||||
LogPolicy *clientlp)
|
LogPolicy *clientlp, Seat **clientseat)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
4
proxy.c
4
proxy.c
@ -395,7 +395,7 @@ static const PlugVtable ProxySocket_plugvt = {
|
|||||||
Socket *new_connection(SockAddr *addr, const char *hostname,
|
Socket *new_connection(SockAddr *addr, const char *hostname,
|
||||||
int port, bool privport,
|
int port, bool privport,
|
||||||
bool oobinline, bool nodelay, bool keepalive,
|
bool oobinline, bool nodelay, bool keepalive,
|
||||||
Plug *plug, Conf *conf, LogPolicy *lp)
|
Plug *plug, Conf *conf, LogPolicy *lp, Seat **seat)
|
||||||
{
|
{
|
||||||
int type = conf_get_int(conf, CONF_proxy_type);
|
int type = conf_get_int(conf, CONF_proxy_type);
|
||||||
|
|
||||||
@ -411,7 +411,7 @@ Socket *new_connection(SockAddr *addr, const char *hostname,
|
|||||||
if (type == PROXY_SSH &&
|
if (type == PROXY_SSH &&
|
||||||
(sret = sshproxy_new_connection(addr, hostname, port, privport,
|
(sret = sshproxy_new_connection(addr, hostname, port, privport,
|
||||||
oobinline, nodelay, keepalive,
|
oobinline, nodelay, keepalive,
|
||||||
plug, conf, lp)) != NULL)
|
plug, conf, lp, seat)) != NULL)
|
||||||
return sret;
|
return sret;
|
||||||
|
|
||||||
if ((sret = platform_new_connection(addr, hostname, port, privport,
|
if ((sret = platform_new_connection(addr, hostname, port, privport,
|
||||||
|
117
sshproxy.c
117
sshproxy.c
@ -16,37 +16,17 @@ const bool ssh_proxy_supported = true;
|
|||||||
/*
|
/*
|
||||||
* TODO for future work:
|
* TODO for future work:
|
||||||
*
|
*
|
||||||
* At present, this use of SSH as a proxy is mostly noninteractive. In
|
* At present, this use of SSH as a proxy is not fully interactive.
|
||||||
* our implementations of the Seat trait, every method that involves
|
* We're borrowing the main backend's LogPolicy for queries like
|
||||||
* interactively prompting the user is implemented by pretending the
|
* askappend(), and we're borrowing the main backend's Seat for host
|
||||||
* user gave a safe default answer. So the effect is very much as if
|
* key prompts and weak-crypto warnings, but one thing we still don't
|
||||||
* you'd used 'plink -batch' as a proxy subprocess - password prompts
|
* have is a functioning implementation of seat_get_userpass_input
|
||||||
* are cancelled and any dubious host key or crypto primitive is
|
* that can display the proxy SSH connection's password prompts (or
|
||||||
* unconditionally rejected - except that it all happens in-process,
|
* similar) in the terminal window before handing the terminal back to
|
||||||
* making it mildly more convenient to set up, perhaps a hair faster,
|
* the main connection.
|
||||||
* and you get all the Event Log data in one place.
|
|
||||||
*
|
*
|
||||||
* But the biggest benefit of in-process SSH proxying would be that
|
* Also, the host key and weak-crypto prompts need adjusting so that
|
||||||
* the interactive prompts from the sub-SSH can be passed through to
|
* it's clear to the user which SSH connection they come from.
|
||||||
* the end user. If your jump host and your ultimate destination host
|
|
||||||
* both require password authentication, you should be able to type
|
|
||||||
* both password in sequence into the PuTTY terminal window; if you're
|
|
||||||
* running a session of this kind for the first time, you should be
|
|
||||||
* able to confirm both host keys one after another. In the current
|
|
||||||
* state of the code, none of that is yet implemented: we're borrowing
|
|
||||||
* the client LogPolicy for things like askappend(), but not the Seat,
|
|
||||||
* which is where all the really important stuff lives.
|
|
||||||
*
|
|
||||||
* To fix that, we'd have to start by arranging for this proxy
|
|
||||||
* implementation to get hold of the 'real' (outer) Seat object, which
|
|
||||||
* means passing it to new_connection as we're already doing with
|
|
||||||
* LogPolicy. Then, each method in this file that receives an
|
|
||||||
* interactive prompt request would handle it by passing it on to the
|
|
||||||
* client Seat if present, with some kind of tweak that would allow
|
|
||||||
* the end user to see clearly that the prompt had come from the proxy
|
|
||||||
* SSH connection rather than the primary one. If no client Seat was
|
|
||||||
* present, we'd have no choice but to fall back to the existing
|
|
||||||
* behaviour of behaving as if in batch mode.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct SshProxy {
|
typedef struct SshProxy {
|
||||||
@ -55,6 +35,7 @@ typedef struct SshProxy {
|
|||||||
LogContext *logctx;
|
LogContext *logctx;
|
||||||
Backend *backend;
|
Backend *backend;
|
||||||
LogPolicy *clientlp;
|
LogPolicy *clientlp;
|
||||||
|
Seat *clientseat;
|
||||||
|
|
||||||
ProxyStderrBuf psb;
|
ProxyStderrBuf psb;
|
||||||
Plug *plug;
|
Plug *plug;
|
||||||
@ -352,16 +333,20 @@ static int sshproxy_verify_ssh_host_key(
|
|||||||
{
|
{
|
||||||
SshProxy *sp = container_of(seat, SshProxy, seat);
|
SshProxy *sp = container_of(seat, SshProxy, seat);
|
||||||
|
|
||||||
|
if (sp->clientseat) {
|
||||||
|
/*
|
||||||
|
* If we have access to the outer Seat, pass this prompt
|
||||||
|
* request on to it. FIXME: appropriately adjusted
|
||||||
|
*/
|
||||||
|
return seat_verify_ssh_host_key(
|
||||||
|
sp->clientseat, host, port, keytype, keystr, keydisp,
|
||||||
|
key_fingerprints, callback, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: if we had access to the outer Seat, we could pass on this
|
* Otherwise, behave as if we're in batch mode: directly verify
|
||||||
* request to *its* verify_ssh_host_key method, appropriately
|
* the host key against the cache, and if that fails, take the
|
||||||
* adjusted to indicate that it comes from the proxy SSH
|
* safe option in the absence of interactive confirmation, and
|
||||||
* connection. (But we'd still have to have this code as a
|
|
||||||
* fallback in case there isn't a Seat available.)
|
|
||||||
*
|
|
||||||
* Instead, we have to behave as if we're in batch mode: directly
|
|
||||||
* verify the host key against the cache, and if that fails, take
|
|
||||||
* the safe option in the absence of interactive confirmation, and
|
|
||||||
* abort the connection.
|
* abort the connection.
|
||||||
*/
|
*/
|
||||||
int hkstatus = verify_host_key(host, port, keytype, keystr);
|
int hkstatus = verify_host_key(host, port, keytype, keystr);
|
||||||
@ -394,12 +379,18 @@ static int sshproxy_confirm_weak_crypto_primitive(
|
|||||||
{
|
{
|
||||||
SshProxy *sp = container_of(seat, SshProxy, seat);
|
SshProxy *sp = container_of(seat, SshProxy, seat);
|
||||||
|
|
||||||
|
if (sp->clientseat) {
|
||||||
|
/*
|
||||||
|
* If we have access to the outer Seat, pass this prompt
|
||||||
|
* request on to it. FIXME: appropriately adjusted
|
||||||
|
*/
|
||||||
|
return seat_confirm_weak_crypto_primitive(
|
||||||
|
sp->clientseat, algtype, algname, callback, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: if we had access to the outer Seat, we could pass on this
|
* Otherwise, behave as if we're in batch mode: take the safest
|
||||||
* request to *its* confirm_weak_crypto_primitive method,
|
* option.
|
||||||
* appropriately adjusted to indicate that it comes from the proxy
|
|
||||||
* SSH connection. (But we'd still have to have this code as a
|
|
||||||
* fallback in case there isn't a Seat available.)
|
|
||||||
*/
|
*/
|
||||||
sshproxy_error(sp, "First %s supported by server is %s, below warning "
|
sshproxy_error(sp, "First %s supported by server is %s, below warning "
|
||||||
"threshold. Abandoning proxy SSH connection.",
|
"threshold. Abandoning proxy SSH connection.",
|
||||||
@ -413,12 +404,18 @@ static int sshproxy_confirm_weak_cached_hostkey(
|
|||||||
{
|
{
|
||||||
SshProxy *sp = container_of(seat, SshProxy, seat);
|
SshProxy *sp = container_of(seat, SshProxy, seat);
|
||||||
|
|
||||||
|
if (sp->clientseat) {
|
||||||
|
/*
|
||||||
|
* If we have access to the outer Seat, pass this prompt
|
||||||
|
* request on to it. FIXME: appropriately adjusted
|
||||||
|
*/
|
||||||
|
return seat_confirm_weak_cached_hostkey(
|
||||||
|
sp->clientseat, algname, betteralgs, callback, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: if we had access to the outer Seat, we could pass on this
|
* Otherwise, behave as if we're in batch mode: take the safest
|
||||||
* request to *its* confirm_weak_cached_hostkey method,
|
* option.
|
||||||
* appropriately adjusted to indicate that it comes from the proxy
|
|
||||||
* SSH connection. (But we'd still have to have this code as a
|
|
||||||
* fallback in case there isn't a Seat available.)
|
|
||||||
*/
|
*/
|
||||||
sshproxy_error(sp, "First host key type stored for server is %s, below "
|
sshproxy_error(sp, "First host key type stored for server is %s, below "
|
||||||
"warning threshold. Abandoning proxy SSH connection.",
|
"warning threshold. Abandoning proxy SSH connection.",
|
||||||
@ -478,7 +475,7 @@ Socket *sshproxy_new_connection(SockAddr *addr, const char *hostname,
|
|||||||
int port, bool privport,
|
int port, bool privport,
|
||||||
bool oobinline, bool nodelay, bool keepalive,
|
bool oobinline, bool nodelay, bool keepalive,
|
||||||
Plug *plug, Conf *clientconf,
|
Plug *plug, Conf *clientconf,
|
||||||
LogPolicy *clientlp)
|
LogPolicy *clientlp, Seat **clientseat)
|
||||||
{
|
{
|
||||||
SshProxy *sp = snew(SshProxy);
|
SshProxy *sp = snew(SshProxy);
|
||||||
memset(sp, 0, sizeof(*sp));
|
memset(sp, 0, sizeof(*sp));
|
||||||
@ -588,7 +585,27 @@ Socket *sshproxy_new_connection(SockAddr *addr, const char *hostname,
|
|||||||
|
|
||||||
sfree(realhost);
|
sfree(realhost);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we've been given useful bits and pieces for interacting with
|
||||||
|
* the end user, squirrel them away now.
|
||||||
|
*/
|
||||||
sp->clientlp = clientlp;
|
sp->clientlp = clientlp;
|
||||||
|
if (clientseat && (backvt->flags & BACKEND_NOTIFIES_SESSION_START)) {
|
||||||
|
/*
|
||||||
|
* We can only keep the client's Seat if our own backend will
|
||||||
|
* tell us when to give it back. (SSH-based backends _should_
|
||||||
|
* do that, but we check the flag here anyway.)
|
||||||
|
*
|
||||||
|
* Also, check if the client already has a TempSeat, and if
|
||||||
|
* so, don't wrap it with another one.
|
||||||
|
*/
|
||||||
|
if (is_tempseat(*clientseat)) {
|
||||||
|
sp->clientseat = tempseat_get_real(*clientseat);
|
||||||
|
} else {
|
||||||
|
sp->clientseat = *clientseat;
|
||||||
|
*clientseat = tempseat_new(sp->clientseat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &sp->sock;
|
return &sp->sock;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user