diff options
author | Damien Miller <djm@mindrot.org> | 2013-08-21 02:44:24 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2013-08-21 02:44:24 +1000 |
commit | 1262b6638f7d01ab110fd373dd90d915c882fe1a (patch) | |
tree | a8f3e50f3d0223f037ebf2193f11bf7d992863f7 /sshconnect.c | |
parent | b7727df37efde4dbe4f5a33b19cbf42022aabf66 (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@
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 124 |
1 files changed, 106 insertions, 18 deletions
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. */ |