summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm <djm>2013-08-20 16:44:24 +0000
committerdjm <djm>2013-08-20 16:44:24 +0000
commitbf40dd8c93f053ab1cd28f46bad35ea9b3948c75 (patch)
tree6a0c61dda875d0d8f4581d950747630c43b6dd92
parentd0cb9e743c8ed7d3b8ff8759985f9215cf332805 (diff)
downloadopenssh-bf40dd8c93f053ab1cd28f46bad35ea9b3948c75.tar.gz
- djm@cvs.openbsd.org 2013/08/20 00:11:38
[readconf.c readconf.h ssh_config.5 sshconnect.c] Add a ssh_config ProxyUseFDPass option that supports the use of ProxyCommands that establish a connection and then pass a connected file descriptor back to ssh(1). This allows the ProxyCommand to exit rather than have to shuffle data back and forth and enables ssh to use getpeername, etc. to obtain address information just like it does with regular directly-connected sockets. ok markus@
-rw-r--r--ChangeLog8
-rw-r--r--readconf.c12
-rw-r--r--readconf.h4
-rw-r--r--ssh_config.512
-rw-r--r--sshconnect.c124
5 files changed, 137 insertions, 23 deletions
diff --git a/ChangeLog b/ChangeLog
index a3ac3d53..6b0afa72 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -50,6 +50,14 @@
[scp.1 ssh.1]
some Bx/Ox conversion;
From: Jan Stary
+ - djm@cvs.openbsd.org 2013/08/20 00:11:38
+ [readconf.c readconf.h ssh_config.5 sshconnect.c]
+ Add a ssh_config ProxyUseFDPass option that supports the use of
+ ProxyCommands that establish a connection and then pass a connected
+ file descriptor back to ssh(1). This allows the ProxyCommand to exit
+ rather than have to shuffle data back and forth and enables ssh to use
+ getpeername, etc. to obtain address information just like it does with
+ regular directly-connected sockets. ok markus@
20130808
- (dtucker) [regress/Makefile regress/test-exec.sh] Don't try to use test -nt
diff --git a/readconf.c b/readconf.c
index 1464430a..7450081c 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.204 2013/06/10 19:19:44 dtucker Exp $ */
+/* $OpenBSD: readconf.c,v 1.205 2013/08/20 00:11:37 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -137,7 +137,7 @@ typedef enum {
oHashKnownHosts,
oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
- oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown,
+ oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
@@ -249,6 +249,7 @@ static struct {
{ "kexalgorithms", oKexAlgorithms },
{ "ipqos", oIPQoS },
{ "requesttty", oRequestTTY },
+ { "proxyusefdpass", oProxyUseFdpass },
{ "ignoreunknown", oIgnoreUnknown },
{ NULL, oBadOption }
@@ -1072,6 +1073,10 @@ parse_int:
charptr = &options->ignored_unknown;
goto parse_string;
+ case oProxyUseFdpass:
+ intptr = &options->proxy_use_fdpass;
+ goto parse_flag;
+
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@@ -1233,6 +1238,7 @@ initialize_options(Options * options)
options->ip_qos_interactive = -1;
options->ip_qos_bulk = -1;
options->request_tty = -1;
+ options->proxy_use_fdpass = -1;
options->ignored_unknown = NULL;
}
@@ -1385,6 +1391,8 @@ fill_default_options(Options * options)
options->ip_qos_bulk = IPTOS_THROUGHPUT;
if (options->request_tty == -1)
options->request_tty = REQUEST_TTY_AUTO;
+ if (options->proxy_use_fdpass == -1)
+ options->proxy_use_fdpass = 0;
/* options->local_command should not be set by default */
/* options->proxy_command should not be set by default */
/* options->user will be set in the main program if appropriate */
diff --git a/readconf.h b/readconf.h
index 23fc500d..ca4a042a 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.95 2013/05/16 04:27:50 djm Exp $ */
+/* $OpenBSD: readconf.h,v 1.96 2013/08/20 00:11:38 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -138,6 +138,8 @@ typedef struct {
int request_tty;
+ int proxy_use_fdpass;
+
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
} Options;
diff --git a/ssh_config.5 b/ssh_config.5
index 5d76c6d2..e89d694c 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $OpenBSD: ssh_config.5,v 1.166 2013/06/27 14:05:37 jmc Exp $
-.Dd $Mdocdate: June 27 2013 $
+.\" $OpenBSD: ssh_config.5,v 1.167 2013/08/20 00:11:38 djm Exp $
+.Dd $Mdocdate: August 20 2013 $
.Dt SSH_CONFIG 5
.Os
.Sh NAME
@@ -937,6 +937,14 @@ For example, the following directive would connect via an HTTP proxy at
.Bd -literal -offset 3n
ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
.Ed
+.It Cm ProxyUseFdpass
+Specifies that the a
+.Cm ProxyCommand
+will pass a connected file descriptor back to
+.Nm ssh
+instead of continuing to execute and pass data.
+The default is
+.Dq no .
.It Cm PubkeyAuthentication
Specifies whether to try public key authentication.
The argument to this keyword must be
diff --git a/sshconnect.c b/sshconnect.c
index 483eb85a..76bb5cda 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.238 2013/05/17 00:13:14 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.239 2013/08/20 00:11:38 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -59,6 +59,7 @@
#include "misc.h"
#include "dns.h"
#include "roaming.h"
+#include "monitor_fdpass.h"
#include "ssh2.h"
#include "version.h"
@@ -78,16 +79,113 @@ extern uid_t original_effective_uid;
static int show_other_keys(struct hostkeys *, Key *);
static void warn_changed_key(Key *);
+/* Expand a proxy command */
+static char *
+expand_proxy_command(const char *proxy_command, const char *user,
+ const char *host, int port)
+{
+ char *tmp, *ret, strport[NI_MAXSERV];
+
+ snprintf(strport, sizeof strport, "%hu", port);
+ xasprintf(&tmp, "exec %s", proxy_command);
+ ret = percent_expand(tmp, "h", host, "p", strport,
+ "r", options.user, (char *)NULL);
+ free(tmp);
+ return ret;
+}
+
+/*
+ * Connect to the given ssh server using a proxy command that passes a
+ * a connected fd back to us.
+ */
+static int
+ssh_proxy_fdpass_connect(const char *host, u_short port,
+ const char *proxy_command)
+{
+ char *command_string;
+ int sp[2], sock;
+ pid_t pid;
+ char *shell;
+
+ if ((shell = getenv("SHELL")) == NULL)
+ shell = _PATH_BSHELL;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0)
+ fatal("Could not create socketpair to communicate with "
+ "proxy dialer: %.100s", strerror(errno));
+
+ command_string = expand_proxy_command(proxy_command, options.user,
+ host, port);
+ debug("Executing proxy dialer command: %.500s", command_string);
+
+ /* Fork and execute the proxy command. */
+ if ((pid = fork()) == 0) {
+ char *argv[10];
+
+ /* Child. Permanently give up superuser privileges. */
+ permanently_drop_suid(original_real_uid);
+
+ close(sp[1]);
+ /* Redirect stdin and stdout. */
+ if (sp[0] != 0) {
+ if (dup2(sp[0], 0) < 0)
+ perror("dup2 stdin");
+ }
+ if (sp[0] != 1) {
+ if (dup2(sp[0], 1) < 0)
+ perror("dup2 stdout");
+ }
+ if (sp[0] >= 2)
+ close(sp[0]);
+
+ /*
+ * Stderr is left as it is so that error messages get
+ * printed on the user's terminal.
+ */
+ argv[0] = shell;
+ argv[1] = "-c";
+ argv[2] = command_string;
+ argv[3] = NULL;
+
+ /*
+ * Execute the proxy command.
+ * Note that we gave up any extra privileges above.
+ */
+ execv(argv[0], argv);
+ perror(argv[0]);
+ exit(1);
+ }
+ /* Parent. */
+ if (pid < 0)
+ fatal("fork failed: %.100s", strerror(errno));
+ close(sp[0]);
+ free(command_string);
+
+ if ((sock = mm_receive_fd(sp[1])) == -1)
+ fatal("proxy dialer did not pass back a connection");
+
+ while (waitpid(pid, NULL, 0) == -1)
+ if (errno != EINTR)
+ fatal("Couldn't wait for child: %s", strerror(errno));
+
+ /* Set the connection file descriptors. */
+ packet_set_connection(sock, sock);
+ packet_set_timeout(options.server_alive_interval,
+ options.server_alive_count_max);
+
+ return 0;
+}
+
/*
* Connect to the given ssh server using a proxy command.
*/
static int
ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
{
- char *command_string, *tmp;
+ char *command_string;
int pin[2], pout[2];
pid_t pid;
- char *shell, strport[NI_MAXSERV];
+ char *shell;
if (!strcmp(proxy_command, "-")) {
packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
@@ -96,29 +194,19 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
return 0;
}
+ if (options.proxy_use_fdpass)
+ return ssh_proxy_fdpass_connect(host, port, proxy_command);
+
if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
shell = _PATH_BSHELL;
- /* Convert the port number into a string. */
- snprintf(strport, sizeof strport, "%hu", port);
-
- /*
- * Build the final command string in the buffer by making the
- * appropriate substitutions to the given proxy command.
- *
- * Use "exec" to avoid "sh -c" processes on some platforms
- * (e.g. Solaris)
- */
- xasprintf(&tmp, "exec %s", proxy_command);
- command_string = percent_expand(tmp, "h", host, "p", strport,
- "r", options.user, (char *)NULL);
- free(tmp);
-
/* Create pipes for communicating with the proxy. */
if (pipe(pin) < 0 || pipe(pout) < 0)
fatal("Could not create pipes to communicate with the proxy: %.100s",
strerror(errno));
+ command_string = expand_proxy_command(proxy_command, options.user,
+ host, port);
debug("Executing proxy command: %.500s", command_string);
/* Fork and execute the proxy command. */