diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | readconf.c | 12 | ||||
-rw-r--r-- | readconf.h | 4 | ||||
-rw-r--r-- | ssh_config.5 | 12 | ||||
-rw-r--r-- | sshconnect.c | 124 |
5 files changed, 137 insertions, 23 deletions
@@ -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 | ||
54 | 20130808 | 62 | 20130808 |
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 |
938 | ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p | 938 | ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p |
939 | .Ed | 939 | .Ed |
940 | .It Cm ProxyUseFdpass | ||
941 | Specifies that the a | ||
942 | .Cm ProxyCommand | ||
943 | will pass a connected file descriptor back to | ||
944 | .Nm ssh | ||
945 | instead of continuing to execute and pass data. | ||
946 | The default is | ||
947 | .Dq no . | ||
940 | .It Cm PubkeyAuthentication | 948 | .It Cm PubkeyAuthentication |
941 | Specifies whether to try public key authentication. | 949 | Specifies whether to try public key authentication. |
942 | The argument to this keyword must be | 950 | The 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; | |||
78 | static int show_other_keys(struct hostkeys *, Key *); | 79 | static int show_other_keys(struct hostkeys *, Key *); |
79 | static void warn_changed_key(Key *); | 80 | static void warn_changed_key(Key *); |
80 | 81 | ||
82 | /* Expand a proxy command */ | ||
83 | static char * | ||
84 | expand_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 | */ | ||
101 | static int | ||
102 | ssh_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 | */ |
84 | static int | 182 | static int |
85 | ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | 183 | ssh_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. */ |