]> asedeno.scripts.mit.edu Git - PuTTY_svn.git/commitdiff
Revamp interface to verify_ssh_host_key() and askalg(). Each of them
authorSimon Tatham <anakin@pobox.com>
Thu, 17 Feb 2005 18:34:24 +0000 (18:34 +0000)
committerSimon Tatham <anakin@pobox.com>
Thu, 17 Feb 2005 18:34:24 +0000 (18:34 +0000)
now returns an integer: 0 means cancel the SSH connection and 1
means continue with it. Additionally, they can return -1, which
means `front end has set an asynchronous alert box in motion, please
wait to be called back with the result', and each one is passed a
callback function pointer and context for this purpose.

I have not yet done the same to askappend() yet, because it will
take a certain amount of reorganisation of logging.c.

Importantly, this checkin means the host key dialog box now works on
OS X.

git-svn-id: http://svn.tartarus.org/sgt/putty@5330 cda61777-01e9-0310-a592-d414129be87e

mac/mac.c
macosx/README.OSX
macosx/osxclass.h
macosx/osxdlg.m
macosx/osxwin.m
putty.h
ssh.c
unix/gtkdlg.c
unix/uxcons.c
windows/wincons.c
windows/windlg.c

index f663deeab15af25515ebb9c87788eb9014c64f71..2fb7d44cf3305a6255b784c1ed583866b1b9f41a 100644 (file)
--- a/mac/mac.c
+++ b/mac/mac.c
@@ -691,8 +691,9 @@ int agent_query(void *in, int inlen, void **out, int *outlen,
 
 /* Temporary null routines for testing. */
 
 
 /* Temporary null routines for testing. */
 
-void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
-                        char *keystr, char *fingerprint)
+int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
+                        char *keystr, char *fingerprint,
+                        void (*callback)(void *ctx, int result), void *ctx)
 {
     Str255 pappname;
     Str255 pfingerprint;
 {
     Str255 pappname;
     Str255 pfingerprint;
@@ -705,64 +706,55 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     c2pstrcpy(pfingerprint, fingerprint);
 
     /*
     c2pstrcpy(pfingerprint, fingerprint);
 
     /*
-     * This function is horribly wrong.  For one thing, the alert
-     * shouldn't be modal, it should be movable modal, or a sheet in
-     * Aqua.  Also, PuTTY might be in the background, in which case we
-     * should use the Notification Manager to wake up the user.  In
-     * any case, we shouldn't hold up processing of other connections'
-     * data just because this one's waiting for the user. Also see the
-     * note below about closing the connection.  All in all, a bit of
-     * a mess really.
+     * The alert shouldn't be modal, it should be movable modal, or
+     * a sheet in Aqua.  Also, PuTTY might be in the background, in
+     * which case we should use the Notification Manager to wake up
+     * the user.  In any case, we shouldn't hold up processing of
+     * other connections' data just because this one's waiting for
+     * the user.
      */
 
     /* Verify the key against the cache */
 
     ret = verify_host_key(host, port, keytype, keystr);
 
      */
 
     /* Verify the key against the cache */
 
     ret = verify_host_key(host, port, keytype, keystr);
 
-    if (ret == 0)                     /* success - key matched OK */
-       return;
-    if (ret == 2) {                   /* key was different */
+    if (ret == 0) {                   /* success - key matched OK */
+       return 1;
+    } else if (ret == 2) {            /* key was different */
        ParamText(pappname, pkeytype, pfingerprint, NULL);
        alertret=CautionAlert(wWrong, NULL);
        if (alertret == 8) {
            /* Cancel */
        ParamText(pappname, pkeytype, pfingerprint, NULL);
        alertret=CautionAlert(wWrong, NULL);
        if (alertret == 8) {
            /* Cancel */
-           goto cancel;
+            return 0;
        } else if (alertret == 9) {
            /* Connect Just Once */
        } else if (alertret == 9) {
            /* Connect Just Once */
+            return 1;
        } else {
            /* Update Key */
            store_host_key(host, port, keytype, keystr);
        } else {
            /* Update Key */
            store_host_key(host, port, keytype, keystr);
+            return 1;
        }
        }
-    }
-    if (ret == 1) {                     /* key was absent */
+    } else /* ret == 1 */ {           /* key was absent */
        ParamText(pkeytype, pfingerprint, pappname, NULL);
        alertret=CautionAlert(wAbsent, NULL);
        if (alertret == 7) {
            /* Cancel */
        ParamText(pkeytype, pfingerprint, pappname, NULL);
        alertret=CautionAlert(wAbsent, NULL);
        if (alertret == 7) {
            /* Cancel */
-           goto cancel;
+            return 0;
        } else if (alertret == 8) {
            /* Connect Just Once */
        } else if (alertret == 8) {
            /* Connect Just Once */
+            return 1;
        } else {
            /* Update Key */
            store_host_key(host, port, keytype, keystr);
        } else {
            /* Update Key */
            store_host_key(host, port, keytype, keystr);
+            return 1;
        }
     }
        }
     }
-
-    return;
-
-  cancel:
-    /*
-     * User chose "Cancel".  Unfortunately, if I tear the
-     * connection down here, Bad Things happen when I return.  I
-     * think this function should actually return something
-     * telling the SSH code to abandon the connection.
-     */        
-    return;
 }
 
 }
 
-void askalg(void *frontend, const char *algtype, const char *algname)
+int askalg(void *frontend, const char *algtype, const char *algname,
+          void (*callback)(void *ctx, int result), void *ctx)
 {
 {
-
+    return 0;
 }
 
 void old_keyfile_warning(void)
 }
 
 void old_keyfile_warning(void)
index 9dded0516bcdfb1369901e1a7f4603db72c8bf90..8d989a63e7d204e423f7305cb40c80a10784fdd7 100644 (file)
@@ -16,13 +16,6 @@ version of the port decides to look somewhere completely different
 for the data and therefore loses them all. If that happens, don't
 say you weren't warned!
 
 for the data and therefore loses them all. If that happens, don't
 say you weren't warned!
 
-Even more importantly, the alert box that confirms host keys is not
-yet implemented, and the application will bomb out and exit if it
-should be needed. This means you cannot make an SSH connection to a
-new host using the GUI PuTTY in this port: you must first run
-`plink' (which should be exactly identical to the version in the
-Unix port) and tell it to confirm the host key.
-
 Other ways in which the port is currently unfinished include:
 
  - terminal display is horribly slow
 Other ways in which the port is currently unfinished include:
 
  - terminal display is horribly slow
