summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2013-08-21 02:44:24 +1000
committerDamien Miller <djm@mindrot.org>2013-08-21 02:44:24 +1000
commit1262b6638f7d01ab110fd373dd90d915c882fe1a (patch)
treea8f3e50f3d0223f037ebf2193f11bf7d992863f7
parentb7727df37efde4dbe4f5a33b19cbf42022aabf66 (diff)
- 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 a3ac3d537..6b0afa720 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -50,6 +50,14 @@
50 [scp.1 ssh.1] 50 [scp.1 ssh.1]
51 some Bx/Ox conversion; 51 some Bx/Ox conversion;
52 From: Jan Stary 52 From: Jan Stary
53 - djm@cvs.openbsd.org 2013/08/20 00:11:38
54 [readconf.c readconf.h ssh_config.5 sshconnect.c]
55 Add a ssh_config ProxyUseFDPass option that supports the use of
56 ProxyCommands that establish a connection and then pass a connected
57 file descriptor back to ssh(1). This allows the ProxyCommand to exit
58 rather than have to shuffle data back and forth and enables ssh to use
59 getpeername, etc. to obtain address information just like it does with
60 regular directly-connected sockets. ok markus@
53 61
5420130808 6220130808
55 - (dtucker) [regress/Makefile regress/test-exec.sh] Don't try to use test -nt 63 - (dtucker) [regress/Makefile regress/test-exec.sh] Don't try to use test -nt
diff --git a/readconf.c b/readconf.c
index 1464430a4..7450081cd 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.204 2013/06/10 19:19:44 dtucker Exp $ */ 1/* $OpenBSD: readconf.c,v 1.205 2013/08/20 00:11:37 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -137,7 +137,7 @@ typedef enum {
137 oHashKnownHosts, 137 oHashKnownHosts,
138 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, 138 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
139 oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, 139 oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
140 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, 140 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
141 oIgnoredUnknownOption, oDeprecated, oUnsupported 141 oIgnoredUnknownOption, oDeprecated, oUnsupported
142} OpCodes; 142} OpCodes;
143 143
@@ -249,6 +249,7 @@ static struct {
249 { "kexalgorithms", oKexAlgorithms }, 249 { "kexalgorithms", oKexAlgorithms },
250 { "ipqos", oIPQoS }, 250 { "ipqos", oIPQoS },
251 { "requesttty", oRequestTTY }, 251 { "requesttty", oRequestTTY },
252 { "proxyusefdpass", oProxyUseFdpass },
252 { "ignoreunknown", oIgnoreUnknown }, 253 { "ignoreunknown", oIgnoreUnknown },
253 254
254 { NULL, oBadOption } 255 { NULL, oBadOption }
@@ -1072,6 +1073,10 @@ parse_int:
1072 charptr = &options->ignored_unknown; 1073 charptr = &options->ignored_unknown;
1073 goto parse_string; 1074 goto parse_string;
1074 1075
1076 case oProxyUseFdpass:
1077 intptr = &options->proxy_use_fdpass;
1078 goto parse_flag;
1079
1075 case oDeprecated: 1080 case oDeprecated:
1076 debug("%s line %d: Deprecated option \"%s\"", 1081 debug("%s line %d: Deprecated option \"%s\"",
1077 filename, linenum, keyword); 1082 filename, linenum, keyword);
@@ -1233,6 +1238,7 @@ initialize_options(Options * options)
1233 options->ip_qos_interactive = -1; 1238 options->ip_qos_interactive = -1;
1234 options->ip_qos_bulk = -1; 1239 options->ip_qos_bulk = -1;
1235 options->request_tty = -1; 1240 options->request_tty = -1;
1241 options->proxy_use_fdpass = -1;
1236 options->ignored_unknown = NULL; 1242 options->ignored_unknown = NULL;
1237} 1243}
1238 1244
@@ -1385,6 +1391,8 @@ fill_default_options(Options * options)
1385 options->ip_qos_bulk = IPTOS_THROUGHPUT; 1391 options->ip_qos_bulk = IPTOS_THROUGHPUT;
1386 if (options->request_tty == -1) 1392 if (options->request_tty == -1)
1387 options->request_tty = REQUEST_TTY_AUTO; 1393 options->request_tty = REQUEST_TTY_AUTO;
1394 if (options->proxy_use_fdpass == -1)
1395 options->proxy_use_fdpass = 0;
1388 /* options->local_command should not be set by default */ 1396 /* options->local_command should not be set by default */
1389 /* options->proxy_command should not be set by default */ 1397 /* options->proxy_command should not be set by default */
1390 /* options->user will be set in the main program if appropriate */ 1398 /* options->user will be set in the main program if appropriate */
diff --git a/readconf.h b/readconf.h
index 23fc500da..ca4a042ad 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.h,v 1.95 2013/05/16 04:27:50 djm Exp $ */ 1/* $OpenBSD: readconf.h,v 1.96 2013/08/20 00:11:38 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -138,6 +138,8 @@ typedef struct {
138 138
139 int request_tty; 139 int request_tty;
140 140
141 int proxy_use_fdpass;
142
141 char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ 143 char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
142} Options; 144} Options;
143 145
diff --git a/ssh_config.5 b/ssh_config.5
index 5d76c6d2d..e89d694c7 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: ssh_config.5,v 1.166 2013/06/27 14:05:37 jmc Exp $ 36.\" $OpenBSD: ssh_config.5,v 1.167 2013/08/20 00:11:38 djm Exp $
37.Dd $Mdocdate: June 27 2013 $ 37.Dd $Mdocdate: August 20 2013 $
38.Dt SSH_CONFIG 5 38.Dt SSH_CONFIG 5
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -937,6 +937,14 @@ For example, the following directive would connect via an HTTP proxy at
937.Bd -literal -offset 3n 937.Bd -literal -offset 3n
938ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p 938ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
939.Ed 939.Ed
940.It Cm ProxyUseFdpass
941Specifies that the a
942.Cm ProxyCommand
943will pass a connected file descriptor back to
944.Nm ssh
945instead of continuing to execute and pass data.
946The default is
947.Dq no .
940.It Cm PubkeyAuthentication 948.It Cm PubkeyAuthentication
941Specifies whether to try public key authentication. 949Specifies whether to try public key authentication.
942The argument to this keyword must be 950The argument to this keyword must be
diff --git a/sshconnect.c b/sshconnect.c
index 483eb85ac..76bb5cdac 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.238 2013/05/17 00:13:14 djm Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.239 2013/08/20 00:11:38 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -59,6 +59,7 @@
59#include "misc.h" 59#include "misc.h"
60#include "dns.h" 60#include "dns.h"
61#include "roaming.h" 61#include "roaming.h"
62#include "monitor_fdpass.h"
62#include "ssh2.h" 63#include "ssh2.h"
63#include "version.h" 64#include "version.h"
64 65
@@ -78,16 +79,113 @@ extern uid_t original_effective_uid;
78static int show_other_keys(struct hostkeys *, Key *); 79static int show_other_keys(struct hostkeys *, Key *);
79static void warn_changed_key(Key *); 80static void warn_changed_key(Key *);
80 81
82/* Expand a proxy command */
83static char *
84expand_proxy_command(const char *proxy_command, const char *user,
85 const char *host, int port)
86{
87 char *tmp, *ret, strport[NI_MAXSERV];
88
89 snprintf(strport, sizeof strport, "%hu", port);
90 xasprintf(&tmp, "exec %s", proxy_command);
91 ret = percent_expand(tmp, "h", host, "p", strport,
92 "r", options.user, (char *)NULL);
93 free(tmp);
94 return ret;
95}
96
97/*
98 * Connect to the given ssh server using a proxy command that passes a
99 * a connected fd back to us.
100 */
101static int
102ssh_proxy_fdpass_connect(const char *host, u_short port,
103 const char *proxy_command)
104{
105 char *command_string;
106 int sp[2], sock;
107 pid_t pid;
108 char *shell;
109
110 if ((shell = getenv("SHELL")) == NULL)
111 shell = _PATH_BSHELL;
112
113 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0)
114 fatal("Could not create socketpair to communicate with "
115 "proxy dialer: %.100s", strerror(errno));
116
117 command_string = expand_proxy_command(proxy_command, options.user,
118 host, port);
119 debug("Executing proxy dialer command: %.500s", command_string);
120
121 /* Fork and execute the proxy command. */
122 if ((pid = fork()) == 0) {
123 char *argv[10];
124
125 /* Child. Permanently give up superuser privileges. */
126 permanently_drop_suid(original_real_uid);
127
128 close(sp[1]);
129 /* Redirect stdin and stdout. */
130 if (sp[0] != 0) {
131 if (dup2(sp[0], 0) < 0)
132 perror("dup2 stdin");
133 }
134 if (sp[0] != 1) {
135 if (dup2(sp[0], 1) < 0)
136 perror("dup2 stdout");
137 }
138 if (sp[0] >= 2)
139 close(sp[0]);
140
141 /*
142 * Stderr is left as it is so that error messages get
143 * printed on the user's terminal.
144 */
145 argv[0] = shell;
146 argv[1] = "-c";
147 argv[2] = command_string;
148 argv[3] = NULL;
149
150 /*
151 * Execute the proxy command.
152 * Note that we gave up any extra privileges above.
153 */
154 execv(argv[0], argv);
155 perror(argv[0]);
156 exit(1);
157 }
158 /* Parent. */
159 if (pid < 0)
160 fatal("fork failed: %.100s", strerror(errno));
161 close(sp[0]);
162 free(command_string);
163
164 if ((sock = mm_receive_fd(sp[1])) == -1)
165 fatal("proxy dialer did not pass back a connection");
166
167 while (waitpid(pid, NULL, 0) == -1)
168 if (errno != EINTR)
169 fatal("Couldn't wait for child: %s", strerror(errno));
170
171 /* Set the connection file descriptors. */
172 packet_set_connection(sock, sock);
173 packet_set_timeout(options.server_alive_interval,
174 options.server_alive_count_max);
175
176 return 0;
177}
178
81/* 179/*
82 * Connect to the given ssh server using a proxy command. 180 * Connect to the given ssh server using a proxy command.
83 */ 181 */
84static int 182static int
85ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) 183ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
86{ 184{
87 char *command_string, *tmp; 185 char *command_string;
88 int pin[2], pout[2]; 186 int pin[2], pout[2];
89 pid_t pid; 187 pid_t pid;
90 char *shell, strport[NI_MAXSERV]; 188 char *shell;
91 189
92 if (!strcmp(proxy_command, "-")) { 190 if (!strcmp(proxy_command, "-")) {
93 packet_set_connection(STDIN_FILENO, STDOUT_FILENO); 191 packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
@@ -96,29 +194,19 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
96 return 0; 194 return 0;
97 } 195 }
98 196
197 if (options.proxy_use_fdpass)
198 return ssh_proxy_fdpass_connect(host, port, proxy_command);
199
99 if ((shell = getenv("SHELL")) == NULL || *shell == '\0') 200 if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
100 shell = _PATH_BSHELL; 201 shell = _PATH_BSHELL;
101 202
102 /* Convert the port number into a string. */
103 snprintf(strport, sizeof strport, "%hu", port);
104
105 /*
106 * Build the final command string in the buffer by making the
107 * appropriate substitutions to the given proxy command.
108 *
109 * Use "exec" to avoid "sh -c" processes on some platforms
110 * (e.g. Solaris)
111 */
112 xasprintf(&tmp, "exec %s", proxy_command);
113 command_string = percent_expand(tmp, "h", host, "p", strport,
114 "r", options.user, (char *)NULL);
115 free(tmp);
116
117 /* Create pipes for communicating with the proxy. */ 203 /* Create pipes for communicating with the proxy. */
118 if (pipe(pin) < 0 || pipe(pout) < 0) 204 if (pipe(pin) < 0 || pipe(pout) < 0)
119 fatal("Could not create pipes to communicate with the proxy: %.100s", 205 fatal("Could not create pipes to communicate with the proxy: %.100s",
120 strerror(errno)); 206 strerror(errno));
121 207
208 command_string = expand_proxy_command(proxy_command, options.user,
209 host, port);
122 debug("Executing proxy command: %.500s", command_string); 210 debug("Executing proxy command: %.500s", command_string);
123 211
124 /* Fork and execute the proxy command. */ 212 /* Fork and execute the proxy command. */