diff options
Diffstat (limited to 'mux.c')
-rw-r--r-- | mux.c | 275 |
1 files changed, 180 insertions, 95 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mux.c,v 1.44 2013/07/12 00:19:58 djm Exp $ */ | 1 | /* $OpenBSD: mux.c,v 1.48 2014/07/17 07:22:19 djm 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 | * |
@@ -105,6 +105,11 @@ struct mux_session_confirm_ctx { | |||
105 | u_int rid; | 105 | u_int rid; |
106 | }; | 106 | }; |
107 | 107 | ||
108 | /* Context for stdio fwd open confirmation callback */ | ||
109 | struct mux_stdio_confirm_ctx { | ||
110 | u_int rid; | ||
111 | }; | ||
112 | |||
108 | /* Context for global channel callback */ | 113 | /* Context for global channel callback */ |
109 | struct mux_channel_confirm_ctx { | 114 | struct mux_channel_confirm_ctx { |
110 | u_int cid; /* channel id */ | 115 | u_int cid; /* channel id */ |
@@ -157,6 +162,7 @@ struct mux_master_state { | |||
157 | #define MUX_FWD_DYNAMIC 3 | 162 | #define MUX_FWD_DYNAMIC 3 |
158 | 163 | ||
159 | static void mux_session_confirm(int, int, void *); | 164 | static void mux_session_confirm(int, int, void *); |
165 | static void mux_stdio_confirm(int, int, void *); | ||
160 | 166 | ||
161 | static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); | 167 | static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); |
162 | static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); | 168 | static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); |
@@ -509,29 +515,33 @@ process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
509 | } | 515 | } |
510 | 516 | ||
511 | static char * | 517 | static char * |
512 | format_forward(u_int ftype, Forward *fwd) | 518 | format_forward(u_int ftype, struct Forward *fwd) |
513 | { | 519 | { |
514 | char *ret; | 520 | char *ret; |
515 | 521 | ||
516 | switch (ftype) { | 522 | switch (ftype) { |
517 | case MUX_FWD_LOCAL: | 523 | case MUX_FWD_LOCAL: |
518 | xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d", | 524 | xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d", |
525 | (fwd->listen_path != NULL) ? fwd->listen_path : | ||
519 | (fwd->listen_host == NULL) ? | 526 | (fwd->listen_host == NULL) ? |
520 | (options.gateway_ports ? "*" : "LOCALHOST") : | 527 | (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") : |
521 | fwd->listen_host, fwd->listen_port, | 528 | fwd->listen_host, fwd->listen_port, |
529 | (fwd->connect_path != NULL) ? fwd->connect_path : | ||
522 | fwd->connect_host, fwd->connect_port); | 530 | fwd->connect_host, fwd->connect_port); |
523 | break; | 531 | break; |
524 | case MUX_FWD_DYNAMIC: | 532 | case MUX_FWD_DYNAMIC: |
525 | xasprintf(&ret, "dynamic forward %.200s:%d -> *", | 533 | xasprintf(&ret, "dynamic forward %.200s:%d -> *", |
526 | (fwd->listen_host == NULL) ? | 534 | (fwd->listen_host == NULL) ? |
527 | (options.gateway_ports ? "*" : "LOCALHOST") : | 535 | (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") : |
528 | fwd->listen_host, fwd->listen_port); | 536 | fwd->listen_host, fwd->listen_port); |
529 | break; | 537 | break; |
530 | case MUX_FWD_REMOTE: | 538 | case MUX_FWD_REMOTE: |
531 | xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d", | 539 | xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d", |
540 | (fwd->listen_path != NULL) ? fwd->listen_path : | ||
532 | (fwd->listen_host == NULL) ? | 541 | (fwd->listen_host == NULL) ? |
533 | "LOCALHOST" : fwd->listen_host, | 542 | "LOCALHOST" : fwd->listen_host, |
534 | fwd->listen_port, | 543 | fwd->listen_port, |
544 | (fwd->connect_path != NULL) ? fwd->connect_path : | ||
535 | fwd->connect_host, fwd->connect_port); | 545 | fwd->connect_host, fwd->connect_port); |
536 | break; | 546 | break; |
537 | default: | 547 | default: |
@@ -551,14 +561,18 @@ compare_host(const char *a, const char *b) | |||
551 | } | 561 | } |
552 | 562 | ||
553 | static int | 563 | static int |
554 | compare_forward(Forward *a, Forward *b) | 564 | compare_forward(struct Forward *a, struct Forward *b) |
555 | { | 565 | { |
556 | if (!compare_host(a->listen_host, b->listen_host)) | 566 | if (!compare_host(a->listen_host, b->listen_host)) |
557 | return 0; | 567 | return 0; |
568 | if (!compare_host(a->listen_path, b->listen_path)) | ||
569 | return 0; | ||
558 | if (a->listen_port != b->listen_port) | 570 | if (a->listen_port != b->listen_port) |
559 | return 0; | 571 | return 0; |
560 | if (!compare_host(a->connect_host, b->connect_host)) | 572 | if (!compare_host(a->connect_host, b->connect_host)) |
561 | return 0; | 573 | return 0; |
574 | if (!compare_host(a->connect_path, b->connect_path)) | ||
575 | return 0; | ||
562 | if (a->connect_port != b->connect_port) | 576 | if (a->connect_port != b->connect_port) |
563 | return 0; | 577 | return 0; |
564 | 578 | ||
@@ -570,7 +584,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) | |||
570 | { | 584 | { |
571 | struct mux_channel_confirm_ctx *fctx = ctxt; | 585 | struct mux_channel_confirm_ctx *fctx = ctxt; |
572 | char *failmsg = NULL; | 586 | char *failmsg = NULL; |
573 | Forward *rfwd; | 587 | struct Forward *rfwd; |
574 | Channel *c; | 588 | Channel *c; |
575 | Buffer out; | 589 | Buffer out; |
576 | 590 | ||
@@ -587,7 +601,8 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) | |||
587 | rfwd = &options.remote_forwards[fctx->fid]; | 601 | rfwd = &options.remote_forwards[fctx->fid]; |
588 | debug("%s: %s for: listen %d, connect %s:%d", __func__, | 602 | debug("%s: %s for: listen %d, connect %s:%d", __func__, |
589 | type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", | 603 | type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", |
590 | rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); | 604 | rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path : |
605 | rfwd->connect_host, rfwd->connect_port); | ||
591 | if (type == SSH2_MSG_REQUEST_SUCCESS) { | 606 | if (type == SSH2_MSG_REQUEST_SUCCESS) { |
592 | if (rfwd->listen_port == 0) { | 607 | if (rfwd->listen_port == 0) { |
593 | rfwd->allocated_port = packet_get_int(); | 608 | rfwd->allocated_port = packet_get_int(); |
@@ -607,8 +622,12 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) | |||
607 | } else { | 622 | } else { |
608 | if (rfwd->listen_port == 0) | 623 | if (rfwd->listen_port == 0) |
609 | channel_update_permitted_opens(rfwd->handle, -1); | 624 | channel_update_permitted_opens(rfwd->handle, -1); |
610 | xasprintf(&failmsg, "remote port forwarding failed for " | 625 | if (rfwd->listen_path != NULL) |
611 | "listen port %d", rfwd->listen_port); | 626 | xasprintf(&failmsg, "remote port forwarding failed for " |
627 | "listen path %s", rfwd->listen_path); | ||
628 | else | ||
629 | xasprintf(&failmsg, "remote port forwarding failed for " | ||
630 | "listen port %d", rfwd->listen_port); | ||
612 | } | 631 | } |
613 | fail: | 632 | fail: |
614 | error("%s: %s", __func__, failmsg); | 633 | error("%s: %s", __func__, failmsg); |
@@ -627,34 +646,46 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) | |||
627 | static int | 646 | static int |
628 | process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | 647 | process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) |
629 | { | 648 | { |
630 | Forward fwd; | 649 | struct Forward fwd; |
631 | char *fwd_desc = NULL; | 650 | char *fwd_desc = NULL; |
651 | char *listen_addr, *connect_addr; | ||
632 | u_int ftype; | 652 | u_int ftype; |
633 | u_int lport, cport; | 653 | u_int lport, cport; |
634 | int i, ret = 0, freefwd = 1; | 654 | int i, ret = 0, freefwd = 1; |
635 | 655 | ||
636 | fwd.listen_host = fwd.connect_host = NULL; | 656 | /* XXX - lport/cport check redundant */ |
637 | if (buffer_get_int_ret(&ftype, m) != 0 || | 657 | if (buffer_get_int_ret(&ftype, m) != 0 || |
638 | (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || | 658 | (listen_addr = buffer_get_string_ret(m, NULL)) == NULL || |
639 | buffer_get_int_ret(&lport, m) != 0 || | 659 | buffer_get_int_ret(&lport, m) != 0 || |
640 | (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || | 660 | (connect_addr = buffer_get_string_ret(m, NULL)) == NULL || |
641 | buffer_get_int_ret(&cport, m) != 0 || | 661 | buffer_get_int_ret(&cport, m) != 0 || |
642 | lport > 65535 || cport > 65535) { | 662 | (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) || |
663 | (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) { | ||
643 | error("%s: malformed message", __func__); | 664 | error("%s: malformed message", __func__); |
644 | ret = -1; | 665 | ret = -1; |
645 | goto out; | 666 | goto out; |
646 | } | 667 | } |
647 | fwd.listen_port = lport; | 668 | if (*listen_addr == '\0') { |
648 | fwd.connect_port = cport; | 669 | free(listen_addr); |
649 | if (*fwd.listen_host == '\0') { | 670 | listen_addr = NULL; |
650 | free(fwd.listen_host); | ||
651 | fwd.listen_host = NULL; | ||
652 | } | 671 | } |
653 | if (*fwd.connect_host == '\0') { | 672 | if (*connect_addr == '\0') { |
654 | free(fwd.connect_host); | 673 | free(connect_addr); |
655 | fwd.connect_host = NULL; | 674 | connect_addr = NULL; |
656 | } | 675 | } |
657 | 676 | ||
677 | memset(&fwd, 0, sizeof(fwd)); | ||
678 | fwd.listen_port = lport; | ||
679 | if (fwd.listen_port == PORT_STREAMLOCAL) | ||
680 | fwd.listen_path = listen_addr; | ||
681 | else | ||
682 | fwd.listen_host = listen_addr; | ||
683 | fwd.connect_port = cport; | ||
684 | if (fwd.connect_port == PORT_STREAMLOCAL) | ||
685 | fwd.connect_path = connect_addr; | ||
686 | else | ||
687 | fwd.connect_host = connect_addr; | ||
688 | |||
658 | debug2("%s: channel %d: request %s", __func__, c->self, | 689 | debug2("%s: channel %d: request %s", __func__, c->self, |
659 | (fwd_desc = format_forward(ftype, &fwd))); | 690 | (fwd_desc = format_forward(ftype, &fwd))); |
660 | 691 | ||
@@ -662,25 +693,30 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
662 | ftype != MUX_FWD_DYNAMIC) { | 693 | ftype != MUX_FWD_DYNAMIC) { |
663 | logit("%s: invalid forwarding type %u", __func__, ftype); | 694 | logit("%s: invalid forwarding type %u", __func__, ftype); |
664 | invalid: | 695 | invalid: |
665 | free(fwd.listen_host); | 696 | free(listen_addr); |
666 | free(fwd.connect_host); | 697 | free(connect_addr); |
667 | buffer_put_int(r, MUX_S_FAILURE); | 698 | buffer_put_int(r, MUX_S_FAILURE); |
668 | buffer_put_int(r, rid); | 699 | buffer_put_int(r, rid); |
669 | buffer_put_cstring(r, "Invalid forwarding request"); | 700 | buffer_put_cstring(r, "Invalid forwarding request"); |
670 | return 0; | 701 | return 0; |
671 | } | 702 | } |
672 | if (fwd.listen_port >= 65536) { | 703 | if (ftype == MUX_FWD_DYNAMIC && fwd.listen_path) { |
704 | logit("%s: streamlocal and dynamic forwards " | ||
705 | "are mutually exclusive", __func__); | ||
706 | goto invalid; | ||
707 | } | ||
708 | if (fwd.listen_port != PORT_STREAMLOCAL && fwd.listen_port >= 65536) { | ||
673 | logit("%s: invalid listen port %u", __func__, | 709 | logit("%s: invalid listen port %u", __func__, |
674 | fwd.listen_port); | 710 | fwd.listen_port); |
675 | goto invalid; | 711 | goto invalid; |
676 | } | 712 | } |
677 | if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC && | 713 | if ((fwd.connect_port != PORT_STREAMLOCAL && fwd.connect_port >= 65536) |
678 | ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { | 714 | || (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { |
679 | logit("%s: invalid connect port %u", __func__, | 715 | logit("%s: invalid connect port %u", __func__, |
680 | fwd.connect_port); | 716 | fwd.connect_port); |
681 | goto invalid; | 717 | goto invalid; |
682 | } | 718 | } |
683 | if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) { | 719 | if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && fwd.connect_path == NULL) { |
684 | logit("%s: missing connect host", __func__); | 720 | logit("%s: missing connect host", __func__); |
685 | goto invalid; | 721 | goto invalid; |
686 | } | 722 | } |
@@ -731,9 +767,8 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
731 | } | 767 | } |
732 | 768 | ||
733 | if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { | 769 | if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { |
734 | if (!channel_setup_local_fwd_listener(fwd.listen_host, | 770 | if (!channel_setup_local_fwd_listener(&fwd, |
735 | fwd.listen_port, fwd.connect_host, fwd.connect_port, | 771 | &options.fwd_opts)) { |
736 | options.gateway_ports)) { | ||
737 | fail: | 772 | fail: |
738 | logit("slave-requested %s failed", fwd_desc); | 773 | logit("slave-requested %s failed", fwd_desc); |
739 | buffer_put_int(r, MUX_S_FAILURE); | 774 | buffer_put_int(r, MUX_S_FAILURE); |
@@ -746,8 +781,7 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
746 | } else { | 781 | } else { |
747 | struct mux_channel_confirm_ctx *fctx; | 782 | struct mux_channel_confirm_ctx *fctx; |
748 | 783 | ||
749 | fwd.handle = channel_request_remote_forwarding(fwd.listen_host, | 784 | fwd.handle = channel_request_remote_forwarding(&fwd); |
750 | fwd.listen_port, fwd.connect_host, fwd.connect_port); | ||
751 | if (fwd.handle < 0) | 785 | if (fwd.handle < 0) |
752 | goto fail; | 786 | goto fail; |
753 | add_remote_forward(&options, &fwd); | 787 | add_remote_forward(&options, &fwd); |
@@ -768,7 +802,9 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
768 | free(fwd_desc); | 802 | free(fwd_desc); |
769 | if (freefwd) { | 803 | if (freefwd) { |
770 | free(fwd.listen_host); | 804 | free(fwd.listen_host); |
805 | free(fwd.listen_path); | ||
771 | free(fwd.connect_host); | 806 | free(fwd.connect_host); |
807 | free(fwd.connect_path); | ||
772 | } | 808 | } |
773 | return ret; | 809 | return ret; |
774 | } | 810 | } |
@@ -776,36 +812,47 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
776 | static int | 812 | static int |
777 | process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | 813 | process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) |
778 | { | 814 | { |
779 | Forward fwd, *found_fwd; | 815 | struct Forward fwd, *found_fwd; |
780 | char *fwd_desc = NULL; | 816 | char *fwd_desc = NULL; |
781 | const char *error_reason = NULL; | 817 | const char *error_reason = NULL; |
818 | char *listen_addr = NULL, *connect_addr = NULL; | ||
782 | u_int ftype; | 819 | u_int ftype; |
783 | int i, listen_port, ret = 0; | 820 | int i, ret = 0; |
784 | u_int lport, cport; | 821 | u_int lport, cport; |
785 | 822 | ||
786 | fwd.listen_host = fwd.connect_host = NULL; | ||
787 | if (buffer_get_int_ret(&ftype, m) != 0 || | 823 | if (buffer_get_int_ret(&ftype, m) != 0 || |
788 | (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || | 824 | (listen_addr = buffer_get_string_ret(m, NULL)) == NULL || |
789 | buffer_get_int_ret(&lport, m) != 0 || | 825 | buffer_get_int_ret(&lport, m) != 0 || |
790 | (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || | 826 | (connect_addr = buffer_get_string_ret(m, NULL)) == NULL || |
791 | buffer_get_int_ret(&cport, m) != 0 || | 827 | buffer_get_int_ret(&cport, m) != 0 || |
792 | lport > 65535 || cport > 65535) { | 828 | (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) || |
829 | (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) { | ||
793 | error("%s: malformed message", __func__); | 830 | error("%s: malformed message", __func__); |
794 | ret = -1; | 831 | ret = -1; |
795 | goto out; | 832 | goto out; |
796 | } | 833 | } |
797 | fwd.listen_port = lport; | ||
798 | fwd.connect_port = cport; | ||
799 | 834 | ||
800 | if (*fwd.listen_host == '\0') { | 835 | if (*listen_addr == '\0') { |
801 | free(fwd.listen_host); | 836 | free(listen_addr); |
802 | fwd.listen_host = NULL; | 837 | listen_addr = NULL; |
803 | } | 838 | } |
804 | if (*fwd.connect_host == '\0') { | 839 | if (*connect_addr == '\0') { |
805 | free(fwd.connect_host); | 840 | free(connect_addr); |
806 | fwd.connect_host = NULL; | 841 | connect_addr = NULL; |
807 | } | 842 | } |
808 | 843 | ||
844 | memset(&fwd, 0, sizeof(fwd)); | ||
845 | fwd.listen_port = lport; | ||
846 | if (fwd.listen_port == PORT_STREAMLOCAL) | ||
847 | fwd.listen_path = listen_addr; | ||
848 | else | ||
849 | fwd.listen_host = listen_addr; | ||
850 | fwd.connect_port = cport; | ||
851 | if (fwd.connect_port == PORT_STREAMLOCAL) | ||
852 | fwd.connect_path = connect_addr; | ||
853 | else | ||
854 | fwd.connect_host = connect_addr; | ||
855 | |||
809 | debug2("%s: channel %d: request cancel %s", __func__, c->self, | 856 | debug2("%s: channel %d: request cancel %s", __func__, c->self, |
810 | (fwd_desc = format_forward(ftype, &fwd))); | 857 | (fwd_desc = format_forward(ftype, &fwd))); |
811 | 858 | ||
@@ -840,18 +887,14 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
840 | * This shouldn't fail unless we confused the host/port | 887 | * This shouldn't fail unless we confused the host/port |
841 | * between options.remote_forwards and permitted_opens. | 888 | * between options.remote_forwards and permitted_opens. |
842 | * However, for dynamic allocated listen ports we need | 889 | * However, for dynamic allocated listen ports we need |
843 | * to lookup the actual listen port. | 890 | * to use the actual listen port. |
844 | */ | 891 | */ |
845 | listen_port = (fwd.listen_port == 0) ? | 892 | if (channel_request_rforward_cancel(found_fwd) == -1) |
846 | found_fwd->allocated_port : fwd.listen_port; | ||
847 | if (channel_request_rforward_cancel(fwd.listen_host, | ||
848 | listen_port) == -1) | ||
849 | error_reason = "port not in permitted opens"; | 893 | error_reason = "port not in permitted opens"; |
850 | } else { /* local and dynamic forwards */ | 894 | } else { /* local and dynamic forwards */ |
851 | /* Ditto */ | 895 | /* Ditto */ |
852 | if (channel_cancel_lport_listener(fwd.listen_host, | 896 | if (channel_cancel_lport_listener(&fwd, fwd.connect_port, |
853 | fwd.listen_port, fwd.connect_port, | 897 | &options.fwd_opts) == -1) |
854 | options.gateway_ports) == -1) | ||
855 | error_reason = "port not found"; | 898 | error_reason = "port not found"; |
856 | } | 899 | } |
857 | 900 | ||
@@ -860,8 +903,11 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
860 | buffer_put_int(r, rid); | 903 | buffer_put_int(r, rid); |
861 | 904 | ||
862 | free(found_fwd->listen_host); | 905 | free(found_fwd->listen_host); |
906 | free(found_fwd->listen_path); | ||
863 | free(found_fwd->connect_host); | 907 | free(found_fwd->connect_host); |
908 | free(found_fwd->connect_path); | ||
864 | found_fwd->listen_host = found_fwd->connect_host = NULL; | 909 | found_fwd->listen_host = found_fwd->connect_host = NULL; |
910 | found_fwd->listen_path = found_fwd->connect_path = NULL; | ||
865 | found_fwd->listen_port = found_fwd->connect_port = 0; | 911 | found_fwd->listen_port = found_fwd->connect_port = 0; |
866 | } else { | 912 | } else { |
867 | buffer_put_int(r, MUX_S_FAILURE); | 913 | buffer_put_int(r, MUX_S_FAILURE); |
@@ -870,8 +916,8 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
870 | } | 916 | } |
871 | out: | 917 | out: |
872 | free(fwd_desc); | 918 | free(fwd_desc); |
873 | free(fwd.listen_host); | 919 | free(listen_addr); |
874 | free(fwd.connect_host); | 920 | free(connect_addr); |
875 | 921 | ||
876 | return ret; | 922 | return ret; |
877 | } | 923 | } |
@@ -883,6 +929,7 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
883 | char *reserved, *chost; | 929 | char *reserved, *chost; |
884 | u_int cport, i, j; | 930 | u_int cport, i, j; |
885 | int new_fd[2]; | 931 | int new_fd[2]; |
932 | struct mux_stdio_confirm_ctx *cctx; | ||
886 | 933 | ||
887 | chost = reserved = NULL; | 934 | chost = reserved = NULL; |
888 | if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || | 935 | if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || |
@@ -962,15 +1009,60 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
962 | 1009 | ||
963 | channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); | 1010 | channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); |
964 | 1011 | ||
965 | /* prepare reply */ | 1012 | cctx = xcalloc(1, sizeof(*cctx)); |
966 | /* XXX defer until channel confirmed */ | 1013 | cctx->rid = rid; |
967 | buffer_put_int(r, MUX_S_SESSION_OPENED); | 1014 | channel_register_open_confirm(nc->self, mux_stdio_confirm, cctx); |
968 | buffer_put_int(r, rid); | 1015 | c->mux_pause = 1; /* stop handling messages until open_confirm done */ |
969 | buffer_put_int(r, nc->self); | ||
970 | 1016 | ||
1017 | /* reply is deferred, sent by mux_session_confirm */ | ||
971 | return 0; | 1018 | return 0; |
972 | } | 1019 | } |
973 | 1020 | ||
1021 | /* Callback on open confirmation in mux master for a mux stdio fwd session. */ | ||
1022 | static void | ||
1023 | mux_stdio_confirm(int id, int success, void *arg) | ||
1024 | { | ||
1025 | struct mux_stdio_confirm_ctx *cctx = arg; | ||
1026 | Channel *c, *cc; | ||
1027 | Buffer reply; | ||
1028 | |||
1029 | if (cctx == NULL) | ||
1030 | fatal("%s: cctx == NULL", __func__); | ||
1031 | if ((c = channel_by_id(id)) == NULL) | ||
1032 | fatal("%s: no channel for id %d", __func__, id); | ||
1033 | if ((cc = channel_by_id(c->ctl_chan)) == NULL) | ||
1034 | fatal("%s: channel %d lacks control channel %d", __func__, | ||
1035 | id, c->ctl_chan); | ||
1036 | |||
1037 | if (!success) { | ||
1038 | debug3("%s: sending failure reply", __func__); | ||
1039 | /* prepare reply */ | ||
1040 | buffer_init(&reply); | ||
1041 | buffer_put_int(&reply, MUX_S_FAILURE); | ||
1042 | buffer_put_int(&reply, cctx->rid); | ||
1043 | buffer_put_cstring(&reply, "Session open refused by peer"); | ||
1044 | goto done; | ||
1045 | } | ||
1046 | |||
1047 | debug3("%s: sending success reply", __func__); | ||
1048 | /* prepare reply */ | ||
1049 | buffer_init(&reply); | ||
1050 | buffer_put_int(&reply, MUX_S_SESSION_OPENED); | ||
1051 | buffer_put_int(&reply, cctx->rid); | ||
1052 | buffer_put_int(&reply, c->self); | ||
1053 | |||
1054 | done: | ||
1055 | /* Send reply */ | ||
1056 | buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); | ||
1057 | buffer_free(&reply); | ||
1058 | |||
1059 | if (cc->mux_pause <= 0) | ||
1060 | fatal("%s: mux_pause %d", __func__, cc->mux_pause); | ||
1061 | cc->mux_pause = 0; /* start processing messages again */ | ||
1062 | c->open_confirm_ctx = NULL; | ||
1063 | free(cctx); | ||
1064 | } | ||
1065 | |||
974 | static int | 1066 | static int |
975 | process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) | 1067 | process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) |
976 | { | 1068 | { |
@@ -1010,7 +1102,7 @@ mux_master_read_cb(Channel *c) | |||
1010 | { | 1102 | { |
1011 | struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; | 1103 | struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; |
1012 | Buffer in, out; | 1104 | Buffer in, out; |
1013 | void *ptr; | 1105 | const u_char *ptr; |
1014 | u_int type, rid, have, i; | 1106 | u_int type, rid, have, i; |
1015 | int ret = -1; | 1107 | int ret = -1; |
1016 | 1108 | ||
@@ -1133,12 +1225,11 @@ mux_tty_alloc_failed(Channel *c) | |||
1133 | void | 1225 | void |
1134 | muxserver_listen(void) | 1226 | muxserver_listen(void) |
1135 | { | 1227 | { |
1136 | struct sockaddr_un addr; | ||
1137 | socklen_t sun_len; | ||
1138 | mode_t old_umask; | 1228 | mode_t old_umask; |
1139 | char *orig_control_path = options.control_path; | 1229 | char *orig_control_path = options.control_path; |
1140 | char rbuf[16+1]; | 1230 | char rbuf[16+1]; |
1141 | u_int i, r; | 1231 | u_int i, r; |
1232 | int oerrno; | ||
1142 | 1233 | ||
1143 | if (options.control_path == NULL || | 1234 | if (options.control_path == NULL || |
1144 | options.control_master == SSHCTL_MASTER_NO) | 1235 | options.control_master == SSHCTL_MASTER_NO) |
@@ -1163,24 +1254,12 @@ muxserver_listen(void) | |||
1163 | xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf); | 1254 | xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf); |
1164 | debug3("%s: temporary control path %s", __func__, options.control_path); | 1255 | debug3("%s: temporary control path %s", __func__, options.control_path); |
1165 | 1256 | ||
1166 | memset(&addr, '\0', sizeof(addr)); | ||
1167 | addr.sun_family = AF_UNIX; | ||
1168 | sun_len = offsetof(struct sockaddr_un, sun_path) + | ||
1169 | strlen(options.control_path) + 1; | ||
1170 | |||
1171 | if (strlcpy(addr.sun_path, options.control_path, | ||
1172 | sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) { | ||
1173 | error("ControlPath \"%s\" too long for Unix domain socket", | ||
1174 | options.control_path); | ||
1175 | goto disable_mux_master; | ||
1176 | } | ||
1177 | |||
1178 | if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) | ||
1179 | fatal("%s socket(): %s", __func__, strerror(errno)); | ||
1180 | |||
1181 | old_umask = umask(0177); | 1257 | old_umask = umask(0177); |
1182 | if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) { | 1258 | muxserver_sock = unix_listener(options.control_path, 64, 0); |
1183 | if (errno == EINVAL || errno == EADDRINUSE) { | 1259 | oerrno = errno; |
1260 | umask(old_umask); | ||
1261 | if (muxserver_sock < 0) { | ||
1262 | if (oerrno == EINVAL || oerrno == EADDRINUSE) { | ||
1184 | error("ControlSocket %s already exists, " | 1263 | error("ControlSocket %s already exists, " |
1185 | "disabling multiplexing", options.control_path); | 1264 | "disabling multiplexing", options.control_path); |
1186 | disable_mux_master: | 1265 | disable_mux_master: |
@@ -1193,13 +1272,11 @@ muxserver_listen(void) | |||
1193 | options.control_path = NULL; | 1272 | options.control_path = NULL; |
1194 | options.control_master = SSHCTL_MASTER_NO; | 1273 | options.control_master = SSHCTL_MASTER_NO; |
1195 | return; | 1274 | return; |
1196 | } else | 1275 | } else { |
1197 | fatal("%s bind(): %s", __func__, strerror(errno)); | 1276 | /* unix_listener() logs the error */ |
1277 | cleanup_exit(255); | ||
1278 | } | ||
1198 | } | 1279 | } |
1199 | umask(old_umask); | ||
1200 | |||
1201 | if (listen(muxserver_sock, 64) == -1) | ||
1202 | fatal("%s listen(): %s", __func__, strerror(errno)); | ||
1203 | 1280 | ||
1204 | /* Now atomically "move" the mux socket into position */ | 1281 | /* Now atomically "move" the mux socket into position */ |
1205 | if (link(options.control_path, orig_control_path) != 0) { | 1282 | if (link(options.control_path, orig_control_path) != 0) { |
@@ -1429,7 +1506,7 @@ mux_client_read_packet(int fd, Buffer *m) | |||
1429 | { | 1506 | { |
1430 | Buffer queue; | 1507 | Buffer queue; |
1431 | u_int need, have; | 1508 | u_int need, have; |
1432 | void *ptr; | 1509 | const u_char *ptr; |
1433 | int oerrno; | 1510 | int oerrno; |
1434 | 1511 | ||
1435 | buffer_init(&queue); | 1512 | buffer_init(&queue); |
@@ -1593,7 +1670,7 @@ mux_client_request_terminate(int fd) | |||
1593 | } | 1670 | } |
1594 | 1671 | ||
1595 | static int | 1672 | static int |
1596 | mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd) | 1673 | mux_client_forward(int fd, int cancel_flag, u_int ftype, struct Forward *fwd) |
1597 | { | 1674 | { |
1598 | Buffer m; | 1675 | Buffer m; |
1599 | char *e, *fwd_desc; | 1676 | char *e, *fwd_desc; |
@@ -1608,11 +1685,19 @@ mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd) | |||
1608 | buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD); | 1685 | buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD); |
1609 | buffer_put_int(&m, muxclient_request_id); | 1686 | buffer_put_int(&m, muxclient_request_id); |
1610 | buffer_put_int(&m, ftype); | 1687 | buffer_put_int(&m, ftype); |
1611 | buffer_put_cstring(&m, | 1688 | if (fwd->listen_path != NULL) { |
1612 | fwd->listen_host == NULL ? "" : fwd->listen_host); | 1689 | buffer_put_cstring(&m, fwd->listen_path); |
1690 | } else { | ||
1691 | buffer_put_cstring(&m, | ||
1692 | fwd->listen_host == NULL ? "" : fwd->listen_host); | ||
1693 | } | ||
1613 | buffer_put_int(&m, fwd->listen_port); | 1694 | buffer_put_int(&m, fwd->listen_port); |
1614 | buffer_put_cstring(&m, | 1695 | if (fwd->connect_path != NULL) { |
1615 | fwd->connect_host == NULL ? "" : fwd->connect_host); | 1696 | buffer_put_cstring(&m, fwd->connect_path); |
1697 | } else { | ||
1698 | buffer_put_cstring(&m, | ||
1699 | fwd->connect_host == NULL ? "" : fwd->connect_host); | ||
1700 | } | ||
1616 | buffer_put_int(&m, fwd->connect_port); | 1701 | buffer_put_int(&m, fwd->connect_port); |
1617 | 1702 | ||
1618 | if (mux_client_write_packet(fd, &m) != 0) | 1703 | if (mux_client_write_packet(fd, &m) != 0) |
@@ -1922,7 +2007,7 @@ mux_client_request_stdio_fwd(int fd) | |||
1922 | case MUX_S_FAILURE: | 2007 | case MUX_S_FAILURE: |
1923 | e = buffer_get_string(&m, NULL); | 2008 | e = buffer_get_string(&m, NULL); |
1924 | buffer_free(&m); | 2009 | buffer_free(&m); |
1925 | fatal("%s: stdio forwarding request failed: %s", __func__, e); | 2010 | fatal("Stdio forwarding request failed: %s", e); |
1926 | default: | 2011 | default: |
1927 | buffer_free(&m); | 2012 | buffer_free(&m); |
1928 | error("%s: unexpected response from master 0x%08x", | 2013 | error("%s: unexpected response from master 0x%08x", |