1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Divide seat_set_trust_status into query and update.

This complicates the API in one sense (more separate functions), but
in another sense, simplifies it (each function does something
simpler). When I start putting one Seat in front of another during SSH
proxying, the latter will be more important - in particular, it means
you can find out _whether_ a seat can support changing trust status
without having to actually attempt a destructive modification.
This commit is contained in:
Simon Tatham 2021-09-12 09:52:46 +01:00
parent c06c9c730f
commit 82177956da
16 changed files with 88 additions and 33 deletions

3
pscp.c
View File

@ -82,7 +82,8 @@ static const SeatVtable pscp_seat_vt = {
.get_windowid = nullseat_get_windowid, .get_windowid = nullseat_get_windowid,
.get_window_pixel_size = nullseat_get_window_pixel_size, .get_window_pixel_size = nullseat_get_window_pixel_size,
.stripctrl_new = console_stripctrl_new, .stripctrl_new = console_stripctrl_new,
.set_trust_status = nullseat_set_trust_status_vacuously, .set_trust_status = nullseat_set_trust_status,
.can_set_trust_status = nullseat_can_set_trust_status_yes,
.verbose = cmdline_seat_verbose, .verbose = cmdline_seat_verbose,
.interactive = nullseat_interactive_no, .interactive = nullseat_interactive_no,
.get_cursor_position = nullseat_get_cursor_position, .get_cursor_position = nullseat_get_cursor_position,

View File

@ -64,7 +64,8 @@ static const SeatVtable psftp_seat_vt = {
.get_windowid = nullseat_get_windowid, .get_windowid = nullseat_get_windowid,
.get_window_pixel_size = nullseat_get_window_pixel_size, .get_window_pixel_size = nullseat_get_window_pixel_size,
.stripctrl_new = console_stripctrl_new, .stripctrl_new = console_stripctrl_new,
.set_trust_status = nullseat_set_trust_status_vacuously, .set_trust_status = nullseat_set_trust_status,
.can_set_trust_status = nullseat_can_set_trust_status_yes,
.verbose = cmdline_seat_verbose, .verbose = cmdline_seat_verbose,
.interactive = nullseat_interactive_yes, .interactive = nullseat_interactive_yes,
.get_cursor_position = nullseat_get_cursor_position, .get_cursor_position = nullseat_get_cursor_position,

22
putty.h
View File

@ -1097,13 +1097,19 @@ struct SeatVtable {
* (and hence, can be trusted if it's asking you for secrets such * (and hence, can be trusted if it's asking you for secrets such
* as your passphrase); false means output is coming from the * as your passphrase); false means output is coming from the
* server. * server.
*/
void (*set_trust_status)(Seat *seat, bool trusted);
/*
* Query whether this Seat can do anything user-visible in
* response to set_trust_status.
* *
* Returns true if the seat has a way to indicate this * Returns true if the seat has a way to indicate this
* distinction. Returns false if not, in which case the backend * distinction. Returns false if not, in which case the backend
* should use a fallback defence against spoofing of PuTTY's local * should use a fallback defence against spoofing of PuTTY's local
* prompts by malicious servers. * prompts by malicious servers.
*/ */
bool (*set_trust_status)(Seat *seat, bool trusted); bool (*can_set_trust_status)(Seat *seat);
/* /*
* Ask the seat whether it would like verbose messages. * Ask the seat whether it would like verbose messages.
@ -1169,8 +1175,10 @@ static inline bool seat_get_window_pixel_size(Seat *seat, int *w, int *h)
static inline StripCtrlChars *seat_stripctrl_new( static inline StripCtrlChars *seat_stripctrl_new(
Seat *seat, BinarySink *bs, SeatInteractionContext sic) Seat *seat, BinarySink *bs, SeatInteractionContext sic)
{ return seat->vt->stripctrl_new(seat, bs, sic); } { return seat->vt->stripctrl_new(seat, bs, sic); }
static inline bool seat_set_trust_status(Seat *seat, bool trusted) static inline void seat_set_trust_status(Seat *seat, bool trusted)
{ return seat->vt->set_trust_status(seat, trusted); } { seat->vt->set_trust_status(seat, trusted); }
static inline bool seat_can_set_trust_status(Seat *seat)
{ return seat->vt->can_set_trust_status(seat); }
static inline bool seat_verbose(Seat *seat) static inline bool seat_verbose(Seat *seat)
{ return seat->vt->verbose(seat); } { return seat->vt->verbose(seat); }
static inline bool seat_interactive(Seat *seat) static inline bool seat_interactive(Seat *seat)
@ -1229,8 +1237,9 @@ bool nullseat_get_windowid(Seat *seat, long *id_out);
bool nullseat_get_window_pixel_size(Seat *seat, int *width, int *height); bool nullseat_get_window_pixel_size(Seat *seat, int *width, int *height);
StripCtrlChars *nullseat_stripctrl_new( StripCtrlChars *nullseat_stripctrl_new(
Seat *seat, BinarySink *bs_out, SeatInteractionContext sic); Seat *seat, BinarySink *bs_out, SeatInteractionContext sic);
bool nullseat_set_trust_status(Seat *seat, bool trusted); void nullseat_set_trust_status(Seat *seat, bool trusted);
bool nullseat_set_trust_status_vacuously(Seat *seat, bool trusted); bool nullseat_can_set_trust_status_yes(Seat *seat);
bool nullseat_can_set_trust_status_no(Seat *seat);
bool nullseat_verbose_no(Seat *seat); bool nullseat_verbose_no(Seat *seat);
bool nullseat_verbose_yes(Seat *seat); bool nullseat_verbose_yes(Seat *seat);
bool nullseat_interactive_no(Seat *seat); bool nullseat_interactive_no(Seat *seat);
@ -1255,7 +1264,8 @@ int console_confirm_weak_cached_hostkey(
void (*callback)(void *ctx, int result), void *ctx); void (*callback)(void *ctx, int result), void *ctx);
StripCtrlChars *console_stripctrl_new( StripCtrlChars *console_stripctrl_new(
Seat *seat, BinarySink *bs_out, SeatInteractionContext sic); Seat *seat, BinarySink *bs_out, SeatInteractionContext sic);
bool console_set_trust_status(Seat *seat, bool trusted); void console_set_trust_status(Seat *seat, bool trusted);
bool console_can_set_trust_status(Seat *seat);
/* /*
* Other centralised seat functions. * Other centralised seat functions.

View File

@ -543,5 +543,6 @@ SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan)
bool ssh1_connection_need_antispoof_prompt(struct ssh1_connection_state *s) bool ssh1_connection_need_antispoof_prompt(struct ssh1_connection_state *s)
{ {
return !seat_set_trust_status(s->ppl.seat, false); seat_set_trust_status(s->ppl.seat, false);
return !seat_can_set_trust_status(s->ppl.seat);
} }

View File

@ -500,6 +500,7 @@ void ssh2channel_send_terminal_size_change(SshChannel *sc, int w, int h)
bool ssh2_connection_need_antispoof_prompt(struct ssh2_connection_state *s) bool ssh2_connection_need_antispoof_prompt(struct ssh2_connection_state *s)
{ {
bool success = seat_set_trust_status(s->ppl.seat, false); seat_set_trust_status(s->ppl.seat, false);
bool success = seat_can_set_trust_status(s->ppl.seat);
return (!success && !ssh_is_bare(s->ppl.ssh)); return (!success && !ssh_is_bare(s->ppl.ssh));
} }

View File

@ -125,6 +125,7 @@ static const SeatVtable server_seat_vt = {
.get_window_pixel_size = nullseat_get_window_pixel_size, .get_window_pixel_size = nullseat_get_window_pixel_size,
.stripctrl_new = nullseat_stripctrl_new, .stripctrl_new = nullseat_stripctrl_new,
.set_trust_status = nullseat_set_trust_status, .set_trust_status = nullseat_set_trust_status,
.can_set_trust_status = nullseat_can_set_trust_status_no,
.verbose = nullseat_verbose_no, .verbose = nullseat_verbose_no,
.interactive = nullseat_interactive_no, .interactive = nullseat_interactive_no,
.get_cursor_position = nullseat_get_cursor_position, .get_cursor_position = nullseat_get_cursor_position,

View File

@ -204,6 +204,7 @@ static const SeatVtable sesschan_seat_vt = {
.get_window_pixel_size = sesschan_get_window_pixel_size, .get_window_pixel_size = sesschan_get_window_pixel_size,
.stripctrl_new = nullseat_stripctrl_new, .stripctrl_new = nullseat_stripctrl_new,
.set_trust_status = nullseat_set_trust_status, .set_trust_status = nullseat_set_trust_status,
.can_set_trust_status = nullseat_can_set_trust_status_no,
.verbose = nullseat_verbose_no, .verbose = nullseat_verbose_no,
.interactive = nullseat_interactive_no, .interactive = nullseat_interactive_no,
.get_cursor_position = nullseat_get_cursor_position, .get_cursor_position = nullseat_get_cursor_position,

View File

@ -1950,7 +1950,8 @@ static void ssh2_userauth_antispoof_msg(
struct ssh2_userauth_state *s, const char *msg) struct ssh2_userauth_state *s, const char *msg)
{ {
strbuf *sb = strbuf_new(); strbuf *sb = strbuf_new();
if (seat_set_trust_status(s->ppl.seat, true)) { seat_set_trust_status(s->ppl.seat, true);
if (seat_can_set_trust_status(s->ppl.seat)) {
/* /*
* If the seat can directly indicate that this message is * If the seat can directly indicate that this message is
* generated by the client, then we can just use the message * generated by the client, then we can just use the message

View File

@ -405,20 +405,24 @@ static int sshproxy_confirm_weak_cached_hostkey(
return 0; return 0;
} }
static bool sshproxy_set_trust_status(Seat *seat, bool trusted) static void sshproxy_set_trust_status(Seat *seat, bool trusted)
{ {
/* /*
* This is called by the proxy SSH connection, to set our Seat * This is called by the proxy SSH connection, to set our Seat
* into a given trust status. We can safely do nothing here and * into a given trust status. We can safely do nothing here, and
* return true to claim we did something (effectively eliminating * have can_set_trust_status return true to claim we did something
* the spoofing defences completely, by suppressing the 'press * (effectively eliminating the spoofing defences completely, by
* Return to begin session' prompt and not providing anything in * suppressing the 'press Return to begin session' prompt and not
* place of it), on the basis that session I/O from the proxy SSH * providing anything in place of it), on the basis that session
* connection is never passed directly on to the end user, so a * I/O from the proxy SSH connection is never passed directly on
* malicious proxy SSH server wouldn't be able to spoof our human * to the end user, so a malicious proxy SSH server wouldn't be
* in any case. * able to spoof our human in any case.
*/ */
return true; }
static bool sshproxy_can_set_trust_status(Seat *seat)
{
return true; /* see comment above */
} }
static const SeatVtable SshProxy_seat_vt = { static const SeatVtable SshProxy_seat_vt = {
@ -442,6 +446,7 @@ static const SeatVtable SshProxy_seat_vt = {
.get_window_pixel_size = nullseat_get_window_pixel_size, .get_window_pixel_size = nullseat_get_window_pixel_size,
.stripctrl_new = nullseat_stripctrl_new, .stripctrl_new = nullseat_stripctrl_new,
.set_trust_status = sshproxy_set_trust_status, .set_trust_status = sshproxy_set_trust_status,
.can_set_trust_status = sshproxy_can_set_trust_status,
.verbose = nullseat_verbose_no, .verbose = nullseat_verbose_no,
.interactive = nullseat_interactive_no, .interactive = nullseat_interactive_no,
.get_cursor_position = nullseat_get_cursor_position, .get_cursor_position = nullseat_get_cursor_position,

View File

@ -321,7 +321,16 @@ int console_askappend(LogPolicy *lp, Filename *filename,
} }
bool console_antispoof_prompt = true; bool console_antispoof_prompt = true;
bool console_set_trust_status(Seat *seat, bool trusted)
void console_set_trust_status(Seat *seat, bool trusted)
{
/* Do nothing in response to a change of trust status, because
* there's nothing we can do in a console environment. However,
* the query function below will make a fiddly decision about
* whether to tell the backend to enable fallback handling. */
}
bool console_can_set_trust_status(Seat *seat)
{ {
if (console_batch_mode || !is_interactive() || !console_antispoof_prompt) { if (console_batch_mode || !is_interactive() || !console_antispoof_prompt) {
/* /*
@ -334,8 +343,8 @@ bool console_set_trust_status(Seat *seat, bool trusted)
* prompt, the user couldn't respond to it via the terminal * prompt, the user couldn't respond to it via the terminal
* anyway. * anyway.
* *
* We also vacuously return success if the user has purposely * We also return true without enabling any defences if the
* disabled the antispoof prompt. * user has purposely disabled the antispoof prompt.
*/ */
return true; return true;
} }

View File

@ -407,6 +407,7 @@ static const SeatVtable plink_seat_vt = {
.get_window_pixel_size = nullseat_get_window_pixel_size, .get_window_pixel_size = nullseat_get_window_pixel_size,
.stripctrl_new = console_stripctrl_new, .stripctrl_new = console_stripctrl_new,
.set_trust_status = console_set_trust_status, .set_trust_status = console_set_trust_status,
.can_set_trust_status = console_can_set_trust_status,
.verbose = cmdline_seat_verbose, .verbose = cmdline_seat_verbose,
.interactive = plink_seat_interactive, .interactive = plink_seat_interactive,
.get_cursor_position = nullseat_get_cursor_position, .get_cursor_position = nullseat_get_cursor_position,

View File

@ -383,7 +383,8 @@ static const char *gtk_seat_get_x_display(Seat *seat);
#ifndef NOT_X_WINDOWS #ifndef NOT_X_WINDOWS
static bool gtk_seat_get_windowid(Seat *seat, long *id); static bool gtk_seat_get_windowid(Seat *seat, long *id);
#endif #endif
static bool gtk_seat_set_trust_status(Seat *seat, bool trusted); static void gtk_seat_set_trust_status(Seat *seat, bool trusted);
static bool gtk_seat_can_set_trust_status(Seat *seat);
static bool gtk_seat_get_cursor_position(Seat *seat, int *x, int *y); static bool gtk_seat_get_cursor_position(Seat *seat, int *x, int *y);
static const SeatVtable gtk_seat_vt = { static const SeatVtable gtk_seat_vt = {
@ -411,6 +412,7 @@ static const SeatVtable gtk_seat_vt = {
.get_window_pixel_size = gtk_seat_get_window_pixel_size, .get_window_pixel_size = gtk_seat_get_window_pixel_size,
.stripctrl_new = gtk_seat_stripctrl_new, .stripctrl_new = gtk_seat_stripctrl_new,
.set_trust_status = gtk_seat_set_trust_status, .set_trust_status = gtk_seat_set_trust_status,
.can_set_trust_status = gtk_seat_can_set_trust_status,
.verbose = nullseat_verbose_yes, .verbose = nullseat_verbose_yes,
.interactive = nullseat_interactive_yes, .interactive = nullseat_interactive_yes,
.get_cursor_position = gtk_seat_get_cursor_position, .get_cursor_position = gtk_seat_get_cursor_position,
@ -5415,10 +5417,14 @@ void new_session_window(Conf *conf, const char *geometry_string)
ldisc_echoedit_update(inst->ldisc); /* cause ldisc to notice changes */ ldisc_echoedit_update(inst->ldisc); /* cause ldisc to notice changes */
} }
static bool gtk_seat_set_trust_status(Seat *seat, bool trusted) static void gtk_seat_set_trust_status(Seat *seat, bool trusted)
{ {
GtkFrontend *inst = container_of(seat, GtkFrontend, seat); GtkFrontend *inst = container_of(seat, GtkFrontend, seat);
term_set_trust_status(inst->term, trusted); term_set_trust_status(inst->term, trusted);
}
static bool gtk_seat_can_set_trust_status(Seat *seat)
{
return true; return true;
} }

View File

@ -35,8 +35,9 @@ bool nullseat_get_window_pixel_size(
Seat *seat, int *width, int *height) { return false; } Seat *seat, int *width, int *height) { return false; }
StripCtrlChars *nullseat_stripctrl_new( StripCtrlChars *nullseat_stripctrl_new(
Seat *seat, BinarySink *bs_out, SeatInteractionContext sic) {return NULL;} Seat *seat, BinarySink *bs_out, SeatInteractionContext sic) {return NULL;}
bool nullseat_set_trust_status(Seat *seat, bool tr) { return false; } void nullseat_set_trust_status(Seat *seat, bool trusted) {}
bool nullseat_set_trust_status_vacuously(Seat *seat, bool tr) { return true; } bool nullseat_can_set_trust_status_yes(Seat *seat) { return true; }
bool nullseat_can_set_trust_status_no(Seat *seat) { return false; }
bool nullseat_verbose_no(Seat *seat) { return false; } bool nullseat_verbose_no(Seat *seat) { return false; }
bool nullseat_verbose_yes(Seat *seat) { return true; } bool nullseat_verbose_yes(Seat *seat) { return true; }
bool nullseat_interactive_no(Seat *seat) { return false; } bool nullseat_interactive_no(Seat *seat) { return false; }

View File

@ -187,7 +187,16 @@ bool is_interactive(void)
} }
bool console_antispoof_prompt = true; bool console_antispoof_prompt = true;
bool console_set_trust_status(Seat *seat, bool trusted)
void console_set_trust_status(Seat *seat, bool trusted)
{
/* Do nothing in response to a change of trust status, because
* there's nothing we can do in a console environment. However,
* the query function below will make a fiddly decision about
* whether to tell the backend to enable fallback handling. */
}
bool console_can_set_trust_status(Seat *seat)
{ {
if (console_batch_mode || !is_interactive() || !console_antispoof_prompt) { if (console_batch_mode || !is_interactive() || !console_antispoof_prompt) {
/* /*
@ -200,8 +209,8 @@ bool console_set_trust_status(Seat *seat, bool trusted)
* prompt, the user couldn't respond to it via the terminal * prompt, the user couldn't respond to it via the terminal
* anyway. * anyway.
* *
* We also vacuously return success if the user has purposely * We also return true without enabling any defences if the
* disabled the antispoof prompt. * user has purposely disabled the antispoof prompt.
*/ */
return true; return true;
} }

View File

@ -101,6 +101,7 @@ static const SeatVtable plink_seat_vt = {
.get_window_pixel_size = nullseat_get_window_pixel_size, .get_window_pixel_size = nullseat_get_window_pixel_size,
.stripctrl_new = console_stripctrl_new, .stripctrl_new = console_stripctrl_new,
.set_trust_status = console_set_trust_status, .set_trust_status = console_set_trust_status,
.can_set_trust_status = console_can_set_trust_status,
.verbose = cmdline_seat_verbose, .verbose = cmdline_seat_verbose,
.interactive = plink_seat_interactive, .interactive = plink_seat_interactive,
.get_cursor_position = nullseat_get_cursor_position, .get_cursor_position = nullseat_get_cursor_position,

View File

@ -323,7 +323,8 @@ static void win_seat_notify_remote_exit(Seat *seat);
static void win_seat_connection_fatal(Seat *seat, const char *msg); static void win_seat_connection_fatal(Seat *seat, const char *msg);
static void win_seat_update_specials_menu(Seat *seat); static void win_seat_update_specials_menu(Seat *seat);
static void win_seat_set_busy_status(Seat *seat, BusyStatus status); static void win_seat_set_busy_status(Seat *seat, BusyStatus status);
static bool win_seat_set_trust_status(Seat *seat, bool trusted); static void win_seat_set_trust_status(Seat *seat, bool trusted);
static bool win_seat_can_set_trust_status(Seat *seat);
static bool win_seat_get_cursor_position(Seat *seat, int *x, int *y); static bool win_seat_get_cursor_position(Seat *seat, int *x, int *y);
static bool win_seat_get_window_pixel_size(Seat *seat, int *x, int *y); static bool win_seat_get_window_pixel_size(Seat *seat, int *x, int *y);
@ -348,6 +349,7 @@ static const SeatVtable win_seat_vt = {
.get_window_pixel_size = win_seat_get_window_pixel_size, .get_window_pixel_size = win_seat_get_window_pixel_size,
.stripctrl_new = win_seat_stripctrl_new, .stripctrl_new = win_seat_stripctrl_new,
.set_trust_status = win_seat_set_trust_status, .set_trust_status = win_seat_set_trust_status,
.can_set_trust_status = win_seat_can_set_trust_status,
.verbose = nullseat_verbose_yes, .verbose = nullseat_verbose_yes,
.interactive = nullseat_interactive_yes, .interactive = nullseat_interactive_yes,
.get_cursor_position = win_seat_get_cursor_position, .get_cursor_position = win_seat_get_cursor_position,
@ -5753,9 +5755,13 @@ static int win_seat_get_userpass_input(
return ret; return ret;
} }
static bool win_seat_set_trust_status(Seat *seat, bool trusted) static void win_seat_set_trust_status(Seat *seat, bool trusted)
{ {
term_set_trust_status(term, trusted); term_set_trust_status(term, trusted);
}
static bool win_seat_can_set_trust_status(Seat *seat)
{
return true; return true;
} }