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]); |
@@ -386,8 +387,10 @@ again: | |||
386 | } | 387 | } |
387 | break; | 388 | break; |
388 | case 'M': | 389 | case 'M': |
389 | options.control_master = | 390 | if (options.control_master == SSHCTL_MASTER_YES) |
390 | (options.control_master >= 1) ? 2 : 1; | 391 | options.control_master = SSHCTL_MASTER_ASK; |
392 | else | ||
393 | options.control_master = SSHCTL_MASTER_YES; | ||
391 | break; | 394 | break; |
392 | case 'p': | 395 | case 'p': |
393 | options.port = a2port(optarg); | 396 | options.port = a2port(optarg); |
@@ -436,7 +439,7 @@ again: | |||
436 | fwd.listen_host = cleanhostname(fwd.listen_host); | 439 | fwd.listen_host = cleanhostname(fwd.listen_host); |
437 | } else { | 440 | } else { |
438 | fwd.listen_port = a2port(fwd.listen_host); | 441 | fwd.listen_port = a2port(fwd.listen_host); |
439 | fwd.listen_host = ""; | 442 | fwd.listen_host = NULL; |
440 | } | 443 | } |
441 | 444 | ||
442 | if (fwd.listen_port == 0) { | 445 | if (fwd.listen_port == 0) { |
@@ -550,7 +553,7 @@ again: | |||
550 | if (no_tty_flag) | 553 | if (no_tty_flag) |
551 | tty_flag = 0; | 554 | tty_flag = 0; |
552 | /* Do not allocate a tty if stdin is not a tty. */ | 555 | /* Do not allocate a tty if stdin is not a tty. */ |
553 | if (!isatty(fileno(stdin)) && !force_tty_flag) { | 556 | if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) { |
554 | if (tty_flag) | 557 | if (tty_flag) |
555 | logit("Pseudo-terminal will not be allocated because stdin is not a terminal."); | 558 | logit("Pseudo-terminal will not be allocated because stdin is not a terminal."); |
556 | tty_flag = 0; | 559 | tty_flag = 0; |
@@ -604,16 +607,31 @@ again: | |||
604 | *p = tolower(*p); | 607 | *p = tolower(*p); |
605 | } | 608 | } |
606 | 609 | ||
610 | /* Get default port if port has not been set. */ | ||
611 | if (options.port == 0) { | ||
612 | sp = getservbyname(SSH_SERVICE_NAME, "tcp"); | ||
613 | options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; | ||
614 | } | ||
615 | |||
607 | if (options.proxy_command != NULL && | 616 | if (options.proxy_command != NULL && |
608 | strcmp(options.proxy_command, "none") == 0) | 617 | strcmp(options.proxy_command, "none") == 0) |
609 | options.proxy_command = NULL; | 618 | options.proxy_command = NULL; |
619 | if (options.control_path != NULL && | ||
620 | strcmp(options.control_path, "none") == 0) | ||
621 | options.control_path = NULL; | ||
610 | 622 | ||
611 | if (options.control_path != NULL) { | 623 | if (options.control_path != NULL) { |
612 | options.control_path = tilde_expand_filename( | 624 | snprintf(buf, sizeof(buf), "%d", options.port); |
613 | options.control_path, original_real_uid); | 625 | cp = tilde_expand_filename(options.control_path, |
626 | original_real_uid); | ||
627 | options.control_path = percent_expand(cp, "p", buf, "h", host, | ||
628 | "r", options.user, (char *)NULL); | ||
629 | xfree(cp); | ||
614 | } | 630 | } |
615 | if (options.control_path != NULL && options.control_master == 0) | 631 | if (mux_command != 0 && options.control_path == NULL) |
616 | control_client(options.control_path); /* This doesn't return */ | 632 | fatal("No ControlPath specified for \"-O\" command"); |
633 | if (options.control_path != NULL) | ||
634 | control_client(options.control_path); | ||
617 | 635 | ||
618 | /* Open a connection to the remote host. */ | 636 | /* Open a connection to the remote host. */ |
619 | if (ssh_connect(host, &hostaddr, options.port, | 637 | if (ssh_connect(host, &hostaddr, options.port, |
@@ -742,110 +760,6 @@ again: | |||
742 | return exit_status; | 760 | return exit_status; |
743 | } | 761 | } |
744 | 762 | ||
745 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" | ||
746 | |||
747 | static void | ||
748 | x11_get_proto(char **_proto, char **_data) | ||
749 | { | ||
750 | char cmd[1024]; | ||
751 | char line[512]; | ||
752 | char xdisplay[512]; | ||
753 | static char proto[512], data[512]; | ||
754 | FILE *f; | ||
755 | int got_data = 0, generated = 0, do_unlink = 0, i; | ||
756 | char *display, *xauthdir, *xauthfile; | ||
757 | struct stat st; | ||
758 | |||
759 | xauthdir = xauthfile = NULL; | ||
760 | *_proto = proto; | ||
761 | *_data = data; | ||
762 | proto[0] = data[0] = '\0'; | ||
763 | |||
764 | if (!options.xauth_location || | ||
765 | (stat(options.xauth_location, &st) == -1)) { | ||
766 | debug("No xauth program."); | ||
767 | } else { | ||
768 | if ((display = getenv("DISPLAY")) == NULL) { | ||
769 | debug("x11_get_proto: DISPLAY not set"); | ||
770 | return; | ||
771 | } | ||
772 | /* | ||
773 | * Handle FamilyLocal case where $DISPLAY does | ||
774 | * not match an authorization entry. For this we | ||
775 | * just try "xauth list unix:displaynum.screennum". | ||
776 | * XXX: "localhost" match to determine FamilyLocal | ||
777 | * is not perfect. | ||
778 | */ | ||
779 | if (strncmp(display, "localhost:", 10) == 0) { | ||
780 | snprintf(xdisplay, sizeof(xdisplay), "unix:%s", | ||
781 | display + 10); | ||
782 | display = xdisplay; | ||
783 | } | ||
784 | if (options.forward_x11_trusted == 0) { | ||
785 | xauthdir = xmalloc(MAXPATHLEN); | ||
786 | xauthfile = xmalloc(MAXPATHLEN); | ||
787 | strlcpy(xauthdir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN); | ||
788 | if (mkdtemp(xauthdir) != NULL) { | ||
789 | do_unlink = 1; | ||
790 | snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile", | ||
791 | xauthdir); | ||
792 | snprintf(cmd, sizeof(cmd), | ||
793 | "%s -f %s generate %s " SSH_X11_PROTO | ||
794 | " untrusted timeout 1200 2>" _PATH_DEVNULL, | ||
795 | options.xauth_location, xauthfile, display); | ||
796 | debug2("x11_get_proto: %s", cmd); | ||
797 | if (system(cmd) == 0) | ||
798 | generated = 1; | ||
799 | } | ||
800 | } | ||
801 | snprintf(cmd, sizeof(cmd), | ||
802 | "%s %s%s list %s . 2>" _PATH_DEVNULL, | ||
803 | options.xauth_location, | ||
804 | generated ? "-f " : "" , | ||
805 | generated ? xauthfile : "", | ||
806 | display); | ||
807 | debug2("x11_get_proto: %s", cmd); | ||
808 | f = popen(cmd, "r"); | ||
809 | if (f && fgets(line, sizeof(line), f) && | ||
810 | sscanf(line, "%*s %511s %511s", proto, data) == 2) | ||
811 | got_data = 1; | ||
812 | if (f) | ||
813 | pclose(f); | ||
814 | } | ||
815 | |||
816 | if (do_unlink) { | ||
817 | unlink(xauthfile); | ||
818 | rmdir(xauthdir); | ||
819 | } | ||
820 | if (xauthdir) | ||
821 | xfree(xauthdir); | ||
822 | if (xauthfile) | ||
823 | xfree(xauthfile); | ||
824 | |||
825 | /* | ||
826 | * If we didn't get authentication data, just make up some | ||
827 | * data. The forwarding code will check the validity of the | ||
828 | * response anyway, and substitute this data. The X11 | ||
829 | * server, however, will ignore this fake data and use | ||
830 | * whatever authentication mechanisms it was using otherwise | ||
831 | * for the local connection. | ||
832 | */ | ||
833 | if (!got_data) { | ||
834 | u_int32_t rnd = 0; | ||
835 | |||
836 | logit("Warning: No xauth data; " | ||
837 | "using fake authentication data for X11 forwarding."); | ||
838 | strlcpy(proto, SSH_X11_PROTO, sizeof proto); | ||
839 | for (i = 0; i < 16; i++) { | ||
840 | if (i % 4 == 0) | ||
841 | rnd = arc4random(); | ||
842 | snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", | ||
843 | rnd & 0xff); | ||
844 | rnd >>= 8; | ||
845 | } | ||
846 | } | ||
847 | } | ||
848 | |||
849 | static void | 763 | static void |
850 | ssh_init_forwarding(void) | 764 | ssh_init_forwarding(void) |
851 | { | 765 | { |
@@ -876,8 +790,8 @@ ssh_init_forwarding(void) | |||
876 | for (i = 0; i < options.num_remote_forwards; i++) { | 790 | for (i = 0; i < options.num_remote_forwards; i++) { |
877 | debug("Remote connections from %.200s:%d forwarded to " | 791 | debug("Remote connections from %.200s:%d forwarded to " |
878 | "local address %.200s:%d", | 792 | "local address %.200s:%d", |
879 | (options.remote_forwards[i].listen_host == NULL) ? | 793 | (options.remote_forwards[i].listen_host == NULL) ? |
880 | (options.gateway_ports ? "*" : "LOCALHOST") : | 794 | (options.gateway_ports ? "*" : "LOCALHOST") : |
881 | options.remote_forwards[i].listen_host, | 795 | options.remote_forwards[i].listen_host, |
882 | options.remote_forwards[i].listen_port, | 796 | options.remote_forwards[i].listen_port, |
883 | options.remote_forwards[i].connect_host, | 797 | options.remote_forwards[i].connect_host, |
@@ -908,6 +822,7 @@ ssh_session(void) | |||
908 | int have_tty = 0; | 822 | int have_tty = 0; |
909 | struct winsize ws; | 823 | struct winsize ws; |
910 | char *cp; | 824 | char *cp; |
825 | const char *display; | ||
911 | 826 | ||
912 | /* Enable compression if requested. */ | 827 | /* Enable compression if requested. */ |
913 | if (options.compression) { | 828 | if (options.compression) { |
@@ -969,13 +884,15 @@ ssh_session(void) | |||
969 | packet_disconnect("Protocol error waiting for pty request response."); | 884 | packet_disconnect("Protocol error waiting for pty request response."); |
970 | } | 885 | } |
971 | /* Request X11 forwarding if enabled and DISPLAY is set. */ | 886 | /* Request X11 forwarding if enabled and DISPLAY is set. */ |
972 | if (options.forward_x11 && getenv("DISPLAY") != NULL) { | 887 | display = getenv("DISPLAY"); |
888 | if (options.forward_x11 && display != NULL) { | ||
973 | char *proto, *data; | 889 | char *proto, *data; |
974 | /* Get reasonable local authentication information. */ | 890 | /* Get reasonable local authentication information. */ |
975 | x11_get_proto(&proto, &data); | 891 | client_x11_get_proto(display, options.xauth_location, |
892 | options.forward_x11_trusted, &proto, &data); | ||
976 | /* Request forwarding with authentication spoofing. */ | 893 | /* Request forwarding with authentication spoofing. */ |
977 | debug("Requesting X11 forwarding with authentication spoofing."); | 894 | debug("Requesting X11 forwarding with authentication spoofing."); |
978 | x11_request_forwarding_with_spoofing(0, proto, data); | 895 | x11_request_forwarding_with_spoofing(0, display, proto, data); |
979 | 896 | ||
980 | /* Read response from the server. */ | 897 | /* Read response from the server. */ |
981 | type = packet_read(); | 898 | type = packet_read(); |
@@ -1077,9 +994,12 @@ ssh_control_listener(void) | |||
1077 | mode_t old_umask; | 994 | mode_t old_umask; |
1078 | int addr_len; | 995 | int addr_len; |
1079 | 996 | ||
1080 | if (options.control_path == NULL || options.control_master <= 0) | 997 | if (options.control_path == NULL || |
998 | options.control_master == SSHCTL_MASTER_NO) | ||
1081 | return; | 999 | return; |
1082 | 1000 | ||
1001 | debug("setting up multiplex master socket"); | ||
1002 | |||
1083 | memset(&addr, '\0', sizeof(addr)); | 1003 | memset(&addr, '\0', sizeof(addr)); |
1084 | addr.sun_family = AF_UNIX; | 1004 | addr.sun_family = AF_UNIX; |
1085 | addr_len = offsetof(struct sockaddr_un, sun_path) + | 1005 | addr_len = offsetof(struct sockaddr_un, sun_path) + |
@@ -1114,15 +1034,18 @@ static void | |||
1114 | ssh_session2_setup(int id, void *arg) | 1034 | ssh_session2_setup(int id, void *arg) |
1115 | { | 1035 | { |
1116 | extern char **environ; | 1036 | extern char **environ; |
1117 | 1037 | const char *display; | |
1118 | int interactive = tty_flag; | 1038 | int interactive = tty_flag; |
1119 | if (options.forward_x11 && getenv("DISPLAY") != NULL) { | 1039 | |
1040 | display = getenv("DISPLAY"); | ||
1041 | if (options.forward_x11 && display != NULL) { | ||
1120 | char *proto, *data; | 1042 | char *proto, *data; |
1121 | /* Get reasonable local authentication information. */ | 1043 | /* Get reasonable local authentication information. */ |
1122 | x11_get_proto(&proto, &data); | 1044 | client_x11_get_proto(display, options.xauth_location, |
1045 | options.forward_x11_trusted, &proto, &data); | ||
1123 | /* Request forwarding with authentication spoofing. */ | 1046 | /* Request forwarding with authentication spoofing. */ |
1124 | debug("Requesting X11 forwarding with authentication spoofing."); | 1047 | debug("Requesting X11 forwarding with authentication spoofing."); |
1125 | x11_request_forwarding_with_spoofing(id, proto, data); | 1048 | x11_request_forwarding_with_spoofing(id, display, proto, data); |
1126 | interactive = 1; | 1049 | interactive = 1; |
1127 | /* XXX wait for reply */ | 1050 | /* XXX wait for reply */ |
1128 | } | 1051 | } |
@@ -1290,13 +1213,18 @@ control_client(const char *path) | |||
1290 | extern char **environ; | 1213 | extern char **environ; |
1291 | u_int flags; | 1214 | u_int flags; |
1292 | 1215 | ||
1293 | if (stdin_null_flag) { | 1216 | if (mux_command == 0) |
1294 | if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) | 1217 | mux_command = SSHMUX_COMMAND_OPEN; |
1295 | fatal("open(/dev/null): %s", strerror(errno)); | 1218 | |
1296 | if (dup2(fd, STDIN_FILENO) == -1) | 1219 | switch (options.control_master) { |
1297 | fatal("dup2: %s", strerror(errno)); | 1220 | case SSHCTL_MASTER_AUTO: |
1298 | if (fd > STDERR_FILENO) | 1221 | case SSHCTL_MASTER_AUTO_ASK: |
1299 | close(fd); | 1222 | debug("auto-mux: Trying existing master"); |
1223 | /* FALLTHROUGH */ | ||
1224 | case SSHCTL_MASTER_NO: | ||
1225 | break; | ||
1226 | default: | ||
1227 | return; | ||
1300 | } | 1228 | } |
1301 | 1229 | ||
1302 | memset(&addr, '\0', sizeof(addr)); | 1230 | memset(&addr, '\0', sizeof(addr)); |
@@ -1311,31 +1239,55 @@ control_client(const char *path) | |||
1311 | if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) | 1239 | if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) |
1312 | fatal("%s socket(): %s", __func__, strerror(errno)); | 1240 | fatal("%s socket(): %s", __func__, strerror(errno)); |
1313 | 1241 | ||
1314 | if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) | 1242 | if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) { |
1315 | fatal("Couldn't connect to %s: %s", path, strerror(errno)); | 1243 | if (mux_command != SSHMUX_COMMAND_OPEN) { |
1244 | fatal("Control socket connect(%.100s): %s", path, | ||
1245 | strerror(errno)); | ||
1246 | } | ||
1247 | if (errno == ENOENT) | ||
1248 | debug("Control socket \"%.100s\" does not exist", path); | ||
1249 | else { | ||
1250 | error("Control socket connect(%.100s): %s", path, | ||
1251 | strerror(errno)); | ||
1252 | } | ||
1253 | close(sock); | ||
1254 | return; | ||
1255 | } | ||
1256 | |||
1257 | if (stdin_null_flag) { | ||
1258 | if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) | ||
1259 | fatal("open(/dev/null): %s", strerror(errno)); | ||
1260 | if (dup2(fd, STDIN_FILENO) == -1) | ||
1261 | fatal("dup2: %s", strerror(errno)); | ||
1262 | if (fd > STDERR_FILENO) | ||
1263 | close(fd); | ||
1264 | } | ||
1316 | 1265 | ||
1317 | if ((term = getenv("TERM")) == NULL) | 1266 | term = getenv("TERM"); |
1318 | term = ""; | ||
1319 | 1267 | ||
1320 | flags = 0; | 1268 | flags = 0; |
1321 | if (tty_flag) | 1269 | if (tty_flag) |
1322 | flags |= SSHMUX_FLAG_TTY; | 1270 | flags |= SSHMUX_FLAG_TTY; |
1323 | if (subsystem_flag) | 1271 | if (subsystem_flag) |
1324 | flags |= SSHMUX_FLAG_SUBSYS; | 1272 | flags |= SSHMUX_FLAG_SUBSYS; |
1273 | if (options.forward_x11) | ||
1274 | flags |= SSHMUX_FLAG_X11_FWD; | ||
1275 | if (options.forward_agent) | ||
1276 | flags |= SSHMUX_FLAG_AGENT_FWD; | ||
1325 | 1277 | ||
1326 | buffer_init(&m); | 1278 | buffer_init(&m); |
1327 | 1279 | ||
1328 | /* Send our command to server */ | 1280 | /* Send our command to server */ |
1329 | buffer_put_int(&m, mux_command); | 1281 | buffer_put_int(&m, mux_command); |
1330 | buffer_put_int(&m, flags); | 1282 | buffer_put_int(&m, flags); |
1331 | if (ssh_msg_send(sock, /* version */1, &m) == -1) | 1283 | if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) |
1332 | fatal("%s: msg_send", __func__); | 1284 | fatal("%s: msg_send", __func__); |
1333 | buffer_clear(&m); | 1285 | buffer_clear(&m); |
1334 | 1286 | ||
1335 | /* Get authorisation status and PID of controlee */ | 1287 | /* Get authorisation status and PID of controlee */ |
1336 | if (ssh_msg_recv(sock, &m) == -1) | 1288 | if (ssh_msg_recv(sock, &m) == -1) |
1337 | fatal("%s: msg_recv", __func__); | 1289 | fatal("%s: msg_recv", __func__); |
1338 | if (buffer_get_char(&m) != 1) | 1290 | if (buffer_get_char(&m) != SSHMUX_VER) |
1339 | fatal("%s: wrong version", __func__); | 1291 | fatal("%s: wrong version", __func__); |
1340 | if (buffer_get_int(&m) != 1) | 1292 | if (buffer_get_int(&m) != 1) |
1341 | fatal("Connection to master denied"); | 1293 | fatal("Connection to master denied"); |
@@ -1359,7 +1311,7 @@ control_client(const char *path) | |||
1359 | } | 1311 | } |
1360 | 1312 | ||
1361 | /* SSHMUX_COMMAND_OPEN */ | 1313 | /* SSHMUX_COMMAND_OPEN */ |
1362 | buffer_put_cstring(&m, term); | 1314 | buffer_put_cstring(&m, term ? term : ""); |
1363 | buffer_append(&command, "\0", 1); | 1315 | buffer_append(&command, "\0", 1); |
1364 | buffer_put_cstring(&m, buffer_ptr(&command)); | 1316 | buffer_put_cstring(&m, buffer_ptr(&command)); |
1365 | 1317 | ||
@@ -1381,7 +1333,7 @@ control_client(const char *path) | |||
1381 | } | 1333 | } |
1382 | } | 1334 | } |
1383 | 1335 | ||
1384 | if (ssh_msg_send(sock, /* version */1, &m) == -1) | 1336 | if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) |
1385 | fatal("%s: msg_send", __func__); | 1337 | fatal("%s: msg_send", __func__); |
1386 | 1338 | ||
1387 | mm_send_fd(sock, STDIN_FILENO); | 1339 | mm_send_fd(sock, STDIN_FILENO); |
@@ -1392,7 +1344,7 @@ control_client(const char *path) | |||
1392 | buffer_clear(&m); | 1344 | buffer_clear(&m); |
1393 | if (ssh_msg_recv(sock, &m) == -1) | 1345 | if (ssh_msg_recv(sock, &m) == -1) |
1394 | fatal("%s: msg_recv", __func__); | 1346 | fatal("%s: msg_recv", __func__); |
1395 | if (buffer_get_char(&m) != 1) | 1347 | if (buffer_get_char(&m) != SSHMUX_VER) |
1396 | fatal("%s: wrong version", __func__); | 1348 | fatal("%s: wrong version", __func__); |
1397 | buffer_free(&m); | 1349 | buffer_free(&m); |
1398 | 1350 | ||