index 5f009a914210fb2174317b2f1aac46a9020bee50..76a8fc7c8d97deb6802ef49ba8691e9c0a8b5c66 100644 (file)
@@ -40,6 +40,8 @@ extern AppController *controller;
     void *ldisc;
     Backend *back;
     void *backhandle;
     void *ldisc;
     Backend *back;
     void *backhandle;
+    void (*alert_callback)(void *, int);
+    void *alert_ctx;
 }
 - (id)initWithConfig:(Config)cfg;
 - (void)drawStartFinish:(BOOL)start;
 }
 - (id)initWithConfig:(Config)cfg;
 - (void)drawStartFinish:(BOOL)start;
@@ -48,6 +50,8 @@ extern AppController *controller;
 - (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
     attr:(unsigned long)attr lattr:(int)lattr;
 - (int)fromBackend:(const char *)data len:(int)len isStderr:(int)is_stderr;
 - (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
     attr:(unsigned long)attr lattr:(int)lattr;
 - (int)fromBackend:(const char *)data len:(int)len isStderr:(int)is_stderr;
+- (void)startAlert:(NSAlert *)alert
+    withCallback:(void (*)(void *, int))callback andCtx:(void *)ctx;
 @end
 
 /*
 @end
 
 /*
index 5bc13a4344a4b18dca0acafb2726046767908d4b..0ea327f5f57da03749191ffef380cfb44df11271 100644 (file)
@@ -311,16 +311,104 @@ int askappend(void *frontend, Filename filename)
     return 0;                         /* FIXME */
 }
 
     return 0;                         /* FIXME */
 }
 
-void askalg(void *frontend, const char *algtype, const char *algname)
+struct algstate {
+    void (*callback)(void *ctx, int result);
+    void *ctx;
+};
+
+static void askalg_callback(void *ctx, int result)
+{
+    struct algstate *state = (struct algstate *)ctx;
+
+    state->callback(state->ctx, result == 0);
+    sfree(state);
+}
+
+int askalg(void *frontend, const char *algtype, const char *algname,
+          void (*callback)(void *ctx, int result), void *ctx)
+{
+    static const char msg[] =
+       "The first %s supported by the server is "
+       "%s, which is below the configured warning threshold.\n"
+       "Continue with connection?";
+
+    char *text;
+    SessionWindow *win = (SessionWindow *)frontend;
+    struct algstate *state;
+    NSAlert *alert;
+
+    text = dupprintf(msg, algtype, algname);
+
+    state = snew(struct algstate);
+    state->callback = callback;
+    state->ctx = ctx;
+
+    alert = [NSAlert alloc];
+    [alert setInformativeText:[NSString stringWithCString:text]];
+    [alert addButtonWithTitle:@"Yes"];
+    [alert addButtonWithTitle:@"No"];
+    [win startAlert:alert withCallback:askalg_callback andCtx:state];
+
+    return -1;
+}
+
+struct hostkeystate {
+    char *host, *keytype, *keystr;
+    int port;
+    void (*callback)(void *ctx, int result);
+    void *ctx;
+};
+
+static void verify_ssh_host_key_callback(void *ctx, int result)
 {
 {
-    fatalbox("Cipher algorithm dialog box not supported yet");
-    return;                           /* FIXME */
+    struct hostkeystate *state = (struct hostkeystate *)ctx;
+
+    if (result == NSAlertThirdButtonReturn)   /* `Accept' */
+       store_host_key(state->host, state->port,
+                      state->keytype, state->keystr);
+    state->callback(state->ctx, result != NSAlertFirstButtonReturn);
+    sfree(state->host);
+    sfree(state->keytype);
+    sfree(state->keystr);
+    sfree(state);
 }
 
 }
 
