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

Add a TermWin method to draw a 'trust sigil'.

This is not yet used by anything, but the idea is that it'll be a
graphic in the terminal window that can't be replicated by a server
sending escape sequences, and hence can be used as a reliable
indication that the text on a particular terminal line is generated by
PuTTY itself and not passed through from the server. This will make it
possible to detect a malicious server trying to mimic local prompts to
trick you out of information that shouldn't be sent over the wire
(such as private-key passphrases).

The trust sigil I've picked is a small copy of the PuTTY icon, which
is thematically nice (it can be read as if the PuTTY icon is the name
of the speaker in a dialogue) and also convenient because we had that
graphic available already on all platforms. (Though the contortions I
had to go through to make the GTK 1 code draw it were quite annoying.)

The trust sigil has the same dimensions as a CJK double-width
character, i.e. it's 2 character cells wide by 1 high.
This commit is contained in:
Simon Tatham 2019-03-10 14:37:11 +00:00
parent e21afff605
commit 2a5d8e05e8
4 changed files with 188 additions and 1 deletions

View File

@ -69,6 +69,10 @@ static void fuzz_draw_cursor(
}
printf("\n");
}
static void fuzz_draw_trust_sigil(TermWin *tw, int x, int y)
{
printf("TRUST@(%d,%d)\n", x, y);
}
static int fuzz_char_width(TermWin *tw, int uc) { return 1; }
static void fuzz_free_draw_ctx(TermWin *tw) {}
static void fuzz_set_cursor_pos(TermWin *tw, int x, int y) {}
@ -101,6 +105,7 @@ static const TermWinVtable fuzz_termwin_vt = {
fuzz_setup_draw_ctx,
fuzz_draw_text,
fuzz_draw_cursor,
fuzz_draw_trust_sigil,
fuzz_char_width,
fuzz_free_draw_ctx,
fuzz_set_cursor_pos,

View File

@ -1099,6 +1099,10 @@ struct TermWinVtable {
* redraw it in different colours). */
void (*draw_cursor)(TermWin *, int x, int y, wchar_t *text, int len,
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);
void (*free_draw_ctx)(TermWin *);
@ -1151,6 +1155,8 @@ static inline void win_draw_cursor(
TermWin *win, int x, int y, wchar_t *text, int len,
unsigned long attrs, int line_attrs, truecolour 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)
{ return win->vt->char_width(win, uc); }
static inline void win_free_draw_ctx(TermWin *win)

View File

@ -88,6 +88,8 @@ struct clipboard_state {
#endif
};
typedef struct XpmHolder XpmHolder; /* only used for GTK 1 */
struct GtkFrontend {
GtkWidget *window, *area, *sbar;
gboolean sbar_visible;
@ -183,6 +185,12 @@ struct GtkFrontend {
#endif
bool send_raw_mouse;
unifont_drawctx uctx;
#if GTK_CHECK_VERSION(2,0,0)
GdkPixbuf *trust_sigil_pb;
#else
GdkPixmap *trust_sigil_pm;
#endif
int trust_sigil_w, trust_sigil_h;
Seat seat;
TermWin termwin;
@ -2311,6 +2319,17 @@ static void delete_inst(GtkFrontend *inst)
log_free(inst->logctx);
inst->logctx = NULL;
}
#if GTK_CHECK_VERSION(2,0,0)
if (inst->trust_sigil_pb) {
g_object_unref(G_OBJECT(inst->trust_sigil_pb));
inst->trust_sigil_pb = NULL;
}
#else
if (inst->trust_sigil_pm) {
gdk_pixmap_unref(inst->trust_sigil_pm);
inst->trust_sigil_pm = NULL;
}
#endif
#ifdef JUST_USE_GTK_CLIPBOARD_UTF8
/*
@ -3991,6 +4010,145 @@ static void gtkwin_draw_cursor(
#endif
}
#if !GTK_CHECK_VERSION(2,0,0)
/*
* For GTK 1, manual code to scale an in-memory XPM, producing a new
* one as output. It will be ugly, but good enough to use as a trust
* sigil.
*/
struct XpmHolder {
char **strings;
size_t nstrings;
};
static void xpmholder_free(XpmHolder *xh)
{
for (size_t i = 0; i < xh->nstrings; i++)
sfree(xh->strings[i]);
sfree(xh->strings);
sfree(xh);
}
static XpmHolder *xpm_scale(const char *const *xpm, int wo, int ho)
{
/* Get image dimensions, # colours, and chars-per-pixel */
int wi = 0, hi = 0, nc = 0, cpp = 0;
int retd = sscanf(xpm[0], "%d %d %d %d", &wi, &hi, &nc, &cpp);
assert(retd == 4);
/* Make output XpmHolder */
XpmHolder *xh = snew(XpmHolder);
xh->nstrings = 1 + nc + ho;
xh->strings = snewn(xh->nstrings, char *);
/* Set up header */
xh->strings[0] = dupprintf("%d %d %d %d", wo, ho, nc, cpp);
for (int i = 0; i < nc; i++)
xh->strings[1 + i] = dupstr(xpm[1 + i]);
/* Scale image */
for (int yo = 0; yo < ho; yo++) {
int yi = yo * hi / ho;
char *ro = snewn(cpp * wo + 1, char);
ro[cpp * wo] = '\0';
xh->strings[1 + nc + yo] = ro;
const char *ri = xpm[1 + nc + yi];
for (int xo = 0; xo < wo; xo++) {
int xi = xo * wi / wo;
memcpy(ro + cpp * xo, ri + cpp * xi, cpp);
}
}
return xh;
}
#endif /* !GTK_CHECK_VERSION(2,0,0) */
static void gtkwin_draw_trust_sigil(TermWin *tw, int cx, int cy)
{
GtkFrontend *inst = container_of(tw, GtkFrontend, termwin);
int x = cx * inst->font_width + inst->window_border;
int y = cy * inst->font_height + inst->window_border;
int w = 2*inst->font_width, h = inst->font_height;
if (inst->trust_sigil_w != w || inst->trust_sigil_h != h ||
#if GTK_CHECK_VERSION(2,0,0)
!inst->trust_sigil_pb
#else
!inst->trust_sigil_pm
#endif
) {
#if GTK_CHECK_VERSION(2,0,0)
if (inst->trust_sigil_pb)
g_object_unref(G_OBJECT(inst->trust_sigil_pb));
#else
if (inst->trust_sigil_pm)
gdk_pixmap_unref(inst->trust_sigil_pm);
#endif
int best_icon_index = 0;
unsigned score = UINT_MAX;
for (int i = 0; i < n_main_icon; i++) {
int iw, ih;
if (sscanf(main_icon[i][0], "%d %d", &iw, &ih) == 2) {
int this_excess = (iw + ih) - (w + h);
unsigned this_score = (abs(this_excess) |
(this_excess > 0 ? 0 : 0x80000000U));
if (this_score < score) {
best_icon_index = i;
score = this_score;
}
}
}
#if GTK_CHECK_VERSION(2,0,0)
GdkPixbuf *icon_unscaled = gdk_pixbuf_new_from_xpm_data(
(const gchar **)main_icon[best_icon_index]);
inst->trust_sigil_pb = gdk_pixbuf_scale_simple(
icon_unscaled, w, h, GDK_INTERP_BILINEAR);
g_object_unref(G_OBJECT(icon_unscaled));
#else
XpmHolder *xh = xpm_scale(main_icon[best_icon_index], w, h);
inst->trust_sigil_pm = gdk_pixmap_create_from_xpm_d(
gtk_widget_get_window(inst->window), NULL,
&inst->cols[258], xh->strings);
xpmholder_free(xh);
#endif
inst->trust_sigil_w = w;
inst->trust_sigil_h = h;
}
#ifdef DRAW_TEXT_GDK
if (inst->uctx.type == DRAWTYPE_GDK) {
#if GTK_CHECK_VERSION(2,0,0)
gdk_draw_pixbuf(inst->uctx.u.gdk.target, inst->uctx.u.gdk.gc,
inst->trust_sigil_pb, 0, 0, x, y, w, h,
GDK_RGB_DITHER_NORMAL, 0, 0);
#else
gdk_draw_pixmap(inst->uctx.u.gdk.target, inst->uctx.u.gdk.gc,
inst->trust_sigil_pm, 0, 0, x, y, w, h);
#endif
}
#endif
#ifdef DRAW_TEXT_CAIRO
if (inst->uctx.type == DRAWTYPE_CAIRO) {
inst->uctx.u.cairo.widget = GTK_WIDGET(inst->area);
cairo_save(inst->uctx.u.cairo.cr);
cairo_translate(inst->uctx.u.cairo.cr, x, y);
gdk_cairo_set_source_pixbuf(inst->uctx.u.cairo.cr,
inst->trust_sigil_pb, 0, 0);
cairo_rectangle(inst->uctx.u.cairo.cr, 0, 0, w, h);
cairo_fill(inst->uctx.u.cairo.cr);
cairo_restore(inst->uctx.u.cairo.cr);
}
#endif
draw_update(inst, x, y, w, h);
}
GdkCursor *make_mouse_ptr(GtkFrontend *inst, int cursor_val)
{
if (cursor_val == -1) {
@ -4964,6 +5122,7 @@ static const TermWinVtable gtk_termwin_vt = {
gtkwin_setup_draw_ctx,
gtkwin_draw_text,
gtkwin_draw_cursor,
gtkwin_draw_trust_sigil,
gtkwin_char_width,
gtkwin_free_draw_ctx,
gtkwin_set_cursor_pos,

View File

@ -231,6 +231,7 @@ static void wintw_draw_text(TermWin *, int x, int y, wchar_t *text, int len,
unsigned long attrs, int lattrs, truecolour tc);
static void wintw_draw_cursor(TermWin *, int x, int y, wchar_t *text, int len,
unsigned long attrs, int lattrs, truecolour tc);
static void wintw_draw_trust_sigil(TermWin *, int x, int y);
static int wintw_char_width(TermWin *, int uc);
static void wintw_free_draw_ctx(TermWin *);
static void wintw_set_cursor_pos(TermWin *, int x, int y);
@ -262,6 +263,7 @@ static const TermWinVtable windows_termwin_vt = {
wintw_setup_draw_ctx,
wintw_draw_text,
wintw_draw_cursor,
wintw_draw_trust_sigil,
wintw_char_width,
wintw_free_draw_ctx,
wintw_set_cursor_pos,
@ -291,6 +293,8 @@ static const TermWinVtable windows_termwin_vt = {
static TermWin wintw[1];
static HDC wintw_hdc;
static HICON icon;
const bool share_can_be_downstream = true;
const bool share_can_be_upstream = true;
@ -674,6 +678,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
prepare_session(conf);
}
icon = LoadIcon(inst, MAKEINTRESOURCE(IDI_MAINICON));
if (!prev) {
WNDCLASSW wndclass;
@ -682,7 +688,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = inst;
wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(IDI_MAINICON));
wndclass.hIcon = icon;
wndclass.hCursor = LoadCursor(NULL, IDC_IBEAM);
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
@ -3986,6 +3992,17 @@ static void wintw_draw_cursor(
}
}
static void wintw_draw_trust_sigil(TermWin *tw, int x, int y)
{
x *= font_width;
y *= font_height;
x += offset_width;
y += offset_height;
DrawIconEx(wintw_hdc, x, y, icon, font_width * 2, font_height,
0, NULL, DI_NORMAL);
}
/* This function gets the actual width of a character in the normal font.
*/
static int wintw_char_width(TermWin *tw, int uc)