mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-01 11:32:48 -05: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:
@ -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)
|
||||
|
Reference in New Issue
Block a user