-void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
-                        char *keystr, char *fingerprint)
+int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
+                        char *keystr, char *fingerprint,
+                        void (*callback)(void *ctx, int result), void *ctx)
 {
 {
+    static const char absenttxt[] =
+       "The server's host key is not cached. You have no guarantee "
+       "that the server is the computer you think it is.\n"
+       "The server's %s key fingerprint is:\n"
+       "%s\n"
+       "If you trust this host, press \"Accept\" to add the key to "
+       "PuTTY's cache and carry on connecting.\n"
+       "If you want to carry on connecting just once, without "
+       "adding the key to the cache, press \"Connect Once\".\n"
+       "If you do not trust this host, press \"Cancel\" to abandon the "
+       "connection.";
+    static const char wrongtxt[] =
+       "WARNING - POTENTIAL SECURITY BREACH!\n"
+       "The server's host key does not match the one PuTTY has "
+       "cached. This means that either the server administrator "
+       "has changed the host key, or you have actually connected "
+       "to another computer pretending to be the server.\n"
+       "The new %s key fingerprint is:\n"
+       "%s\n"
+       "If you were expecting this change and trust the new key, "
+       "press \"Accept\" to update PuTTY's cache and continue connecting.\n"
+       "If you want to carry on connecting but without updating "
+       "the cache, press \"Connect Once\".\n"
+       "If you want to abandon the connection completely, press "
+       "\"Cancel\" to cancel. Pressing \"Cancel\" is the ONLY guaranteed "
+       "safe choice.";
+
     int ret;
     int ret;
+    char *text;
+    SessionWindow *win = (SessionWindow *)frontend;
+    struct hostkeystate *state;
+    NSAlert *alert;
 
     /*
      * Verify the key.
 
     /*
      * Verify the key.
@@ -328,30 +416,27 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)
-       return;
-
-    /*
-     * FIXME FIXME FIXME. I currently lack any sensible means of
-     * asking the user for a verification non-application-modally,
-     * _or_ any means of closing just this connection if the answer
-     * is no (the Unix and Windows ports just exit() in this
-     * situation since they're one-connection-per-process).
-     * 
-     * What I need to do is to make this function optionally-
-     * asynchronous, much like the interface to agent_query(). It
-     * can either run modally and return a result directly, _or_ it
-     * can kick off a non-modal dialog, return a `please wait'
-     * status, and the dialog can call the backend back when the
-     * result comes in. Also, in either case, the aye/nay result
-     * wants to be passed to the backend so that it can tear down
-     * the connection if the answer was nay.
-     * 
-     * For the moment, I simply bomb out if we have an unrecognised
-     * host key. This makes this port safe but not very useful: you
-     * can only use it at all if you already have a host key cache
-     * set up by running the Unix port.
-     */
-    fatalbox("Host key dialog box not supported yet");
+       return 1;
+
+    text = dupprintf((ret == 2 ? wrongtxt : absenttxt), keytype, fingerprint);
+
+    state = snew(struct hostkeystate);
+    state->callback = callback;
+    state->ctx = ctx;
+    state->host = dupstr(host);
+    state->port = port;
+    state->keytype = dupstr(keytype);
+    state->keystr = dupstr(keystr);
+
+    alert = [[NSAlert alloc] init];
+    [alert setInformativeText:[NSString stringWithCString:text]];
+    [alert addButtonWithTitle:@"Cancel"];
+    [alert addButtonWithTitle:@"Connect Once"];
+    [alert addButtonWithTitle:@"Accept"];
+    [win startAlert:alert withCallback:verify_ssh_host_key_callback
+     andCtx:state];
+
+    return -1;
 }
 
 void old_keyfile_warning(void)
 }
 
 void old_keyfile_warning(void)
index a54f771f43423da40c3f53a04b2d342003d24f6e..8166f913ae900fe559a730f44b3c2259eb1d1d17 100644 (file)
 {
     NSRect rect = { {0,0}, {0,0} };
 
 {
     NSRect rect = { {0,0}, {0,0} };
 
+    alert_ctx = NULL;
+
     cfg = aCfg;                               /* structure copy */
 
     init_ucs(&ucsdata, cfg.line_codepage, cfg.utf8_override,
     cfg = aCfg;                               /* structure copy */
 
     init_ucs(&ucsdata, cfg.line_codepage, cfg.utf8_override,
      * terminal, the backend, the ldisc, the logctx, you name it.
      * Do so.
      */
      * terminal, the backend, the ldisc, the logctx, you name it.
      * Do so.
      */
+    sfree(alert_ctx);
     [super dealloc];
 }
 
     [super dealloc];
 }
 
@@ -778,6 +781,23 @@ printf("n=%d c=U+%04x cm=U+%04x m=%08x\n", n, c, cm, m);
     return term_data(term, is_stderr, data, len);
 }
 
     return term_data(term, is_stderr, data, len);
 }
 
+- (void)startAlert:(NSAlert *)alert
+    withCallback:(void (*)(void *, int))callback andCtx:(void *)ctx
+{
+    alert_callback = callback;
+    alert_ctx = ctx;                /* NB this is assumed to need freeing! */
+    [alert beginSheetModalForWindow:self modalDelegate:self
+     didEndSelector:@selector(alertSheetDidEnd:returnCode:contextInfo:)
+     contextInfo:NULL];
+}
+
+- (void)alertSheetDidEnd:(NSAlert *)alert returnCode:(int)returnCode
+    contextInfo:(void *)contextInfo
+{
+    alert_callback(alert_ctx, returnCode);   /* transfers ownership of ctx */
+    alert_ctx = NULL;
+}
+
 @end
 
 int from_backend(void *frontend, int is_stderr, const char *data, int len)
 @end
 
 int from_backend(void *frontend, int is_stderr, const char *data, int len)
diff --git a/putty.h b/putty.h
index 0b49dfa88af6b6b764a338ca1713366d56d4235b..46708f102228df5909c55416ffd35f20fb478300 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -896,9 +896,26 @@ int wc_unescape(char *output, const char *wildcard);
  * Exports from windlg.c
  */
 void logevent(void *frontend, const char *);
  * Exports from windlg.c
  */
 void logevent(void *frontend, const char *);
-void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
-                        char *keystr, char *fingerprint);
-void askalg(void *frontend, const char *algtype, const char *algname);
+/*
+ * verify_ssh_host_key() can return one of three values:
+ * 
+ *  - +1 means `key was OK' (either already known or the user just
+ *    approved it) `so continue with the connection'
+ * 
+ *  - 0 means `key was not OK, abandon the connection'
+ * 
+ *  - -1 means `I've initiated enquiries, please wait to be called
+ *    back via the provided function with a result that's either 0
+ *    or +1'.
+ */
+int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
+                        char *keystr, char *fingerprint,
+                        void (*callback)(void *ctx, int result), void *ctx);
+/*
+ * askalg has the same set of return values as verify_ssh_host_key.
+ */
+int askalg(void *frontend, const char *algtype, const char *algname,
+          void (*callback)(void *ctx, int result), void *ctx);
 int askappend(void *frontend, Filename filename);
 
 /*
 int askappend(void *frontend, Filename filename);
 
 /*
diff --git a/ssh.c b/ssh.c
index e2e80772c8a9a5d653da05f2dcbdfa477ec2527d..e41e9a9eb63537acb72d2911c377258c66bcaebc 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -726,10 +726,23 @@ struct ssh_tag {
     Config cfg;
 
     /*
     Config cfg;
 
     /*
-     * Used to transfer data back from async agent callbacks.
+     * Used to transfer data back from async callbacks.
      */
     void *agent_response;
     int agent_response_len;
      */
     void *agent_response;
     int agent_response_len;
