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:
parent
92ccb964a2
commit
8574822b9b
52
mac/mac.c
52
mac/mac.c
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
141
macosx/osxdlg.m
141
macosx/osxdlg.m
@ -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)
|
||||
|
@ -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
23
putty.h
@ -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
260
ssh.c
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user