diff options
-rw-r--r-- | channels.c | 392 | ||||
-rw-r--r-- | channels.h | 12 | ||||
-rw-r--r-- | clientloop.c | 45 | ||||
-rw-r--r-- | clientloop.h | 5 | ||||
-rw-r--r-- | mux.c | 69 | ||||
-rw-r--r-- | opacket.h | 4 | ||||
-rw-r--r-- | packet.c | 93 | ||||
-rw-r--r-- | packet.h | 6 | ||||
-rw-r--r-- | ssh.c | 27 |
9 files changed, 612 insertions, 41 deletions
diff --git a/channels.c b/channels.c index 5d8c2a0c0..ae248414b 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.353 2016/09/19 07:52:42 natano Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.354 2016/09/30 09:19:13 markus 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 |
@@ -71,6 +71,7 @@ | |||
71 | #include "ssh.h" | 71 | #include "ssh.h" |
72 | #include "ssh1.h" | 72 | #include "ssh1.h" |
73 | #include "ssh2.h" | 73 | #include "ssh2.h" |
74 | #include "ssherr.h" | ||
74 | #include "packet.h" | 75 | #include "packet.h" |
75 | #include "log.h" | 76 | #include "log.h" |
76 | #include "misc.h" | 77 | #include "misc.h" |
@@ -120,6 +121,7 @@ typedef struct { | |||
120 | char *listen_host; /* Remote side should listen address. */ | 121 | char *listen_host; /* Remote side should listen address. */ |
121 | char *listen_path; /* Remote side should listen path. */ | 122 | char *listen_path; /* Remote side should listen path. */ |
122 | int listen_port; /* Remote side should listen port. */ | 123 | int listen_port; /* Remote side should listen port. */ |
124 | Channel *downstream; /* Downstream mux*/ | ||
123 | } ForwardPermission; | 125 | } ForwardPermission; |
124 | 126 | ||
125 | /* 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. */ |
@@ -183,6 +185,7 @@ static int IPv4or6 = AF_UNSPEC; | |||
183 | 185 | ||
184 | /* helper */ | 186 | /* helper */ |
185 | 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); | ||
186 | 189 | ||
187 | /* non-blocking connect helpers */ | 190 | /* non-blocking connect helpers */ |
188 | static int connect_next(struct channel_connect *); | 191 | static int connect_next(struct channel_connect *); |
@@ -207,6 +210,20 @@ channel_by_id(int id) | |||
207 | return c; | 210 | return c; |
208 | } | 211 | } |
209 | 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 | |||
210 | /* | 227 | /* |
211 | * Returns the channel if it is allowed to receive protocol messages. | 228 | * Returns the channel if it is allowed to receive protocol messages. |
212 | * Private channels, like listening sockets, may not receive messages. | 229 | * Private channels, like listening sockets, may not receive messages. |
@@ -229,6 +246,7 @@ channel_lookup(int id) | |||
229 | case SSH_CHANNEL_INPUT_DRAINING: | 246 | case SSH_CHANNEL_INPUT_DRAINING: |
230 | case SSH_CHANNEL_OUTPUT_DRAINING: | 247 | case SSH_CHANNEL_OUTPUT_DRAINING: |
231 | case SSH_CHANNEL_ABANDONED: | 248 | case SSH_CHANNEL_ABANDONED: |
249 | case SSH_CHANNEL_MUX_PROXY: | ||
232 | return (c); | 250 | return (c); |
233 | } | 251 | } |
234 | logit("Non-public channel %d, type %d.", id, c->type); | 252 | logit("Non-public channel %d, type %d.", id, c->type); |
@@ -410,14 +428,56 @@ channel_free(Channel *c) | |||
410 | { | 428 | { |
411 | char *s; | 429 | char *s; |
412 | u_int i, n; | 430 | u_int i, n; |
431 | Channel *other; | ||
413 | struct channel_confirm *cc; | 432 | struct channel_confirm *cc; |
414 | 433 | ||
415 | for (n = 0, i = 0; i < channels_alloc; i++) | 434 | for (n = 0, i = 0; i < channels_alloc; i++) { |
416 | if (channels[i]) | 435 | if ((other = channels[i]) != NULL) { |
417 | 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 | } | ||
418 | debug("channel %d: free: %s, nchannels %u", c->self, | 449 | debug("channel %d: free: %s, nchannels %u", c->self, |
419 | c->remote_name ? c->remote_name : "???", n); | 450 | c->remote_name ? c->remote_name : "???", n); |
420 | 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 | |||
421 | s = channel_open_message(); | 481 | s = channel_open_message(); |
422 | debug3("channel %d: status: %s", c->self, s); | 482 | debug3("channel %d: status: %s", c->self, s); |
423 | free(s); | 483 | free(s); |
@@ -563,6 +623,7 @@ channel_still_open(void) | |||
563 | case SSH_CHANNEL_OPEN: | 623 | case SSH_CHANNEL_OPEN: |
564 | case SSH_CHANNEL_X11_OPEN: | 624 | case SSH_CHANNEL_X11_OPEN: |
565 | case SSH_CHANNEL_MUX_CLIENT: | 625 | case SSH_CHANNEL_MUX_CLIENT: |
626 | case SSH_CHANNEL_MUX_PROXY: | ||
566 | return 1; | 627 | return 1; |
567 | case SSH_CHANNEL_INPUT_DRAINING: | 628 | case SSH_CHANNEL_INPUT_DRAINING: |
568 | case SSH_CHANNEL_OUTPUT_DRAINING: | 629 | case SSH_CHANNEL_OUTPUT_DRAINING: |
@@ -596,6 +657,7 @@ channel_find_open(void) | |||
596 | case SSH_CHANNEL_RPORT_LISTENER: | 657 | case SSH_CHANNEL_RPORT_LISTENER: |
597 | case SSH_CHANNEL_MUX_LISTENER: | 658 | case SSH_CHANNEL_MUX_LISTENER: |
598 | case SSH_CHANNEL_MUX_CLIENT: | 659 | case SSH_CHANNEL_MUX_CLIENT: |
660 | case SSH_CHANNEL_MUX_PROXY: | ||
599 | case SSH_CHANNEL_OPENING: | 661 | case SSH_CHANNEL_OPENING: |
600 | case SSH_CHANNEL_CONNECTING: | 662 | case SSH_CHANNEL_CONNECTING: |
601 | case SSH_CHANNEL_ZOMBIE: | 663 | case SSH_CHANNEL_ZOMBIE: |
@@ -621,7 +683,6 @@ channel_find_open(void) | |||
621 | return -1; | 683 | return -1; |
622 | } | 684 | } |
623 | 685 | ||
624 | |||
625 | /* | 686 | /* |
626 | * Returns a message describing the currently open forwarded connections, | 687 | * Returns a message describing the currently open forwarded connections, |
627 | * 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 |
@@ -650,7 +711,6 @@ channel_open_message(void) | |||
650 | case SSH_CHANNEL_AUTH_SOCKET: | 711 | case SSH_CHANNEL_AUTH_SOCKET: |
651 | case SSH_CHANNEL_ZOMBIE: | 712 | case SSH_CHANNEL_ZOMBIE: |
652 | case SSH_CHANNEL_ABANDONED: | 713 | case SSH_CHANNEL_ABANDONED: |
653 | case SSH_CHANNEL_MUX_CLIENT: | ||
654 | case SSH_CHANNEL_MUX_LISTENER: | 714 | case SSH_CHANNEL_MUX_LISTENER: |
655 | case SSH_CHANNEL_UNIX_LISTENER: | 715 | case SSH_CHANNEL_UNIX_LISTENER: |
656 | case SSH_CHANNEL_RUNIX_LISTENER: | 716 | case SSH_CHANNEL_RUNIX_LISTENER: |
@@ -663,6 +723,8 @@ channel_open_message(void) | |||
663 | case SSH_CHANNEL_X11_OPEN: | 723 | case SSH_CHANNEL_X11_OPEN: |
664 | case SSH_CHANNEL_INPUT_DRAINING: | 724 | case SSH_CHANNEL_INPUT_DRAINING: |
665 | case SSH_CHANNEL_OUTPUT_DRAINING: | 725 | case SSH_CHANNEL_OUTPUT_DRAINING: |
726 | case SSH_CHANNEL_MUX_PROXY: | ||
727 | case SSH_CHANNEL_MUX_CLIENT: | ||
666 | snprintf(buf, sizeof buf, | 728 | snprintf(buf, sizeof buf, |
667 | " #%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", |
668 | c->self, c->remote_name, | 730 | c->self, c->remote_name, |
@@ -2360,6 +2422,278 @@ channel_output_poll(void) | |||
2360 | } | 2422 | } |
2361 | } | 2423 | } |
2362 | 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, id, remote_id, listen_port, idx; | ||
2476 | |||
2477 | /* sshbuf_dump(&downstream->input, stderr); */ | ||
2478 | if ((r = sshbuf_get_string_direct(&downstream->input, &cp, &have)) | ||
2479 | != 0) { | ||
2480 | error("%s: malformed message: %s", __func__, ssh_err(r)); | ||
2481 | return -1; | ||
2482 | } | ||
2483 | if (have < 2) { | ||
2484 | error("%s: short message", __func__); | ||
2485 | return -1; | ||
2486 | } | ||
2487 | type = cp[1]; | ||
2488 | /* skip padlen + type */ | ||
2489 | cp += 2; | ||
2490 | have -= 2; | ||
2491 | if (ssh_packet_log_type(type)) | ||
2492 | debug3("%s: channel %u: down->up: type %u", __func__, | ||
2493 | downstream->self, type); | ||
2494 | |||
2495 | switch (type) { | ||
2496 | case SSH2_MSG_CHANNEL_OPEN: | ||
2497 | if ((original = sshbuf_from(cp, have)) == NULL || | ||
2498 | (modified = sshbuf_new()) == NULL) { | ||
2499 | error("%s: alloc", __func__); | ||
2500 | goto out; | ||
2501 | } | ||
2502 | if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0 || | ||
2503 | (r = sshbuf_get_u32(original, &id)) != 0) { | ||
2504 | error("%s: parse error %s", __func__, ssh_err(r)); | ||
2505 | goto out; | ||
2506 | } | ||
2507 | c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY, | ||
2508 | -1, -1, -1, 0, 0, 0, ctype, 1); | ||
2509 | c->mux_ctx = downstream; /* point to mux client */ | ||
2510 | c->mux_downstream_id = id; /* original downstream id */ | ||
2511 | if ((r = sshbuf_put_cstring(modified, ctype)) != 0 || | ||
2512 | (r = sshbuf_put_u32(modified, c->self)) != 0 || | ||
2513 | (r = sshbuf_putb(modified, original)) != 0) { | ||
2514 | error("%s: compose error %s", __func__, ssh_err(r)); | ||
2515 | channel_free(c); | ||
2516 | goto out; | ||
2517 | } | ||
2518 | break; | ||
2519 | case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: | ||
2520 | /* | ||
2521 | * Almost the same as SSH2_MSG_CHANNEL_OPEN, except then we | ||
2522 | * need to parse 'remote_id' instead of 'ctype'. | ||
2523 | */ | ||
2524 | if ((original = sshbuf_from(cp, have)) == NULL || | ||
2525 | (modified = sshbuf_new()) == NULL) { | ||
2526 | error("%s: alloc", __func__); | ||
2527 | goto out; | ||
2528 | } | ||
2529 | if ((r = sshbuf_get_u32(original, &remote_id)) != 0 || | ||
2530 | (r = sshbuf_get_u32(original, &id)) != 0) { | ||
2531 | error("%s: parse error %s", __func__, ssh_err(r)); | ||
2532 | goto out; | ||
2533 | } | ||
2534 | c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY, | ||
2535 | -1, -1, -1, 0, 0, 0, "mux-down-connect", 1); | ||
2536 | c->mux_ctx = downstream; /* point to mux client */ | ||
2537 | c->mux_downstream_id = id; | ||
2538 | c->remote_id = remote_id; | ||
2539 | if ((r = sshbuf_put_u32(modified, remote_id)) != 0 || | ||
2540 | (r = sshbuf_put_u32(modified, c->self)) != 0 || | ||
2541 | (r = sshbuf_putb(modified, original)) != 0) { | ||
2542 | error("%s: compose error %s", __func__, ssh_err(r)); | ||
2543 | channel_free(c); | ||
2544 | goto out; | ||
2545 | } | ||
2546 | break; | ||
2547 | case SSH2_MSG_GLOBAL_REQUEST: | ||
2548 | if ((original = sshbuf_from(cp, have)) == NULL) { | ||
2549 | error("%s: alloc", __func__); | ||
2550 | goto out; | ||
2551 | } | ||
2552 | if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0) { | ||
2553 | error("%s: parse error %s", __func__, ssh_err(r)); | ||
2554 | goto out; | ||
2555 | } | ||
2556 | if (strcmp(ctype, "tcpip-forward") != 0) { | ||
2557 | error("%s: unsupported request %s", __func__, ctype); | ||
2558 | goto out; | ||
2559 | } | ||
2560 | if ((r = sshbuf_get_u8(original, NULL)) != 0 || | ||
2561 | (r = sshbuf_get_cstring(original, &listen_host, NULL)) != 0 || | ||
2562 | (r = sshbuf_get_u32(original, &listen_port)) != 0) { | ||
2563 | error("%s: parse error %s", __func__, ssh_err(r)); | ||
2564 | goto out; | ||
2565 | } | ||
2566 | /* Record that connection to this host/port is permitted. */ | ||
2567 | permitted_opens = xreallocarray(permitted_opens, | ||
2568 | num_permitted_opens + 1, sizeof(*permitted_opens)); | ||
2569 | idx = num_permitted_opens++; | ||
2570 | permitted_opens[idx].host_to_connect = xstrdup("<mux>"); | ||
2571 | permitted_opens[idx].port_to_connect = -1; | ||
2572 | permitted_opens[idx].listen_host = listen_host; | ||
2573 | permitted_opens[idx].listen_port = listen_port; | ||
2574 | permitted_opens[idx].downstream = downstream; | ||
2575 | listen_host = NULL; | ||
2576 | break; | ||
2577 | case SSH2_MSG_CHANNEL_CLOSE: | ||
2578 | if (have < 4) | ||
2579 | break; | ||
2580 | remote_id = PEEK_U32(cp); | ||
2581 | if ((c = channel_by_remote_id(remote_id)) != NULL) { | ||
2582 | if (c->flags & CHAN_CLOSE_RCVD) | ||
2583 | channel_free(c); | ||
2584 | else | ||
2585 | c->flags |= CHAN_CLOSE_SENT; | ||
2586 | } | ||
2587 | break; | ||
2588 | } | ||
2589 | if (modified) { | ||
2590 | if ((r = sshpkt_start(ssh, type)) != 0 || | ||
2591 | (r = sshpkt_putb(ssh, modified)) != 0 || | ||
2592 | (r = sshpkt_send(ssh)) != 0) { | ||
2593 | error("%s: send %s", __func__, ssh_err(r)); | ||
2594 | goto out; | ||
2595 | } | ||
2596 | } else { | ||
2597 | if ((r = sshpkt_start(ssh, type)) != 0 || | ||
2598 | (r = sshpkt_put(ssh, cp, have)) != 0 || | ||
2599 | (r = sshpkt_send(ssh)) != 0) { | ||
2600 | error("%s: send %s", __func__, ssh_err(r)); | ||
2601 | goto out; | ||
2602 | } | ||
2603 | } | ||
2604 | ret = 0; | ||
2605 | out: | ||
2606 | free(ctype); | ||
2607 | free(listen_host); | ||
2608 | sshbuf_free(original); | ||
2609 | sshbuf_free(modified); | ||
2610 | return ret; | ||
2611 | } | ||
2612 | |||
2613 | /* | ||
2614 | * receive packets from upstream server and de-multiplex packets | ||
2615 | * to correct downstream: | ||
2616 | * implemented as a helper for channel input handlers, | ||
2617 | * replaces local (proxy) channel ID with downstream channel ID. | ||
2618 | */ | ||
2619 | int | ||
2620 | channel_proxy_upstream(Channel *c, int type, u_int32_t seq, void *ctxt) | ||
2621 | { | ||
2622 | struct ssh *ssh = active_state; | ||
2623 | struct sshbuf *b = NULL; | ||
2624 | Channel *downstream; | ||
2625 | const u_char *cp = NULL; | ||
2626 | size_t len; | ||
2627 | int r; | ||
2628 | |||
2629 | /* | ||
2630 | * When receiving packets from the peer we need to check whether we | ||
2631 | * need to forward the packets to the mux client. In this case we | ||
2632 | * restore the orignal channel id and keep track of CLOSE messages, | ||
2633 | * so we can cleanup the channel. | ||
2634 | */ | ||
2635 | if (c == NULL || c->type != SSH_CHANNEL_MUX_PROXY) | ||
2636 | return 0; | ||
2637 | if ((downstream = c->mux_ctx) == NULL) | ||
2638 | return 0; | ||
2639 | switch (type) { | ||
2640 | case SSH2_MSG_CHANNEL_CLOSE: | ||
2641 | case SSH2_MSG_CHANNEL_DATA: | ||
2642 | case SSH2_MSG_CHANNEL_EOF: | ||
2643 | case SSH2_MSG_CHANNEL_EXTENDED_DATA: | ||
2644 | case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: | ||
2645 | case SSH2_MSG_CHANNEL_OPEN_FAILURE: | ||
2646 | case SSH2_MSG_CHANNEL_WINDOW_ADJUST: | ||
2647 | case SSH2_MSG_CHANNEL_SUCCESS: | ||
2648 | case SSH2_MSG_CHANNEL_FAILURE: | ||
2649 | case SSH2_MSG_CHANNEL_REQUEST: | ||
2650 | break; | ||
2651 | default: | ||
2652 | debug2("%s: channel %u: unsupported type %u", __func__, | ||
2653 | c->self, type); | ||
2654 | return 0; | ||
2655 | } | ||
2656 | if ((b = sshbuf_new()) == NULL) { | ||
2657 | error("%s: alloc reply", __func__); | ||
2658 | goto out; | ||
2659 | } | ||
2660 | /* get remaining payload (after id) */ | ||
2661 | cp = sshpkt_ptr(ssh, &len); | ||
2662 | if (cp == NULL) { | ||
2663 | error("%s: no packet", __func__); | ||
2664 | goto out; | ||
2665 | } | ||
2666 | /* translate id and send to muxclient */ | ||
2667 | if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */ | ||
2668 | (r = sshbuf_put_u8(b, type)) != 0 || | ||
2669 | (r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 || | ||
2670 | (r = sshbuf_put(b, cp, len)) != 0 || | ||
2671 | (r = sshbuf_put_stringb(&downstream->output, b)) != 0) { | ||
2672 | error("%s: compose for muxclient %s", __func__, ssh_err(r)); | ||
2673 | goto out; | ||
2674 | } | ||
2675 | /* sshbuf_dump(b, stderr); */ | ||
2676 | if (ssh_packet_log_type(type)) | ||
2677 | debug3("%s: channel %u: up->down: type %u", __func__, c->self, | ||
2678 | type); | ||
2679 | out: | ||
2680 | /* update state */ | ||
2681 | switch (type) { | ||
2682 | case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: | ||
2683 | /* record remote_id for SSH2_MSG_CHANNEL_CLOSE */ | ||
2684 | if (cp && len > 4) | ||
2685 | c->remote_id = PEEK_U32(cp); | ||
2686 | break; | ||
2687 | case SSH2_MSG_CHANNEL_CLOSE: | ||
2688 | if (c->flags & CHAN_CLOSE_SENT) | ||
2689 | channel_free(c); | ||
2690 | else | ||
2691 | c->flags |= CHAN_CLOSE_RCVD; | ||
2692 | break; | ||
2693 | } | ||
2694 | sshbuf_free(b); | ||
2695 | return 1; | ||
2696 | } | ||
2363 | 2697 | ||
2364 | /* -- protocol input */ | 2698 | /* -- protocol input */ |
2365 | 2699 | ||
@@ -2377,6 +2711,8 @@ channel_input_data(int type, u_int32_t seq, void *ctxt) | |||
2377 | c = channel_lookup(id); | 2711 | c = channel_lookup(id); |
2378 | if (c == NULL) | 2712 | if (c == NULL) |
2379 | packet_disconnect("Received data for nonexistent channel %d.", id); | 2713 | packet_disconnect("Received data for nonexistent channel %d.", id); |
2714 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2715 | return 0; | ||
2380 | 2716 | ||
2381 | /* Ignore any data for non-open channels (might happen on close) */ | 2717 | /* Ignore any data for non-open channels (might happen on close) */ |
2382 | if (c->type != SSH_CHANNEL_OPEN && | 2718 | if (c->type != SSH_CHANNEL_OPEN && |
@@ -2439,6 +2775,8 @@ channel_input_extended_data(int type, u_int32_t seq, void *ctxt) | |||
2439 | 2775 | ||
2440 | if (c == NULL) | 2776 | if (c == NULL) |
2441 | packet_disconnect("Received extended_data for bad channel %d.", id); | 2777 | packet_disconnect("Received extended_data for bad channel %d.", id); |
2778 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2779 | return 0; | ||
2442 | if (c->type != SSH_CHANNEL_OPEN) { | 2780 | if (c->type != SSH_CHANNEL_OPEN) { |
2443 | logit("channel %d: ext data for non open", id); | 2781 | logit("channel %d: ext data for non open", id); |
2444 | return 0; | 2782 | return 0; |
@@ -2484,6 +2822,8 @@ channel_input_ieof(int type, u_int32_t seq, void *ctxt) | |||
2484 | c = channel_lookup(id); | 2822 | c = channel_lookup(id); |
2485 | if (c == NULL) | 2823 | if (c == NULL) |
2486 | packet_disconnect("Received ieof for nonexistent channel %d.", id); | 2824 | packet_disconnect("Received ieof for nonexistent channel %d.", id); |
2825 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2826 | return 0; | ||
2487 | chan_rcvd_ieof(c); | 2827 | chan_rcvd_ieof(c); |
2488 | 2828 | ||
2489 | /* XXX force input close */ | 2829 | /* XXX force input close */ |
@@ -2508,7 +2848,8 @@ channel_input_close(int type, u_int32_t seq, void *ctxt) | |||
2508 | c = channel_lookup(id); | 2848 | c = channel_lookup(id); |
2509 | if (c == NULL) | 2849 | if (c == NULL) |
2510 | packet_disconnect("Received close for nonexistent channel %d.", id); | 2850 | packet_disconnect("Received close for nonexistent channel %d.", id); |
2511 | 2851 | if (channel_proxy_upstream(c, type, seq, ctxt)) | |
2852 | return 0; | ||
2512 | /* | 2853 | /* |
2513 | * Send a confirmation that we have closed the channel and no more | 2854 | * Send a confirmation that we have closed the channel and no more |
2514 | * data is coming for it. | 2855 | * data is coming for it. |
@@ -2543,9 +2884,11 @@ channel_input_oclose(int type, u_int32_t seq, void *ctxt) | |||
2543 | int id = packet_get_int(); | 2884 | int id = packet_get_int(); |
2544 | Channel *c = channel_lookup(id); | 2885 | Channel *c = channel_lookup(id); |
2545 | 2886 | ||
2546 | packet_check_eom(); | ||
2547 | if (c == NULL) | 2887 | if (c == NULL) |
2548 | packet_disconnect("Received oclose for nonexistent channel %d.", id); | 2888 | packet_disconnect("Received oclose for nonexistent channel %d.", id); |
2889 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2890 | return 0; | ||
2891 | packet_check_eom(); | ||
2549 | chan_rcvd_oclose(c); | 2892 | chan_rcvd_oclose(c); |
2550 | return 0; | 2893 | return 0; |
2551 | } | 2894 | } |
@@ -2557,10 +2900,12 @@ channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt) | |||
2557 | int id = packet_get_int(); | 2900 | int id = packet_get_int(); |
2558 | Channel *c = channel_lookup(id); | 2901 | Channel *c = channel_lookup(id); |
2559 | 2902 | ||
2560 | packet_check_eom(); | ||
2561 | if (c == NULL) | 2903 | if (c == NULL) |
2562 | packet_disconnect("Received close confirmation for " | 2904 | packet_disconnect("Received close confirmation for " |
2563 | "out-of-range channel %d.", id); | 2905 | "out-of-range channel %d.", id); |
2906 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2907 | return 0; | ||
2908 | packet_check_eom(); | ||
2564 | if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED) | 2909 | if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED) |
2565 | packet_disconnect("Received close confirmation for " | 2910 | packet_disconnect("Received close confirmation for " |
2566 | "non-closed channel %d (type %d).", id, c->type); | 2911 | "non-closed channel %d (type %d).", id, c->type); |
@@ -2578,7 +2923,12 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) | |||
2578 | id = packet_get_int(); | 2923 | id = packet_get_int(); |
2579 | c = channel_lookup(id); | 2924 | c = channel_lookup(id); |
2580 | 2925 | ||
2581 | if (c==NULL || c->type != SSH_CHANNEL_OPENING) | 2926 | if (c==NULL) |
2927 | packet_disconnect("Received open confirmation for " | ||
2928 | "unknown channel %d.", id); | ||
2929 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2930 | return 0; | ||
2931 | if (c->type != SSH_CHANNEL_OPENING) | ||
2582 | packet_disconnect("Received open confirmation for " | 2932 | packet_disconnect("Received open confirmation for " |
2583 | "non-opening channel %d.", id); | 2933 | "non-opening channel %d.", id); |
2584 | remote_id = packet_get_int(); | 2934 | remote_id = packet_get_int(); |
@@ -2628,7 +2978,12 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt) | |||
2628 | id = packet_get_int(); | 2978 | id = packet_get_int(); |
2629 | c = channel_lookup(id); | 2979 | c = channel_lookup(id); |
2630 | 2980 | ||
2631 | if (c==NULL || c->type != SSH_CHANNEL_OPENING) | 2981 | if (c==NULL) |
2982 | packet_disconnect("Received open failure for " | ||
2983 | "unknown channel %d.", id); | ||
2984 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2985 | return 0; | ||
2986 | if (c->type != SSH_CHANNEL_OPENING) | ||
2632 | packet_disconnect("Received open failure for " | 2987 | packet_disconnect("Received open failure for " |
2633 | "non-opening channel %d.", id); | 2988 | "non-opening channel %d.", id); |
2634 | if (compat20) { | 2989 | if (compat20) { |
@@ -2672,6 +3027,8 @@ channel_input_window_adjust(int type, u_int32_t seq, void *ctxt) | |||
2672 | logit("Received window adjust for non-open channel %d.", id); | 3027 | logit("Received window adjust for non-open channel %d.", id); |
2673 | return 0; | 3028 | return 0; |
2674 | } | 3029 | } |
3030 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
3031 | return 0; | ||
2675 | adjust = packet_get_int(); | 3032 | adjust = packet_get_int(); |
2676 | packet_check_eom(); | 3033 | packet_check_eom(); |
2677 | debug2("channel %d: rcvd adjust %u", id, adjust); | 3034 | debug2("channel %d: rcvd adjust %u", id, adjust); |
@@ -2726,14 +3083,15 @@ channel_input_status_confirm(int type, u_int32_t seq, void *ctxt) | |||
2726 | packet_set_alive_timeouts(0); | 3083 | packet_set_alive_timeouts(0); |
2727 | 3084 | ||
2728 | id = packet_get_int(); | 3085 | id = packet_get_int(); |
2729 | packet_check_eom(); | ||
2730 | |||
2731 | debug2("channel_input_status_confirm: type %d id %d", type, id); | 3086 | debug2("channel_input_status_confirm: type %d id %d", type, id); |
2732 | 3087 | ||
2733 | if ((c = channel_lookup(id)) == NULL) { | 3088 | if ((c = channel_lookup(id)) == NULL) { |
2734 | logit("channel_input_status_confirm: %d: unknown", id); | 3089 | logit("channel_input_status_confirm: %d: unknown", id); |
2735 | return 0; | 3090 | return 0; |
2736 | } | 3091 | } |
3092 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
3093 | return 0; | ||
3094 | packet_check_eom(); | ||
2737 | if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) | 3095 | if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) |
2738 | return 0; | 3096 | return 0; |
2739 | cc->cb(type, c, cc->ctx); | 3097 | cc->cb(type, c, cc->ctx); |
@@ -3287,6 +3645,7 @@ channel_request_remote_forwarding(struct Forward *fwd) | |||
3287 | permitted_opens[idx].listen_path = NULL; | 3645 | permitted_opens[idx].listen_path = NULL; |
3288 | permitted_opens[idx].listen_port = fwd->listen_port; | 3646 | permitted_opens[idx].listen_port = fwd->listen_port; |
3289 | } | 3647 | } |
3648 | permitted_opens[idx].downstream = NULL; | ||
3290 | } | 3649 | } |
3291 | return (idx); | 3650 | return (idx); |
3292 | } | 3651 | } |
@@ -3382,6 +3741,7 @@ channel_request_rforward_cancel_tcpip(const char *host, u_short port) | |||
3382 | free(permitted_opens[i].listen_host); | 3741 | free(permitted_opens[i].listen_host); |
3383 | permitted_opens[i].listen_host = NULL; | 3742 | permitted_opens[i].listen_host = NULL; |
3384 | permitted_opens[i].listen_path = NULL; | 3743 | permitted_opens[i].listen_path = NULL; |
3744 | permitted_opens[i].downstream = NULL; | ||
3385 | 3745 | ||
3386 | return 0; | 3746 | return 0; |
3387 | } | 3747 | } |
@@ -3419,6 +3779,7 @@ channel_request_rforward_cancel_streamlocal(const char *path) | |||
3419 | permitted_opens[i].listen_host = NULL; | 3779 | permitted_opens[i].listen_host = NULL; |
3420 | free(permitted_opens[i].listen_path); | 3780 | free(permitted_opens[i].listen_path); |
3421 | permitted_opens[i].listen_path = NULL; | 3781 | permitted_opens[i].listen_path = NULL; |
3782 | permitted_opens[i].downstream = NULL; | ||
3422 | 3783 | ||
3423 | return 0; | 3784 | return 0; |
3424 | } | 3785 | } |
@@ -3501,6 +3862,7 @@ channel_add_permitted_opens(char *host, int port) | |||
3501 | permitted_opens[num_permitted_opens].listen_host = NULL; | 3862 | permitted_opens[num_permitted_opens].listen_host = NULL; |
3502 | permitted_opens[num_permitted_opens].listen_path = NULL; | 3863 | permitted_opens[num_permitted_opens].listen_path = NULL; |
3503 | permitted_opens[num_permitted_opens].listen_port = 0; | 3864 | permitted_opens[num_permitted_opens].listen_port = 0; |
3865 | permitted_opens[num_permitted_opens].downstream = NULL; | ||
3504 | num_permitted_opens++; | 3866 | num_permitted_opens++; |
3505 | 3867 | ||
3506 | all_opens_permitted = 0; | 3868 | all_opens_permitted = 0; |
@@ -3763,6 +4125,10 @@ connect_to(const char *name, int port, char *ctype, char *rname) | |||
3763 | return c; | 4125 | return c; |
3764 | } | 4126 | } |
3765 | 4127 | ||
4128 | /* | ||
4129 | * returns either the newly connected channel or the downstream channel | ||
4130 | * that needs to deal with this connection. | ||
4131 | */ | ||
3766 | Channel * | 4132 | Channel * |
3767 | channel_connect_by_listen_address(const char *listen_host, | 4133 | channel_connect_by_listen_address(const char *listen_host, |
3768 | u_short listen_port, char *ctype, char *rname) | 4134 | u_short listen_port, char *ctype, char *rname) |
@@ -3772,6 +4138,8 @@ channel_connect_by_listen_address(const char *listen_host, | |||
3772 | for (i = 0; i < num_permitted_opens; i++) { | 4138 | for (i = 0; i < num_permitted_opens; i++) { |
3773 | if (open_listen_match_tcpip(&permitted_opens[i], listen_host, | 4139 | if (open_listen_match_tcpip(&permitted_opens[i], listen_host, |
3774 | listen_port, 1)) { | 4140 | listen_port, 1)) { |
4141 | if (permitted_opens[i].downstream) | ||
4142 | return permitted_opens[i].downstream; | ||
3775 | return connect_to( | 4143 | return connect_to( |
3776 | permitted_opens[i].host_to_connect, | 4144 | permitted_opens[i].host_to_connect, |
3777 | permitted_opens[i].port_to_connect, ctype, rname); | 4145 | permitted_opens[i].port_to_connect, ctype, rname); |
diff --git a/channels.h b/channels.h index 9d76c9d2a..95363e98a 100644 --- a/channels.h +++ b/channels.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.h,v 1.118 2015/07/01 02:26:31 djm Exp $ */ | 1 | /* $OpenBSD: channels.h,v 1.119 2016/09/30 09:19:13 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -58,7 +58,8 @@ | |||
58 | #define SSH_CHANNEL_ABANDONED 17 /* Abandoned session, eg mux */ | 58 | #define SSH_CHANNEL_ABANDONED 17 /* Abandoned session, eg mux */ |
59 | #define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */ | 59 | #define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */ |
60 | #define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */ | 60 | #define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */ |
61 | #define SSH_CHANNEL_MAX_TYPE 20 | 61 | #define SSH_CHANNEL_MUX_PROXY 20 /* proxy channel for mux-slave */ |
62 | #define SSH_CHANNEL_MAX_TYPE 21 | ||
62 | 63 | ||
63 | #define CHANNEL_CANCEL_PORT_STATIC -1 | 64 | #define CHANNEL_CANCEL_PORT_STATIC -1 |
64 | 65 | ||
@@ -162,6 +163,7 @@ struct Channel { | |||
162 | mux_callback_fn *mux_rcb; | 163 | mux_callback_fn *mux_rcb; |
163 | void *mux_ctx; | 164 | void *mux_ctx; |
164 | int mux_pause; | 165 | int mux_pause; |
166 | int mux_downstream_id; | ||
165 | }; | 167 | }; |
166 | 168 | ||
167 | #define CHAN_EXTENDED_IGNORE 0 | 169 | #define CHAN_EXTENDED_IGNORE 0 |
@@ -209,6 +211,7 @@ struct Channel { | |||
209 | /* channel management */ | 211 | /* channel management */ |
210 | 212 | ||
211 | Channel *channel_by_id(int); | 213 | Channel *channel_by_id(int); |
214 | Channel *channel_by_remote_id(int); | ||
212 | Channel *channel_lookup(int); | 215 | Channel *channel_lookup(int); |
213 | Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int); | 216 | Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int); |
214 | void channel_set_fds(int, int, int, int, int, int, int, u_int); | 217 | void channel_set_fds(int, int, int, int, int, int, int, u_int); |
@@ -228,6 +231,11 @@ void channel_cancel_cleanup(int); | |||
228 | int channel_close_fd(int *); | 231 | int channel_close_fd(int *); |
229 | void channel_send_window_changes(void); | 232 | void channel_send_window_changes(void); |
230 | 233 | ||
234 | /* mux proxy support */ | ||
235 | |||
236 | int channel_proxy_downstream(Channel *mc); | ||
237 | int channel_proxy_upstream(Channel *, int, u_int32_t, void *); | ||
238 | |||
231 | /* protocol handler */ | 239 | /* protocol handler */ |
232 | 240 | ||
233 | int channel_input_close(int, u_int32_t, void *); | 241 | int channel_input_close(int, u_int32_t, void *); |
diff --git a/clientloop.c b/clientloop.c index 58e712241..4289a4081 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.288 2016/09/17 18:00:27 tedu Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.289 2016/09/30 09:19:13 markus 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 |
@@ -1883,11 +1883,14 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt) | |||
1883 | } | 1883 | } |
1884 | 1884 | ||
1885 | static Channel * | 1885 | static Channel * |
1886 | client_request_forwarded_tcpip(const char *request_type, int rchan) | 1886 | client_request_forwarded_tcpip(const char *request_type, int rchan, |
1887 | u_int rwindow, u_int rmaxpack) | ||
1887 | { | 1888 | { |
1888 | Channel *c = NULL; | 1889 | Channel *c = NULL; |
1890 | struct sshbuf *b = NULL; | ||
1889 | char *listen_address, *originator_address; | 1891 | char *listen_address, *originator_address; |
1890 | u_short listen_port, originator_port; | 1892 | u_short listen_port, originator_port; |
1893 | int r; | ||
1891 | 1894 | ||
1892 | /* Get rest of the packet */ | 1895 | /* Get rest of the packet */ |
1893 | listen_address = packet_get_string(NULL); | 1896 | listen_address = packet_get_string(NULL); |
@@ -1902,6 +1905,31 @@ client_request_forwarded_tcpip(const char *request_type, int rchan) | |||
1902 | c = channel_connect_by_listen_address(listen_address, listen_port, | 1905 | c = channel_connect_by_listen_address(listen_address, listen_port, |
1903 | "forwarded-tcpip", originator_address); | 1906 | "forwarded-tcpip", originator_address); |
1904 | 1907 | ||
1908 | if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) { | ||
1909 | if ((b = sshbuf_new()) == NULL) { | ||
1910 | error("%s: alloc reply", __func__); | ||
1911 | goto out; | ||
1912 | } | ||
1913 | /* reconstruct and send to muxclient */ | ||
1914 | if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */ | ||
1915 | (r = sshbuf_put_u8(b, SSH2_MSG_CHANNEL_OPEN)) != 0 || | ||
1916 | (r = sshbuf_put_cstring(b, request_type)) != 0 || | ||
1917 | (r = sshbuf_put_u32(b, rchan)) != 0 || | ||
1918 | (r = sshbuf_put_u32(b, rwindow)) != 0 || | ||
1919 | (r = sshbuf_put_u32(b, rmaxpack)) != 0 || | ||
1920 | (r = sshbuf_put_cstring(b, listen_address)) != 0 || | ||
1921 | (r = sshbuf_put_u32(b, listen_port)) != 0 || | ||
1922 | (r = sshbuf_put_cstring(b, originator_address)) != 0 || | ||
1923 | (r = sshbuf_put_u32(b, originator_port)) != 0 || | ||
1924 | (r = sshbuf_put_stringb(&c->output, b)) != 0) { | ||
1925 | error("%s: compose for muxclient %s", __func__, | ||
1926 | ssh_err(r)); | ||
1927 | goto out; | ||
1928 | } | ||
1929 | } | ||
1930 | |||
1931 | out: | ||
1932 | sshbuf_free(b); | ||
1905 | free(originator_address); | 1933 | free(originator_address); |
1906 | free(listen_address); | 1934 | free(listen_address); |
1907 | return c; | 1935 | return c; |
@@ -2057,7 +2085,8 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt) | |||
2057 | ctype, rchan, rwindow, rmaxpack); | 2085 | ctype, rchan, rwindow, rmaxpack); |
2058 | 2086 | ||
2059 | if (strcmp(ctype, "forwarded-tcpip") == 0) { | 2087 | if (strcmp(ctype, "forwarded-tcpip") == 0) { |
2060 | c = client_request_forwarded_tcpip(ctype, rchan); | 2088 | c = client_request_forwarded_tcpip(ctype, rchan, rwindow, |
2089 | rmaxpack); | ||
2061 | } else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) { | 2090 | } else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) { |
2062 | c = client_request_forwarded_streamlocal(ctype, rchan); | 2091 | c = client_request_forwarded_streamlocal(ctype, rchan); |
2063 | } else if (strcmp(ctype, "x11") == 0) { | 2092 | } else if (strcmp(ctype, "x11") == 0) { |
@@ -2065,8 +2094,9 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt) | |||
2065 | } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { | 2094 | } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { |
2066 | c = client_request_agent(ctype, rchan); | 2095 | c = client_request_agent(ctype, rchan); |
2067 | } | 2096 | } |
2068 | /* XXX duplicate : */ | 2097 | if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) { |
2069 | if (c != NULL) { | 2098 | debug3("proxied to downstream: %s", ctype); |
2099 | } else if (c != NULL) { | ||
2070 | debug("confirm %s", ctype); | 2100 | debug("confirm %s", ctype); |
2071 | c->remote_id = rchan; | 2101 | c->remote_id = rchan; |
2072 | c->remote_window = rwindow; | 2102 | c->remote_window = rwindow; |
@@ -2102,6 +2132,9 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt) | |||
2102 | char *rtype; | 2132 | char *rtype; |
2103 | 2133 | ||
2104 | id = packet_get_int(); | 2134 | id = packet_get_int(); |
2135 | c = channel_lookup(id); | ||
2136 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2137 | return 0; | ||
2105 | rtype = packet_get_string(NULL); | 2138 | rtype = packet_get_string(NULL); |
2106 | reply = packet_get_char(); | 2139 | reply = packet_get_char(); |
2107 | 2140 | ||
@@ -2110,7 +2143,7 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt) | |||
2110 | 2143 | ||
2111 | if (id == -1) { | 2144 | if (id == -1) { |
2112 | error("client_input_channel_req: request for channel -1"); | 2145 | error("client_input_channel_req: request for channel -1"); |
2113 | } else if ((c = channel_lookup(id)) == NULL) { | 2146 | } else if (c == NULL) { |
2114 | error("client_input_channel_req: channel %d: " | 2147 | error("client_input_channel_req: channel %d: " |
2115 | "unknown channel", id); | 2148 | "unknown channel", id); |
2116 | } else if (strcmp(rtype, "eow@openssh.com") == 0) { | 2149 | } else if (strcmp(rtype, "eow@openssh.com") == 0) { |
diff --git a/clientloop.h b/clientloop.h index f4d4c69b7..ae83aa8cf 100644 --- a/clientloop.h +++ b/clientloop.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.h,v 1.32 2016/01/13 23:04:47 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.h,v 1.33 2016/09/30 09:19:13 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -71,9 +71,10 @@ void client_expect_confirm(int, const char *, enum confirm_action); | |||
71 | #define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */ | 71 | #define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */ |
72 | #define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */ | 72 | #define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */ |
73 | #define SSHMUX_COMMAND_CANCEL_FWD 7 /* Cancel forwarding(s) */ | 73 | #define SSHMUX_COMMAND_CANCEL_FWD 7 /* Cancel forwarding(s) */ |
74 | #define SSHMUX_COMMAND_PROXY 8 /* Open new connection */ | ||
74 | 75 | ||
75 | void muxserver_listen(void); | 76 | void muxserver_listen(void); |
76 | void muxclient(const char *); | 77 | int muxclient(const char *); |
77 | void mux_exit_message(Channel *, int); | 78 | void mux_exit_message(Channel *, int); |
78 | void mux_tty_alloc_failed(Channel *); | 79 | void mux_tty_alloc_failed(Channel *); |
79 | 80 | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mux.c,v 1.61 2016/08/08 22:40:57 dtucker Exp $ */ | 1 | /* $OpenBSD: mux.c,v 1.62 2016/09/30 09:19:13 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -79,6 +79,7 @@ | |||
79 | #include "key.h" | 79 | #include "key.h" |
80 | #include "readconf.h" | 80 | #include "readconf.h" |
81 | #include "clientloop.h" | 81 | #include "clientloop.h" |
82 | #include "ssherr.h" | ||
82 | 83 | ||
83 | /* from ssh.c */ | 84 | /* from ssh.c */ |
84 | extern int tty_flag; | 85 | extern int tty_flag; |
@@ -144,6 +145,7 @@ struct mux_master_state { | |||
144 | #define MUX_C_CLOSE_FWD 0x10000007 | 145 | #define MUX_C_CLOSE_FWD 0x10000007 |
145 | #define MUX_C_NEW_STDIO_FWD 0x10000008 | 146 | #define MUX_C_NEW_STDIO_FWD 0x10000008 |
146 | #define MUX_C_STOP_LISTENING 0x10000009 | 147 | #define MUX_C_STOP_LISTENING 0x10000009 |
148 | #define MUX_C_PROXY 0x1000000f | ||
147 | #define MUX_S_OK 0x80000001 | 149 | #define MUX_S_OK 0x80000001 |
148 | #define MUX_S_PERMISSION_DENIED 0x80000002 | 150 | #define MUX_S_PERMISSION_DENIED 0x80000002 |
149 | #define MUX_S_FAILURE 0x80000003 | 151 | #define MUX_S_FAILURE 0x80000003 |
@@ -152,6 +154,7 @@ struct mux_master_state { | |||
152 | #define MUX_S_SESSION_OPENED 0x80000006 | 154 | #define MUX_S_SESSION_OPENED 0x80000006 |
153 | #define MUX_S_REMOTE_PORT 0x80000007 | 155 | #define MUX_S_REMOTE_PORT 0x80000007 |
154 | #define MUX_S_TTY_ALLOC_FAIL 0x80000008 | 156 | #define MUX_S_TTY_ALLOC_FAIL 0x80000008 |
157 | #define MUX_S_PROXY 0x8000000f | ||
155 | 158 | ||
156 | /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ | 159 | /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ |
157 | #define MUX_FWD_LOCAL 1 | 160 | #define MUX_FWD_LOCAL 1 |
@@ -169,6 +172,7 @@ static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); | |||
169 | static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); | 172 | static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); |
170 | static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); | 173 | static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); |
171 | static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *); | 174 | static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *); |
175 | static int process_mux_proxy(u_int, Channel *, Buffer *, Buffer *); | ||
172 | 176 | ||
173 | static const struct { | 177 | static const struct { |
174 | u_int type; | 178 | u_int type; |
@@ -182,6 +186,7 @@ static const struct { | |||
182 | { MUX_C_CLOSE_FWD, process_mux_close_fwd }, | 186 | { MUX_C_CLOSE_FWD, process_mux_close_fwd }, |
183 | { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, | 187 | { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, |
184 | { MUX_C_STOP_LISTENING, process_mux_stop_listening }, | 188 | { MUX_C_STOP_LISTENING, process_mux_stop_listening }, |
189 | { MUX_C_PROXY, process_mux_proxy }, | ||
185 | { 0, NULL } | 190 | { 0, NULL } |
186 | }; | 191 | }; |
187 | 192 | ||
@@ -1110,6 +1115,18 @@ process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
1110 | return 0; | 1115 | return 0; |
1111 | } | 1116 | } |
1112 | 1117 | ||
1118 | static int | ||
1119 | process_mux_proxy(u_int rid, Channel *c, Buffer *m, Buffer *r) | ||
1120 | { | ||
1121 | debug("%s: channel %d: proxy request", __func__, c->self); | ||
1122 | |||
1123 | c->mux_rcb = channel_proxy_downstream; | ||
1124 | buffer_put_int(r, MUX_S_PROXY); | ||
1125 | buffer_put_int(r, rid); | ||
1126 | |||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1113 | /* Channel callbacks fired on read/write from mux slave fd */ | 1130 | /* Channel callbacks fired on read/write from mux slave fd */ |
1114 | static int | 1131 | static int |
1115 | mux_master_read_cb(Channel *c) | 1132 | mux_master_read_cb(Channel *c) |
@@ -1960,6 +1977,41 @@ mux_client_request_session(int fd) | |||
1960 | } | 1977 | } |
1961 | 1978 | ||
1962 | static int | 1979 | static int |
1980 | mux_client_proxy(int fd) | ||
1981 | { | ||
1982 | Buffer m; | ||
1983 | char *e; | ||
1984 | u_int type, rid; | ||
1985 | |||
1986 | buffer_init(&m); | ||
1987 | buffer_put_int(&m, MUX_C_PROXY); | ||
1988 | buffer_put_int(&m, muxclient_request_id); | ||
1989 | if (mux_client_write_packet(fd, &m) != 0) | ||
1990 | fatal("%s: write packet: %s", __func__, strerror(errno)); | ||
1991 | |||
1992 | buffer_clear(&m); | ||
1993 | |||
1994 | /* Read their reply */ | ||
1995 | if (mux_client_read_packet(fd, &m) != 0) { | ||
1996 | buffer_free(&m); | ||
1997 | return 0; | ||
1998 | } | ||
1999 | type = buffer_get_int(&m); | ||
2000 | if (type != MUX_S_PROXY) { | ||
2001 | e = buffer_get_string(&m, NULL); | ||
2002 | fatal("%s: master returned error: %s", __func__, e); | ||
2003 | } | ||
2004 | if ((rid = buffer_get_int(&m)) != muxclient_request_id) | ||
2005 | fatal("%s: out of sequence reply: my id %u theirs %u", | ||
2006 | __func__, muxclient_request_id, rid); | ||
2007 | buffer_free(&m); | ||
2008 | |||
2009 | debug3("%s: done", __func__); | ||
2010 | muxclient_request_id++; | ||
2011 | return 0; | ||
2012 | } | ||
2013 | |||
2014 | static int | ||
1963 | mux_client_request_stdio_fwd(int fd) | 2015 | mux_client_request_stdio_fwd(int fd) |
1964 | { | 2016 | { |
1965 | Buffer m; | 2017 | Buffer m; |
@@ -2105,7 +2157,7 @@ mux_client_request_stop_listening(int fd) | |||
2105 | } | 2157 | } |
2106 | 2158 | ||
2107 | /* Multiplex client main loop. */ | 2159 | /* Multiplex client main loop. */ |
2108 | void | 2160 | int |
2109 | muxclient(const char *path) | 2161 | muxclient(const char *path) |
2110 | { | 2162 | { |
2111 | struct sockaddr_un addr; | 2163 | struct sockaddr_un addr; |
@@ -2128,7 +2180,7 @@ muxclient(const char *path) | |||
2128 | case SSHCTL_MASTER_NO: | 2180 | case SSHCTL_MASTER_NO: |
2129 | break; | 2181 | break; |
2130 | default: | 2182 | default: |
2131 | return; | 2183 | return -1; |
2132 | } | 2184 | } |
2133 | 2185 | ||
2134 | memset(&addr, '\0', sizeof(addr)); | 2186 | memset(&addr, '\0', sizeof(addr)); |
@@ -2164,14 +2216,14 @@ muxclient(const char *path) | |||
2164 | strerror(errno)); | 2216 | strerror(errno)); |
2165 | } | 2217 | } |
2166 | close(sock); | 2218 | close(sock); |
2167 | return; | 2219 | return -1; |
2168 | } | 2220 | } |
2169 | set_nonblock(sock); | 2221 | set_nonblock(sock); |
2170 | 2222 | ||
2171 | if (mux_client_hello_exchange(sock) != 0) { | 2223 | if (mux_client_hello_exchange(sock) != 0) { |
2172 | error("%s: master hello exchange failed", __func__); | 2224 | error("%s: master hello exchange failed", __func__); |
2173 | close(sock); | 2225 | close(sock); |
2174 | return; | 2226 | return -1; |
2175 | } | 2227 | } |
2176 | 2228 | ||
2177 | switch (muxclient_command) { | 2229 | switch (muxclient_command) { |
@@ -2191,10 +2243,10 @@ muxclient(const char *path) | |||
2191 | case SSHMUX_COMMAND_OPEN: | 2243 | case SSHMUX_COMMAND_OPEN: |
2192 | if (mux_client_forwards(sock, 0) != 0) { | 2244 | if (mux_client_forwards(sock, 0) != 0) { |
2193 | error("%s: master forward request failed", __func__); | 2245 | error("%s: master forward request failed", __func__); |
2194 | return; | 2246 | return -1; |
2195 | } | 2247 | } |
2196 | mux_client_request_session(sock); | 2248 | mux_client_request_session(sock); |
2197 | return; | 2249 | return -1; |
2198 | case SSHMUX_COMMAND_STDIO_FWD: | 2250 | case SSHMUX_COMMAND_STDIO_FWD: |
2199 | mux_client_request_stdio_fwd(sock); | 2251 | mux_client_request_stdio_fwd(sock); |
2200 | exit(0); | 2252 | exit(0); |
@@ -2207,6 +2259,9 @@ muxclient(const char *path) | |||
2207 | error("%s: master cancel forward request failed", | 2259 | error("%s: master cancel forward request failed", |
2208 | __func__); | 2260 | __func__); |
2209 | exit(0); | 2261 | exit(0); |
2262 | case SSHMUX_COMMAND_PROXY: | ||
2263 | mux_client_proxy(sock); | ||
2264 | return (sock); | ||
2210 | default: | 2265 | default: |
2211 | fatal("unrecognised muxclient_command %d", muxclient_command); | 2266 | fatal("unrecognised muxclient_command %d", muxclient_command); |
2212 | } | 2267 | } |
@@ -153,5 +153,9 @@ void packet_disconnect(const char *, ...) | |||
153 | ssh_packet_set_rekey_limits(active_state, x, y) | 153 | ssh_packet_set_rekey_limits(active_state, x, y) |
154 | #define packet_get_bytes(x,y) \ | 154 | #define packet_get_bytes(x,y) \ |
155 | ssh_packet_get_bytes(active_state, x, y) | 155 | ssh_packet_get_bytes(active_state, x, y) |
156 | #define packet_set_mux() \ | ||
157 | ssh_packet_set_mux(active_state) | ||
158 | #define packet_get_mux() \ | ||
159 | ssh_packet_get_mux(active_state) | ||
156 | 160 | ||
157 | #endif /* _OPACKET_H */ | 161 | #endif /* _OPACKET_H */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: packet.c,v 1.241 2016/09/28 21:44:52 djm Exp $ */ | 1 | /* $OpenBSD: packet.c,v 1.242 2016/09/30 09:19:13 markus 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 |
@@ -204,6 +204,9 @@ struct session_state { | |||
204 | /* Used in packet_send2 */ | 204 | /* Used in packet_send2 */ |
205 | int rekeying; | 205 | int rekeying; |
206 | 206 | ||
207 | /* Used in ssh_packet_send_mux() */ | ||
208 | int mux; | ||
209 | |||
207 | /* Used in packet_set_interactive */ | 210 | /* Used in packet_set_interactive */ |
208 | int set_interactive_called; | 211 | int set_interactive_called; |
209 | 212 | ||
@@ -325,6 +328,19 @@ ssh_packet_set_timeout(struct ssh *ssh, int timeout, int count) | |||
325 | state->packet_timeout_ms = timeout * count * 1000; | 328 | state->packet_timeout_ms = timeout * count * 1000; |
326 | } | 329 | } |
327 | 330 | ||
331 | void | ||
332 | ssh_packet_set_mux(struct ssh *ssh) | ||
333 | { | ||
334 | ssh->state->mux = 1; | ||
335 | ssh->state->rekeying = 0; | ||
336 | } | ||
337 | |||
338 | int | ||
339 | ssh_packet_get_mux(struct ssh *ssh) | ||
340 | { | ||
341 | return ssh->state->mux; | ||
342 | } | ||
343 | |||
328 | int | 344 | int |
329 | ssh_packet_stop_discard(struct ssh *ssh) | 345 | ssh_packet_stop_discard(struct ssh *ssh) |
330 | { | 346 | { |
@@ -1078,7 +1094,7 @@ ssh_packet_enable_delayed_compress(struct ssh *ssh) | |||
1078 | } | 1094 | } |
1079 | 1095 | ||
1080 | /* Used to mute debug logging for noisy packet types */ | 1096 | /* Used to mute debug logging for noisy packet types */ |
1081 | static int | 1097 | int |
1082 | ssh_packet_log_type(u_char type) | 1098 | ssh_packet_log_type(u_char type) |
1083 | { | 1099 | { |
1084 | switch (type) { | 1100 | switch (type) { |
@@ -1623,6 +1639,44 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep) | |||
1623 | return r; | 1639 | return r; |
1624 | } | 1640 | } |
1625 | 1641 | ||
1642 | static int | ||
1643 | ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | ||
1644 | { | ||
1645 | struct session_state *state = ssh->state; | ||
1646 | const u_char *cp; | ||
1647 | size_t need; | ||
1648 | int r; | ||
1649 | |||
1650 | if (ssh->kex) | ||
1651 | return SSH_ERR_INTERNAL_ERROR; | ||
1652 | *typep = SSH_MSG_NONE; | ||
1653 | cp = sshbuf_ptr(state->input); | ||
1654 | if (state->packlen == 0) { | ||
1655 | if (sshbuf_len(state->input) < 4 + 1) | ||
1656 | return 0; /* packet is incomplete */ | ||
1657 | state->packlen = PEEK_U32(cp); | ||
1658 | if (state->packlen < 4 + 1 || | ||
1659 | state->packlen > PACKET_MAX_SIZE) | ||
1660 | return SSH_ERR_MESSAGE_INCOMPLETE; | ||
1661 | } | ||
1662 | need = state->packlen + 4; | ||
1663 | if (sshbuf_len(state->input) < need) | ||
1664 | return 0; /* packet is incomplete */ | ||
1665 | sshbuf_reset(state->incoming_packet); | ||
1666 | if ((r = sshbuf_put(state->incoming_packet, cp + 4, | ||
1667 | state->packlen)) != 0 || | ||
1668 | (r = sshbuf_consume(state->input, need)) != 0 || | ||
1669 | (r = sshbuf_get_u8(state->incoming_packet, NULL)) != 0 || | ||
1670 | (r = sshbuf_get_u8(state->incoming_packet, typep)) != 0) | ||
1671 | return r; | ||
1672 | if (ssh_packet_log_type(*typep)) | ||
1673 | debug3("%s: type %u", __func__, *typep); | ||
1674 | /* sshbuf_dump(state->incoming_packet, stderr); */ | ||
1675 | /* reset for next packet */ | ||
1676 | state->packlen = 0; | ||
1677 | return r; | ||
1678 | } | ||
1679 | |||
1626 | int | 1680 | int |
1627 | ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | 1681 | ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) |
1628 | { | 1682 | { |
@@ -1635,6 +1689,9 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | |||
1635 | struct sshcomp *comp = NULL; | 1689 | struct sshcomp *comp = NULL; |
1636 | int r; | 1690 | int r; |
1637 | 1691 | ||
1692 | if (state->mux) | ||
1693 | return ssh_packet_read_poll2_mux(ssh, typep, seqnr_p); | ||
1694 | |||
1638 | *typep = SSH_MSG_NONE; | 1695 | *typep = SSH_MSG_NONE; |
1639 | 1696 | ||
1640 | if (state->packet_discard) | 1697 | if (state->packet_discard) |
@@ -2875,11 +2932,43 @@ sshpkt_start(struct ssh *ssh, u_char type) | |||
2875 | return sshbuf_put(ssh->state->outgoing_packet, buf, len); | 2932 | return sshbuf_put(ssh->state->outgoing_packet, buf, len); |
2876 | } | 2933 | } |
2877 | 2934 | ||
2935 | static int | ||
2936 | ssh_packet_send_mux(struct ssh *ssh) | ||
2937 | { | ||
2938 | struct session_state *state = ssh->state; | ||
2939 | u_char type, *cp; | ||
2940 | size_t len; | ||
2941 | int r; | ||
2942 | |||
2943 | if (ssh->kex) | ||
2944 | return SSH_ERR_INTERNAL_ERROR; | ||
2945 | len = sshbuf_len(state->outgoing_packet); | ||
2946 | if (len < 6) | ||
2947 | return SSH_ERR_INTERNAL_ERROR; | ||
2948 | cp = sshbuf_mutable_ptr(state->outgoing_packet); | ||
2949 | type = cp[5]; | ||
2950 | if (ssh_packet_log_type(type)) | ||
2951 | debug3("%s: type %u", __func__, type); | ||
2952 | /* drop everything, but the connection protocol */ | ||
2953 | if (type >= SSH2_MSG_CONNECTION_MIN && | ||
2954 | type <= SSH2_MSG_CONNECTION_MAX) { | ||
2955 | POKE_U32(cp, len - 4); | ||
2956 | if ((r = sshbuf_putb(state->output, | ||
2957 | state->outgoing_packet)) != 0) | ||
2958 | return r; | ||
2959 | /* sshbuf_dump(state->output, stderr); */ | ||
2960 | } | ||
2961 | sshbuf_reset(state->outgoing_packet); | ||
2962 | return 0; | ||
2963 | } | ||
2964 | |||
2878 | /* send it */ | 2965 | /* send it */ |
2879 | 2966 | ||
2880 | int | 2967 | int |
2881 | sshpkt_send(struct ssh *ssh) | 2968 | sshpkt_send(struct ssh *ssh) |
2882 | { | 2969 | { |
2970 | if (ssh->state && ssh->state->mux) | ||
2971 | return ssh_packet_send_mux(ssh); | ||
2883 | if (compat20) | 2972 | if (compat20) |
2884 | return ssh_packet_send2(ssh); | 2973 | return ssh_packet_send2(ssh); |
2885 | else | 2974 | else |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: packet.h,v 1.72 2016/09/28 16:33:07 djm Exp $ */ | 1 | /* $OpenBSD: packet.h,v 1.73 2016/09/30 09:19:13 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -97,6 +97,10 @@ void ssh_packet_set_interactive(struct ssh *, int, int, int); | |||
97 | int ssh_packet_is_interactive(struct ssh *); | 97 | int ssh_packet_is_interactive(struct ssh *); |
98 | void ssh_packet_set_server(struct ssh *); | 98 | void ssh_packet_set_server(struct ssh *); |
99 | void ssh_packet_set_authenticated(struct ssh *); | 99 | void ssh_packet_set_authenticated(struct ssh *); |
100 | void ssh_packet_set_mux(struct ssh *); | ||
101 | int ssh_packet_get_mux(struct ssh *); | ||
102 | |||
103 | int ssh_packet_log_type(u_char); | ||
100 | 104 | ||
101 | int ssh_packet_send1(struct ssh *); | 105 | int ssh_packet_send1(struct ssh *); |
102 | int ssh_packet_send2_wrapped(struct ssh *); | 106 | int ssh_packet_send2_wrapped(struct ssh *); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.446 2016/09/12 23:31:27 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.447 2016/09/30 09:19:13 markus 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 |
@@ -213,10 +213,6 @@ static int ssh_session2(void); | |||
213 | static void load_public_identity_files(void); | 213 | static void load_public_identity_files(void); |
214 | static void main_sigchld_handler(int); | 214 | static void main_sigchld_handler(int); |
215 | 215 | ||
216 | /* from muxclient.c */ | ||
217 | void muxclient(const char *); | ||
218 | void muxserver_listen(void); | ||
219 | |||
220 | /* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ | 216 | /* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ |
221 | static void | 217 | static void |
222 | tilde_expand_paths(char **paths, u_int num_paths) | 218 | tilde_expand_paths(char **paths, u_int num_paths) |
@@ -668,6 +664,8 @@ main(int ac, char **av) | |||
668 | muxclient_command = SSHMUX_COMMAND_STOP; | 664 | muxclient_command = SSHMUX_COMMAND_STOP; |
669 | else if (strcmp(optarg, "cancel") == 0) | 665 | else if (strcmp(optarg, "cancel") == 0) |
670 | muxclient_command = SSHMUX_COMMAND_CANCEL_FWD; | 666 | muxclient_command = SSHMUX_COMMAND_CANCEL_FWD; |
667 | else if (strcmp(optarg, "proxy") == 0) | ||
668 | muxclient_command = SSHMUX_COMMAND_PROXY; | ||
671 | else | 669 | else |
672 | fatal("Invalid multiplex command."); | 670 | fatal("Invalid multiplex command."); |
673 | break; | 671 | break; |
@@ -1162,7 +1160,8 @@ main(int ac, char **av) | |||
1162 | tty_flag = options.request_tty != REQUEST_TTY_NO; | 1160 | tty_flag = options.request_tty != REQUEST_TTY_NO; |
1163 | 1161 | ||
1164 | /* Force no tty */ | 1162 | /* Force no tty */ |
1165 | if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0) | 1163 | if (options.request_tty == REQUEST_TTY_NO || |
1164 | (muxclient_command && muxclient_command != SSHMUX_COMMAND_PROXY)) | ||
1166 | tty_flag = 0; | 1165 | tty_flag = 0; |
1167 | /* Do not allocate a tty if stdin is not a tty. */ | 1166 | /* Do not allocate a tty if stdin is not a tty. */ |
1168 | if ((!isatty(fileno(stdin)) || stdin_null_flag) && | 1167 | if ((!isatty(fileno(stdin)) || stdin_null_flag) && |
@@ -1239,8 +1238,16 @@ main(int ac, char **av) | |||
1239 | 1238 | ||
1240 | if (muxclient_command != 0 && options.control_path == NULL) | 1239 | if (muxclient_command != 0 && options.control_path == NULL) |
1241 | fatal("No ControlPath specified for \"-O\" command"); | 1240 | fatal("No ControlPath specified for \"-O\" command"); |
1242 | if (options.control_path != NULL) | 1241 | if (options.control_path != NULL) { |
1243 | muxclient(options.control_path); | 1242 | int sock; |
1243 | if ((sock = muxclient(options.control_path)) >= 0) { | ||
1244 | packet_set_connection(sock, sock); | ||
1245 | ssh = active_state; /* XXX */ | ||
1246 | enable_compat20(); /* XXX */ | ||
1247 | packet_set_mux(); | ||
1248 | goto skip_connect; | ||
1249 | } | ||
1250 | } | ||
1244 | 1251 | ||
1245 | /* | 1252 | /* |
1246 | * If hostname canonicalisation was not enabled, then we may not | 1253 | * If hostname canonicalisation was not enabled, then we may not |
@@ -1443,6 +1450,7 @@ main(int ac, char **av) | |||
1443 | options.certificate_files[i] = NULL; | 1450 | options.certificate_files[i] = NULL; |
1444 | } | 1451 | } |
1445 | 1452 | ||
1453 | skip_connect: | ||
1446 | exit_status = compat20 ? ssh_session2() : ssh_session(); | 1454 | exit_status = compat20 ? ssh_session2() : ssh_session(); |
1447 | packet_close(); | 1455 | packet_close(); |
1448 | 1456 | ||
@@ -1953,7 +1961,8 @@ ssh_session2(void) | |||
1953 | ssh_init_forwarding(); | 1961 | ssh_init_forwarding(); |
1954 | 1962 | ||
1955 | /* Start listening for multiplex clients */ | 1963 | /* Start listening for multiplex clients */ |
1956 | muxserver_listen(); | 1964 | if (!packet_get_mux()) |
1965 | muxserver_listen(); | ||
1957 | 1966 | ||
1958 | /* | 1967 | /* |
1959 | * If we are in control persist mode and have a working mux listen | 1968 | * If we are in control persist mode and have a working mux listen |