+    int user_response;
+
+    /*
+     * The SSH connection can be set as `frozen', meaning we are
+     * not currently accepting incoming data from the network. This
+     * is slightly more serious than setting the _socket_ as
+     * frozen, because we may already have had data passed to us
+     * from the network which we need to delay processing until
+     * after the freeze is lifted, so we also need a bufchain to
+     * store that data.
+     */
+    int frozen;
+    bufchain queued_incoming_data;
 
     /*
      * Dispatch table for packet types that we may have to deal
 
     /*
      * Dispatch table for packet types that we may have to deal
@@ -2331,6 +2344,49 @@ static int do_ssh_init(Ssh ssh, unsigned char c)
     crFinish(0);
 }
 
     crFinish(0);
 }
 
+static void ssh_process_incoming_data(Ssh ssh,
+                                     unsigned char **data, int *datalen)
+{
+    struct Packet *pktin = ssh->s_rdpkt(ssh, data, datalen);
+    if (pktin) {
+       ssh->protocol(ssh, NULL, 0, pktin);
+       ssh_free_packet(pktin);
+    }
+}
+
+static void ssh_queue_incoming_data(Ssh ssh,
+                                   unsigned char **data, int *datalen)
+{
+    bufchain_add(&ssh->queued_incoming_data, *data, *datalen);
+    *data += *datalen;
+    *datalen = 0;
+}
+
+static void ssh_process_queued_incoming_data(Ssh ssh)
+{
+    void *vdata;
+    unsigned char *data;
+    int len, origlen;
+
+    while (!ssh->frozen && bufchain_size(&ssh->queued_incoming_data)) {
+       bufchain_prefix(&ssh->queued_incoming_data, &vdata, &len);
+       data = vdata;
+       origlen = len;
+
+       while (!ssh->frozen && len > 0)
+           ssh_process_incoming_data(ssh, &data, &len);
+
+       if (origlen > len)
+           bufchain_consume(&ssh->queued_incoming_data, origlen - len);
+    }
+}
+
+static void ssh_set_frozen(Ssh ssh, int frozen)
+{
+    sk_set_frozen(ssh->s, frozen);
+    ssh->frozen = frozen;
+}
+
 static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen)
 {
     crBegin(ssh->ssh_gotdata_crstate);
 static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen)
 {
     crBegin(ssh->ssh_gotdata_crstate);
@@ -2360,13 +2416,19 @@ static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen)
      */
     if (datalen == 0)
        crReturnV;
      */
     if (datalen == 0)
        crReturnV;
+
+    /*
+     * Process queued data if there is any.
+     */
+    ssh_process_queued_incoming_data(ssh);
+
     while (1) {
        while (datalen > 0) {
     while (1) {
        while (datalen > 0) {
-           struct Packet *pktin = ssh->s_rdpkt(ssh, &data, &datalen);
-           if (pktin) {
-               ssh->protocol(ssh, NULL, 0, pktin);
-               ssh_free_packet(pktin);
-           }
+           if (ssh->frozen)
+               ssh_queue_incoming_data(ssh, &data, &datalen);
+
+           ssh_process_incoming_data(ssh, &data, &datalen);
+
            if (ssh->state == SSH_STATE_CLOSED)
                return;
        }
            if (ssh->state == SSH_STATE_CLOSED)
                return;
        }
@@ -2554,9 +2616,9 @@ static void ssh1_throttle(Ssh ssh, int adjust)
     ssh->v1_throttle_count += adjust;
     assert(ssh->v1_throttle_count >= 0);
     if (ssh->v1_throttle_count && !old_count) {
     ssh->v1_throttle_count += adjust;
     assert(ssh->v1_throttle_count >= 0);
     if (ssh->v1_throttle_count && !old_count) {
-       sk_set_frozen(ssh->s, 1);
+       ssh_set_frozen(ssh, 1);
     } else if (!ssh->v1_throttle_count && old_count) {
     } else if (!ssh->v1_throttle_count && old_count) {
-       sk_set_frozen(ssh->s, 0);
+       ssh_set_frozen(ssh, 0);
     }
 }
 
     }
 }
 
@@ -2680,6 +2742,24 @@ static void ssh_agent_callback(void *sshv, void *reply, int replylen)
        do_ssh2_authconn(ssh, NULL, -1, NULL);
 }
 
        do_ssh2_authconn(ssh, NULL, -1, NULL);
 }
 
+static void ssh_dialog_callback(void *sshv, int ret)
+{
+    Ssh ssh = (Ssh) sshv;
+
+    ssh->user_response = ret;
+
+    if (ssh->version == 1)
+       do_ssh1_login(ssh, NULL, -1, NULL);
+    else
+       do_ssh2_transport(ssh, NULL, -1, NULL);
+
+    /*
+     * This may have unfrozen the SSH connection, so do a
+     * queued-data run.
+     */
+    ssh_process_queued_incoming_data(ssh);
+}
+
 static void ssh_agentf_callback(void *cv, void *reply, int replylen)
 {
     struct ssh_channel *c = (struct ssh_channel *)cv;
 static void ssh_agentf_callback(void *cv, void *reply, int replylen)
 {
     struct ssh_channel *c = (struct ssh_channel *)cv;
@@ -2741,6 +2821,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
        Bignum challenge;
        char *commentp;
        int commentlen;
        Bignum challenge;
        char *commentp;
        int commentlen;
+        int dlgret;
     };
     crState(do_ssh1_login_state);
 
     };
     crState(do_ssh1_login_state);
 
@@ -2828,10 +2909,30 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
            fatalbox("Out of memory");
        rsastr_fmt(keystr, &hostkey);
        rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey);
            fatalbox("Out of memory");
        rsastr_fmt(keystr, &hostkey);
        rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey);
