aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPSSHTunnel.m
diff options
context:
space:
mode:
authorAbhi Beckert <me@abhibeckert.com>2017-02-17 14:13:22 +1000
committerAbhi Beckert <me@abhibeckert.com>2017-02-17 14:13:22 +1000
commit0de6f372e1fe9723d01f9e73a75efe4930b68937 (patch)
treec0e1f1d253bb0472e7138ae27fc273ce9723cb30 /Source/SPSSHTunnel.m
parent357468e4c570a48dac02b946532c976a7dd88e0c (diff)
parentd2b1a5b84cb295eba8617f7e80681e0eeca46f0d (diff)
downloadsequelpro-0de6f372e1fe9723d01f9e73a75efe4930b68937.tar.gz
sequelpro-0de6f372e1fe9723d01f9e73a75efe4930b68937.tar.bz2
sequelpro-0de6f372e1fe9723d01f9e73a75efe4930b68937.zip
Merge remote-tracking branch 'sequelpro/master'
Diffstat (limited to 'Source/SPSSHTunnel.m')
-rw-r--r--Source/SPSSHTunnel.m47
1 files changed, 46 insertions, 1 deletions
diff --git a/Source/SPSSHTunnel.m b/Source/SPSSHTunnel.m
index 390c516c..1306b16f 100644
--- a/Source/SPSSHTunnel.m
+++ b/Source/SPSSHTunnel.m
@@ -383,6 +383,7 @@ static unsigned short getRandomPort();
} else {
TA(@"-L", ([NSString stringWithFormat:@"%ld:%@:%ld", (long)localPort, remoteHost, (long)remotePort]));
}
+#undef TA
[task setArguments:taskArguments];
@@ -414,10 +415,54 @@ static unsigned short getRandomPort();
[task setStandardError:standardError];
[[ NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(standardErrorHandler:)
- name:@"NSFileHandleDataAvailableNotification"
+ name:NSFileHandleDataAvailableNotification
object:[standardError fileHandleForReading]];
[[standardError fileHandleForReading] waitForDataInBackgroundAndNotify];
+ {
+ static BOOL hasCheckedTTY = NO;
+ if(!hasCheckedTTY) {
+ int fd = open("/dev/tty", O_RDWR);
+ if(fd >= 0) {
+ close(fd);
+ fprintf(stderr, (
+ "!!!\n"
+ "!!! You are running Sequel Pro from a TTY.\n"
+ "!!! Any SSH connections that require user input (e.g. a password/passphrase) will fail\n"
+ "!!! and appear stalled indefinitely.\n"
+ "!!! Sorry!\n"
+ "!!!\n"
+ ));
+ fflush(stderr);
+ // Explanation:
+ // OpenSSH by default requests passwords AND yes/no questions directly from the TTY,
+ // if it is part of a session group that has a controlling terminal (which is the case for
+ // processes created by Terminal.app).
+ //
+ // But this won't work, because only the foreground process group can read from /dev/tty and
+ // NSTask will create a new (background) process group for OpenSSH on launch.
+ // Side note: The internal method called from -[NSTask launch]
+ // -[NSConcreteTask launchWithDictionary:] accepts key @"_NSTaskNoNewProcessGroup" to skip that.
+ //
+ // Now, there are two preconditions for OpenSSH to use our SSH_ASKPASS utility instead:
+ // 1) The "DISPLAY" envvar has to be set
+ // 2) There must be no controlling terminal (ie. open("/dev/tty") fails)
+ // (See readpass.c#read_passphrase() in OpenSSH for the relevant code)
+ //
+ // -[NSTask launch] internally uses posix_spawn() and according to its documentation
+ // "The new process also inherits the following attributes from the calling
+ // process: [...] control terminal [...]"
+ // So if we wanted to avoid that, we would have to reimplement the whole NSTask class
+ // and use fork()+exec*()+setsid() instead (or use GNUStep's NSTask which already does this).
+ //
+ // We could also do ioctl(fd, TIOCNOTTY, 0); before launching the child process, but
+ // changing our own controlling terminal does not seem like a good idea in the middle
+ // of the application lifecycle, when we don't know what other Cocoa code may use it...
+ }
+ hasCheckedTTY = YES;
+ }
+ }
+
@try {
// Launch and run the tunnel
[task launch]; //throws for invalid paths, missing +x permission