diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 472 |
1 files changed, 401 insertions, 71 deletions
diff --git a/channels.c b/channels.c index 9f9e972f4..bef8ad6aa 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.351 2016/07/19 11:38:53 dtucker Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.356 2016/10/18 17:32:54 dtucker 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 |
@@ -42,7 +42,6 @@ | |||
42 | #include "includes.h" | 42 | #include "includes.h" |
43 | 43 | ||
44 | #include <sys/types.h> | 44 | #include <sys/types.h> |
45 | #include <sys/param.h> /* MIN MAX */ | ||
46 | #include <sys/stat.h> | 45 | #include <sys/stat.h> |
47 | #include <sys/ioctl.h> | 46 | #include <sys/ioctl.h> |
48 | #include <sys/un.h> | 47 | #include <sys/un.h> |
@@ -72,6 +71,7 @@ | |||
72 | #include "ssh.h" | 71 | #include "ssh.h" |
73 | #include "ssh1.h" | 72 | #include "ssh1.h" |
74 | #include "ssh2.h" | 73 | #include "ssh2.h" |
74 | #include "ssherr.h" | ||
75 | #include "packet.h" | 75 | #include "packet.h" |
76 | #include "log.h" | 76 | #include "log.h" |
77 | #include "misc.h" | 77 | #include "misc.h" |
@@ -121,6 +121,7 @@ typedef struct { | |||
121 | char *listen_host; /* Remote side should listen address. */ | 121 | char *listen_host; /* Remote side should listen address. */ |
122 | char *listen_path; /* Remote side should listen path. */ | 122 | char *listen_path; /* Remote side should listen path. */ |
123 | int listen_port; /* Remote side should listen port. */ | 123 | int listen_port; /* Remote side should listen port. */ |
124 | Channel *downstream; /* Downstream mux*/ | ||
124 | } ForwardPermission; | 125 | } ForwardPermission; |
125 | 126 | ||
126 | /* List of all permitted host/port pairs to connect by the user. */ | 127 | /* List of all permitted host/port pairs to connect by the user. */ |
@@ -184,6 +185,7 @@ static int IPv4or6 = AF_UNSPEC; | |||
184 | 185 | ||
185 | /* helper */ | 186 | /* helper */ |
186 | static void port_open_helper(Channel *c, char *rtype); | 187 | static void port_open_helper(Channel *c, char *rtype); |
188 | static const char *channel_rfwd_bind_host(const char *listen_host); | ||
187 | 189 | ||
188 | /* non-blocking connect helpers */ | 190 | /* non-blocking connect helpers */ |
189 | static int connect_next(struct channel_connect *); | 191 | static int connect_next(struct channel_connect *); |
@@ -208,6 +210,20 @@ channel_by_id(int id) | |||
208 | return c; | 210 | return c; |
209 | } | 211 | } |
210 | 212 | ||
213 | Channel * | ||
214 | channel_by_remote_id(int remote_id) | ||
215 | { | ||
216 | Channel *c; | ||
217 | u_int i; | ||
218 | |||
219 | for (i = 0; i < channels_alloc; i++) { | ||
220 | c = channels[i]; | ||
221 | if (c != NULL && c->remote_id == remote_id) | ||
222 | return c; | ||
223 | } | ||
224 | return NULL; | ||
225 | } | ||
226 | |||
211 | /* | 227 | /* |
212 | * Returns the channel if it is allowed to receive protocol messages. | 228 | * Returns the channel if it is allowed to receive protocol messages. |
213 | * Private channels, like listening sockets, may not receive messages. | 229 | * Private channels, like listening sockets, may not receive messages. |
@@ -230,6 +246,7 @@ channel_lookup(int id) | |||
230 | case SSH_CHANNEL_INPUT_DRAINING: | 246 | case SSH_CHANNEL_INPUT_DRAINING: |
231 | case SSH_CHANNEL_OUTPUT_DRAINING: | 247 | case SSH_CHANNEL_OUTPUT_DRAINING: |
232 | case SSH_CHANNEL_ABANDONED: | 248 | case SSH_CHANNEL_ABANDONED: |
249 | case SSH_CHANNEL_MUX_PROXY: | ||
233 | return (c); | 250 | return (c); |
234 | } | 251 | } |
235 | logit("Non-public channel %d, type %d.", id, c->type); | 252 | logit("Non-public channel %d, type %d.", id, c->type); |
@@ -245,9 +262,9 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, | |||
245 | int extusage, int nonblock, int is_tty) | 262 | int extusage, int nonblock, int is_tty) |
246 | { | 263 | { |
247 | /* Update the maximum file descriptor value. */ | 264 | /* Update the maximum file descriptor value. */ |
248 | channel_max_fd = MAX(channel_max_fd, rfd); | 265 | channel_max_fd = MAXIMUM(channel_max_fd, rfd); |
249 | channel_max_fd = MAX(channel_max_fd, wfd); | 266 | channel_max_fd = MAXIMUM(channel_max_fd, wfd); |
250 | channel_max_fd = MAX(channel_max_fd, efd); | 267 | channel_max_fd = MAXIMUM(channel_max_fd, efd); |
251 | 268 | ||
252 | if (rfd != -1) | 269 | if (rfd != -1) |
253 | fcntl(rfd, F_SETFD, FD_CLOEXEC); | 270 | fcntl(rfd, F_SETFD, FD_CLOEXEC); |
@@ -373,9 +390,9 @@ channel_find_maxfd(void) | |||
373 | for (i = 0; i < channels_alloc; i++) { | 390 | for (i = 0; i < channels_alloc; i++) { |
374 | c = channels[i]; | 391 | c = channels[i]; |
375 | if (c != NULL) { | 392 | if (c != NULL) { |
376 | max = MAX(max, c->rfd); | 393 | max = MAXIMUM(max, c->rfd); |
377 | max = MAX(max, c->wfd); | 394 | max = MAXIMUM(max, c->wfd); |
378 | max = MAX(max, c->efd); | 395 | max = MAXIMUM(max, c->efd); |
379 | } | 396 | } |
380 | } | 397 | } |
381 | return max; | 398 | return max; |
@@ -411,14 +428,56 @@ channel_free(Channel *c) | |||
411 | { | 428 | { |
412 | char *s; | 429 | char *s; |
413 | u_int i, n; | 430 | u_int i, n; |
431 | Channel *other; | ||
414 | struct channel_confirm *cc; | 432 | struct channel_confirm *cc; |
415 | 433 | ||
416 | for (n = 0, i = 0; i < channels_alloc; i++) | 434 | for (n = 0, i = 0; i < channels_alloc; i++) { |
417 | if (channels[i]) | 435 | if ((other = channels[i]) != NULL) { |
418 | n++; | 436 | n++; |
437 | |||
438 | /* detach from mux client and prepare for closing */ | ||
439 | if (c->type == SSH_CHANNEL_MUX_CLIENT && | ||
440 | other->type == SSH_CHANNEL_MUX_PROXY && | ||
441 | other->mux_ctx == c) { | ||
442 | other->mux_ctx = NULL; | ||
443 | other->type = SSH_CHANNEL_OPEN; | ||
444 | other->istate = CHAN_INPUT_CLOSED; | ||
445 | other->ostate = CHAN_OUTPUT_CLOSED; | ||
446 | } | ||
447 | } | ||
448 | } | ||
419 | debug("channel %d: free: %s, nchannels %u", c->self, | 449 | debug("channel %d: free: %s, nchannels %u", c->self, |
420 | c->remote_name ? c->remote_name : "???", n); | 450 | c->remote_name ? c->remote_name : "???", n); |
421 | 451 | ||
452 | /* XXX more MUX cleanup: remove remote forwardings */ | ||
453 | if (c->type == SSH_CHANNEL_MUX_CLIENT) { | ||
454 | for (i = 0; i < (u_int)num_permitted_opens; i++) { | ||
455 | if (permitted_opens[i].downstream != c) | ||
456 | continue; | ||
457 | /* cancel on the server, since mux client is gone */ | ||
458 | debug("channel %d: cleanup remote forward for %s:%u", | ||
459 | c->self, | ||
460 | permitted_opens[i].listen_host, | ||
461 | permitted_opens[i].listen_port); | ||
462 | packet_start(SSH2_MSG_GLOBAL_REQUEST); | ||
463 | packet_put_cstring("cancel-tcpip-forward"); | ||
464 | packet_put_char(0); | ||
465 | packet_put_cstring(channel_rfwd_bind_host( | ||
466 | permitted_opens[i].listen_host)); | ||
467 | packet_put_int(permitted_opens[i].listen_port); | ||
468 | packet_send(); | ||
469 | /* unregister */ | ||
470 | permitted_opens[i].listen_port = 0; | ||
471 | permitted_opens[i].port_to_connect = 0; | ||
472 | free(permitted_opens[i].host_to_connect); | ||
473 | permitted_opens[i].host_to_connect = NULL; | ||
474 | free(permitted_opens[i].listen_host); | ||
475 | permitted_opens[i].listen_host = NULL; | ||
476 | permitted_opens[i].listen_path = NULL; | ||
477 | permitted_opens[i].downstream = NULL; | ||
478 | } | ||
479 | } | ||
480 | |||
422 | s = channel_open_message(); | 481 | s = channel_open_message(); |
423 | debug3("channel %d: status: %s", c->self, s); | 482 | debug3("channel %d: status: %s", c->self, s); |
424 | free(s); | 483 | free(s); |
@@ -564,6 +623,7 @@ channel_still_open(void) | |||
564 | case SSH_CHANNEL_OPEN: | 623 | case SSH_CHANNEL_OPEN: |
565 | case SSH_CHANNEL_X11_OPEN: | 624 | case SSH_CHANNEL_X11_OPEN: |
566 | case SSH_CHANNEL_MUX_CLIENT: | 625 | case SSH_CHANNEL_MUX_CLIENT: |
626 | case SSH_CHANNEL_MUX_PROXY: | ||
567 | return 1; | 627 | return 1; |
568 | case SSH_CHANNEL_INPUT_DRAINING: | 628 | case SSH_CHANNEL_INPUT_DRAINING: |
569 | case SSH_CHANNEL_OUTPUT_DRAINING: | 629 | case SSH_CHANNEL_OUTPUT_DRAINING: |
@@ -597,6 +657,7 @@ channel_find_open(void) | |||
597 | case SSH_CHANNEL_RPORT_LISTENER: | 657 | case SSH_CHANNEL_RPORT_LISTENER: |
598 | case SSH_CHANNEL_MUX_LISTENER: | 658 | case SSH_CHANNEL_MUX_LISTENER: |
599 | case SSH_CHANNEL_MUX_CLIENT: | 659 | case SSH_CHANNEL_MUX_CLIENT: |
660 | case SSH_CHANNEL_MUX_PROXY: | ||
600 | case SSH_CHANNEL_OPENING: | 661 | case SSH_CHANNEL_OPENING: |
601 | case SSH_CHANNEL_CONNECTING: | 662 | case SSH_CHANNEL_CONNECTING: |
602 | case SSH_CHANNEL_ZOMBIE: | 663 | case SSH_CHANNEL_ZOMBIE: |
@@ -622,7 +683,6 @@ channel_find_open(void) | |||
622 | return -1; | 683 | return -1; |
623 | } | 684 | } |
624 | 685 | ||
625 | |||
626 | /* | 686 | /* |
627 | * Returns a message describing the currently open forwarded connections, | 687 | * Returns a message describing the currently open forwarded connections, |
628 | * suitable for sending to the client. The message contains crlf pairs for | 688 | * suitable for sending to the client. The message contains crlf pairs for |
@@ -651,7 +711,6 @@ channel_open_message(void) | |||
651 | case SSH_CHANNEL_AUTH_SOCKET: | 711 | case SSH_CHANNEL_AUTH_SOCKET: |
652 | case SSH_CHANNEL_ZOMBIE: | 712 | case SSH_CHANNEL_ZOMBIE: |
653 | case SSH_CHANNEL_ABANDONED: | 713 | case SSH_CHANNEL_ABANDONED: |
654 | case SSH_CHANNEL_MUX_CLIENT: | ||
655 | case SSH_CHANNEL_MUX_LISTENER: | 714 | case SSH_CHANNEL_MUX_LISTENER: |
656 | case SSH_CHANNEL_UNIX_LISTENER: | 715 | case SSH_CHANNEL_UNIX_LISTENER: |
657 | case SSH_CHANNEL_RUNIX_LISTENER: | 716 | case SSH_CHANNEL_RUNIX_LISTENER: |
@@ -664,6 +723,8 @@ channel_open_message(void) | |||
664 | case SSH_CHANNEL_X11_OPEN: | 723 | case SSH_CHANNEL_X11_OPEN: |
665 | case SSH_CHANNEL_INPUT_DRAINING: | 724 | case SSH_CHANNEL_INPUT_DRAINING: |
666 | case SSH_CHANNEL_OUTPUT_DRAINING: | 725 | case SSH_CHANNEL_OUTPUT_DRAINING: |
726 | case SSH_CHANNEL_MUX_PROXY: | ||
727 | case SSH_CHANNEL_MUX_CLIENT: | ||
667 | snprintf(buf, sizeof buf, | 728 | snprintf(buf, sizeof buf, |
668 | " #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n", | 729 | " #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n", |
669 | c->self, c->remote_name, | 730 | c->self, c->remote_name, |
@@ -1898,7 +1959,7 @@ read_mux(Channel *c, u_int need) | |||
1898 | 1959 | ||
1899 | if (buffer_len(&c->input) < need) { | 1960 | if (buffer_len(&c->input) < need) { |
1900 | rlen = need - buffer_len(&c->input); | 1961 | rlen = need - buffer_len(&c->input); |
1901 | len = read(c->rfd, buf, MIN(rlen, CHAN_RBUF)); | 1962 | len = read(c->rfd, buf, MINIMUM(rlen, CHAN_RBUF)); |
1902 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | 1963 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) |
1903 | return buffer_len(&c->input); | 1964 | return buffer_len(&c->input); |
1904 | if (len <= 0) { | 1965 | if (len <= 0) { |
@@ -2201,7 +2262,7 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
2201 | { | 2262 | { |
2202 | u_int n, sz, nfdset; | 2263 | u_int n, sz, nfdset; |
2203 | 2264 | ||
2204 | n = MAX(*maxfdp, channel_max_fd); | 2265 | n = MAXIMUM(*maxfdp, channel_max_fd); |
2205 | 2266 | ||
2206 | nfdset = howmany(n+1, NFDBITS); | 2267 | nfdset = howmany(n+1, NFDBITS); |
2207 | /* Explicitly test here, because xrealloc isn't always called */ | 2268 | /* Explicitly test here, because xrealloc isn't always called */ |
@@ -2361,6 +2422,284 @@ channel_output_poll(void) | |||
2361 | } | 2422 | } |
2362 | } | 2423 | } |
2363 | 2424 | ||
2425 | /* -- mux proxy support */ | ||
2426 | |||
2427 | /* | ||
2428 | * When multiplexing channel messages for mux clients we have to deal | ||
2429 | * with downstream messages from the mux client and upstream messages | ||
2430 | * from the ssh server: | ||
2431 | * 1) Handling downstream messages is straightforward and happens | ||
2432 | * in channel_proxy_downstream(): | ||
2433 | * - We forward all messages (mostly) unmodified to the server. | ||
2434 | * - However, in order to route messages from upstream to the correct | ||
2435 | * downstream client, we have to replace the channel IDs used by the | ||
2436 | * mux clients with a unique channel ID because the mux clients might | ||
2437 | * use conflicting channel IDs. | ||
2438 | * - so we inspect and change both SSH2_MSG_CHANNEL_OPEN and | ||
2439 | * SSH2_MSG_CHANNEL_OPEN_CONFIRMATION messages, create a local | ||
2440 | * SSH_CHANNEL_MUX_PROXY channel and replace the mux clients ID | ||
2441 | * with the newly allocated channel ID. | ||
2442 | * 2) Upstream messages are received by matching SSH_CHANNEL_MUX_PROXY | ||
2443 | * channels and procesed by channel_proxy_upstream(). The local channel ID | ||
2444 | * is then translated back to the original mux client ID. | ||
2445 | * 3) In both cases we need to keep track of matching SSH2_MSG_CHANNEL_CLOSE | ||
2446 | * messages so we can clean up SSH_CHANNEL_MUX_PROXY channels. | ||
2447 | * 4) The SSH_CHANNEL_MUX_PROXY channels also need to closed when the | ||
2448 | * downstream mux client are removed. | ||
2449 | * 5) Handling SSH2_MSG_CHANNEL_OPEN messages from the upstream server | ||
2450 | * requires more work, because they are not addressed to a specific | ||
2451 | * channel. E.g. client_request_forwarded_tcpip() needs to figure | ||
2452 | * out whether the request is addressed to the local client or a | ||
2453 | * specific downstream client based on the listen-address/port. | ||
2454 | * 6) Agent and X11-Forwarding have a similar problem and are currenly | ||
2455 | * not supported as the matching session/channel cannot be identified | ||
2456 | * easily. | ||
2457 | */ | ||
2458 | |||
2459 | /* | ||
2460 | * receive packets from downstream mux clients: | ||
2461 | * channel callback fired on read from mux client, creates | ||
2462 | * SSH_CHANNEL_MUX_PROXY channels and translates channel IDs | ||
2463 | * on channel creation. | ||
2464 | */ | ||
2465 | int | ||
2466 | channel_proxy_downstream(Channel *downstream) | ||
2467 | { | ||
2468 | Channel *c = NULL; | ||
2469 | struct ssh *ssh = active_state; | ||
2470 | struct sshbuf *original = NULL, *modified = NULL; | ||
2471 | const u_char *cp; | ||
2472 | char *ctype = NULL, *listen_host = NULL; | ||
2473 | u_char type; | ||
2474 | size_t have; | ||
2475 | int ret = -1, r, idx; | ||
2476 | u_int id, remote_id, listen_port; | ||
2477 | |||
2478 | /* sshbuf_dump(&downstream->input, stderr); */ | ||
2479 | if ((r = sshbuf_get_string_direct(&downstream->input, &cp, &have)) | ||
2480 | != 0) { | ||
2481 | error("%s: malformed message: %s", __func__, ssh_err(r)); | ||
2482 | return -1; | ||
2483 | } | ||
2484 | if (have < 2) { | ||
2485 | error("%s: short message", __func__); | ||
2486 | return -1; | ||
2487 | } | ||
2488 | type = cp[1]; | ||
2489 | /* skip padlen + type */ | ||
2490 | cp += 2; | ||
2491 | have -= 2; | ||
2492 | if (ssh_packet_log_type(type)) | ||
2493 | debug3("%s: channel %u: down->up: type %u", __func__, | ||
2494 | downstream->self, type); | ||
2495 | |||
2496 | switch (type) { | ||
2497 | case SSH2_MSG_CHANNEL_OPEN: | ||
2498 | if ((original = sshbuf_from(cp, have)) == NULL || | ||
2499 | (modified = sshbuf_new()) == NULL) { | ||
2500 | error("%s: alloc", __func__); | ||
2501 | goto out; | ||
2502 | } | ||
2503 | if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0 || | ||
2504 | (r = sshbuf_get_u32(original, &id)) != 0) { | ||
2505 | error("%s: parse error %s", __func__, ssh_err(r)); | ||
2506 | goto out; | ||
2507 | } | ||
2508 | c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY, | ||
2509 | -1, -1, -1, 0, 0, 0, ctype, 1); | ||
2510 | c->mux_ctx = downstream; /* point to mux client */ | ||
2511 | c->mux_downstream_id = id; /* original downstream id */ | ||
2512 | if ((r = sshbuf_put_cstring(modified, ctype)) != 0 || | ||
2513 | (r = sshbuf_put_u32(modified, c->self)) != 0 || | ||
2514 | (r = sshbuf_putb(modified, original)) != 0) { | ||
2515 | error("%s: compose error %s", __func__, ssh_err(r)); | ||
2516 | channel_free(c); | ||
2517 | goto out; | ||
2518 | } | ||
2519 | break; | ||
2520 | case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: | ||
2521 | /* | ||
2522 | * Almost the same as SSH2_MSG_CHANNEL_OPEN, except then we | ||
2523 | * need to parse 'remote_id' instead of 'ctype'. | ||
2524 | */ | ||
2525 | if ((original = sshbuf_from(cp, have)) == NULL || | ||
2526 | (modified = sshbuf_new()) == NULL) { | ||
2527 | error("%s: alloc", __func__); | ||
2528 | goto out; | ||
2529 | } | ||
2530 | if ((r = sshbuf_get_u32(original, &remote_id)) != 0 || | ||
2531 | (r = sshbuf_get_u32(original, &id)) != 0) { | ||
2532 | error("%s: parse error %s", __func__, ssh_err(r)); | ||
2533 | goto out; | ||
2534 | } | ||
2535 | c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY, | ||
2536 | -1, -1, -1, 0, 0, 0, "mux-down-connect", 1); | ||
2537 | c->mux_ctx = downstream; /* point to mux client */ | ||
2538 | c->mux_downstream_id = id; | ||
2539 | c->remote_id = remote_id; | ||
2540 | if ((r = sshbuf_put_u32(modified, remote_id)) != 0 || | ||
2541 | (r = sshbuf_put_u32(modified, c->self)) != 0 || | ||
2542 | (r = sshbuf_putb(modified, original)) != 0) { | ||
2543 | error("%s: compose error %s", __func__, ssh_err(r)); | ||
2544 | channel_free(c); | ||
2545 | goto out; | ||
2546 | } | ||
2547 | break; | ||
2548 | case SSH2_MSG_GLOBAL_REQUEST: | ||
2549 | if ((original = sshbuf_from(cp, have)) == NULL) { | ||
2550 | error("%s: alloc", __func__); | ||
2551 | goto out; | ||
2552 | } | ||
2553 | if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0) { | ||
2554 | error("%s: parse error %s", __func__, ssh_err(r)); | ||
2555 | goto out; | ||
2556 | } | ||
2557 | if (strcmp(ctype, "tcpip-forward") != 0) { | ||
2558 | error("%s: unsupported request %s", __func__, ctype); | ||
2559 | goto out; | ||
2560 | } | ||
2561 | if ((r = sshbuf_get_u8(original, NULL)) != 0 || | ||
2562 | (r = sshbuf_get_cstring(original, &listen_host, NULL)) != 0 || | ||
2563 | (r = sshbuf_get_u32(original, &listen_port)) != 0) { | ||
2564 | error("%s: parse error %s", __func__, ssh_err(r)); | ||
2565 | goto out; | ||
2566 | } | ||
2567 | if (listen_port > 65535) { | ||
2568 | error("%s: tcpip-forward for %s: bad port %u", | ||
2569 | __func__, listen_host, listen_port); | ||
2570 | goto out; | ||
2571 | } | ||
2572 | /* Record that connection to this host/port is permitted. */ | ||
2573 | permitted_opens = xreallocarray(permitted_opens, | ||
2574 | num_permitted_opens + 1, sizeof(*permitted_opens)); | ||
2575 | idx = num_permitted_opens++; | ||
2576 | permitted_opens[idx].host_to_connect = xstrdup("<mux>"); | ||
2577 | permitted_opens[idx].port_to_connect = -1; | ||
2578 | permitted_opens[idx].listen_host = listen_host; | ||
2579 | permitted_opens[idx].listen_port = (int)listen_port; | ||
2580 | permitted_opens[idx].downstream = downstream; | ||
2581 | listen_host = NULL; | ||
2582 | break; | ||
2583 | case SSH2_MSG_CHANNEL_CLOSE: | ||
2584 | if (have < 4) | ||
2585 | break; | ||
2586 | remote_id = PEEK_U32(cp); | ||
2587 | if ((c = channel_by_remote_id(remote_id)) != NULL) { | ||
2588 | if (c->flags & CHAN_CLOSE_RCVD) | ||
2589 | channel_free(c); | ||
2590 | else | ||
2591 | c->flags |= CHAN_CLOSE_SENT; | ||
2592 | } | ||
2593 | break; | ||
2594 | } | ||
2595 | if (modified) { | ||
2596 | if ((r = sshpkt_start(ssh, type)) != 0 || | ||
2597 | (r = sshpkt_putb(ssh, modified)) != 0 || | ||
2598 | (r = sshpkt_send(ssh)) != 0) { | ||
2599 | error("%s: send %s", __func__, ssh_err(r)); | ||
2600 | goto out; | ||
2601 | } | ||
2602 | } else { | ||
2603 | if ((r = sshpkt_start(ssh, type)) != 0 || | ||
2604 | (r = sshpkt_put(ssh, cp, have)) != 0 || | ||
2605 | (r = sshpkt_send(ssh)) != 0) { | ||
2606 | error("%s: send %s", __func__, ssh_err(r)); | ||
2607 | goto out; | ||
2608 | } | ||
2609 | } | ||
2610 | ret = 0; | ||
2611 | out: | ||
2612 | free(ctype); | ||
2613 | free(listen_host); | ||
2614 | sshbuf_free(original); | ||
2615 | sshbuf_free(modified); | ||
2616 | return ret; | ||
2617 | } | ||
2618 | |||
2619 | /* | ||
2620 | * receive packets from upstream server and de-multiplex packets | ||
2621 | * to correct downstream: | ||
2622 | * implemented as a helper for channel input handlers, | ||
2623 | * replaces local (proxy) channel ID with downstream channel ID. | ||
2624 | */ | ||
2625 | int | ||
2626 | channel_proxy_upstream(Channel *c, int type, u_int32_t seq, void *ctxt) | ||
2627 | { | ||
2628 | struct ssh *ssh = active_state; | ||
2629 | struct sshbuf *b = NULL; | ||
2630 | Channel *downstream; | ||
2631 | const u_char *cp = NULL; | ||
2632 | size_t len; | ||
2633 | int r; | ||
2634 | |||
2635 | /* | ||
2636 | * When receiving packets from the peer we need to check whether we | ||
2637 | * need to forward the packets to the mux client. In this case we | ||
2638 | * restore the orignal channel id and keep track of CLOSE messages, | ||
2639 | * so we can cleanup the channel. | ||
2640 | */ | ||
2641 | if (c == NULL || c->type != SSH_CHANNEL_MUX_PROXY) | ||
2642 | return 0; | ||
2643 | if ((downstream = c->mux_ctx) == NULL) | ||
2644 | return 0; | ||
2645 | switch (type) { | ||
2646 | case SSH2_MSG_CHANNEL_CLOSE: | ||
2647 | case SSH2_MSG_CHANNEL_DATA: | ||
2648 | case SSH2_MSG_CHANNEL_EOF: | ||
2649 | case SSH2_MSG_CHANNEL_EXTENDED_DATA: | ||
2650 | case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: | ||
2651 | case SSH2_MSG_CHANNEL_OPEN_FAILURE: | ||
2652 | case SSH2_MSG_CHANNEL_WINDOW_ADJUST: | ||
2653 | case SSH2_MSG_CHANNEL_SUCCESS: | ||
2654 | case SSH2_MSG_CHANNEL_FAILURE: | ||
2655 | case SSH2_MSG_CHANNEL_REQUEST: | ||
2656 | break; | ||
2657 | default: | ||
2658 | debug2("%s: channel %u: unsupported type %u", __func__, | ||
2659 | c->self, type); | ||
2660 | return 0; | ||
2661 | } | ||
2662 | if ((b = sshbuf_new()) == NULL) { | ||
2663 | error("%s: alloc reply", __func__); | ||
2664 | goto out; | ||
2665 | } | ||
2666 | /* get remaining payload (after id) */ | ||
2667 | cp = sshpkt_ptr(ssh, &len); | ||
2668 | if (cp == NULL) { | ||
2669 | error("%s: no packet", __func__); | ||
2670 | goto out; | ||
2671 | } | ||
2672 | /* translate id and send to muxclient */ | ||
2673 | if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */ | ||
2674 | (r = sshbuf_put_u8(b, type)) != 0 || | ||
2675 | (r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 || | ||
2676 | (r = sshbuf_put(b, cp, len)) != 0 || | ||
2677 | (r = sshbuf_put_stringb(&downstream->output, b)) != 0) { | ||
2678 | error("%s: compose for muxclient %s", __func__, ssh_err(r)); | ||
2679 | goto out; | ||
2680 | } | ||
2681 | /* sshbuf_dump(b, stderr); */ | ||
2682 | if (ssh_packet_log_type(type)) | ||
2683 | debug3("%s: channel %u: up->down: type %u", __func__, c->self, | ||
2684 | type); | ||
2685 | out: | ||
2686 | /* update state */ | ||
2687 | switch (type) { | ||
2688 | case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: | ||
2689 | /* record remote_id for SSH2_MSG_CHANNEL_CLOSE */ | ||
2690 | if (cp && len > 4) | ||
2691 | c->remote_id = PEEK_U32(cp); | ||
2692 | break; | ||
2693 | case SSH2_MSG_CHANNEL_CLOSE: | ||
2694 | if (c->flags & CHAN_CLOSE_SENT) | ||
2695 | channel_free(c); | ||
2696 | else | ||
2697 | c->flags |= CHAN_CLOSE_RCVD; | ||
2698 | break; | ||
2699 | } | ||
2700 | sshbuf_free(b); | ||
2701 | return 1; | ||
2702 | } | ||
2364 | 2703 | ||
2365 | /* -- protocol input */ | 2704 | /* -- protocol input */ |
2366 | 2705 | ||
@@ -2378,6 +2717,8 @@ channel_input_data(int type, u_int32_t seq, void *ctxt) | |||
2378 | c = channel_lookup(id); | 2717 | c = channel_lookup(id); |
2379 | if (c == NULL) | 2718 | if (c == NULL) |
2380 | packet_disconnect("Received data for nonexistent channel %d.", id); | 2719 | packet_disconnect("Received data for nonexistent channel %d.", id); |
2720 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2721 | return 0; | ||
2381 | 2722 | ||
2382 | /* Ignore any data for non-open channels (might happen on close) */ | 2723 | /* Ignore any data for non-open channels (might happen on close) */ |
2383 | if (c->type != SSH_CHANNEL_OPEN && | 2724 | if (c->type != SSH_CHANNEL_OPEN && |
@@ -2440,6 +2781,8 @@ channel_input_extended_data(int type, u_int32_t seq, void *ctxt) | |||
2440 | 2781 | ||
2441 | if (c == NULL) | 2782 | if (c == NULL) |
2442 | packet_disconnect("Received extended_data for bad channel %d.", id); | 2783 | packet_disconnect("Received extended_data for bad channel %d.", id); |
2784 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2785 | return 0; | ||
2443 | if (c->type != SSH_CHANNEL_OPEN) { | 2786 | if (c->type != SSH_CHANNEL_OPEN) { |
2444 | logit("channel %d: ext data for non open", id); | 2787 | logit("channel %d: ext data for non open", id); |
2445 | return 0; | 2788 | return 0; |
@@ -2485,6 +2828,8 @@ channel_input_ieof(int type, u_int32_t seq, void *ctxt) | |||
2485 | c = channel_lookup(id); | 2828 | c = channel_lookup(id); |
2486 | if (c == NULL) | 2829 | if (c == NULL) |
2487 | packet_disconnect("Received ieof for nonexistent channel %d.", id); | 2830 | packet_disconnect("Received ieof for nonexistent channel %d.", id); |
2831 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2832 | return 0; | ||
2488 | chan_rcvd_ieof(c); | 2833 | chan_rcvd_ieof(c); |
2489 | 2834 | ||
2490 | /* XXX force input close */ | 2835 | /* XXX force input close */ |
@@ -2509,7 +2854,8 @@ channel_input_close(int type, u_int32_t seq, void *ctxt) | |||
2509 | c = channel_lookup(id); | 2854 | c = channel_lookup(id); |
2510 | if (c == NULL) | 2855 | if (c == NULL) |
2511 | packet_disconnect("Received close for nonexistent channel %d.", id); | 2856 | packet_disconnect("Received close for nonexistent channel %d.", id); |
2512 | 2857 | if (channel_proxy_upstream(c, type, seq, ctxt)) | |
2858 | return 0; | ||
2513 | /* | 2859 | /* |
2514 | * Send a confirmation that we have closed the channel and no more | 2860 | * Send a confirmation that we have closed the channel and no more |
2515 | * data is coming for it. | 2861 | * data is coming for it. |
@@ -2544,9 +2890,11 @@ channel_input_oclose(int type, u_int32_t seq, void *ctxt) | |||
2544 | int id = packet_get_int(); | 2890 | int id = packet_get_int(); |
2545 | Channel *c = channel_lookup(id); | 2891 | Channel *c = channel_lookup(id); |
2546 | 2892 | ||
2547 | packet_check_eom(); | ||
2548 | if (c == NULL) | 2893 | if (c == NULL) |
2549 | packet_disconnect("Received oclose for nonexistent channel %d.", id); | 2894 | packet_disconnect("Received oclose for nonexistent channel %d.", id); |
2895 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2896 | return 0; | ||
2897 | packet_check_eom(); | ||
2550 | chan_rcvd_oclose(c); | 2898 | chan_rcvd_oclose(c); |
2551 | return 0; | 2899 | return 0; |
2552 | } | 2900 | } |
@@ -2558,10 +2906,12 @@ channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt) | |||
2558 | int id = packet_get_int(); | 2906 | int id = packet_get_int(); |
2559 | Channel *c = channel_lookup(id); | 2907 | Channel *c = channel_lookup(id); |
2560 | 2908 | ||
2561 | packet_check_eom(); | ||
2562 | if (c == NULL) | 2909 | if (c == NULL) |
2563 | packet_disconnect("Received close confirmation for " | 2910 | packet_disconnect("Received close confirmation for " |
2564 | "out-of-range channel %d.", id); | 2911 | "out-of-range channel %d.", id); |
2912 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2913 | return 0; | ||
2914 | packet_check_eom(); | ||
2565 | if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED) | 2915 | if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED) |
2566 | packet_disconnect("Received close confirmation for " | 2916 | packet_disconnect("Received close confirmation for " |
2567 | "non-closed channel %d (type %d).", id, c->type); | 2917 | "non-closed channel %d (type %d).", id, c->type); |
@@ -2579,7 +2929,12 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) | |||
2579 | id = packet_get_int(); | 2929 | id = packet_get_int(); |
2580 | c = channel_lookup(id); | 2930 | c = channel_lookup(id); |
2581 | 2931 | ||
2582 | if (c==NULL || c->type != SSH_CHANNEL_OPENING) | 2932 | if (c==NULL) |
2933 | packet_disconnect("Received open confirmation for " | ||
2934 | "unknown channel %d.", id); | ||
2935 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2936 | return 0; | ||
2937 | if (c->type != SSH_CHANNEL_OPENING) | ||
2583 | packet_disconnect("Received open confirmation for " | 2938 | packet_disconnect("Received open confirmation for " |
2584 | "non-opening channel %d.", id); | 2939 | "non-opening channel %d.", id); |
2585 | remote_id = packet_get_int(); | 2940 | remote_id = packet_get_int(); |
@@ -2629,7 +2984,12 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt) | |||
2629 | id = packet_get_int(); | 2984 | id = packet_get_int(); |
2630 | c = channel_lookup(id); | 2985 | c = channel_lookup(id); |
2631 | 2986 | ||
2632 | if (c==NULL || c->type != SSH_CHANNEL_OPENING) | 2987 | if (c==NULL) |
2988 | packet_disconnect("Received open failure for " | ||
2989 | "unknown channel %d.", id); | ||
2990 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2991 | return 0; | ||
2992 | if (c->type != SSH_CHANNEL_OPENING) | ||
2633 | packet_disconnect("Received open failure for " | 2993 | packet_disconnect("Received open failure for " |
2634 | "non-opening channel %d.", id); | 2994 | "non-opening channel %d.", id); |
2635 | if (compat20) { | 2995 | if (compat20) { |
@@ -2673,6 +3033,8 @@ channel_input_window_adjust(int type, u_int32_t seq, void *ctxt) | |||
2673 | logit("Received window adjust for non-open channel %d.", id); | 3033 | logit("Received window adjust for non-open channel %d.", id); |
2674 | return 0; | 3034 | return 0; |
2675 | } | 3035 | } |
3036 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
3037 | return 0; | ||
2676 | adjust = packet_get_int(); | 3038 | adjust = packet_get_int(); |
2677 | packet_check_eom(); | 3039 | packet_check_eom(); |
2678 | debug2("channel %d: rcvd adjust %u", id, adjust); | 3040 | debug2("channel %d: rcvd adjust %u", id, adjust); |
@@ -2727,14 +3089,15 @@ channel_input_status_confirm(int type, u_int32_t seq, void *ctxt) | |||
2727 | packet_set_alive_timeouts(0); | 3089 | packet_set_alive_timeouts(0); |
2728 | 3090 | ||
2729 | id = packet_get_int(); | 3091 | id = packet_get_int(); |
2730 | packet_check_eom(); | ||
2731 | |||
2732 | debug2("channel_input_status_confirm: type %d id %d", type, id); | 3092 | debug2("channel_input_status_confirm: type %d id %d", type, id); |
2733 | 3093 | ||
2734 | if ((c = channel_lookup(id)) == NULL) { | 3094 | if ((c = channel_lookup(id)) == NULL) { |
2735 | logit("channel_input_status_confirm: %d: unknown", id); | 3095 | logit("channel_input_status_confirm: %d: unknown", id); |
2736 | return 0; | 3096 | return 0; |
2737 | } | 3097 | } |
3098 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
3099 | return 0; | ||
3100 | packet_check_eom(); | ||
2738 | if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) | 3101 | if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) |
2739 | return 0; | 3102 | return 0; |
2740 | cc->cb(type, c, cc->ctx); | 3103 | cc->cb(type, c, cc->ctx); |
@@ -3288,6 +3651,7 @@ channel_request_remote_forwarding(struct Forward *fwd) | |||
3288 | permitted_opens[idx].listen_path = NULL; | 3651 | permitted_opens[idx].listen_path = NULL; |
3289 | permitted_opens[idx].listen_port = fwd->listen_port; | 3652 | permitted_opens[idx].listen_port = fwd->listen_port; |
3290 | } | 3653 | } |
3654 | permitted_opens[idx].downstream = NULL; | ||
3291 | } | 3655 | } |
3292 | return (idx); | 3656 | return (idx); |
3293 | } | 3657 | } |
@@ -3383,6 +3747,7 @@ channel_request_rforward_cancel_tcpip(const char *host, u_short port) | |||
3383 | free(permitted_opens[i].listen_host); | 3747 | free(permitted_opens[i].listen_host); |
3384 | permitted_opens[i].listen_host = NULL; | 3748 | permitted_opens[i].listen_host = NULL; |
3385 | permitted_opens[i].listen_path = NULL; | 3749 | permitted_opens[i].listen_path = NULL; |
3750 | permitted_opens[i].downstream = NULL; | ||
3386 | 3751 | ||
3387 | return 0; | 3752 | return 0; |
3388 | } | 3753 | } |
@@ -3420,6 +3785,7 @@ channel_request_rforward_cancel_streamlocal(const char *path) | |||
3420 | permitted_opens[i].listen_host = NULL; | 3785 | permitted_opens[i].listen_host = NULL; |
3421 | free(permitted_opens[i].listen_path); | 3786 | free(permitted_opens[i].listen_path); |
3422 | permitted_opens[i].listen_path = NULL; | 3787 | permitted_opens[i].listen_path = NULL; |
3788 | permitted_opens[i].downstream = NULL; | ||
3423 | 3789 | ||
3424 | return 0; | 3790 | return 0; |
3425 | } | 3791 | } |
@@ -3440,45 +3806,6 @@ channel_request_rforward_cancel(struct Forward *fwd) | |||
3440 | } | 3806 | } |
3441 | 3807 | ||
3442 | /* | 3808 | /* |
3443 | * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates | ||
3444 | * listening for the port, and sends back a success reply (or disconnect | ||
3445 | * message if there was an error). | ||
3446 | */ | ||
3447 | int | ||
3448 | channel_input_port_forward_request(int is_root, struct ForwardOptions *fwd_opts) | ||
3449 | { | ||
3450 | int success = 0; | ||
3451 | struct Forward fwd; | ||
3452 | |||
3453 | /* Get arguments from the packet. */ | ||
3454 | memset(&fwd, 0, sizeof(fwd)); | ||
3455 | fwd.listen_port = packet_get_int(); | ||
3456 | fwd.connect_host = packet_get_string(NULL); | ||
3457 | fwd.connect_port = packet_get_int(); | ||
3458 | |||
3459 | #ifndef HAVE_CYGWIN | ||
3460 | /* | ||
3461 | * Check that an unprivileged user is not trying to forward a | ||
3462 | * privileged port. | ||
3463 | */ | ||
3464 | if (fwd.listen_port < IPPORT_RESERVED && !is_root) | ||
3465 | packet_disconnect( | ||
3466 | "Requested forwarding of port %d but user is not root.", | ||
3467 | fwd.listen_port); | ||
3468 | if (fwd.connect_port == 0) | ||
3469 | packet_disconnect("Dynamic forwarding denied."); | ||
3470 | #endif | ||
3471 | |||
3472 | /* Initiate forwarding */ | ||
3473 | success = channel_setup_local_fwd_listener(&fwd, fwd_opts); | ||
3474 | |||
3475 | /* Free the argument string. */ | ||
3476 | free(fwd.connect_host); | ||
3477 | |||
3478 | return (success ? 0 : -1); | ||
3479 | } | ||
3480 | |||
3481 | /* | ||
3482 | * Permits opening to any host/port if permitted_opens[] is empty. This is | 3809 | * Permits opening to any host/port if permitted_opens[] is empty. This is |
3483 | * usually called by the server, because the user could connect to any port | 3810 | * usually called by the server, because the user could connect to any port |
3484 | * anyway, and the server has no way to know but to trust the client anyway. | 3811 | * anyway, and the server has no way to know but to trust the client anyway. |
@@ -3502,6 +3829,7 @@ channel_add_permitted_opens(char *host, int port) | |||
3502 | permitted_opens[num_permitted_opens].listen_host = NULL; | 3829 | permitted_opens[num_permitted_opens].listen_host = NULL; |
3503 | permitted_opens[num_permitted_opens].listen_path = NULL; | 3830 | permitted_opens[num_permitted_opens].listen_path = NULL; |
3504 | permitted_opens[num_permitted_opens].listen_port = 0; | 3831 | permitted_opens[num_permitted_opens].listen_port = 0; |
3832 | permitted_opens[num_permitted_opens].downstream = NULL; | ||
3505 | num_permitted_opens++; | 3833 | num_permitted_opens++; |
3506 | 3834 | ||
3507 | all_opens_permitted = 0; | 3835 | all_opens_permitted = 0; |
@@ -3633,7 +3961,7 @@ connect_next(struct channel_connect *cctx) | |||
3633 | { | 3961 | { |
3634 | int sock, saved_errno; | 3962 | int sock, saved_errno; |
3635 | struct sockaddr_un *sunaddr; | 3963 | struct sockaddr_un *sunaddr; |
3636 | char ntop[NI_MAXHOST], strport[MAX(NI_MAXSERV,sizeof(sunaddr->sun_path))]; | 3964 | char ntop[NI_MAXHOST], strport[MAXIMUM(NI_MAXSERV,sizeof(sunaddr->sun_path))]; |
3637 | 3965 | ||
3638 | for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { | 3966 | for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { |
3639 | switch (cctx->ai->ai_family) { | 3967 | switch (cctx->ai->ai_family) { |
@@ -3764,6 +4092,10 @@ connect_to(const char *name, int port, char *ctype, char *rname) | |||
3764 | return c; | 4092 | return c; |
3765 | } | 4093 | } |
3766 | 4094 | ||
4095 | /* | ||
4096 | * returns either the newly connected channel or the downstream channel | ||
4097 | * that needs to deal with this connection. | ||
4098 | */ | ||
3767 | Channel * | 4099 | Channel * |
3768 | channel_connect_by_listen_address(const char *listen_host, | 4100 | channel_connect_by_listen_address(const char *listen_host, |
3769 | u_short listen_port, char *ctype, char *rname) | 4101 | u_short listen_port, char *ctype, char *rname) |
@@ -3773,6 +4105,8 @@ channel_connect_by_listen_address(const char *listen_host, | |||
3773 | for (i = 0; i < num_permitted_opens; i++) { | 4105 | for (i = 0; i < num_permitted_opens; i++) { |
3774 | if (open_listen_match_tcpip(&permitted_opens[i], listen_host, | 4106 | if (open_listen_match_tcpip(&permitted_opens[i], listen_host, |
3775 | listen_port, 1)) { | 4107 | listen_port, 1)) { |
4108 | if (permitted_opens[i].downstream) | ||
4109 | return permitted_opens[i].downstream; | ||
3776 | return connect_to( | 4110 | return connect_to( |
3777 | permitted_opens[i].host_to_connect, | 4111 | permitted_opens[i].host_to_connect, |
3778 | permitted_opens[i].port_to_connect, ctype, rname); | 4112 | permitted_opens[i].port_to_connect, ctype, rname); |
@@ -4216,7 +4550,6 @@ x11_request_forwarding_with_spoofing(int client_session_id, const char *disp, | |||
4216 | char *new_data; | 4550 | char *new_data; |
4217 | int screen_number; | 4551 | int screen_number; |
4218 | const char *cp; | 4552 | const char *cp; |
4219 | u_int32_t rnd = 0; | ||
4220 | 4553 | ||
4221 | if (x11_saved_display == NULL) | 4554 | if (x11_saved_display == NULL) |
4222 | x11_saved_display = xstrdup(disp); | 4555 | x11_saved_display = xstrdup(disp); |
@@ -4237,23 +4570,20 @@ x11_request_forwarding_with_spoofing(int client_session_id, const char *disp, | |||
4237 | if (x11_saved_proto == NULL) { | 4570 | if (x11_saved_proto == NULL) { |
4238 | /* Save protocol name. */ | 4571 | /* Save protocol name. */ |
4239 | x11_saved_proto = xstrdup(proto); | 4572 | x11_saved_proto = xstrdup(proto); |
4240 | /* | 4573 | |
4241 | * Extract real authentication data and generate fake data | 4574 | /* Extract real authentication data. */ |
4242 | * of the same length. | ||
4243 | */ | ||
4244 | x11_saved_data = xmalloc(data_len); | 4575 | x11_saved_data = xmalloc(data_len); |
4245 | x11_fake_data = xmalloc(data_len); | ||
4246 | for (i = 0; i < data_len; i++) { | 4576 | for (i = 0; i < data_len; i++) { |
4247 | if (sscanf(data + 2 * i, "%2x", &value) != 1) | 4577 | if (sscanf(data + 2 * i, "%2x", &value) != 1) |
4248 | fatal("x11_request_forwarding: bad " | 4578 | fatal("x11_request_forwarding: bad " |
4249 | "authentication data: %.100s", data); | 4579 | "authentication data: %.100s", data); |
4250 | if (i % 4 == 0) | ||
4251 | rnd = arc4random(); | ||
4252 | x11_saved_data[i] = value; | 4580 | x11_saved_data[i] = value; |
4253 | x11_fake_data[i] = rnd & 0xff; | ||
4254 | rnd >>= 8; | ||
4255 | } | 4581 | } |
4256 | x11_saved_data_len = data_len; | 4582 | x11_saved_data_len = data_len; |
4583 | |||
4584 | /* Generate fake data of the same length. */ | ||
4585 | x11_fake_data = xmalloc(data_len); | ||
4586 | arc4random_buf(x11_fake_data, data_len); | ||
4257 | x11_fake_data_len = data_len; | 4587 | x11_fake_data_len = data_len; |
4258 | } | 4588 | } |
4259 | 4589 | ||