-       verify_ssh_host_key(ssh->frontend,
-                           ssh->savedhost, ssh->savedport, "rsa", keystr,
-                           fingerprint);
+
+        ssh_set_frozen(ssh, 1);
+       s->dlgret = verify_ssh_host_key(ssh->frontend,
+                                        ssh->savedhost, ssh->savedport,
+                                        "rsa", keystr, fingerprint,
+                                        ssh_dialog_callback, ssh);
        sfree(keystr);
        sfree(keystr);
+        if (s->dlgret < 0) {
+            do {
+                crReturn(0);
+                if (pktin) {
+                    bombout(("Unexpected data from server while waiting"
+                             " for user host key response"));
+                    crStop(0);
+                }
+            } while (pktin || inlen > 0);
+            s->dlgret = ssh->user_response;
+        }
+        ssh_set_frozen(ssh, 0);
+
+        if (s->dlgret == 0) {
+            ssh->close_expected = TRUE;
+            ssh_closing((Plug)ssh, NULL, 0, 0);
+        }
     }
 
     for (i = 0; i < 32; i++) {
     }
 
     for (i = 0; i < 32; i++) {
@@ -2893,9 +2994,25 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
 
        /* Warn about chosen cipher if necessary. */
        if (warn) {
 
        /* Warn about chosen cipher if necessary. */
        if (warn) {
-            sk_set_frozen(ssh->s, 1);
-           askalg(ssh->frontend, "cipher", cipher_string);
-            sk_set_frozen(ssh->s, 0);
+            ssh_set_frozen(ssh, 1);
+           s->dlgret = askalg(ssh->frontend, "cipher", cipher_string,
+                              ssh_dialog_callback, ssh);
+           if (s->dlgret < 0) {
+               do {
+                   crReturn(0);
+                   if (pktin) {
+                       bombout(("Unexpected data from server while waiting"
+                                " for user response"));
+                       crStop(0);
+                   }
+               } while (pktin || inlen > 0);
+               s->dlgret = ssh->user_response;
+           }
+            ssh_set_frozen(ssh, 0);
+           if (s->dlgret == 0) {
+               ssh->close_expected = TRUE;
+               ssh_closing((Plug)ssh, NULL, 0, 0);
+           }
         }
     }
 
         }
     }
 
@@ -4732,6 +4849,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
        const struct ssh_compress *preferred_comp;
        int got_session_id, activated_authconn;
        struct Packet *pktout;
        const struct ssh_compress *preferred_comp;
        int got_session_id, activated_authconn;
        struct Packet *pktout;
+        int dlgret;
+       int guessok;
     };
     crState(do_ssh2_transport_state);
 
     };
     crState(do_ssh2_transport_state);
 
@@ -4945,7 +5064,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
      */
     {
        char *str;
      */
     {
        char *str;
-       int i, j, len, guessok;
+       int i, j, len;
 
        if (pktin->type != SSH2_MSG_KEXINIT) {
            bombout(("expected key exchange packet from server"));
 
        if (pktin->type != SSH2_MSG_KEXINIT) {
            bombout(("expected key exchange packet from server"));
@@ -4971,10 +5090,26 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
            }
            if (ssh->kex) {
                if (s->warn) {
            }
            if (ssh->kex) {
                if (s->warn) {
-                    sk_set_frozen(ssh->s, 1);
-                   askalg(ssh->frontend, "key-exchange algorithm",
-                          ssh->kex->name);
-                    sk_set_frozen(ssh->s, 0);
+                   ssh_set_frozen(ssh, 1);
+                   s->dlgret = askalg(ssh->frontend, "key-exchange algorithm",
+                                      ssh->kex->name,
+                                      ssh_dialog_callback, ssh);
+                   if (s->dlgret < 0) {
+                       do {
+                           crReturn(0);
+                           if (pktin) {
+                               bombout(("Unexpected data from server while"
+                                        " waiting for user response"));
+                               crStop(0);
+                           }
+                       } while (pktin || inlen > 0);
+                       s->dlgret = ssh->user_response;
+                   }
+                   ssh_set_frozen(ssh, 0);
+                   if (s->dlgret == 0) {
+                       ssh->close_expected = TRUE;
+                       ssh_closing((Plug)ssh, NULL, 0, 0);
+                   }
                 }
                break;
            }
                 }
                break;
            }
@@ -4989,7 +5124,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
         * the first algorithm in our list, even if it's still the algorithm
         * we end up using.
         */
         * the first algorithm in our list, even if it's still the algorithm
         * we end up using.
         */
-       guessok =
+       s->guessok =
            first_in_commasep_string(s->preferred_kex[0]->name, str, len);
        ssh_pkt_getstring(pktin, &str, &len);    /* host key algorithms */
        for (i = 0; i < lenof(hostkey_algs); i++) {
            first_in_commasep_string(s->preferred_kex[0]->name, str, len);
        ssh_pkt_getstring(pktin, &str, &len);    /* host key algorithms */
        for (i = 0; i < lenof(hostkey_algs); i++) {
@@ -4998,7 +5133,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
                break;
            }
        }
                break;
            }
        }
-       guessok = guessok &&
+       s->guessok = s->guessok &&
            first_in_commasep_string(hostkey_algs[0]->name, str, len);
        ssh_pkt_getstring(pktin, &str, &len);    /* client->server cipher */
        s->warn = 0;
            first_in_commasep_string(hostkey_algs[0]->name, str, len);
        ssh_pkt_getstring(pktin, &str, &len);    /* client->server cipher */
        s->warn = 0;
