aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPSSHTunnel.m
diff options
context:
space:
mode:
Diffstat (limited to 'Source/SPSSHTunnel.m')
-rw-r--r--Source/SPSSHTunnel.m87
1 files changed, 72 insertions, 15 deletions
diff --git a/Source/SPSSHTunnel.m b/Source/SPSSHTunnel.m
index 433ccad4..c4c01783 100644
--- a/Source/SPSSHTunnel.m
+++ b/Source/SPSSHTunnel.m
@@ -53,7 +53,17 @@
stateChangeSelector = nil;
lastError = nil;
- passwordConnection = nil;
+ // Set up a connection for use by the tunnel process
+ tunnelConnectionName = [NSString stringWithFormat:@"SequelPro-%f", [[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] hash]];
+ tunnelConnection = [[NSConnection defaultConnection] retain];
+ [tunnelConnection runInNewThread];
+ [tunnelConnection removeRunLoop:[NSRunLoop currentRunLoop]];
+ [tunnelConnection setRootObject:self];
+ if ([tunnelConnection registerName:tunnelConnectionName] == NO) {
+ return nil;
+ }
+
+ parentWindow = nil;
password = nil;
keychainName = nil;
keychainAccount = nil;
@@ -78,6 +88,18 @@
}
/*
+ * Set the parent window of the connection for use with dialogs.
+ */
+- (void)setParentWindow:(NSWindow *)theWindow
+{
+ parentWindow = theWindow;
+ if (![NSBundle loadNibNamed:@"SSHQuestionDialog" owner:self]) {
+ NSLog(@"SSH query dialog could not be loaded; SSH tunnels will not function correctly.");
+ parentWindow = nil;
+ }
+}
+
+/*
* Sets the password to be stored (and returned to the tunnel authenticator) locally.
* Providing a keychain name is much more secure.
*/
@@ -85,16 +107,7 @@
{
if (passwordInKeychain) return NO;
password = [[NSString alloc] initWithString:thePassword];
- passwordConnection = [[NSConnection defaultConnection] retain];
- [passwordConnection runInNewThread];
- [passwordConnection removeRunLoop:[NSRunLoop currentRunLoop]];
- [passwordConnection setRootObject:self];
- passwordConnectionName = [NSString stringWithFormat:@"SequelPro-%f", [[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] hash]];
- passwordConnectionVerifyHash = [NSString stringWithFormat:@"%f", [[NSString stringWithFormat:@"%f%i", [[NSDate date] timeIntervalSince1970]] hash]];
- if ([passwordConnection registerName:passwordConnectionName] == NO) {
- [password release], password = nil;
- return NO;
- }
+ tunnelConnectionVerifyHash = [NSString stringWithFormat:@"%f", [[NSString stringWithFormat:@"%f%i", [[NSDate date] timeIntervalSince1970]] hash]];
return YES;
}
@@ -105,7 +118,6 @@
*/
- (BOOL) setPasswordKeychainName:(NSString *)theName account:(NSString *)theAccount
{
- if (passwordConnection) [passwordConnection release], passwordConnection = nil;
if (password) [password release], password = nil;
passwordInKeychain = YES;
@@ -157,6 +169,16 @@
connectionState = SPSSH_STATE_CONNECTING;
if (delegate) [delegate performSelectorOnMainThread:stateChangeSelector withObject:self waitUntilDone:NO];
+ // Enforce a parent window being present for dialogs
+ if (!parentWindow) {
+ connectionState = SPSSH_STATE_IDLE;
+ if (delegate) [delegate performSelectorOnMainThread:stateChangeSelector withObject:self waitUntilDone:NO];
+ if (lastError) [lastError release];
+ lastError = [[NSString alloc] initWithString:@"SSH Tunnel started without a parent window. A parent window must be present."];
+ [pool release];
+ return;
+ }
+
int connectionTimeout = [[[NSUserDefaults standardUserDefaults] objectForKey:@"ConnectionTimeout"] intValue];
if (!connectionTimeout) connectionTimeout = 10;
BOOL useKeepAlive = [[[NSUserDefaults standardUserDefaults] objectForKey:@"UseKeepAlive"] doubleValue];
@@ -221,14 +243,14 @@
[taskEnvironment removeObjectForKey: @"SSH_AUTH_SOCK"];
[taskEnvironment setObject:authenticationAppPath forKey:@"SSH_ASKPASS"];
[taskEnvironment setObject:@":0" forKey:@"DISPLAY"];
+ [taskEnvironment setObject:tunnelConnectionName forKey:@"SP_CONNECTION_NAME"];
if (passwordInKeychain) {
[taskEnvironment setObject:[[NSNumber numberWithInt:SPSSH_PASSWORD_USES_KEYCHAIN] stringValue] forKey:@"SP_PASSWORD_METHOD"];
[taskEnvironment setObject:keychainName forKey:@"SP_KEYCHAIN_ITEM_NAME"];
[taskEnvironment setObject:keychainAccount forKey:@"SP_KEYCHAIN_ITEM_ACCOUNT"];
} else {
[taskEnvironment setObject:[[NSNumber numberWithInt:SPSSH_PASSWORD_ASKS_UI] stringValue] forKey:@"SP_PASSWORD_METHOD"];
- [taskEnvironment setObject:passwordConnectionName forKey:@"SP_CONNECTION_NAME"];
- [taskEnvironment setObject:passwordConnectionVerifyHash forKey:@"SP_CONNECTION_VERIFY_HASH"];
+ [taskEnvironment setObject:tunnelConnectionVerifyHash forKey:@"SP_CONNECTION_VERIFY_HASH"];
}
[task setEnvironment:taskEnvironment];
@@ -360,8 +382,43 @@
- (NSString *)getPasswordWithVerificationHash:(NSString *)theHash
{
if (passwordInKeychain) return nil;
- if (![theHash isEqualToString:passwordConnectionVerifyHash]) return nil;
+ if (![theHash isEqualToString:tunnelConnectionVerifyHash]) return nil;
return password;
}
+/*
+ * Method to allow an SSH tunnel to request the response to a question, returning the response as
+ * a boolean. This is used by the SSH_ASKPASS environment setting to deal with situations like
+ * host key mismatches.
+ */
+- (BOOL) getResponseForQuestion:(NSString *)theQuestion
+{
+
+ // Ask how to proceed
+ [sshQuestionText setStringValue:theQuestion];
+ [NSApp beginSheet:sshQuestionDialog modalForWindow:parentWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
+ int sshQueryResponseCode = [NSApp runModalForWindow:sshQuestionDialog];
+ [NSApp endSheet:sshQuestionDialog];
+ [sshQuestionDialog orderOut:nil];
+
+ switch (sshQueryResponseCode) {
+
+ // Yes
+ case 1:
+ return YES;
+
+ // No
+ default:
+ return NO;
+ }
+}
+
+/*
+ * Ends an existing modal session
+ */
+- (IBAction) closeSheet:(id)sender
+{
+ [NSApp stopModalWithCode:[sender tag]];
+}
+
@end