summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c248
1 files changed, 167 insertions, 81 deletions
diff --git a/sshconnect.c b/sshconnect.c
index ad960fdbf..a2fbf9e65 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.244 2014/01/09 23:26:48 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,47 +79,122 @@ 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, "%d", 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
174 return 0;
175}
176
81/* 177/*
82 * Connect to the given ssh server using a proxy command. 178 * Connect to the given ssh server using a proxy command.
83 */ 179 */
84static int 180static int
85ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) 181ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
86{ 182{
87 char *command_string, *tmp; 183 char *command_string;
88 int pin[2], pout[2]; 184 int pin[2], pout[2];
89 pid_t pid; 185 pid_t pid;
90 char *shell, strport[NI_MAXSERV]; 186 char *shell;
91
92 if (!strcmp(proxy_command, "-")) {
93 packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
94 packet_set_timeout(options.server_alive_interval,
95 options.server_alive_count_max);
96 return 0;
97 }
98 187
99 if ((shell = getenv("SHELL")) == NULL || *shell == '\0') 188 if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
100 shell = _PATH_BSHELL; 189 shell = _PATH_BSHELL;
101 190
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. */ 191 /* Create pipes for communicating with the proxy. */
118 if (pipe(pin) < 0 || pipe(pout) < 0) 192 if (pipe(pin) < 0 || pipe(pout) < 0)
119 fatal("Could not create pipes to communicate with the proxy: %.100s", 193 fatal("Could not create pipes to communicate with the proxy: %.100s",
120 strerror(errno)); 194 strerror(errno));
121 195
196 command_string = expand_proxy_command(proxy_command, options.user,
197 host, port);
122 debug("Executing proxy command: %.500s", command_string); 198 debug("Executing proxy command: %.500s", command_string);
123 199
124 /* Fork and execute the proxy command. */ 200 /* Fork and execute the proxy command. */
@@ -170,8 +246,6 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
170 246
171 /* Set the connection file descriptors. */ 247 /* Set the connection file descriptors. */
172 packet_set_connection(pout[0], pin[1]); 248 packet_set_connection(pout[0], pin[1]);
173 packet_set_timeout(options.server_alive_interval,
174 options.server_alive_count_max);
175 249
176 /* Indicate OK return */ 250 /* Indicate OK return */
177 return 0; 251 return 0;
@@ -194,34 +268,18 @@ ssh_kill_proxy_command(void)
194static int 268static int
195ssh_create_socket(int privileged, struct addrinfo *ai) 269ssh_create_socket(int privileged, struct addrinfo *ai)
196{ 270{
197 int sock, gaierr; 271 int sock, r, gaierr;
198 struct addrinfo hints, *res; 272 struct addrinfo hints, *res;
199 273
200 /*
201 * If we are running as root and want to connect to a privileged
202 * port, bind our own socket to a privileged port.
203 */
204 if (privileged) {
205 int p = IPPORT_RESERVED - 1;
206 PRIV_START;
207 sock = rresvport_af(&p, ai->ai_family);
208 PRIV_END;
209 if (sock < 0)
210 error("rresvport: af=%d %.100s", ai->ai_family,
211 strerror(errno));
212 else
213 debug("Allocated local port %d.", p);
214 return sock;
215 }
216 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 274 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
217 if (sock < 0) { 275 if (sock < 0) {
218 error("socket: %.100s", strerror(errno)); 276 error("socket: %s", strerror(errno));
219 return -1; 277 return -1;
220 } 278 }
221 fcntl(sock, F_SETFD, FD_CLOEXEC); 279 fcntl(sock, F_SETFD, FD_CLOEXEC);
222 280
223 /* Bind the socket to an alternative local IP address */ 281 /* Bind the socket to an alternative local IP address */
224 if (options.bind_address == NULL) 282 if (options.bind_address == NULL && !privileged)
225 return sock; 283 return sock;
226 284
227 memset(&hints, 0, sizeof(hints)); 285 memset(&hints, 0, sizeof(hints));
@@ -236,11 +294,28 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
236 close(sock); 294 close(sock);
237 return -1; 295 return -1;
238 } 296 }
239 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { 297 /*
240 error("bind: %s: %s", options.bind_address, strerror(errno)); 298 * If we are running as root and want to connect to a privileged
241 close(sock); 299 * port, bind our own socket to a privileged port.
242 freeaddrinfo(res); 300 */
243 return -1; 301 if (privileged) {
302 PRIV_START;
303 r = bindresvport_sa(sock, res->ai_addr);
304 PRIV_END;
305 if (r < 0) {
306 error("bindresvport_sa: af=%d %s", ai->ai_family,
307 strerror(errno));
308 goto fail;
309 }
310 } else {
311 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
312 error("bind: %s: %s", options.bind_address,
313 strerror(errno));
314 fail:
315 close(sock);
316 freeaddrinfo(res);
317 return -1;
318 }
244 } 319 }
245 freeaddrinfo(res); 320 freeaddrinfo(res);
246 return sock; 321 return sock;
@@ -340,33 +415,18 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
340 * and %p substituted for host and port, respectively) to use to contact 415 * and %p substituted for host and port, respectively) to use to contact
341 * the daemon. 416 * the daemon.
342 */ 417 */
343int 418static int
344ssh_connect(const char *host, struct sockaddr_storage * hostaddr, 419ssh_connect_direct(const char *host, struct addrinfo *aitop,
345 u_short port, int family, int connection_attempts, int *timeout_ms, 420 struct sockaddr_storage *hostaddr, u_short port, int family,
346 int want_keepalive, int needpriv, const char *proxy_command) 421 int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
347{ 422{
348 int gaierr;
349 int on = 1; 423 int on = 1;
350 int sock = -1, attempt; 424 int sock = -1, attempt;
351 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 425 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
352 struct addrinfo hints, *ai, *aitop; 426 struct addrinfo *ai;
353 427
354 debug2("ssh_connect: needpriv %d", needpriv); 428 debug2("ssh_connect: needpriv %d", needpriv);
355 429
356 /* If a proxy command is given, connect using it. */
357 if (proxy_command != NULL)
358 return ssh_proxy_connect(host, port, proxy_command);
359
360 /* No proxy command. */
361
362 memset(&hints, 0, sizeof(hints));
363 hints.ai_family = family;
364 hints.ai_socktype = SOCK_STREAM;
365 snprintf(strport, sizeof strport, "%u", port);
366 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
367 fatal("%s: Could not resolve hostname %.100s: %s", __progname,
368 host, ssh_gai_strerror(gaierr));
369
370 for (attempt = 0; attempt < connection_attempts; attempt++) { 430 for (attempt = 0; attempt < connection_attempts; attempt++) {
371 if (attempt > 0) { 431 if (attempt > 0) {
372 /* Sleep a moment before retrying. */ 432 /* Sleep a moment before retrying. */
@@ -378,7 +438,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
378 * sequence until the connection succeeds. 438 * sequence until the connection succeeds.
379 */ 439 */
380 for (ai = aitop; ai; ai = ai->ai_next) { 440 for (ai = aitop; ai; ai = ai->ai_next) {
381 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 441 if (ai->ai_family != AF_INET &&
442 ai->ai_family != AF_INET6)
382 continue; 443 continue;
383 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 444 if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
384 ntop, sizeof(ntop), strport, sizeof(strport), 445 ntop, sizeof(ntop), strport, sizeof(strport),
@@ -411,8 +472,6 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
411 break; /* Successful connection. */ 472 break; /* Successful connection. */
412 } 473 }
413 474
414 freeaddrinfo(aitop);
415
416 /* Return failure if we didn't get a successful connection. */ 475 /* Return failure if we didn't get a successful connection. */
417 if (sock == -1) { 476 if (sock == -1) {
418 error("ssh: connect to host %s port %s: %s", 477 error("ssh: connect to host %s port %s: %s",
@@ -430,12 +489,28 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
430 489
431 /* Set the connection. */ 490 /* Set the connection. */
432 packet_set_connection(sock, sock); 491 packet_set_connection(sock, sock);
433 packet_set_timeout(options.server_alive_interval,
434 options.server_alive_count_max);
435 492
436 return 0; 493 return 0;
437} 494}
438 495
496int
497ssh_connect(const char *host, struct addrinfo *addrs,
498 struct sockaddr_storage *hostaddr, u_short port, int family,
499 int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
500{
501 if (options.proxy_command == NULL) {
502 return ssh_connect_direct(host, addrs, hostaddr, port, family,
503 connection_attempts, timeout_ms, want_keepalive, needpriv);
504 } else if (strcmp(options.proxy_command, "-") == 0) {
505 packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
506 return 0; /* Always succeeds */
507 } else if (options.proxy_use_fdpass) {
508 return ssh_proxy_fdpass_connect(host, port,
509 options.proxy_command);
510 }
511 return ssh_proxy_connect(host, port, options.proxy_command);
512}
513
439static void 514static void
440send_client_banner(int connection_out, int minor1) 515send_client_banner(int connection_out, int minor1)
441{ 516{
@@ -587,6 +662,12 @@ ssh_exchange_identification(int timeout_ms)
587 fatal("Protocol major versions differ: %d vs. %d", 662 fatal("Protocol major versions differ: %d vs. %d",
588 (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 663 (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
589 remote_major); 664 remote_major);
665 if ((datafellows & SSH_BUG_DERIVEKEY) != 0)
666 fatal("Server version \"%.100s\" uses unsafe key agreement; "
667 "refusing connection", remote_version);
668 if ((datafellows & SSH_BUG_RSASIGMD5) != 0)
669 logit("Server version \"%.100s\" uses unsafe RSA signature "
670 "scheme; disabling use of RSA keys", remote_version);
590 if (!client_banner_sent) 671 if (!client_banner_sent)
591 send_client_banner(connection_out, minor1); 672 send_client_banner(connection_out, minor1);
592 chop(server_version_string); 673 chop(server_version_string);
@@ -1181,7 +1262,7 @@ void
1181ssh_login(Sensitive *sensitive, const char *orighost, 1262ssh_login(Sensitive *sensitive, const char *orighost,
1182 struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms) 1263 struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms)
1183{ 1264{
1184 char *host, *cp; 1265 char *host;
1185 char *server_user, *local_user; 1266 char *server_user, *local_user;
1186 1267
1187 local_user = xstrdup(pw->pw_name); 1268 local_user = xstrdup(pw->pw_name);
@@ -1189,9 +1270,7 @@ ssh_login(Sensitive *sensitive, const char *orighost,
1189 1270
1190 /* Convert the user-supplied hostname into all lowercase. */ 1271 /* Convert the user-supplied hostname into all lowercase. */
1191 host = xstrdup(orighost); 1272 host = xstrdup(orighost);
1192 for (cp = host; *cp; cp++) 1273 lowercase(host);
1193 if (isupper(*cp))
1194 *cp = (char)tolower(*cp);
1195 1274
1196 /* Exchange protocol version identification strings with the server. */ 1275 /* Exchange protocol version identification strings with the server. */
1197 ssh_exchange_identification(timeout_ms); 1276 ssh_exchange_identification(timeout_ms);
@@ -1233,7 +1312,14 @@ ssh_put_password(char *password)
1233static int 1312static int
1234show_other_keys(struct hostkeys *hostkeys, Key *key) 1313show_other_keys(struct hostkeys *hostkeys, Key *key)
1235{ 1314{
1236 int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, KEY_ECDSA, -1}; 1315 int type[] = {
1316 KEY_RSA1,
1317 KEY_RSA,
1318 KEY_DSA,
1319 KEY_ECDSA,
1320 KEY_ED25519,
1321 -1
1322 };
1237 int i, ret = 0; 1323 int i, ret = 0;
1238 char *fp, *ra; 1324 char *fp, *ra;
1239 const struct hostkey_entry *found; 1325 const struct hostkey_entry *found;