|
@@ -659,12 +659,22 @@ typedef struct {
|
|
* sufficient).
|
|
* sufficient).
|
|
*/
|
|
*/
|
|
bool to_server;
|
|
bool to_server;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Indicates whether the prompts originated _at_ the server, so
|
|
|
|
+ * that the front end can display some kind of trust sigil that
|
|
|
|
+ * distinguishes (say) a legit private-key passphrase prompt from
|
|
|
|
+ * a fake one sent by a malicious server.
|
|
|
|
+ */
|
|
|
|
+ bool from_server;
|
|
|
|
+
|
|
char *name; /* Short description, perhaps for dialog box title */
|
|
char *name; /* Short description, perhaps for dialog box title */
|
|
bool name_reqd; /* Display of `name' required or optional? */
|
|
bool name_reqd; /* Display of `name' required or optional? */
|
|
char *instruction; /* Long description, maybe with embedded newlines */
|
|
char *instruction; /* Long description, maybe with embedded newlines */
|
|
bool instr_reqd; /* Display of `instruction' required or optional? */
|
|
bool instr_reqd; /* Display of `instruction' required or optional? */
|
|
size_t n_prompts; /* May be zero (in which case display the foregoing,
|
|
size_t n_prompts; /* May be zero (in which case display the foregoing,
|
|
* if any, and return success) */
|
|
* if any, and return success) */
|
|
|
|
+ size_t prompts_size; /* allocated storage capacity for prompts[] */
|
|
prompt_t **prompts;
|
|
prompt_t **prompts;
|
|
void *data; /* slot for housekeeping data, managed by
|
|
void *data; /* slot for housekeeping data, managed by
|
|
* seat_get_userpass_input(); initially NULL */
|
|
* seat_get_userpass_input(); initially NULL */
|
|
@@ -739,6 +749,10 @@ typedef enum BusyStatus {
|
|
* suspended */
|
|
* suspended */
|
|
} BusyStatus;
|
|
} BusyStatus;
|
|
|
|
|
|
|
|
+typedef enum SeatInteractionContext {
|
|
|
|
+ SIC_BANNER, SIC_KI_PROMPTS
|
|
|
|
+} SeatInteractionContext;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Data type 'Seat', which is an API intended to contain essentially
|
|
* Data type 'Seat', which is an API intended to contain essentially
|
|
* everything that a back end might need to talk to its client for:
|
|
* everything that a back end might need to talk to its client for:
|
|
@@ -929,6 +943,29 @@ struct SeatVtable {
|
|
* true.
|
|
* true.
|
|
*/
|
|
*/
|
|
bool (*get_window_pixel_size)(Seat *seat, int *width, int *height);
|
|
bool (*get_window_pixel_size)(Seat *seat, int *width, int *height);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Return a StripCtrlChars appropriate for sanitising untrusted
|
|
|
|
+ * terminal data (e.g. SSH banners, prompts) being sent to the
|
|
|
|
+ * user of this seat. May return NULL if no sanitisation is
|
|
|
|
+ * needed.
|
|
|
|
+ */
|
|
|
|
+ StripCtrlChars *(*stripctrl_new)(
|
|
|
|
+ Seat *seat, BinarySink *bs_out, SeatInteractionContext sic);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Set the seat's current idea of where output is coming from.
|
|
|
|
+ * True means that output is being generated by our own code base
|
|
|
|
+ * (and hence, can be trusted if it's asking you for secrets such
|
|
|
|
+ * as your passphrase); false means output is coming from the
|
|
|
|
+ * server.
|
|
|
|
+ *
|
|
|
|
+ * Returns true if the seat has a way to indicate this
|
|
|
|
+ * distinction. Returns false if not, in which case the backend
|
|
|
|
+ * should use a fallback defence against spoofing of PuTTY's local
|
|
|
|
+ * prompts by malicious servers.
|
|
|
|
+ */
|
|
|
|
+ bool (*set_trust_status)(Seat *seat, bool trusted);
|
|
};
|
|
};
|
|
|
|
|
|
static inline size_t seat_output(
|
|
static inline size_t seat_output(
|
|
@@ -969,6 +1006,11 @@ static inline bool seat_get_windowid(Seat *seat, long *id_out)
|
|
{ return seat->vt->get_windowid(seat, id_out); }
|
|
{ return seat->vt->get_windowid(seat, id_out); }
|
|
static inline bool seat_get_window_pixel_size(Seat *seat, int *w, int *h)
|
|
static inline bool seat_get_window_pixel_size(Seat *seat, int *w, int *h)
|
|
{ return seat->vt->get_window_pixel_size(seat, w, h); }
|
|
{ return seat->vt->get_window_pixel_size(seat, w, h); }
|
|
|
|
+static inline StripCtrlChars *seat_stripctrl_new(
|
|
|
|
+ Seat *seat, BinarySink *bs, SeatInteractionContext sic)
|
|
|
|
+{ return seat->vt->stripctrl_new(seat, bs, sic); }
|
|
|
|
+static inline bool seat_set_trust_status(Seat *seat, bool trusted)
|
|
|
|
+{ return seat->vt->set_trust_status(seat, trusted); }
|
|
|
|
|
|
/* Unlike the seat's actual method, the public entry point
|
|
/* Unlike the seat's actual method, the public entry point
|
|
* seat_connection_fatal is a wrapper function with a printf-like API,
|
|
* seat_connection_fatal is a wrapper function with a printf-like API,
|
|
@@ -978,8 +1020,12 @@ void seat_connection_fatal(Seat *seat, const char *fmt, ...);
|
|
/* Handy aliases for seat_output which set is_stderr to a fixed value. */
|
|
/* Handy aliases for seat_output which set is_stderr to a fixed value. */
|
|
static inline size_t seat_stdout(Seat *seat, const void *data, size_t len)
|
|
static inline size_t seat_stdout(Seat *seat, const void *data, size_t len)
|
|
{ return seat_output(seat, false, data, len); }
|
|
{ return seat_output(seat, false, data, len); }
|
|
|
|
+static inline size_t seat_stdout_pl(Seat *seat, ptrlen data)
|
|
|
|
+{ return seat_output(seat, false, data.ptr, data.len); }
|
|
static inline size_t seat_stderr(Seat *seat, const void *data, size_t len)
|
|
static inline size_t seat_stderr(Seat *seat, const void *data, size_t len)
|
|
{ return seat_output(seat, true, data, len); }
|
|
{ return seat_output(seat, true, data, len); }
|
|
|
|
+static inline size_t seat_stderr_pl(Seat *seat, ptrlen data)
|
|
|
|
+{ return seat_output(seat, true, data.ptr, data.len); }
|
|
|
|
|
|
/*
|
|
/*
|
|
* Stub methods for seat implementations that want to use the obvious
|
|
* Stub methods for seat implementations that want to use the obvious
|
|
@@ -1013,6 +1059,10 @@ void nullseat_echoedit_update(Seat *seat, bool echoing, bool editing);
|
|
const char *nullseat_get_x_display(Seat *seat);
|
|
const char *nullseat_get_x_display(Seat *seat);
|
|
bool nullseat_get_windowid(Seat *seat, long *id_out);
|
|
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(
|
|
|
|
+ Seat *seat, BinarySink *bs_out, SeatInteractionContext sic);
|
|
|
|
+bool nullseat_set_trust_status(Seat *seat, bool trusted);
|
|
|
|
+bool nullseat_set_trust_status_vacuously(Seat *seat, bool trusted);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Seat functions provided by the platform's console-application
|
|
* Seat functions provided by the platform's console-application
|
|
@@ -1030,6 +1080,9 @@ int console_confirm_weak_crypto_primitive(
|
|
int console_confirm_weak_cached_hostkey(
|
|
int console_confirm_weak_cached_hostkey(
|
|
Seat *seat, const char *algname, const char *betteralgs,
|
|
Seat *seat, const char *algname, const char *betteralgs,
|
|
void (*callback)(void *ctx, int result), void *ctx);
|
|
void (*callback)(void *ctx, int result), void *ctx);
|
|
|
|
+StripCtrlChars *console_stripctrl_new(
|
|
|
|
+ Seat *seat, BinarySink *bs_out, SeatInteractionContext sic);
|
|
|
|
+bool console_set_trust_status(Seat *seat, bool trusted);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Other centralised seat functions.
|
|
* Other centralised seat functions.
|
|
@@ -1065,6 +1118,10 @@ struct TermWinVtable {
|
|
* redraw it in different colours). */
|
|
* redraw it in different colours). */
|
|
void (*draw_cursor)(TermWin *, int x, int y, wchar_t *text, int len,
|
|
void (*draw_cursor)(TermWin *, int x, int y, wchar_t *text, int len,
|
|
unsigned long attrs, int line_attrs, truecolour tc);
|
|
unsigned long attrs, int line_attrs, truecolour tc);
|
|
|
|
+ /* Draw the sigil indicating that a line of text has come from
|
|
|
|
+ * PuTTY itself rather than the far end (defence against end-of-
|
|
|
|
+ * authentication spoofing) */
|
|
|
|
+ void (*draw_trust_sigil)(TermWin *, int x, int y);
|
|
int (*char_width)(TermWin *, int uc);
|
|
int (*char_width)(TermWin *, int uc);
|
|
void (*free_draw_ctx)(TermWin *);
|
|
void (*free_draw_ctx)(TermWin *);
|
|
|
|
|
|
@@ -1117,6 +1174,8 @@ static inline void win_draw_cursor(
|
|
TermWin *win, int x, int y, wchar_t *text, int len,
|
|
TermWin *win, int x, int y, wchar_t *text, int len,
|
|
unsigned long attrs, int line_attrs, truecolour tc)
|
|
unsigned long attrs, int line_attrs, truecolour tc)
|
|
{ win->vt->draw_cursor(win, x, y, text, len, attrs, line_attrs, tc); }
|
|
{ win->vt->draw_cursor(win, x, y, text, len, attrs, line_attrs, tc); }
|
|
|
|
+static inline void win_draw_trust_sigil(TermWin *win, int x, int y)
|
|
|
|
+{ win->vt->draw_trust_sigil(win, x, y); }
|
|
static inline int win_char_width(TermWin *win, int uc)
|
|
static inline int win_char_width(TermWin *win, int uc)
|
|
{ return win->vt->char_width(win, uc); }
|
|
{ return win->vt->char_width(win, uc); }
|
|
static inline void win_free_draw_ctx(TermWin *win)
|
|
static inline void win_free_draw_ctx(TermWin *win)
|
|
@@ -1587,6 +1646,7 @@ void term_provide_logctx(Terminal *term, LogContext *logctx);
|
|
void term_set_focus(Terminal *term, bool has_focus);
|
|
void term_set_focus(Terminal *term, bool has_focus);
|
|
char *term_get_ttymode(Terminal *term, const char *mode);
|
|
char *term_get_ttymode(Terminal *term, const char *mode);
|
|
int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input);
|
|
int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input);
|
|
|
|
+void term_set_trust_status(Terminal *term, bool trusted);
|
|
|
|
|
|
typedef enum SmallKeypadKey {
|
|
typedef enum SmallKeypadKey {
|
|
SKK_HOME, SKK_END, SKK_INSERT, SKK_DELETE, SKK_PGUP, SKK_PGDN,
|
|
SKK_HOME, SKK_END, SKK_INSERT, SKK_DELETE, SKK_PGUP, SKK_PGDN,
|
|
@@ -1866,7 +1926,7 @@ bool have_ssh_host_key(const char *host, int port, const char *keytype);
|
|
* Exports from console frontends (wincons.c, uxcons.c)
|
|
* Exports from console frontends (wincons.c, uxcons.c)
|
|
* that aren't equivalents to things in windlg.c et al.
|
|
* that aren't equivalents to things in windlg.c et al.
|
|
*/
|
|
*/
|
|
-extern bool console_batch_mode;
|
|
|
|
|
|
+extern bool console_batch_mode, console_antispoof_prompt;
|
|
int console_get_userpass_input(prompts_t *p);
|
|
int console_get_userpass_input(prompts_t *p);
|
|
bool is_interactive(void);
|
|
bool is_interactive(void);
|
|
void console_print_error_msg(const char *prefix, const char *msg);
|
|
void console_print_error_msg(const char *prefix, const char *msg);
|
|
@@ -1937,6 +1997,7 @@ void setup_config_box(struct controlbox *b, bool midsession,
|
|
/*
|
|
/*
|
|
* Exports from minibidi.c.
|
|
* Exports from minibidi.c.
|
|
*/
|
|
*/
|
|
|
|
+#define BIDI_CHAR_INDEX_NONE ((unsigned short)-1)
|
|
typedef struct bidi_char {
|
|
typedef struct bidi_char {
|
|
unsigned int origwc, wc;
|
|
unsigned int origwc, wc;
|
|
unsigned short index, nchars;
|
|
unsigned short index, nchars;
|
|
@@ -2027,7 +2088,7 @@ bool open_for_write_would_lose_data(const Filename *fn);
|
|
* The reason for this is that an OS's system clock might not agree
|
|
* The reason for this is that an OS's system clock might not agree
|
|
* exactly with the timing mechanisms it supplies to wait for a
|
|
* exactly with the timing mechanisms it supplies to wait for a
|
|
* given interval. I'll illustrate this by the simple example of
|
|
* given interval. I'll illustrate this by the simple example of
|
|
- * Unix Plink, which uses timeouts to select() in a way which for
|
|
|
|
|
|
+ * Unix Plink, which uses timeouts to poll() in a way which for
|
|
* these purposes can simply be considered to be a wait() function.
|
|
* these purposes can simply be considered to be a wait() function.
|
|
* Suppose, for the sake of argument, that this wait() function
|
|
* Suppose, for the sake of argument, that this wait() function
|
|
* tends to return early by 1%. Then a possible sequence of actions
|
|
* tends to return early by 1%. Then a possible sequence of actions
|
|
@@ -2099,12 +2160,12 @@ unsigned long timing_last_clock(void);
|
|
* instead request notifications when a callback is available, so that
|
|
* instead request notifications when a callback is available, so that
|
|
* it knows to ask its delegate event loop to do the same thing. Also,
|
|
* it knows to ask its delegate event loop to do the same thing. Also,
|
|
* if a front end needs to know whether a callback is pending without
|
|
* if a front end needs to know whether a callback is pending without
|
|
- * actually running it (e.g. so as to put a zero timeout on a select()
|
|
|
|
|
|
+ * actually running it (e.g. so as to put a zero timeout on a poll()
|
|
* call) then it can call toplevel_callback_pending(), which will
|
|
* call) then it can call toplevel_callback_pending(), which will
|
|
* return true if at least one callback is in the queue.
|
|
* return true if at least one callback is in the queue.
|
|
*
|
|
*
|
|
* run_toplevel_callbacks() returns true if it ran any actual code.
|
|
* run_toplevel_callbacks() returns true if it ran any actual code.
|
|
- * This can be used as a means of speculatively terminating a select
|
|
|
|
|
|
+ * This can be used as a means of speculatively terminating a poll
|
|
* loop, as in PSFTP, for example - if a callback has run then perhaps
|
|
* loop, as in PSFTP, for example - if a callback has run then perhaps
|
|
* it might have done whatever the loop's caller was waiting for.
|
|
* it might have done whatever the loop's caller was waiting for.
|
|
*/
|
|
*/
|
|
@@ -2146,10 +2207,12 @@ void request_callback_notifications(toplevel_callback_notify_fn_t notify,
|
|
#endif
|
|
#endif
|
|
|
|
|
|
/* SURROGATE PAIR */
|
|
/* SURROGATE PAIR */
|
|
|
|
+#ifndef HIGH_SURROGATE_START /* in some toolchains <winnls.h> defines these */
|
|
#define HIGH_SURROGATE_START 0xd800
|
|
#define HIGH_SURROGATE_START 0xd800
|
|
#define HIGH_SURROGATE_END 0xdbff
|
|
#define HIGH_SURROGATE_END 0xdbff
|
|
#define LOW_SURROGATE_START 0xdc00
|
|
#define LOW_SURROGATE_START 0xdc00
|
|
#define LOW_SURROGATE_END 0xdfff
|
|
#define LOW_SURROGATE_END 0xdfff
|
|
|
|
+#endif
|
|
|
|
|
|
/* These macros exist in the Windows API, so the environment may
|
|
/* These macros exist in the Windows API, so the environment may
|
|
* provide them. If not, define them in terms of the above. */
|
|
* provide them. If not, define them in terms of the above. */
|