diff options
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 155 |
1 files changed, 143 insertions, 12 deletions
diff --git a/clientloop.c b/clientloop.c index 1e250883f..47f3c7ecd 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -59,7 +59,7 @@ | |||
59 | */ | 59 | */ |
60 | 60 | ||
61 | #include "includes.h" | 61 | #include "includes.h" |
62 | RCSID("$OpenBSD: clientloop.c,v 1.135 2005/03/01 10:09:52 djm Exp $"); | 62 | RCSID("$OpenBSD: clientloop.c,v 1.141 2005/07/16 01:35:24 djm Exp $"); |
63 | 63 | ||
64 | #include "ssh.h" | 64 | #include "ssh.h" |
65 | #include "ssh1.h" | 65 | #include "ssh1.h" |
@@ -140,6 +140,8 @@ int session_ident = -1; | |||
140 | struct confirm_ctx { | 140 | struct confirm_ctx { |
141 | int want_tty; | 141 | int want_tty; |
142 | int want_subsys; | 142 | int want_subsys; |
143 | int want_x_fwd; | ||
144 | int want_agent_fwd; | ||
143 | Buffer cmd; | 145 | Buffer cmd; |
144 | char *term; | 146 | char *term; |
145 | struct termios tio; | 147 | struct termios tio; |
@@ -208,6 +210,109 @@ get_current_time(void) | |||
208 | return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; | 210 | return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; |
209 | } | 211 | } |
210 | 212 | ||
213 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" | ||
214 | void | ||
215 | client_x11_get_proto(const char *display, const char *xauth_path, | ||
216 | u_int trusted, char **_proto, char **_data) | ||
217 | { | ||
218 | char cmd[1024]; | ||
219 | char line[512]; | ||
220 | char xdisplay[512]; | ||
221 | static char proto[512], data[512]; | ||
222 | FILE *f; | ||
223 | int got_data = 0, generated = 0, do_unlink = 0, i; | ||
224 | char *xauthdir, *xauthfile; | ||
225 | struct stat st; | ||
226 | |||
227 | xauthdir = xauthfile = NULL; | ||
228 | *_proto = proto; | ||
229 | *_data = data; | ||
230 | proto[0] = data[0] = '\0'; | ||
231 | |||
232 | if (xauth_path == NULL ||(stat(xauth_path, &st) == -1)) { | ||
233 | debug("No xauth program."); | ||
234 | } else { | ||
235 | if (display == NULL) { | ||
236 | debug("x11_get_proto: DISPLAY not set"); | ||
237 | return; | ||
238 | } | ||
239 | /* | ||
240 | * Handle FamilyLocal case where $DISPLAY does | ||
241 | * not match an authorization entry. For this we | ||
242 | * just try "xauth list unix:displaynum.screennum". | ||
243 | * XXX: "localhost" match to determine FamilyLocal | ||
244 | * is not perfect. | ||
245 | */ | ||
246 | if (strncmp(display, "localhost:", 10) == 0) { | ||
247 | snprintf(xdisplay, sizeof(xdisplay), "unix:%s", | ||
248 | display + 10); | ||
249 | display = xdisplay; | ||
250 | } | ||
251 | if (trusted == 0) { | ||
252 | xauthdir = xmalloc(MAXPATHLEN); | ||
253 | xauthfile = xmalloc(MAXPATHLEN); | ||
254 | strlcpy(xauthdir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN); | ||
255 | if (mkdtemp(xauthdir) != NULL) { | ||
256 | do_unlink = 1; | ||
257 | snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile", | ||
258 | xauthdir); | ||
259 | snprintf(cmd, sizeof(cmd), | ||
260 | "%s -f %s generate %s " SSH_X11_PROTO | ||
261 | " untrusted timeout 1200 2>" _PATH_DEVNULL, | ||
262 | xauth_path, xauthfile, display); | ||
263 | debug2("x11_get_proto: %s", cmd); | ||
264 | if (system(cmd) == 0) | ||
265 | generated = 1; | ||
266 | } | ||
267 | } | ||
268 | snprintf(cmd, sizeof(cmd), | ||
269 | "%s %s%s list %s . 2>" _PATH_DEVNULL, | ||
270 | xauth_path, | ||
271 | generated ? "-f " : "" , | ||
272 | generated ? xauthfile : "", | ||
273 | display); | ||
274 | debug2("x11_get_proto: %s", cmd); | ||
275 | f = popen(cmd, "r"); | ||
276 | if (f && fgets(line, sizeof(line), f) && | ||
277 | sscanf(line, "%*s %511s %511s", proto, data) == 2) | ||
278 | got_data = 1; | ||
279 | if (f) | ||
280 | pclose(f); | ||
281 | } | ||
282 | |||
283 | if (do_unlink) { | ||
284 | unlink(xauthfile); | ||
285 | rmdir(xauthdir); | ||
286 | } | ||
287 | if (xauthdir) | ||
288 | xfree(xauthdir); | ||
289 | if (xauthfile) | ||
290 | xfree(xauthfile); | ||
291 | |||
292 | /* | ||
293 | * If we didn't get authentication data, just make up some | ||
294 | * data. The forwarding code will check the validity of the | ||
295 | * response anyway, and substitute this data. The X11 | ||
296 | * server, however, will ignore this fake data and use | ||
297 | * whatever authentication mechanisms it was using otherwise | ||
298 | * for the local connection. | ||
299 | */ | ||
300 | if (!got_data) { | ||
301 | u_int32_t rnd = 0; | ||
302 | |||
303 | logit("Warning: No xauth data; " | ||
304 | "using fake authentication data for X11 forwarding."); | ||
305 | strlcpy(proto, SSH_X11_PROTO, sizeof proto); | ||
306 | for (i = 0; i < 16; i++) { | ||
307 | if (i % 4 == 0) | ||
308 | rnd = arc4random(); | ||
309 | snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", | ||
310 | rnd & 0xff); | ||
311 | rnd >>= 8; | ||
312 | } | ||
313 | } | ||
314 | } | ||
315 | |||
211 | /* | 316 | /* |
212 | * This is called when the interactive is entered. This checks if there is | 317 | * This is called when the interactive is entered. This checks if there is |
213 | * an EOF coming on stdin. We must check this explicitly, as select() does | 318 | * an EOF coming on stdin. We must check this explicitly, as select() does |
@@ -528,6 +633,7 @@ static void | |||
528 | client_extra_session2_setup(int id, void *arg) | 633 | client_extra_session2_setup(int id, void *arg) |
529 | { | 634 | { |
530 | struct confirm_ctx *cctx = arg; | 635 | struct confirm_ctx *cctx = arg; |
636 | const char *display; | ||
531 | Channel *c; | 637 | Channel *c; |
532 | int i; | 638 | int i; |
533 | 639 | ||
@@ -536,6 +642,24 @@ client_extra_session2_setup(int id, void *arg) | |||
536 | if ((c = channel_lookup(id)) == NULL) | 642 | if ((c = channel_lookup(id)) == NULL) |
537 | fatal("%s: no channel for id %d", __func__, id); | 643 | fatal("%s: no channel for id %d", __func__, id); |
538 | 644 | ||
645 | display = getenv("DISPLAY"); | ||
646 | if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { | ||
647 | char *proto, *data; | ||
648 | /* Get reasonable local authentication information. */ | ||
649 | client_x11_get_proto(display, options.xauth_location, | ||
650 | options.forward_x11_trusted, &proto, &data); | ||
651 | /* Request forwarding with authentication spoofing. */ | ||
652 | debug("Requesting X11 forwarding with authentication spoofing."); | ||
653 | x11_request_forwarding_with_spoofing(id, display, proto, data); | ||
654 | /* XXX wait for reply */ | ||
655 | } | ||
656 | |||
657 | if (cctx->want_agent_fwd && options.forward_agent) { | ||
658 | debug("Requesting authentication agent forwarding."); | ||
659 | channel_request_start(id, "auth-agent-req@openssh.com", 0); | ||
660 | packet_send(); | ||
661 | } | ||
662 | |||
539 | client_session2_setup(id, cctx->want_tty, cctx->want_subsys, | 663 | client_session2_setup(id, cctx->want_tty, cctx->want_subsys, |
540 | cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, | 664 | cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, |
541 | client_subsystem_reply); | 665 | client_subsystem_reply); |
@@ -556,12 +680,12 @@ client_process_control(fd_set * readset) | |||
556 | { | 680 | { |
557 | Buffer m; | 681 | Buffer m; |
558 | Channel *c; | 682 | Channel *c; |
559 | int client_fd, new_fd[3], ver, i, allowed; | 683 | int client_fd, new_fd[3], ver, allowed; |
560 | socklen_t addrlen; | 684 | socklen_t addrlen; |
561 | struct sockaddr_storage addr; | 685 | struct sockaddr_storage addr; |
562 | struct confirm_ctx *cctx; | 686 | struct confirm_ctx *cctx; |
563 | char *cmd; | 687 | char *cmd; |
564 | u_int len, env_len, command, flags; | 688 | u_int i, len, env_len, command, flags; |
565 | uid_t euid; | 689 | uid_t euid; |
566 | gid_t egid; | 690 | gid_t egid; |
567 | 691 | ||
@@ -601,7 +725,7 @@ client_process_control(fd_set * readset) | |||
601 | buffer_free(&m); | 725 | buffer_free(&m); |
602 | return; | 726 | return; |
603 | } | 727 | } |
604 | if ((ver = buffer_get_char(&m)) != 1) { | 728 | if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { |
605 | error("%s: wrong client version %d", __func__, ver); | 729 | error("%s: wrong client version %d", __func__, ver); |
606 | buffer_free(&m); | 730 | buffer_free(&m); |
607 | close(client_fd); | 731 | close(client_fd); |
@@ -616,24 +740,26 @@ client_process_control(fd_set * readset) | |||
616 | 740 | ||
617 | switch (command) { | 741 | switch (command) { |
618 | case SSHMUX_COMMAND_OPEN: | 742 | case SSHMUX_COMMAND_OPEN: |
619 | if (options.control_master == 2) | 743 | if (options.control_master == SSHCTL_MASTER_ASK || |
744 | options.control_master == SSHCTL_MASTER_AUTO_ASK) | ||
620 | allowed = ask_permission("Allow shared connection " | 745 | allowed = ask_permission("Allow shared connection " |
621 | "to %s? ", host); | 746 | "to %s? ", host); |
622 | /* continue below */ | 747 | /* continue below */ |
623 | break; | 748 | break; |
624 | case SSHMUX_COMMAND_TERMINATE: | 749 | case SSHMUX_COMMAND_TERMINATE: |
625 | if (options.control_master == 2) | 750 | if (options.control_master == SSHCTL_MASTER_ASK || |
751 | options.control_master == SSHCTL_MASTER_AUTO_ASK) | ||
626 | allowed = ask_permission("Terminate shared connection " | 752 | allowed = ask_permission("Terminate shared connection " |
627 | "to %s? ", host); | 753 | "to %s? ", host); |
628 | if (allowed) | 754 | if (allowed) |
629 | quit_pending = 1; | 755 | quit_pending = 1; |
630 | /* FALLTHROUGH */ | 756 | /* FALLTHROUGH */ |
631 | case SSHMUX_COMMAND_ALIVE_CHECK: | 757 | case SSHMUX_COMMAND_ALIVE_CHECK: |
632 | /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */ | 758 | /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */ |
633 | buffer_clear(&m); | 759 | buffer_clear(&m); |
634 | buffer_put_int(&m, allowed); | 760 | buffer_put_int(&m, allowed); |
635 | buffer_put_int(&m, getpid()); | 761 | buffer_put_int(&m, getpid()); |
636 | if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { | 762 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { |
637 | error("%s: client msg_send failed", __func__); | 763 | error("%s: client msg_send failed", __func__); |
638 | close(client_fd); | 764 | close(client_fd); |
639 | buffer_free(&m); | 765 | buffer_free(&m); |
@@ -653,7 +779,7 @@ client_process_control(fd_set * readset) | |||
653 | buffer_clear(&m); | 779 | buffer_clear(&m); |
654 | buffer_put_int(&m, allowed); | 780 | buffer_put_int(&m, allowed); |
655 | buffer_put_int(&m, getpid()); | 781 | buffer_put_int(&m, getpid()); |
656 | if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { | 782 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { |
657 | error("%s: client msg_send failed", __func__); | 783 | error("%s: client msg_send failed", __func__); |
658 | close(client_fd); | 784 | close(client_fd); |
659 | buffer_free(&m); | 785 | buffer_free(&m); |
@@ -674,7 +800,7 @@ client_process_control(fd_set * readset) | |||
674 | buffer_free(&m); | 800 | buffer_free(&m); |
675 | return; | 801 | return; |
676 | } | 802 | } |
677 | if ((ver = buffer_get_char(&m)) != 1) { | 803 | if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { |
678 | error("%s: wrong client version %d", __func__, ver); | 804 | error("%s: wrong client version %d", __func__, ver); |
679 | buffer_free(&m); | 805 | buffer_free(&m); |
680 | close(client_fd); | 806 | close(client_fd); |
@@ -685,6 +811,8 @@ client_process_control(fd_set * readset) | |||
685 | memset(cctx, 0, sizeof(*cctx)); | 811 | memset(cctx, 0, sizeof(*cctx)); |
686 | cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; | 812 | cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; |
687 | cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; | 813 | cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; |
814 | cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0; | ||
815 | cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0; | ||
688 | cctx->term = buffer_get_string(&m, &len); | 816 | cctx->term = buffer_get_string(&m, &len); |
689 | 817 | ||
690 | cmd = buffer_get_string(&m, &len); | 818 | cmd = buffer_get_string(&m, &len); |
@@ -718,7 +846,7 @@ client_process_control(fd_set * readset) | |||
718 | 846 | ||
719 | /* This roundtrip is just for synchronisation of ttymodes */ | 847 | /* This roundtrip is just for synchronisation of ttymodes */ |
720 | buffer_clear(&m); | 848 | buffer_clear(&m); |
721 | if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { | 849 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { |
722 | error("%s: client msg_send failed", __func__); | 850 | error("%s: client msg_send failed", __func__); |
723 | close(client_fd); | 851 | close(client_fd); |
724 | close(new_fd[0]); | 852 | close(new_fd[0]); |
@@ -866,7 +994,10 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
866 | u_char ch; | 994 | u_char ch; |
867 | char *s; | 995 | char *s; |
868 | 996 | ||
869 | for (i = 0; i < len; i++) { | 997 | if (len <= 0) |
998 | return (0); | ||
999 | |||
1000 | for (i = 0; i < (u_int)len; i++) { | ||
870 | /* Get one character at a time. */ | 1001 | /* Get one character at a time. */ |
871 | ch = buf[i]; | 1002 | ch = buf[i]; |
872 | 1003 | ||