@@ -5016,10 +5151,27 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
            }
            if (s->cscipher_tobe) {
                if (s->warn) {
            }
            if (s->cscipher_tobe) {
                if (s->warn) {
-                    sk_set_frozen(ssh->s, 1);
-                   askalg(ssh->frontend, "client-to-server cipher",
-                          s->cscipher_tobe->name);
-                    sk_set_frozen(ssh->s, 0);
+                   ssh_set_frozen(ssh, 1);
+                   s->dlgret = askalg(ssh->frontend,
+                                      "client-to-server cipher",
+                                      s->cscipher_tobe->name,
+                                      ssh_dialog_callback, ssh);
+                   if (s->dlgret < 0) {
+                       do {
+                           crReturn(0);
+                           if (pktin) {
+                               bombout(("Unexpected data from server while"
+                                        " waiting for user response"));
+                               crStop(0);
+                           }
+                       } while (pktin || inlen > 0);
+                       s->dlgret = ssh->user_response;
+                   }
+                   ssh_set_frozen(ssh, 0);
+                   if (s->dlgret == 0) {
+                       ssh->close_expected = TRUE;
+                       ssh_closing((Plug)ssh, NULL, 0, 0);
+                   }
                 }
                break;
            }
                 }
                break;
            }
@@ -5046,10 +5198,27 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
            }
            if (s->sccipher_tobe) {
                if (s->warn) {
            }
            if (s->sccipher_tobe) {
                if (s->warn) {
-                    sk_set_frozen(ssh->s, 1);
-                   askalg(ssh->frontend, "server-to-client cipher",
-                          s->sccipher_tobe->name);
-                    sk_set_frozen(ssh->s, 0);
+                   ssh_set_frozen(ssh, 1);
+                   s->dlgret = askalg(ssh->frontend,
+                                      "server-to-client cipher",
+                                      s->sccipher_tobe->name,
+                                      ssh_dialog_callback, ssh);
+                   if (s->dlgret < 0) {
+                       do {
+                           crReturn(0);
+                           if (pktin) {
+                               bombout(("Unexpected data from server while"
+                                        " waiting for user response"));
+                               crStop(0);
+                           }
+                       } while (pktin || inlen > 0);
+                       s->dlgret = ssh->user_response;
+                   }
+                   ssh_set_frozen(ssh, 0);
+                   if (s->dlgret == 0) {
+                       ssh->close_expected = TRUE;
+                       ssh_closing((Plug)ssh, NULL, 0, 0);
+                   }
                 }
                break;
            }
                 }
                break;
            }
@@ -5094,7 +5263,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
        }
        ssh_pkt_getstring(pktin, &str, &len);  /* client->server language */
        ssh_pkt_getstring(pktin, &str, &len);  /* server->client language */
        }
        ssh_pkt_getstring(pktin, &str, &len);  /* client->server language */
        ssh_pkt_getstring(pktin, &str, &len);  /* server->client language */
-       if (ssh2_pkt_getbool(pktin) && !guessok) /* first_kex_packet_follows */
+       if (ssh2_pkt_getbool(pktin) && !s->guessok) /* first_kex_packet_follows */
            crWaitUntil(pktin);                /* Ignore packet */
     }
 
            crWaitUntil(pktin);                /* Ignore packet */
     }
 
@@ -5218,11 +5387,29 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
      */
     s->keystr = ssh->hostkey->fmtkey(s->hkey);
     s->fingerprint = ssh->hostkey->fingerprint(s->hkey);
      */
     s->keystr = ssh->hostkey->fmtkey(s->hkey);
     s->fingerprint = ssh->hostkey->fingerprint(s->hkey);
-    sk_set_frozen(ssh->s, 1);
-    verify_ssh_host_key(ssh->frontend,
-                       ssh->savedhost, ssh->savedport, ssh->hostkey->keytype,
-                       s->keystr, s->fingerprint);
-    sk_set_frozen(ssh->s, 0);
+    ssh_set_frozen(ssh, 1);
+    s->dlgret = verify_ssh_host_key(ssh->frontend,
+                                    ssh->savedhost, ssh->savedport,
+                                    ssh->hostkey->keytype, s->keystr,
+                                   s->fingerprint,
+                                    ssh_dialog_callback, ssh);
+    if (s->dlgret < 0) {
+        do {
+            crReturn(0);
+            if (pktin) {
+                bombout(("Unexpected data from server while waiting"
+                         " for user host key response"));
+                    crStop(0);
+            }
+        } while (pktin || inlen > 0);
+        s->dlgret = ssh->user_response;
+    }
+    ssh_set_frozen(ssh, 0);
+    if (s->dlgret == 0) {
+        ssh->close_expected = TRUE;
+        ssh_closing((Plug)ssh, NULL, 0, 0);
+        crStop(0);
+    }
     if (!s->got_session_id) {     /* don't bother logging this in rekeys */
        logevent("Host key fingerprint is:");
        logevent(s->fingerprint);
     if (!s->got_session_id) {     /* don't bother logging this in rekeys */
        logevent("Host key fingerprint is:");
        logevent(s->fingerprint);
@@ -7477,6 +7664,8 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
     ssh->queueing = FALSE;
     ssh->qhead = ssh->qtail = NULL;
     ssh->deferred_rekey_reason = NULL;
     ssh->queueing = FALSE;
     ssh->qhead = ssh->qtail = NULL;
     ssh->deferred_rekey_reason = NULL;
+    bufchain_init(&ssh->queued_incoming_data);
+    ssh->frozen = FALSE;
 
     *backend_handle = ssh;
 
 
     *backend_handle = ssh;
 
@@ -7603,6 +7792,7 @@ static void ssh_free(void *handle)
     expire_timer_context(ssh);
     if (ssh->pinger)
        pinger_free(ssh->pinger);
     expire_timer_context(ssh);
     if (ssh->pinger)
        pinger_free(ssh->pinger);
+    bufchain_clear(&ssh->queued_incoming_data);
     sfree(ssh);
 
     random_unref();
     sfree(ssh);
 
     random_unref();
index 2a293804a18718d5396a9de852bdee26cb521f6a..2ef18313c7e9ca27619345630737ba015e04af94 100644 (file)
@@ -2294,8 +2294,9 @@ int reallyclose(void *frontend)
     return ret;
 }
 
     return ret;
 }
 
