From 624f5b7d47088979dc6d45c994f1988c10653c09 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 26 Nov 2017 14:29:42 +0000 Subject: [PATCH] Make the GTK host-key verification box non-modal. I've switched it to using the new non-modal create_message_box, and provided a callback function which handles the cleanup afterwards. I had expected this to be a lot more work, because I'd imagined that I'd have to contort the coroutines in ssh.c to give them the ability to wait for an asynchronously delivered result from that user prompt. But in fact that wasn't necessary, because just such a mechanism has been sitting there unused since commit 8574822b9 in 2005, when I added it as part of my _previous_ attempt to write an OS X front end! (The abandoned one written in native ObjC + Cocoa.) --- unix/gtkdlg.c | 75 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 35973d9a..e6f88e6d 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -3513,6 +3513,54 @@ int reallyclose(void *frontend) return ret; } +struct verify_ssh_host_key_result_ctx { + char *host; + int port; + char *keytype; + char *keystr; + void (*callback)(void *callback_ctx, int result); + void *callback_ctx; + void *frontend; +}; + +static void verify_ssh_host_key_result_callback(void *vctx, int result) +{ + struct verify_ssh_host_key_result_ctx *ctx = + (struct verify_ssh_host_key_result_ctx *)vctx; + + if (result >= 0) { + int logical_result; + + /* + * Convert the dialog-box return value (one of three + * possibilities) into the return value we pass back to the SSH + * code (one of only two possibilities, because the SSH code + * doesn't care whether we saved the host key or not). + */ + if (result == 2) { + store_host_key(ctx->host, ctx->port, ctx->keytype, ctx->keystr); + logical_result = 1; /* continue with connection */ + } else if (result == 1) { + logical_result = 1; /* continue with connection */ + } else { + logical_result = 0; /* do not continue with connection */ + } + + ctx->callback(ctx->callback_ctx, logical_result); + } + + /* + * Clean up this context structure, whether or not a result was + * ever actually delivered from the dialog box. + */ + unregister_network_prompt_dialog(ctx->frontend); + + sfree(ctx->host); + sfree(ctx->keytype); + sfree(ctx->keystr); + sfree(ctx); +} + int verify_ssh_host_key(void *frontend, char *host, int port, const char *keytype, char *keystr, char *fingerprint, void (*callback)(void *ctx, int result), void *ctx) @@ -3554,6 +3602,8 @@ int verify_ssh_host_key(void *frontend, char *host, int port, char *text; int ret; + struct verify_ssh_host_key_result_ctx *result_ctx; + GtkWidget *mainwin, *msgbox; /* * Verify the key. @@ -3565,19 +3615,24 @@ int verify_ssh_host_key(void *frontend, char *host, int port, text = dupprintf((ret == 2 ? wrongtxt : absenttxt), keytype, fingerprint); - ret = message_box(GTK_WIDGET(get_window(frontend)), - "PuTTY Security Alert", text, - string_width(fingerprint), - TRUE, &buttons_hostkey); + result_ctx = snew(struct verify_ssh_host_key_result_ctx); + result_ctx->callback = callback; + result_ctx->callback_ctx = ctx; + result_ctx->host = dupstr(host); + result_ctx->port = port; + result_ctx->keytype = dupstr(keytype); + result_ctx->keystr = dupstr(keystr); + result_ctx->frontend = frontend; + + mainwin = GTK_WIDGET(get_window(frontend)); + msgbox = create_message_box( + mainwin, "PuTTY Security Alert", text, string_width(fingerprint), TRUE, + &buttons_hostkey, verify_ssh_host_key_result_callback, result_ctx); + register_network_prompt_dialog(frontend, msgbox); sfree(text); - if (ret == 2) { - store_host_key(host, port, keytype, keystr); - return 1; /* continue with connection */ - } else if (ret == 1) - return 1; /* continue with connection */ - return 0; /* do not continue with connection */ + return -1; /* dialog still in progress */ } /*