Revamp interface to verify_ssh_host_key() and askalg(). Each of them
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 17 Feb 2005 18:34:24 +0000 (18:34 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
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: svn://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 f663dee..2fb7d44 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 9dded05..8d989a6 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 5f009a9..76a8fc7 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 5bc13a4..0ea327f 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 a54f771..8166f91 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 0b49dfa..46708f1 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 e2e8077..e41e9a9 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 2a29380..2ef1831 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 7f05d1f..ef2866c 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 3417720..0791358 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 8903871..742a761 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;
 }
 
 /*
 }
 
 /*