-void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
-                        char *keystr, char *fingerprint)
+int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
+                        char *keystr, char *fingerprint,
+                        void (*callback)(void *ctx, int result), void *ctx)
 {
     static const char absenttxt[] =
        "The server's host key is not cached. You have no guarantee "
 {
     static const char absenttxt[] =
        "The server's host key is not cached. You have no guarantee "
@@ -2332,7 +2333,7 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)                     /* success - key matched OK */
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)                     /* success - key matched OK */
-       return;
+       return 1;
 
     text = dupprintf((ret == 2 ? wrongtxt : absenttxt), keytype, fingerprint);
 
 
     text = dupprintf((ret == 2 ? wrongtxt : absenttxt), keytype, fingerprint);
 
@@ -2347,16 +2348,20 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     sfree(text);
 
     if (ret == 0)
     sfree(text);
 
     if (ret == 0)
-       cleanup_exit(0);
-    else if (ret == 2)
-       store_host_key(host, port, keytype, keystr);
+        return 0;                      /* do not continue with connection */
+    else {
+        if (ret == 2)
+            store_host_key(host, port, keytype, keystr);
+        return 1;                      /* continue with connection */
+    }
 }
 
 /*
  * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
  */
 }
 
 /*
  * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
  */
-void askalg(void *frontend, const char *algtype, const char *algname)
+int askalg(void *frontend, const char *algtype, const char *algname,
+          void (*callback)(void *ctx, int result), void *ctx)
 {
     static const char msg[] =
        "The first %s supported by the server is "
 {
     static const char msg[] =
        "The first %s supported by the server is "
@@ -2375,9 +2380,9 @@ void askalg(void *frontend, const char *algtype, const char *algname)
     sfree(text);
 
     if (ret) {
     sfree(text);
 
     if (ret) {
-       return;
+       return 1;
     } else {
     } else {
-       cleanup_exit(0);
+       return 0;
     }
 }
 
     }
 }
 
index 7f05d1fa5fc3057ebadd2bcb806dc37be93559d8..ef2866ccca5b56918b05928e4834be7cb96d684d 100644 (file)
@@ -47,8 +47,9 @@ void timer_change_notify(long next)
 {
 }
 
 {
 }
 
-void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
-                        char *keystr, char *fingerprint)
+int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
+                        char *keystr, char *fingerprint,
+                        void (*callback)(void *ctx, int result), void *ctx)
 {
     int ret;
 
 {
     int ret;
 
@@ -107,12 +108,12 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)                     /* success - key matched OK */
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)                     /* success - key matched OK */
-       return;
+       return 1;
 
     if (ret == 2) {                   /* key was different */
        if (console_batch_mode) {
            fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
 
     if (ret == 2) {                   /* key was different */
        if (console_batch_mode) {
            fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
-           cleanup_exit(1);
+           return 0;
        }
        fprintf(stderr, wrongmsg, keytype, fingerprint);
        fflush(stderr);
        }
        fprintf(stderr, wrongmsg, keytype, fingerprint);
        fflush(stderr);
@@ -120,7 +121,7 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     if (ret == 1) {                   /* key was absent */
        if (console_batch_mode) {
            fprintf(stderr, absentmsg_batch, keytype, fingerprint);
     if (ret == 1) {                   /* key was absent */
        if (console_batch_mode) {
            fprintf(stderr, absentmsg_batch, keytype, fingerprint);
-           cleanup_exit(1);
+           return 0;
        }
        fprintf(stderr, absentmsg, keytype, fingerprint);
        fflush(stderr);
        }
        fprintf(stderr, absentmsg, keytype, fingerprint);
        fflush(stderr);
@@ -140,9 +141,10 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
        if (line[0] == 'y' || line[0] == 'Y')
            store_host_key(host, port, keytype, keystr);
     if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
        if (line[0] == 'y' || line[0] == 'Y')
            store_host_key(host, port, keytype, keystr);
+        return 1;
     } else {
        fprintf(stderr, abandoned);
     } else {
        fprintf(stderr, abandoned);
-       cleanup_exit(0);
+        return 0;
     }
 }
 
     }
 }
 
@@ -150,7 +152,8 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
  * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
  */
  * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
  */
-void askalg(void *frontend, const char *algtype, const char *algname)
+int askalg(void *frontend, const char *algtype, const char *algname,
+          void (*callback)(void *ctx, int result), void *ctx)
 {
     static const char msg[] =
        "The first %s supported by the server is\n"
 {
     static const char msg[] =
        "The first %s supported by the server is\n"
@@ -166,7 +169,7 @@ void askalg(void *frontend, const char *algtype, const char *algname)
 
     if (console_batch_mode) {
        fprintf(stderr, msg_batch, algtype, algname);
 
     if (console_batch_mode) {
        fprintf(stderr, msg_batch, algtype, algname);
-       cleanup_exit(1);
+       return 0;
     }
 
     fprintf(stderr, msg, algtype, algname);
     }
 
     fprintf(stderr, msg, algtype, algname);
@@ -184,10 +187,10 @@ void askalg(void *frontend, const char *algtype, const char *algname)
     }
 
     if (line[0] == 'y' || line[0] == 'Y') {
     }
 
     if (line[0] == 'y' || line[0] == 'Y') {
-       return;
+       return 1;
     } else {
        fprintf(stderr, abandoned);
     } else {
        fprintf(stderr, abandoned);
-       cleanup_exit(0);
+       return 0;
     }
 }
 
     }
 }
 
index 3417720a3542e0cb1a2c622dce8ae3dec553ef05..0791358643becb0544802789ec851f8a1978cc16 100644 (file)
@@ -45,8 +45,9 @@ void timer_change_notify(long next)
 {
 }
 
 {
 }
 
