summaryrefslogtreecommitdiff
path: root/sshconnect.c
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 /sshconnect.c
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@
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c124
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;
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. */