summaryrefslogtreecommitdiff
path: root/ssh.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssh.c')
-rw-r--r--ssh.c140
1 files changed, 105 insertions, 35 deletions
diff --git a/ssh.c b/ssh.c
index f9ff91f04..03a23fb6a 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.436 2016/02/15 09:47:49 dtucker Exp $ */ 1/* $OpenBSD: ssh.c,v 1.445 2016/07/17 04:20:16 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
@@ -67,6 +67,7 @@
67#include <string.h> 67#include <string.h>
68#include <unistd.h> 68#include <unistd.h>
69#include <limits.h> 69#include <limits.h>
70#include <locale.h>
70 71
71#include <netinet/in.h> 72#include <netinet/in.h>
72#include <arpa/inet.h> 73#include <arpa/inet.h>
@@ -151,10 +152,6 @@ int ostdin_null_flag, ono_shell_flag, otty_flag, orequest_tty;
151 */ 152 */
152int fork_after_authentication_flag = 0; 153int fork_after_authentication_flag = 0;
153 154
154/* forward stdio to remote host and port */
155char *stdio_forward_host = NULL;
156int stdio_forward_port = 0;
157
158/* 155/*
159 * General data structure for command line options and options configurable 156 * General data structure for command line options and options configurable
160 * in configuration files. See readconf.h. 157 * in configuration files. See readconf.h.
@@ -202,10 +199,11 @@ usage(void)
202 fprintf(stderr, 199 fprintf(stderr,
203"usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" 200"usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n"
204" [-D [bind_address:]port] [-E log_file] [-e escape_char]\n" 201" [-D [bind_address:]port] [-E log_file] [-e escape_char]\n"
205" [-F configfile] [-I pkcs11] [-i identity_file] [-L address]\n" 202" [-F configfile] [-I pkcs11] [-i identity_file]\n"
206" [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" 203" [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]\n"
207" [-Q query_option] [-R address] [-S ctl_path] [-W host:port]\n" 204" [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]\n"
208" [-w local_tun[:remote_tun]] [user@]hostname [command]\n" 205" [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]\n"
206" [user@]hostname [command]\n"
209 ); 207 );
210 exit(255); 208 exit(255);
211} 209}
@@ -334,7 +332,7 @@ resolve_addr(const char *name, int port, char *caddr, size_t clen)
334 * NB. this function must operate with a options having undefined members. 332 * NB. this function must operate with a options having undefined members.
335 */ 333 */
336static int 334static int
337check_follow_cname(char **namep, const char *cname) 335check_follow_cname(int direct, char **namep, const char *cname)
338{ 336{
339 int i; 337 int i;
340 struct allowed_cname *rule; 338 struct allowed_cname *rule;
@@ -346,9 +344,9 @@ check_follow_cname(char **namep, const char *cname)
346 return 0; 344 return 0;
347 /* 345 /*
348 * Don't attempt to canonicalize names that will be interpreted by 346 * Don't attempt to canonicalize names that will be interpreted by
349 * a proxy unless the user specifically requests so. 347 * a proxy or jump host unless the user specifically requests so.
350 */ 348 */
351 if (!option_clear_or_none(options.proxy_command) && 349 if (!direct &&
352 options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) 350 options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
353 return 0; 351 return 0;
354 debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname); 352 debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname);
@@ -375,7 +373,7 @@ check_follow_cname(char **namep, const char *cname)
375static struct addrinfo * 373static struct addrinfo *
376resolve_canonicalize(char **hostp, int port) 374resolve_canonicalize(char **hostp, int port)
377{ 375{
378 int i, ndots; 376 int i, direct, ndots;
379 char *cp, *fullhost, newname[NI_MAXHOST]; 377 char *cp, *fullhost, newname[NI_MAXHOST];
380 struct addrinfo *addrs; 378 struct addrinfo *addrs;
381 379
@@ -386,7 +384,9 @@ resolve_canonicalize(char **hostp, int port)
386 * Don't attempt to canonicalize names that will be interpreted by 384 * Don't attempt to canonicalize names that will be interpreted by
387 * a proxy unless the user specifically requests so. 385 * a proxy unless the user specifically requests so.
388 */ 386 */
389 if (!option_clear_or_none(options.proxy_command) && 387 direct = option_clear_or_none(options.proxy_command) &&
388 options.jump_host == NULL;
389 if (!direct &&
390 options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) 390 options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
391 return NULL; 391 return NULL;
392 392
@@ -441,7 +441,7 @@ resolve_canonicalize(char **hostp, int port)
441 /* Remove trailing '.' */ 441 /* Remove trailing '.' */
442 fullhost[strlen(fullhost) - 1] = '\0'; 442 fullhost[strlen(fullhost) - 1] = '\0';
443 /* Follow CNAME if requested */ 443 /* Follow CNAME if requested */
444 if (!check_follow_cname(&fullhost, newname)) { 444 if (!check_follow_cname(direct, &fullhost, newname)) {
445 debug("Canonicalized hostname \"%s\" => \"%s\"", 445 debug("Canonicalized hostname \"%s\" => \"%s\"",
446 *hostp, fullhost); 446 *hostp, fullhost);
447 } 447 }
@@ -513,7 +513,8 @@ set_addrinfo_port(struct addrinfo *addrs, int port)
513int 513int
514main(int ac, char **av) 514main(int ac, char **av)
515{ 515{
516 int i, r, opt, exit_status, use_syslog, config_test = 0; 516 struct ssh *ssh = NULL;
517 int i, r, opt, exit_status, use_syslog, direct, config_test = 0;
517 char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile; 518 char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile;
518 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 519 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
519 char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex; 520 char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex;
@@ -592,6 +593,8 @@ main(int ac, char **av)
592 */ 593 */
593 umask(022); 594 umask(022);
594 595
596 setlocale(LC_CTYPE, "");
597
595 /* 598 /*
596 * Initialize option structure to indicate that no values have been 599 * Initialize option structure to indicate that no values have been
597 * set. 600 * set.
@@ -606,7 +609,7 @@ main(int ac, char **av)
606 609
607 again: 610 again:
608 while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" 611 while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
609 "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { 612 "ACD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
610 switch (opt) { 613 switch (opt) {
611 case '1': 614 case '1':
612 options.protocol = SSH_PROTO_1; 615 options.protocol = SSH_PROTO_1;
@@ -650,7 +653,7 @@ main(int ac, char **av)
650 options.fwd_opts.gateway_ports = 1; 653 options.fwd_opts.gateway_ports = 1;
651 break; 654 break;
652 case 'O': 655 case 'O':
653 if (stdio_forward_host != NULL) 656 if (options.stdio_forward_host != NULL)
654 fatal("Cannot specify multiplexing " 657 fatal("Cannot specify multiplexing "
655 "command with -W"); 658 "command with -W");
656 else if (muxclient_command != 0) 659 else if (muxclient_command != 0)
@@ -731,6 +734,15 @@ main(int ac, char **av)
731 fprintf(stderr, "no support for PKCS#11.\n"); 734 fprintf(stderr, "no support for PKCS#11.\n");
732#endif 735#endif
733 break; 736 break;
737 case 'J':
738 if (options.jump_host != NULL)
739 fatal("Only a single -J option permitted");
740 if (options.proxy_command != NULL)
741 fatal("Cannot specify -J with ProxyCommand");
742 if (parse_jump(optarg, &options, 1) == -1)
743 fatal("Invalid -J argument");
744 options.proxy_command = xstrdup("none");
745 break;
734 case 't': 746 case 't':
735 if (options.request_tty == REQUEST_TTY_YES) 747 if (options.request_tty == REQUEST_TTY_YES)
736 options.request_tty = REQUEST_TTY_FORCE; 748 options.request_tty = REQUEST_TTY_FORCE;
@@ -742,8 +754,10 @@ main(int ac, char **av)
742 debug_flag = 1; 754 debug_flag = 1;
743 options.log_level = SYSLOG_LEVEL_DEBUG1; 755 options.log_level = SYSLOG_LEVEL_DEBUG1;
744 } else { 756 } else {
745 if (options.log_level < SYSLOG_LEVEL_DEBUG3) 757 if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
758 debug_flag++;
746 options.log_level++; 759 options.log_level++;
760 }
747 } 761 }
748 break; 762 break;
749 case 'V': 763 case 'V':
@@ -769,13 +783,13 @@ main(int ac, char **av)
769 } 783 }
770 break; 784 break;
771 case 'W': 785 case 'W':
772 if (stdio_forward_host != NULL) 786 if (options.stdio_forward_host != NULL)
773 fatal("stdio forward already specified"); 787 fatal("stdio forward already specified");
774 if (muxclient_command != 0) 788 if (muxclient_command != 0)
775 fatal("Cannot specify stdio forward with -O"); 789 fatal("Cannot specify stdio forward with -O");
776 if (parse_forward(&fwd, optarg, 1, 0)) { 790 if (parse_forward(&fwd, optarg, 1, 0)) {
777 stdio_forward_host = fwd.listen_host; 791 options.stdio_forward_host = fwd.listen_host;
778 stdio_forward_port = fwd.listen_port; 792 options.stdio_forward_port = fwd.listen_port;
779 free(fwd.connect_host); 793 free(fwd.connect_host);
780 } else { 794 } else {
781 fprintf(stderr, 795 fprintf(stderr,
@@ -785,8 +799,6 @@ main(int ac, char **av)
785 } 799 }
786 options.request_tty = REQUEST_TTY_NO; 800 options.request_tty = REQUEST_TTY_NO;
787 no_shell_flag = 1; 801 no_shell_flag = 1;
788 options.clear_forwardings = 1;
789 options.exit_on_forward_failure = 1;
790 break; 802 break;
791 case 'q': 803 case 'q':
792 options.log_level = SYSLOG_LEVEL_QUIET; 804 options.log_level = SYSLOG_LEVEL_QUIET;
@@ -1043,9 +1055,10 @@ main(int ac, char **av)
1043 * has specifically requested canonicalisation for this case via 1055 * has specifically requested canonicalisation for this case via
1044 * CanonicalizeHostname=always 1056 * CanonicalizeHostname=always
1045 */ 1057 */
1046 if (addrs == NULL && options.num_permitted_cnames != 0 && 1058 direct = option_clear_or_none(options.proxy_command) &&
1047 (option_clear_or_none(options.proxy_command) || 1059 options.jump_host == NULL;
1048 options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) { 1060 if (addrs == NULL && options.num_permitted_cnames != 0 && (direct ||
1061 options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
1049 if ((addrs = resolve_host(host, options.port, 1062 if ((addrs = resolve_host(host, options.port,
1050 option_clear_or_none(options.proxy_command), 1063 option_clear_or_none(options.proxy_command),
1051 cname, sizeof(cname))) == NULL) { 1064 cname, sizeof(cname))) == NULL) {
@@ -1053,7 +1066,7 @@ main(int ac, char **av)
1053 if (option_clear_or_none(options.proxy_command)) 1066 if (option_clear_or_none(options.proxy_command))
1054 cleanup_exit(255); /* logged in resolve_host */ 1067 cleanup_exit(255); /* logged in resolve_host */
1055 } else 1068 } else
1056 check_follow_cname(&host, cname); 1069 check_follow_cname(direct, &host, cname);
1057 } 1070 }
1058 1071
1059 /* 1072 /*
@@ -1078,6 +1091,41 @@ main(int ac, char **av)
1078 /* Fill configuration defaults. */ 1091 /* Fill configuration defaults. */
1079 fill_default_options(&options); 1092 fill_default_options(&options);
1080 1093
1094 /*
1095 * If ProxyJump option specified, then construct a ProxyCommand now.
1096 */
1097 if (options.jump_host != NULL) {
1098 char port_s[8];
1099
1100 /* Consistency check */
1101 if (options.proxy_command != NULL)
1102 fatal("inconsistent options: ProxyCommand+ProxyJump");
1103 /* Never use FD passing for ProxyJump */
1104 options.proxy_use_fdpass = 0;
1105 snprintf(port_s, sizeof(port_s), "%d", options.jump_port);
1106 xasprintf(&options.proxy_command,
1107 "ssh%s%s%s%s%s%s%s%s%s%.*s -W %%h:%%p %s",
1108 /* Optional "-l user" argument if jump_user set */
1109 options.jump_user == NULL ? "" : " -l ",
1110 options.jump_user == NULL ? "" : options.jump_user,
1111 /* Optional "-p port" argument if jump_port set */
1112 options.jump_port <= 0 ? "" : " -p ",
1113 options.jump_port <= 0 ? "" : port_s,
1114 /* Optional additional jump hosts ",..." */
1115 options.jump_extra == NULL ? "" : " -J ",
1116 options.jump_extra == NULL ? "" : options.jump_extra,
1117 /* Optional "-F" argumment if -F specified */
1118 config == NULL ? "" : " -F ",
1119 config == NULL ? "" : config,
1120 /* Optional "-v" arguments if -v set */
1121 debug_flag ? " -" : "",
1122 debug_flag, "vvv",
1123 /* Mandatory hostname */
1124 options.jump_host);
1125 debug("Setting implicit ProxyCommand from ProxyJump: %s",
1126 options.proxy_command);
1127 }
1128
1081 if (options.port == 0) 1129 if (options.port == 0)
1082 options.port = default_ssh_port(); 1130 options.port = default_ssh_port();
1083 channel_set_af(options.address_family); 1131 channel_set_af(options.address_family);
@@ -1220,6 +1268,8 @@ main(int ac, char **av)
1220 packet_set_timeout(options.server_alive_interval, 1268 packet_set_timeout(options.server_alive_interval,
1221 options.server_alive_count_max); 1269 options.server_alive_count_max);
1222 1270
1271 ssh = active_state; /* XXX */
1272
1223 if (timeout_ms > 0) 1273 if (timeout_ms > 0)
1224 debug3("timeout: %d ms remain after connect", timeout_ms); 1274 debug3("timeout: %d ms remain after connect", timeout_ms);
1225 1275
@@ -1332,6 +1382,23 @@ main(int ac, char **av)
1332 /* load options.identity_files */ 1382 /* load options.identity_files */
1333 load_public_identity_files(); 1383 load_public_identity_files();
1334 1384
1385 /* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */
1386 if (options.identity_agent &&
1387 strcmp(options.identity_agent, SSH_AUTHSOCKET_ENV_NAME) != 0) {
1388 if (strcmp(options.identity_agent, "none") == 0) {
1389 unsetenv(SSH_AUTHSOCKET_ENV_NAME);
1390 } else {
1391 p = tilde_expand_filename(options.identity_agent,
1392 original_real_uid);
1393 cp = percent_expand(p, "d", pw->pw_dir,
1394 "u", pw->pw_name, "l", thishost, "h", host,
1395 "r", options.user, (char *)NULL);
1396 setenv(SSH_AUTHSOCKET_ENV_NAME, cp, 1);
1397 free(cp);
1398 free(p);
1399 }
1400 }
1401
1335 /* Expand ~ in known host file names. */ 1402 /* Expand ~ in known host file names. */
1336 tilde_expand_paths(options.system_hostfiles, 1403 tilde_expand_paths(options.system_hostfiles,
1337 options.num_system_hostfiles); 1404 options.num_system_hostfiles);
@@ -1346,7 +1413,7 @@ main(int ac, char **av)
1346 1413
1347 if (packet_connection_is_on_socket()) { 1414 if (packet_connection_is_on_socket()) {
1348 verbose("Authenticated to %s ([%s]:%d).", host, 1415 verbose("Authenticated to %s ([%s]:%d).", host,
1349 get_remote_ipaddr(), get_remote_port()); 1416 ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
1350 } else { 1417 } else {
1351 verbose("Authenticated to %s (via proxy).", host); 1418 verbose("Authenticated to %s (via proxy).", host);
1352 } 1419 }
@@ -1392,7 +1459,7 @@ static void
1392control_persist_detach(void) 1459control_persist_detach(void)
1393{ 1460{
1394 pid_t pid; 1461 pid_t pid;
1395 int devnull; 1462 int devnull, keep_stderr;
1396 1463
1397 debug("%s: backgrounding master process", __func__); 1464 debug("%s: backgrounding master process", __func__);
1398 1465
@@ -1423,8 +1490,10 @@ control_persist_detach(void)
1423 error("%s: open(\"/dev/null\"): %s", __func__, 1490 error("%s: open(\"/dev/null\"): %s", __func__,
1424 strerror(errno)); 1491 strerror(errno));
1425 } else { 1492 } else {
1493 keep_stderr = log_is_on_stderr() && debug_flag;
1426 if (dup2(devnull, STDIN_FILENO) == -1 || 1494 if (dup2(devnull, STDIN_FILENO) == -1 ||
1427 dup2(devnull, STDOUT_FILENO) == -1) 1495 dup2(devnull, STDOUT_FILENO) == -1 ||
1496 (!keep_stderr && dup2(devnull, STDERR_FILENO) == -1))
1428 error("%s: dup2: %s", __func__, strerror(errno)); 1497 error("%s: dup2: %s", __func__, strerror(errno));
1429 if (devnull > STDERR_FILENO) 1498 if (devnull > STDERR_FILENO)
1430 close(devnull); 1499 close(devnull);
@@ -1516,18 +1585,19 @@ ssh_init_stdio_forwarding(void)
1516 Channel *c; 1585 Channel *c;
1517 int in, out; 1586 int in, out;
1518 1587
1519 if (stdio_forward_host == NULL) 1588 if (options.stdio_forward_host == NULL)
1520 return; 1589 return;
1521 if (!compat20) 1590 if (!compat20)
1522 fatal("stdio forwarding require Protocol 2"); 1591 fatal("stdio forwarding require Protocol 2");
1523 1592
1524 debug3("%s: %s:%d", __func__, stdio_forward_host, stdio_forward_port); 1593 debug3("%s: %s:%d", __func__, options.stdio_forward_host,
1594 options.stdio_forward_port);
1525 1595
1526 if ((in = dup(STDIN_FILENO)) < 0 || 1596 if ((in = dup(STDIN_FILENO)) < 0 ||
1527 (out = dup(STDOUT_FILENO)) < 0) 1597 (out = dup(STDOUT_FILENO)) < 0)
1528 fatal("channel_connect_stdio_fwd: dup() in/out failed"); 1598 fatal("channel_connect_stdio_fwd: dup() in/out failed");
1529 if ((c = channel_connect_stdio_fwd(stdio_forward_host, 1599 if ((c = channel_connect_stdio_fwd(options.stdio_forward_host,
1530 stdio_forward_port, in, out)) == NULL) 1600 options.stdio_forward_port, in, out)) == NULL)
1531 fatal("%s: channel_connect_stdio_fwd failed", __func__); 1601 fatal("%s: channel_connect_stdio_fwd failed", __func__);
1532 channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0); 1602 channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0);
1533 channel_register_open_confirm(c->self, ssh_stdio_confirm, NULL); 1603 channel_register_open_confirm(c->self, ssh_stdio_confirm, NULL);