/* 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;
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);
- 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 */
- goto cancel;
+ return 0;
} else if (alertret == 9) {
/* Connect Just Once */
+ return 1;
} 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 */
- goto cancel;
+ return 0;
} else if (alertret == 8) {
/* Connect Just Once */
+ return 1;
} 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)
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
void *ldisc;
Backend *back;
void *backhandle;
+ void (*alert_callback)(void *, int);
+ void *alert_ctx;
}
- (id)initWithConfig:(Config)cfg;
- (void)drawStartFinish:(BOOL)start;
- (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
/*
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;
+ char *text;
+ SessionWindow *win = (SessionWindow *)frontend;
+ struct hostkeystate *state;
+ NSAlert *alert;
/*
* Verify the key.
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)
{
NSRect rect = { {0,0}, {0,0} };
+ alert_ctx = NULL;
+
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.
*/
+ sfree(alert_ctx);
[super dealloc];
}
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)
* 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);
/*
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;
+ 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
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);
*/
if (datalen == 0)
crReturnV;
+
+ /*
+ * Process queued data if there is any.
+ */
+ ssh_process_queued_incoming_data(ssh);
+
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;
}
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) {
- sk_set_frozen(ssh->s, 0);
+ ssh_set_frozen(ssh, 0);
}
}
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;
Bignum challenge;
char *commentp;
int commentlen;
+ int dlgret;
};
crState(do_ssh1_login_state);
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);
+ 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++) {
/* 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);
+ }
}
}
const struct ssh_compress *preferred_comp;
int got_session_id, activated_authconn;
struct Packet *pktout;
+ int dlgret;
+ int guessok;
};
crState(do_ssh2_transport_state);
*/
{
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 (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;
}
* 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++) {
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;
}
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;
}
}
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;
}
}
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 */
}
*/
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);
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;
expire_timer_context(ssh);
if (ssh->pinger)
pinger_free(ssh->pinger);
+ bufchain_clear(&ssh->queued_incoming_data);
sfree(ssh);
random_unref();
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 "
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);
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).
*/
-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 "
sfree(text);
if (ret) {
- return;
+ return 1;
} else {
- cleanup_exit(0);
+ return 0;
}
}
{
}
-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;
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);
- cleanup_exit(1);
+ return 0;
}
fprintf(stderr, wrongmsg, keytype, fingerprint);
fflush(stderr);
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);
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);
- cleanup_exit(0);
+ return 0;
}
}
* 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"
if (console_batch_mode) {
fprintf(stderr, msg_batch, algtype, algname);
- cleanup_exit(1);
+ return 0;
}
fprintf(stderr, msg, algtype, algname);
}
if (line[0] == 'y' || line[0] == 'Y') {
- return;
+ return 1;
} else {
fprintf(stderr, abandoned);
- cleanup_exit(0);
+ return 0;
}
}
{
}
-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;
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);
- cleanup_exit(1);
+ return 0;
}
fprintf(stderr, wrongmsg, keytype, fingerprint);
fflush(stderr);
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);
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);
- cleanup_exit(0);
+ return 0;
}
}
* 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;
if (console_batch_mode) {
fprintf(stderr, msg_batch, algtype, algname);
- cleanup_exit(1);
+ return 0;
}
fprintf(stderr, msg, algtype, algname);
SetConsoleMode(hin, savemode);
if (line[0] == 'y' || line[0] == 'Y') {
- return;
+ return 1;
} else {
fprintf(stderr, abandoned);
- cleanup_exit(0);
+ return 0;
}
}
}
}
-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;
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 (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 (mbret == IDYES)
store_host_key(host, port, keytype, keystr);
if (mbret == IDCANCEL)
- cleanup_exit(0);
+ return 0;
+ return 1;
}
}
* 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[] =
sfree(message);
sfree(title);
if (mbret == IDYES)
- return;
+ return 1;
else
- cleanup_exit(0);
+ return 0;
}
/*