1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-25 01:02:24 +00:00

Revamp interface to verify_ssh_host_key() and askalg(). Each of them

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.

[originally from svn r5330]
This commit is contained in:
Simon Tatham 2005-02-17 18:34:24 +00:00
parent 92ccb964a2
commit 8574822b9b
11 changed files with 456 additions and 140 deletions

View File

@ -691,8 +691,9 @@ int agent_query(void *in, int inlen, void **out, int *outlen,
/* 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;
@ -705,64 +706,55 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
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)

View 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!
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

View File

@ -40,6 +40,8 @@ extern AppController *controller;
void *ldisc;
Backend *back;
void *backhandle;
void (*alert_callback)(void *, int);
void *alert_ctx;
}
- (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)startAlert:(NSAlert *)alert
withCallback:(void (*)(void *, int))callback andCtx:(void *)ctx;
@end
/*

View File

@ -311,16 +311,104 @@ int askappend(void *frontend, Filename filename)
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)
{
fatalbox("Cipher algorithm dialog box not supported yet");
return; /* FIXME */
struct algstate *state = (struct algstate *)ctx;
state->callback(state->ctx, result == 0);
sfree(state);
}
void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
char *keystr, char *fingerprint)
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)
{
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);
}
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.
@ -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)
return;
return 1;
/*
* 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");
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)

View File

@ -207,6 +207,8 @@
{
NSRect rect = { {0,0}, {0,0} };
alert_ctx = NULL;
cfg = aCfg; /* structure copy */
init_ucs(&ucsdata, cfg.line_codepage, cfg.utf8_override,
@ -307,6 +309,7 @@
* terminal, the backend, the ldisc, the logctx, you name it.
* Do so.
*/
sfree(alert_ctx);
[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);
}
- (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)

23
putty.h
View File

@ -896,9 +896,26 @@ int wc_unescape(char *output, const char *wildcard);
* 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);
/*

260
ssh.c
View File

@ -726,10 +726,23 @@ struct ssh_tag {
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
@ -2331,6 +2344,49 @@ static int do_ssh_init(Ssh ssh, unsigned char c)
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);
@ -2360,13 +2416,19 @@ static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen)
*/
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;
}
@ -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) {
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);
}
}
@ -2680,6 +2742,24 @@ static void ssh_agent_callback(void *sshv, void *reply, int replylen)
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;
@ -2741,6 +2821,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
Bignum challenge;
char *commentp;
int commentlen;
int dlgret;
};
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);
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++) {
@ -2893,9 +2994,25 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
/* 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;
int dlgret;
int guessok;
};
crState(do_ssh2_transport_state);
@ -4945,7 +5064,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
*/
{
char *str;
int i, j, len, guessok;
int i, j, len;
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) {
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;
}
@ -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.
*/
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++) {
@ -4998,7 +5133,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
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;
@ -5016,10 +5151,27 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
}
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;
}
@ -5046,10 +5198,27 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
}
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;
}
@ -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 */
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 */
}
@ -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);
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);
@ -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;
bufchain_init(&ssh->queued_incoming_data);
ssh->frozen = FALSE;
*backend_handle = ssh;
@ -7603,6 +7792,7 @@ static void ssh_free(void *handle)
expire_timer_context(ssh);
if (ssh->pinger)
pinger_free(ssh->pinger);
bufchain_clear(&ssh->queued_incoming_data);
sfree(ssh);
random_unref();

View File

@ -2294,8 +2294,9 @@ int reallyclose(void *frontend)
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 "
@ -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 */
return;
return 1;
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)
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 "
@ -2375,9 +2380,9 @@ void askalg(void *frontend, const char *algtype, const char *algname)
sfree(text);
if (ret) {
return;
return 1;
} else {
cleanup_exit(0);
return 0;
}
}

View 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;
@ -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 */
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);
@ -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);
cleanup_exit(1);
return 0;
}
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);
return 1;
} 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).
*/
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"
@ -166,7 +169,7 @@ void askalg(void *frontend, const char *algtype, const char *algname)
if (console_batch_mode) {
fprintf(stderr, msg_batch, algtype, algname);
cleanup_exit(1);
return 0;
}
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') {
return;
return 1;
} else {
fprintf(stderr, abandoned);
cleanup_exit(0);
return 0;
}
}

View 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;
@ -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 */
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);
@ -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);
cleanup_exit(1);
return 0;
}
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);
return 1;
} 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).
*/
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;
@ -173,7 +176,7 @@ void askalg(void *frontend, const char *algtype, const char *algname)
if (console_batch_mode) {
fprintf(stderr, msg_batch, algtype, algname);
cleanup_exit(1);
return 0;
}
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') {
return;
return 1;
} else {
fprintf(stderr, abandoned);
cleanup_exit(0);
return 0;
}
}

View 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;
@ -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 */
return;
return 1;
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)
cleanup_exit(0);
return 0;
return 1;
}
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)
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).
*/
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[] =
@ -838,9 +842,9 @@ void askalg(void *frontend, const char *algtype, const char *algname)
sfree(message);
sfree(title);
if (mbret == IDYES)
return;
return 1;
else
cleanup_exit(0);
return 0;
}
/*