-void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
-                        char *keystr, char *fingerprint)
+int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
+                        char *keystr, char *fingerprint,
+                        void (*callback)(void *ctx, int result), void *ctx)
 {
     int ret;
     HANDLE hin;
 {
     int ret;
     HANDLE hin;
@@ -111,12 +112,12 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)                     /* success - key matched OK */
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)                     /* success - key matched OK */
-       return;
+       return 1;
 
     if (ret == 2) {                   /* key was different */
        if (console_batch_mode) {
            fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
 
     if (ret == 2) {                   /* key was different */
        if (console_batch_mode) {
            fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
-           cleanup_exit(1);
+            return 0;
        }
        fprintf(stderr, wrongmsg, keytype, fingerprint);
        fflush(stderr);
        }
        fprintf(stderr, wrongmsg, keytype, fingerprint);
        fflush(stderr);
@@ -124,7 +125,7 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     if (ret == 1) {                   /* key was absent */
        if (console_batch_mode) {
            fprintf(stderr, absentmsg_batch, keytype, fingerprint);
     if (ret == 1) {                   /* key was absent */
        if (console_batch_mode) {
            fprintf(stderr, absentmsg_batch, keytype, fingerprint);
-           cleanup_exit(1);
+            return 0;
        }
        fprintf(stderr, absentmsg, keytype, fingerprint);
        fflush(stderr);
        }
        fprintf(stderr, absentmsg, keytype, fingerprint);
        fflush(stderr);
@@ -140,9 +141,10 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
        if (line[0] == 'y' || line[0] == 'Y')
            store_host_key(host, port, keytype, keystr);
     if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
        if (line[0] == 'y' || line[0] == 'Y')
            store_host_key(host, port, keytype, keystr);
+        return 1;
     } else {
        fprintf(stderr, abandoned);
     } else {
        fprintf(stderr, abandoned);
-       cleanup_exit(0);
+        return 0;
     }
 }
 
     }
 }
 
@@ -154,7 +156,8 @@ void update_specials_menu(void *frontend)
  * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
  */
  * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
  */
-void askalg(void *frontend, const char *algtype, const char *algname)
+int askalg(void *frontend, const char *algtype, const char *algname,
+          void (*callback)(void *ctx, int result), void *ctx)
 {
     HANDLE hin;
     DWORD savemode, i;
 {
     HANDLE hin;
     DWORD savemode, i;
@@ -173,7 +176,7 @@ void askalg(void *frontend, const char *algtype, const char *algname)
 
     if (console_batch_mode) {
        fprintf(stderr, msg_batch, algtype, algname);
 
     if (console_batch_mode) {
        fprintf(stderr, msg_batch, algtype, algname);
-       cleanup_exit(1);
+       return 0;
     }
 
     fprintf(stderr, msg, algtype, algname);
     }
 
     fprintf(stderr, msg, algtype, algname);
@@ -187,10 +190,10 @@ void askalg(void *frontend, const char *algtype, const char *algname)
     SetConsoleMode(hin, savemode);
 
     if (line[0] == 'y' || line[0] == 'Y') {
     SetConsoleMode(hin, savemode);
 
     if (line[0] == 'y' || line[0] == 'Y') {
-       return;
+       return 1;
     } else {
        fprintf(stderr, abandoned);
     } else {
        fprintf(stderr, abandoned);
-       cleanup_exit(0);
+       return 0;
     }
 }
 
     }
 }
 
index 8903871412b88ee30be03b943517847eef60bab2..742a761b7c4a3bd7cc9f37b59c0beca7f3874fc2 100644 (file)
@@ -723,8 +723,9 @@ static VOID CALLBACK verify_ssh_host_key_help(LPHELPINFO lpHelpInfo)
     }
 }
 
     }
 }
 
-void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
-                        char *keystr, char *fingerprint)
+int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
+                        char *keystr, char *fingerprint,
+                        void (*callback)(void *ctx, int result), void *ctx)
 {
     int ret;
 
 {
     int ret;
 
@@ -782,7 +783,7 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)                     /* success - key matched OK */
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)                     /* success - key matched OK */
-       return;
+       return 1;
     if (ret == 2) {                   /* key was different */
        int mbret;
        mbox.lpszText = dupprintf(wrongmsg, appname, keytype, fingerprint,
     if (ret == 2) {                   /* key was different */
        int mbret;
        mbox.lpszText = dupprintf(wrongmsg, appname, keytype, fingerprint,
@@ -797,7 +798,8 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
        if (mbret == IDYES)
            store_host_key(host, port, keytype, keystr);
        if (mbret == IDCANCEL)
        if (mbret == IDYES)
            store_host_key(host, port, keytype, keystr);
        if (mbret == IDCANCEL)
-           cleanup_exit(0);
+           return 0;
+        return 1;
     }
     if (ret == 1) {                   /* key was absent */
        int mbret;
     }
     if (ret == 1) {                   /* key was absent */
        int mbret;
@@ -812,7 +814,8 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
        if (mbret == IDYES)
            store_host_key(host, port, keytype, keystr);
        if (mbret == IDCANCEL)
        if (mbret == IDYES)
            store_host_key(host, port, keytype, keystr);
        if (mbret == IDCANCEL)
-           cleanup_exit(0);
+           return 0;
+        return 1;
     }
 }
 
     }
 }
 
@@ -820,7 +823,8 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
  * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
  */
  * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
  */
-void askalg(void *frontend, const char *algtype, const char *algname)
+int askalg(void *frontend, const char *algtype, const char *algname,
+          void (*callback)(void *ctx, int result), void *ctx)
 {
     static const char mbtitle[] = "%s Security Alert";
     static const char msg[] =
 {
     static const char mbtitle[] = "%s Security Alert";
     static const char msg[] =
@@ -838,9 +842,9 @@ void askalg(void *frontend, const char *algtype, const char *algname)
     sfree(message);
     sfree(title);
     if (mbret == IDYES)
     sfree(message);
     sfree(title);
     if (mbret == IDYES)
-       return;
+       return 1;
     else
     else
-       cleanup_exit(0);
+       return 0;
 }
 
 /*
 }
 
 /*