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:
parent
e21afff605
commit
2a5d8e05e8
@ -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,
|
||||
|
6
putty.h
6
putty.h
@ -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)
|
||||
|
159
unix/gtkwin.c
159
unix/gtkwin.c
@ -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,
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user