mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-02-03 21:52:24 +00:00
Actually print announcements of Interactors' identity.
Finally, the payoff from all of this refactoring: now, when a proxy prompts interactively during connection setup, you get a message in advance telling you which Interactor is originating the following messages. To achieve this, I've arranged to link Interactors together into a list, so that any Interactor created by a proxy has a 'parent' pointer pointing to the Interactor its client passed to new_connection(). This allows interactor_announce() to follow the links back up the chain and count them, so that it knows whether it's a primary connection, or a proxy, or a proxy-for-a-proxy, or more generally an nth-order proxy, and can include that in its announcement. And secondly, once interactor_announce() reaches the top of the chain, it can use that as a storage location agreed on by all Interactors in the whole setup, to tell each other which one of them was the last to do anything interactive. Then, whenever there's a change of Interactor, a message can be printed to indicate it to the user; and when the same Interactor does multiple things in succession, you don't get a slew of pointless messages in between them all.
This commit is contained in:
parent
7460594433
commit
215b9d1775
@ -32,6 +32,13 @@ void interactor_return_seat(Interactor *itr)
|
|||||||
interactor_set_seat(itr, realseat);
|
interactor_set_seat(itr, realseat);
|
||||||
tempseat_free(tempseat);
|
tempseat_free(tempseat);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have a parent Interactor, and anyone has ever called
|
||||||
|
* interactor_announce, then all Interactors from now on will
|
||||||
|
* announce themselves even if they have nothing to say.
|
||||||
|
*/
|
||||||
|
interactor_announce(itr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We're about to hand this seat back to the parent Interactor to
|
* We're about to hand this seat back to the parent Interactor to
|
||||||
* do its own thing with. It will typically expect to start in the
|
* do its own thing with. It will typically expect to start in the
|
||||||
@ -44,12 +51,55 @@ void interactor_return_seat(Interactor *itr)
|
|||||||
InteractionReadySeat interactor_announce(Interactor *itr)
|
InteractionReadySeat interactor_announce(Interactor *itr)
|
||||||
{
|
{
|
||||||
Seat *seat = interactor_get_seat(itr);
|
Seat *seat = interactor_get_seat(itr);
|
||||||
|
assert(!is_tempseat(seat) &&
|
||||||
/* TODO: print an announcement of this Interactor's identity, when
|
"Shouldn't call announce when someone else is using our seat");
|
||||||
* appropriate */
|
|
||||||
|
|
||||||
InteractionReadySeat iseat;
|
InteractionReadySeat iseat;
|
||||||
iseat.seat = seat;
|
iseat.seat = seat;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the Interactor at the top of the chain, so that all the
|
||||||
|
* Interactors in a stack can share that one's last-to-talk field.
|
||||||
|
* Also, count how far we had to go to get to it, to put in the
|
||||||
|
* message.
|
||||||
|
*/
|
||||||
|
Interactor *itr_top = itr;
|
||||||
|
unsigned level = 0;
|
||||||
|
while (itr_top->parent) {
|
||||||
|
itr_top = itr_top->parent;
|
||||||
|
level++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generally, we should announce ourself if the previous
|
||||||
|
* Interactor that said anything was not us. That includes if
|
||||||
|
* there was no previous Interactor to talk (i.e. if we're the
|
||||||
|
* first to say anything) - *except* that the primary Interactor
|
||||||
|
* doesn't need to announce itself, if no proxy has intervened
|
||||||
|
* before it.
|
||||||
|
*/
|
||||||
|
bool need_announcement = (itr_top->last_to_talk != itr);
|
||||||
|
if (!itr->parent && !itr_top->last_to_talk)
|
||||||
|
need_announcement = false;
|
||||||
|
|
||||||
|
if (need_announcement) {
|
||||||
|
const char *prefix = "";
|
||||||
|
if (itr_top->last_to_talk != NULL)
|
||||||
|
prefix = "\r\n";
|
||||||
|
|
||||||
|
char *desc = interactor_description(itr);
|
||||||
|
char *adjective = (level == 0 ? dupstr("primary") :
|
||||||
|
level == 1 ? dupstr("proxy") :
|
||||||
|
dupprintf("proxy^%u", level));
|
||||||
|
char *msg = dupprintf("%sMaking %s %s", prefix, adjective, desc);
|
||||||
|
sfree(adjective);
|
||||||
|
sfree(desc);
|
||||||
|
|
||||||
|
seat_antispoof_msg(iseat, msg);
|
||||||
|
sfree(msg);
|
||||||
|
|
||||||
|
itr_top->last_to_talk = itr;
|
||||||
|
}
|
||||||
|
|
||||||
return iseat;
|
return iseat;
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,6 @@ const bool ssh_proxy_supported = true;
|
|||||||
/*
|
/*
|
||||||
* TODO for future work:
|
* TODO for future work:
|
||||||
*
|
*
|
||||||
* All the interactive prompts we present to the main Seat - the host
|
|
||||||
* key and weak-crypto dialog boxes, and all prompts presented via the
|
|
||||||
* userpass_input system - need adjusting so that it's clear to the
|
|
||||||
* user _which_ SSH connection they come from. At the moment, you just
|
|
||||||
* get shown a host key fingerprint or a cryptic "login as:" prompt,
|
|
||||||
* and you have to guess which server you're currently supposed to be
|
|
||||||
* interpreting it relative to.
|
|
||||||
*
|
|
||||||
* If the user manually aborts the attempt to make the proxy SSH
|
* If the user manually aborts the attempt to make the proxy SSH
|
||||||
* connection (e.g. by hitting ^C at a userpass prompt, or refusing to
|
* connection (e.g. by hitting ^C at a userpass prompt, or refusing to
|
||||||
* accept the proxy server's host key), then an assertion failure
|
* accept the proxy server's host key), then an assertion failure
|
||||||
@ -607,6 +599,7 @@ Socket *sshproxy_new_connection(SockAddr *addr, const char *hostname,
|
|||||||
*/
|
*/
|
||||||
if (clientitr) {
|
if (clientitr) {
|
||||||
sp->clientitr = clientitr;
|
sp->clientitr = clientitr;
|
||||||
|
interactor_set_child(sp->clientitr, sp->backend->interactor);
|
||||||
|
|
||||||
sp->clientlp = interactor_logpolicy(clientitr);
|
sp->clientlp = interactor_logpolicy(clientitr);
|
||||||
|
|
||||||
|
15
putty.h
15
putty.h
@ -661,6 +661,19 @@ struct InteractionReadySeat {
|
|||||||
*/
|
*/
|
||||||
struct Interactor {
|
struct Interactor {
|
||||||
const InteractorVtable *vt;
|
const InteractorVtable *vt;
|
||||||
|
|
||||||
|
/* The parent Interactor that we are a proxy for, if any. */
|
||||||
|
Interactor *parent;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're the top-level Interactor (parent==NULL), then this
|
||||||
|
* field records the last Interactor that actually did anything
|
||||||
|
* interactive, so that we know when to announce a changeover
|
||||||
|
* between levels of proxying.
|
||||||
|
*
|
||||||
|
* If parent != NULL, this field is not used.
|
||||||
|
*/
|
||||||
|
Interactor *last_to_talk;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InteractorVtable {
|
struct InteractorVtable {
|
||||||
@ -706,6 +719,8 @@ static inline Seat *interactor_get_seat(Interactor *itr)
|
|||||||
static inline void interactor_set_seat(Interactor *itr, Seat *seat)
|
static inline void interactor_set_seat(Interactor *itr, Seat *seat)
|
||||||
{ itr->vt->set_seat(itr, seat); }
|
{ itr->vt->set_seat(itr, seat); }
|
||||||
|
|
||||||
|
static inline void interactor_set_child(Interactor *parent, Interactor *child)
|
||||||
|
{ child->parent = parent; }
|
||||||
Seat *interactor_borrow_seat(Interactor *itr);
|
Seat *interactor_borrow_seat(Interactor *itr);
|
||||||
void interactor_return_seat(Interactor *itr);
|
void interactor_return_seat(Interactor *itr);
|
||||||
InteractionReadySeat interactor_announce(Interactor *itr);
|
InteractionReadySeat interactor_announce(Interactor *itr);
|
||||||
|
Loading…
Reference in New Issue
Block a user