diff options
Diffstat (limited to 'ssh.c')
-rw-r--r-- | ssh.c | 232 |
1 files changed, 92 insertions, 140 deletions
@@ -40,7 +40,7 @@ | |||
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include "includes.h" | 42 | #include "includes.h" |
43 | RCSID("$OpenBSD: ssh.c,v 1.234 2005/03/10 22:01:06 deraadt Exp $"); | 43 | RCSID("$OpenBSD: ssh.c,v 1.249 2005/07/30 01:26:16 djm Exp $"); |
44 | 44 | ||
45 | #include <openssl/evp.h> | 45 | #include <openssl/evp.h> |
46 | #include <openssl/err.h> | 46 | #include <openssl/err.h> |
@@ -145,7 +145,7 @@ pid_t proxy_command_pid = 0; | |||
145 | int control_fd = -1; | 145 | int control_fd = -1; |
146 | 146 | ||
147 | /* Multiplexing control command */ | 147 | /* Multiplexing control command */ |
148 | static u_int mux_command = SSHMUX_COMMAND_OPEN; | 148 | static u_int mux_command = 0; |
149 | 149 | ||
150 | /* Only used in control client mode */ | 150 | /* Only used in control client mode */ |
151 | volatile sig_atomic_t control_client_terminate = 0; | 151 | volatile sig_atomic_t control_client_terminate = 0; |
@@ -185,6 +185,7 @@ main(int ac, char **av) | |||
185 | int dummy; | 185 | int dummy; |
186 | extern int optind, optreset; | 186 | extern int optind, optreset; |
187 | extern char *optarg; | 187 | extern char *optarg; |
188 | struct servent *sp; | ||
188 | Forward fwd; | 189 | Forward fwd; |
189 | 190 | ||
190 | __progname = ssh_get_progname(av[0]); | 191 | __progname = ssh_get_progname(av[0]); |
@@ -391,8 +392,10 @@ again: | |||
391 | } | 392 | } |
392 | break; | 393 | break; |
393 | case 'M': | 394 | case 'M': |
394 | options.control_master = | 395 | if (options.control_master == SSHCTL_MASTER_YES) |
395 | (options.control_master >= 1) ? 2 : 1; | 396 | options.control_master = SSHCTL_MASTER_ASK; |
397 | else | ||
398 | options.control_master = SSHCTL_MASTER_YES; | ||
396 | break; | 399 | break; |
397 | case 'p': | 400 | case 'p': |
398 | options.port = a2port(optarg); | 401 | options.port = a2port(optarg); |
@@ -441,7 +444,7 @@ again: | |||
441 | fwd.listen_host = cleanhostname(fwd.listen_host); | 444 | fwd.listen_host = cleanhostname(fwd.listen_host); |
442 | } else { | 445 | } else { |
443 | fwd.listen_port = a2port(fwd.listen_host); | 446 | fwd.listen_port = a2port(fwd.listen_host); |
444 | fwd.listen_host = ""; | 447 | fwd.listen_host = NULL; |
445 | } | 448 | } |
446 | 449 | ||
447 | if (fwd.listen_port == 0) { | 450 | if (fwd.listen_port == 0) { |
@@ -555,7 +558,7 @@ again: | |||
555 | if (no_tty_flag) | 558 | if (no_tty_flag) |
556 | tty_flag = 0; | 559 | tty_flag = 0; |
557 | /* Do not allocate a tty if stdin is not a tty. */ | 560 | /* Do not allocate a tty if stdin is not a tty. */ |
558 | if (!isatty(fileno(stdin)) && !force_tty_flag) { | 561 | if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) { |
559 | if (tty_flag) | 562 | if (tty_flag) |
560 | logit("Pseudo-terminal will not be allocated because stdin is not a terminal."); | 563 | logit("Pseudo-terminal will not be allocated because stdin is not a terminal."); |
561 | tty_flag = 0; | 564 | tty_flag = 0; |
@@ -609,16 +612,31 @@ again: | |||
609 | *p = tolower(*p); | 612 | *p = tolower(*p); |
610 | } | 613 | } |
611 | 614 | ||
615 | /* Get default port if port has not been set. */ | ||
616 | if (options.port == 0) { | ||
617 | sp = getservbyname(SSH_SERVICE_NAME, "tcp"); | ||
618 | options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; | ||
619 | } | ||
620 | |||
612 | if (options.proxy_command != NULL && | 621 | if (options.proxy_command != NULL && |
613 | strcmp(options.proxy_command, "none") == 0) | 622 | strcmp(options.proxy_command, "none") == 0) |
614 | options.proxy_command = NULL; | 623 | options.proxy_command = NULL; |
624 | if (options.control_path != NULL && | ||
625 | strcmp(options.control_path, "none") == 0) | ||
626 | options.control_path = NULL; | ||
615 | 627 | ||
616 | if (options.control_path != NULL) { | 628 | if (options.control_path != NULL) { |
617 | options.control_path = tilde_expand_filename( | 629 | snprintf(buf, sizeof(buf), "%d", options.port); |
618 | options.control_path, original_real_uid); | 630 | cp = tilde_expand_filename(options.control_path, |
631 | original_real_uid); | ||
632 | options.control_path = percent_expand(cp, "p", buf, "h", host, | ||
633 | "r", options.user, (char *)NULL); | ||
634 | xfree(cp); | ||
619 | } | 635 | } |
620 | if (options.control_path != NULL && options.control_master == 0) | 636 | if (mux_command != 0 && options.control_path == NULL) |
621 | control_client(options.control_path); /* This doesn't return */ | 637 | fatal("No ControlPath specified for \"-O\" command"); |
638 | if (options.control_path != NULL) | ||
639 | control_client(options.control_path); | ||
622 | 640 | ||
623 | /* Open a connection to the remote host. */ | 641 | /* Open a connection to the remote host. */ |
624 | if (ssh_connect(host, &hostaddr, options.port, | 642 | if (ssh_connect(host, &hostaddr, options.port, |
@@ -747,110 +765,6 @@ again: | |||
747 | return exit_status; | 765 | return exit_status; |
748 | } | 766 | } |
749 | 767 | ||
750 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" | ||
751 | |||
752 | static void | ||
753 | x11_get_proto(char **_proto, char **_data) | ||
754 | { | ||
755 | char cmd[1024]; | ||
756 | char line[512]; | ||
757 | char xdisplay[512]; | ||
758 | static char proto[512], data[512]; | ||
759 | FILE *f; | ||
760 | int got_data = 0, generated = 0, do_unlink = 0, i; | ||
761 | char *display, *xauthdir, *xauthfile; | ||
762 | struct stat st; | ||
763 | |||
764 | xauthdir = xauthfile = NULL; | ||
765 | *_proto = proto; | ||
766 | *_data = data; | ||
767 | proto[0] = data[0] = '\0'; | ||
768 | |||
769 | if (!options.xauth_location || | ||
770 | (stat(options.xauth_location, &st) == -1)) { | ||
771 | debug("No xauth program."); | ||
772 | } else { | ||
773 | if ((display = getenv("DISPLAY")) == NULL) { | ||
774 | debug("x11_get_proto: DISPLAY not set"); | ||
775 | return; | ||
776 | } | ||
777 | /* | ||
778 | * Handle FamilyLocal case where $DISPLAY does | ||
779 | * not match an authorization entry. For this we | ||
780 | * just try "xauth list unix:displaynum.screennum". | ||
781 | * XXX: "localhost" match to determine FamilyLocal | ||
782 | * is not perfect. | ||
783 | */ | ||
784 | if (strncmp(display, "localhost:", 10) == 0) { | ||
785 | snprintf(xdisplay, sizeof(xdisplay), "unix:%s", | ||
786 | display + 10); | ||
787 | display = xdisplay; | ||
788 | } | ||
789 | if (options.forward_x11_trusted == 0) { | ||
790 | xauthdir = xmalloc(MAXPATHLEN); | ||
791 | xauthfile = xmalloc(MAXPATHLEN); | ||
792 | strlcpy(xauthdir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN); | ||
793 | if (mkdtemp(xauthdir) != NULL) { | ||
794 | do_unlink = 1; | ||
795 | snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile", | ||
796 | xauthdir); | ||
797 | snprintf(cmd, sizeof(cmd), | ||
798 | "%s -f %s generate %s " SSH_X11_PROTO | ||
799 | " untrusted timeout 1200 2>" _PATH_DEVNULL, | ||
800 | options.xauth_location, xauthfile, display); | ||
801 | debug2("x11_get_proto: %s", cmd); | ||
802 | if (system(cmd) == 0) | ||
803 | generated = 1; | ||
804 | } | ||
805 | } | ||
806 | snprintf(cmd, sizeof(cmd), | ||
807 | "%s %s%s list %s . 2>" _PATH_DEVNULL, | ||
808 | options.xauth_location, | ||
809 | generated ? "-f " : "" , | ||
810 | generated ? xauthfile : "", | ||
811 | display); | ||
812 | debug2("x11_get_proto: %s", cmd); | ||
813 | f = popen(cmd, "r"); | ||
814 | if (f && fgets(line, sizeof(line), f) && | ||
815 | sscanf(line, "%*s %511s %511s", proto, data) == 2) | ||
816 | got_data = 1; | ||
817 | if (f) | ||
818 | pclose(f); | ||
819 | } | ||
820 | |||
821 | if (do_unlink) { | ||
822 | unlink(xauthfile); | ||
823 | rmdir(xauthdir); | ||
824 | } | ||
825 | if (xauthdir) | ||
826 | xfree(xauthdir); | ||
827 | if (xauthfile) | ||
828 | xfree(xauthfile); | ||
829 | |||
830 | /* | ||
831 | * If we didn't get authentication data, just make up some | ||
832 | * data. The forwarding code will check the validity of the | ||
833 | * response anyway, and substitute this data. The X11 | ||
834 | * server, however, will ignore this fake data and use | ||
835 | * whatever authentication mechanisms it was using otherwise | ||
836 | * for the local connection. | ||
837 | */ | ||
838 | if (!got_data) { | ||
839 | u_int32_t rnd = 0; | ||
840 | |||
841 | logit("Warning: No xauth data; " | ||
842 | "using fake authentication data for X11 forwarding."); | ||
843 | strlcpy(proto, SSH_X11_PROTO, sizeof proto); | ||
844 | for (i = 0; i < 16; i++) { | ||
845 | if (i % 4 == 0) | ||
846 | rnd = arc4random(); | ||
847 | snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", | ||
848 | rnd & 0xff); | ||
849 | rnd >>= 8; | ||
850 | } | ||
851 | } | ||
852 | } | ||
853 | |||
854 | static void | 768 | static void |
855 | ssh_init_forwarding(void) | 769 | ssh_init_forwarding(void) |
856 | { | 770 | { |
@@ -881,8 +795,8 @@ ssh_init_forwarding(void) | |||
881 | for (i = 0; i < options.num_remote_forwards; i++) { | 795 | for (i = 0; i < options.num_remote_forwards; i++) { |
882 | debug("Remote connections from %.200s:%d forwarded to " | 796 | debug("Remote connections from %.200s:%d forwarded to " |
883 | "local address %.200s:%d", | 797 | "local address %.200s:%d", |
884 | (options.remote_forwards[i].listen_host == NULL) ? | 798 | (options.remote_forwards[i].listen_host == NULL) ? |
885 | (options.gateway_ports ? "*" : "LOCALHOST") : | 799 | (options.gateway_ports ? "*" : "LOCALHOST") : |
886 | options.remote_forwards[i].listen_host, | 800 | options.remote_forwards[i].listen_host, |
887 | options.remote_forwards[i].listen_port, | 801 | options.remote_forwards[i].listen_port, |
888 | options.remote_forwards[i].connect_host, | 802 | options.remote_forwards[i].connect_host, |
@@ -913,6 +827,7 @@ ssh_session(void) | |||
913 | int have_tty = 0; | 827 | int have_tty = 0; |
914 | struct winsize ws; | 828 | struct winsize ws; |
915 | char *cp; | 829 | char *cp; |
830 | const char *display; | ||
916 | 831 | ||
917 | /* Enable compression if requested. */ | 832 | /* Enable compression if requested. */ |
918 | if (options.compression) { | 833 | if (options.compression) { |
@@ -974,13 +889,15 @@ ssh_session(void) | |||
974 | packet_disconnect("Protocol error waiting for pty request response."); | 889 | packet_disconnect("Protocol error waiting for pty request response."); |
975 | } | 890 | } |
976 | /* Request X11 forwarding if enabled and DISPLAY is set. */ | 891 | /* Request X11 forwarding if enabled and DISPLAY is set. */ |
977 | if (options.forward_x11 && getenv("DISPLAY") != NULL) { | 892 | display = getenv("DISPLAY"); |
893 | if (options.forward_x11 && display != NULL) { | ||
978 | char *proto, *data; | 894 | char *proto, *data; |
979 | /* Get reasonable local authentication information. */ | 895 | /* Get reasonable local authentication information. */ |
980 | x11_get_proto(&proto, &data); | 896 | client_x11_get_proto(display, options.xauth_location, |
897 | options.forward_x11_trusted, &proto, &data); | ||
981 | /* Request forwarding with authentication spoofing. */ | 898 | /* Request forwarding with authentication spoofing. */ |
982 | debug("Requesting X11 forwarding with authentication spoofing."); | 899 | debug("Requesting X11 forwarding with authentication spoofing."); |
983 | x11_request_forwarding_with_spoofing(0, proto, data); | 900 | x11_request_forwarding_with_spoofing(0, display, proto, data); |
984 | 901 | ||
985 | /* Read response from the server. */ | 902 | /* Read response from the server. */ |
986 | type = packet_read(); | 903 | type = packet_read(); |
@@ -1082,9 +999,12 @@ ssh_control_listener(void) | |||
1082 | mode_t old_umask; | 999 | mode_t old_umask; |
1083 | int addr_len; | 1000 | int addr_len; |
1084 | 1001 | ||
1085 | if (options.control_path == NULL || options.control_master <= 0) | 1002 | if (options.control_path == NULL || |
1003 | options.control_master == SSHCTL_MASTER_NO) | ||
1086 | return; | 1004 | return; |
1087 | 1005 | ||
1006 | debug("setting up multiplex master socket"); | ||
1007 | |||
1088 | memset(&addr, '\0', sizeof(addr)); | 1008 | memset(&addr, '\0', sizeof(addr)); |
1089 | addr.sun_family = AF_UNIX; | 1009 | addr.sun_family = AF_UNIX; |
1090 | addr_len = offsetof(struct sockaddr_un, sun_path) + | 1010 | addr_len = offsetof(struct sockaddr_un, sun_path) + |
@@ -1119,15 +1039,18 @@ static void | |||
1119 | ssh_session2_setup(int id, void *arg) | 1039 | ssh_session2_setup(int id, void *arg) |
1120 | { | 1040 | { |
1121 | extern char **environ; | 1041 | extern char **environ; |
1122 | 1042 | const char *display; | |
1123 | int interactive = tty_flag; | 1043 | int interactive = tty_flag; |
1124 | if (options.forward_x11 && getenv("DISPLAY") != NULL) { | 1044 | |
1045 | display = getenv("DISPLAY"); | ||
1046 | if (options.forward_x11 && display != NULL) { | ||
1125 | char *proto, *data; | 1047 | char *proto, *data; |
1126 | /* Get reasonable local authentication information. */ | 1048 | /* Get reasonable local authentication information. */ |
1127 | x11_get_proto(&proto, &data); | 1049 | client_x11_get_proto(display, options.xauth_location, |
1050 | options.forward_x11_trusted, &proto, &data); | ||
1128 | /* Request forwarding with authentication spoofing. */ | 1051 | /* Request forwarding with authentication spoofing. */ |
1129 | debug("Requesting X11 forwarding with authentication spoofing."); | 1052 | debug("Requesting X11 forwarding with authentication spoofing."); |
1130 | x11_request_forwarding_with_spoofing(id, proto, data); | 1053 | x11_request_forwarding_with_spoofing(id, display, proto, data); |
1131 | interactive = 1; | 1054 | interactive = 1; |
1132 | /* XXX wait for reply */ | 1055 | /* XXX wait for reply */ |
1133 | } | 1056 | } |
@@ -1295,13 +1218,18 @@ control_client(const char *path) | |||
1295 | extern char **environ; | 1218 | extern char **environ; |
1296 | u_int flags; | 1219 | u_int flags; |
1297 | 1220 | ||
1298 | if (stdin_null_flag) { | 1221 | if (mux_command == 0) |
1299 | if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) | 1222 | mux_command = SSHMUX_COMMAND_OPEN; |
1300 | fatal("open(/dev/null): %s", strerror(errno)); | 1223 | |
1301 | if (dup2(fd, STDIN_FILENO) == -1) | 1224 | switch (options.control_master) { |
1302 | fatal("dup2: %s", strerror(errno)); | 1225 | case SSHCTL_MASTER_AUTO: |
1303 | if (fd > STDERR_FILENO) | 1226 | case SSHCTL_MASTER_AUTO_ASK: |
1304 | close(fd); | 1227 | debug("auto-mux: Trying existing master"); |
1228 | /* FALLTHROUGH */ | ||
1229 | case SSHCTL_MASTER_NO: | ||
1230 | break; | ||
1231 | default: | ||
1232 | return; | ||
1305 | } | 1233 | } |
1306 | 1234 | ||
1307 | memset(&addr, '\0', sizeof(addr)); | 1235 | memset(&addr, '\0', sizeof(addr)); |
@@ -1316,31 +1244,55 @@ control_client(const char *path) | |||
1316 | if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) | 1244 | if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) |
1317 | fatal("%s socket(): %s", __func__, strerror(errno)); | 1245 | fatal("%s socket(): %s", __func__, strerror(errno)); |
1318 | 1246 | ||
1319 | if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) | 1247 | if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) { |
1320 | fatal("Couldn't connect to %s: %s", path, strerror(errno)); | 1248 | if (mux_command != SSHMUX_COMMAND_OPEN) { |
1249 | fatal("Control socket connect(%.100s): %s", path, | ||
1250 | strerror(errno)); | ||
1251 | } | ||
1252 | if (errno == ENOENT) | ||
1253 | debug("Control socket \"%.100s\" does not exist", path); | ||
1254 | else { | ||
1255 | error("Control socket connect(%.100s): %s", path, | ||
1256 | strerror(errno)); | ||
1257 | } | ||
1258 | close(sock); | ||
1259 | return; | ||
1260 | } | ||
1261 | |||
1262 | if (stdin_null_flag) { | ||
1263 | if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) | ||
1264 | fatal("open(/dev/null): %s", strerror(errno)); | ||
1265 | if (dup2(fd, STDIN_FILENO) == -1) | ||
1266 | fatal("dup2: %s", strerror(errno)); | ||
1267 | if (fd > STDERR_FILENO) | ||
1268 | close(fd); | ||
1269 | } | ||
1321 | 1270 | ||
1322 | if ((term = getenv("TERM")) == NULL) | 1271 | term = getenv("TERM"); |
1323 | term = ""; | ||
1324 | 1272 | ||
1325 | flags = 0; | 1273 | flags = 0; |
1326 | if (tty_flag) | 1274 | if (tty_flag) |
1327 | flags |= SSHMUX_FLAG_TTY; | 1275 | flags |= SSHMUX_FLAG_TTY; |
1328 | if (subsystem_flag) | 1276 | if (subsystem_flag) |
1329 | flags |= SSHMUX_FLAG_SUBSYS; | 1277 | flags |= SSHMUX_FLAG_SUBSYS; |
1278 | if (options.forward_x11) | ||
1279 | flags |= SSHMUX_FLAG_X11_FWD; | ||
1280 | if (options.forward_agent) | ||
1281 | flags |= SSHMUX_FLAG_AGENT_FWD; | ||
1330 | 1282 | ||
1331 | buffer_init(&m); | 1283 | buffer_init(&m); |
1332 | 1284 | ||
1333 | /* Send our command to server */ | 1285 | /* Send our command to server */ |
1334 | buffer_put_int(&m, mux_command); | 1286 | buffer_put_int(&m, mux_command); |
1335 | buffer_put_int(&m, flags); | 1287 | buffer_put_int(&m, flags); |
1336 | if (ssh_msg_send(sock, /* version */1, &m) == -1) | 1288 | if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) |
1337 | fatal("%s: msg_send", __func__); | 1289 | fatal("%s: msg_send", __func__); |
1338 | buffer_clear(&m); | 1290 | buffer_clear(&m); |
1339 | 1291 | ||
1340 | /* Get authorisation status and PID of controlee */ | 1292 | /* Get authorisation status and PID of controlee */ |
1341 | if (ssh_msg_recv(sock, &m) == -1) | 1293 | if (ssh_msg_recv(sock, &m) == -1) |
1342 | fatal("%s: msg_recv", __func__); | 1294 | fatal("%s: msg_recv", __func__); |
1343 | if (buffer_get_char(&m) != 1) | 1295 | if (buffer_get_char(&m) != SSHMUX_VER) |
1344 | fatal("%s: wrong version", __func__); | 1296 | fatal("%s: wrong version", __func__); |
1345 | if (buffer_get_int(&m) != 1) | 1297 | if (buffer_get_int(&m) != 1) |
1346 | fatal("Connection to master denied"); | 1298 | fatal("Connection to master denied"); |
@@ -1364,7 +1316,7 @@ control_client(const char *path) | |||
1364 | } | 1316 | } |
1365 | 1317 | ||
1366 | /* SSHMUX_COMMAND_OPEN */ | 1318 | /* SSHMUX_COMMAND_OPEN */ |
1367 | buffer_put_cstring(&m, term); | 1319 | buffer_put_cstring(&m, term ? term : ""); |
1368 | buffer_append(&command, "\0", 1); | 1320 | buffer_append(&command, "\0", 1); |
1369 | buffer_put_cstring(&m, buffer_ptr(&command)); | 1321 | buffer_put_cstring(&m, buffer_ptr(&command)); |
1370 | 1322 | ||
@@ -1386,7 +1338,7 @@ control_client(const char *path) | |||
1386 | } | 1338 | } |
1387 | } | 1339 | } |
1388 | 1340 | ||
1389 | if (ssh_msg_send(sock, /* version */1, &m) == -1) | 1341 | if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) |
1390 | fatal("%s: msg_send", __func__); | 1342 | fatal("%s: msg_send", __func__); |
1391 | 1343 | ||
1392 | mm_send_fd(sock, STDIN_FILENO); | 1344 | mm_send_fd(sock, STDIN_FILENO); |
@@ -1397,7 +1349,7 @@ control_client(const char *path) | |||
1397 | buffer_clear(&m); | 1349 | buffer_clear(&m); |
1398 | if (ssh_msg_recv(sock, &m) == -1) | 1350 | if (ssh_msg_recv(sock, &m) == -1) |
1399 | fatal("%s: msg_recv", __func__); | 1351 | fatal("%s: msg_recv", __func__); |
1400 | if (buffer_get_char(&m) != 1) | 1352 | if (buffer_get_char(&m) != SSHMUX_VER) |
1401 | fatal("%s: wrong version", __func__); | 1353 | fatal("%s: wrong version", __func__); |
1402 | buffer_free(&m); | 1354 | buffer_free(&m); |
1403 | 1355 | ||