diff options
Diffstat (limited to 'mux.c')
-rw-r--r-- | mux.c | 181 |
1 files changed, 152 insertions, 29 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mux.c,v 1.14 2010/01/30 02:54:53 djm Exp $ */ | 1 | /* $OpenBSD: mux.c,v 1.21 2010/06/25 23:15:36 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 | * |
@@ -71,6 +71,7 @@ | |||
71 | #include "xmalloc.h" | 71 | #include "xmalloc.h" |
72 | #include "log.h" | 72 | #include "log.h" |
73 | #include "ssh.h" | 73 | #include "ssh.h" |
74 | #include "ssh2.h" | ||
74 | #include "pathnames.h" | 75 | #include "pathnames.h" |
75 | #include "misc.h" | 76 | #include "misc.h" |
76 | #include "match.h" | 77 | #include "match.h" |
@@ -106,6 +107,14 @@ struct mux_session_confirm_ctx { | |||
106 | char *term; | 107 | char *term; |
107 | struct termios tio; | 108 | struct termios tio; |
108 | char **env; | 109 | char **env; |
110 | u_int rid; | ||
111 | }; | ||
112 | |||
113 | /* Context for global channel callback */ | ||
114 | struct mux_channel_confirm_ctx { | ||
115 | u_int cid; /* channel id */ | ||
116 | u_int rid; /* request id */ | ||
117 | int fid; /* forward id */ | ||
109 | }; | 118 | }; |
110 | 119 | ||
111 | /* fd to control socket */ | 120 | /* fd to control socket */ |
@@ -143,13 +152,14 @@ struct mux_master_state { | |||
143 | #define MUX_S_EXIT_MESSAGE 0x80000004 | 152 | #define MUX_S_EXIT_MESSAGE 0x80000004 |
144 | #define MUX_S_ALIVE 0x80000005 | 153 | #define MUX_S_ALIVE 0x80000005 |
145 | #define MUX_S_SESSION_OPENED 0x80000006 | 154 | #define MUX_S_SESSION_OPENED 0x80000006 |
155 | #define MUX_S_REMOTE_PORT 0x80000007 | ||
146 | 156 | ||
147 | /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ | 157 | /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ |
148 | #define MUX_FWD_LOCAL 1 | 158 | #define MUX_FWD_LOCAL 1 |
149 | #define MUX_FWD_REMOTE 2 | 159 | #define MUX_FWD_REMOTE 2 |
150 | #define MUX_FWD_DYNAMIC 3 | 160 | #define MUX_FWD_DYNAMIC 3 |
151 | 161 | ||
152 | static void mux_session_confirm(int, void *); | 162 | static void mux_session_confirm(int, int, void *); |
153 | 163 | ||
154 | static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); | 164 | static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); |
155 | static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); | 165 | static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); |
@@ -206,7 +216,7 @@ mux_master_control_cleanup_cb(int cid, void *unused) | |||
206 | fatal("%s: channel_by_id(%i) == NULL", __func__, cid); | 216 | fatal("%s: channel_by_id(%i) == NULL", __func__, cid); |
207 | if (c->remote_id != -1) { | 217 | if (c->remote_id != -1) { |
208 | if ((sc = channel_by_id(c->remote_id)) == NULL) | 218 | if ((sc = channel_by_id(c->remote_id)) == NULL) |
209 | debug2("%s: channel %d n session channel %d", | 219 | fatal("%s: channel %d missing session channel %d", |
210 | __func__, c->self, c->remote_id); | 220 | __func__, c->self, c->remote_id); |
211 | c->remote_id = -1; | 221 | c->remote_id = -1; |
212 | sc->ctl_chan = -1; | 222 | sc->ctl_chan = -1; |
@@ -301,6 +311,7 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
301 | /* Reply for SSHMUX_COMMAND_OPEN */ | 311 | /* Reply for SSHMUX_COMMAND_OPEN */ |
302 | cctx = xcalloc(1, sizeof(*cctx)); | 312 | cctx = xcalloc(1, sizeof(*cctx)); |
303 | cctx->term = NULL; | 313 | cctx->term = NULL; |
314 | cctx->rid = rid; | ||
304 | cmd = reserved = NULL; | 315 | cmd = reserved = NULL; |
305 | if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || | 316 | if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || |
306 | buffer_get_int_ret(&cctx->want_tty, m) != 0 || | 317 | buffer_get_int_ret(&cctx->want_tty, m) != 0 || |
@@ -454,14 +465,10 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
454 | 465 | ||
455 | channel_send_open(nc->self); | 466 | channel_send_open(nc->self); |
456 | channel_register_open_confirm(nc->self, mux_session_confirm, cctx); | 467 | channel_register_open_confirm(nc->self, mux_session_confirm, cctx); |
457 | channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 0); | 468 | c->mux_pause = 1; /* stop handling messages until open_confirm done */ |
458 | 469 | channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); | |
459 | /* prepare reply */ | ||
460 | /* XXX defer until mux_session_confirm() fires */ | ||
461 | buffer_put_int(r, MUX_S_SESSION_OPENED); | ||
462 | buffer_put_int(r, rid); | ||
463 | buffer_put_int(r, nc->self); | ||
464 | 470 | ||
471 | /* reply is deferred, sent by mux_session_confirm */ | ||
465 | return 0; | 472 | return 0; |
466 | } | 473 | } |
467 | 474 | ||
@@ -559,6 +566,61 @@ compare_forward(Forward *a, Forward *b) | |||
559 | return 1; | 566 | return 1; |
560 | } | 567 | } |
561 | 568 | ||
569 | static void | ||
570 | mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) | ||
571 | { | ||
572 | struct mux_channel_confirm_ctx *fctx = ctxt; | ||
573 | char *failmsg = NULL; | ||
574 | Forward *rfwd; | ||
575 | Channel *c; | ||
576 | Buffer out; | ||
577 | |||
578 | if ((c = channel_by_id(fctx->cid)) == NULL) { | ||
579 | /* no channel for reply */ | ||
580 | error("%s: unknown channel", __func__); | ||
581 | return; | ||
582 | } | ||
583 | buffer_init(&out); | ||
584 | if (fctx->fid >= options.num_remote_forwards) { | ||
585 | xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid); | ||
586 | goto fail; | ||
587 | } | ||
588 | rfwd = &options.remote_forwards[fctx->fid]; | ||
589 | debug("%s: %s for: listen %d, connect %s:%d", __func__, | ||
590 | type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", | ||
591 | rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); | ||
592 | if (type == SSH2_MSG_REQUEST_SUCCESS) { | ||
593 | if (rfwd->listen_port == 0) { | ||
594 | rfwd->allocated_port = packet_get_int(); | ||
595 | logit("Allocated port %u for mux remote forward" | ||
596 | " to %s:%d", rfwd->allocated_port, | ||
597 | rfwd->connect_host, rfwd->connect_port); | ||
598 | buffer_put_int(&out, MUX_S_REMOTE_PORT); | ||
599 | buffer_put_int(&out, fctx->rid); | ||
600 | buffer_put_int(&out, rfwd->allocated_port); | ||
601 | } else { | ||
602 | buffer_put_int(&out, MUX_S_OK); | ||
603 | buffer_put_int(&out, fctx->rid); | ||
604 | } | ||
605 | goto out; | ||
606 | } else { | ||
607 | xasprintf(&failmsg, "remote port forwarding failed for " | ||
608 | "listen port %d", rfwd->listen_port); | ||
609 | } | ||
610 | fail: | ||
611 | error("%s: %s", __func__, failmsg); | ||
612 | buffer_put_int(&out, MUX_S_FAILURE); | ||
613 | buffer_put_int(&out, fctx->rid); | ||
614 | buffer_put_cstring(&out, failmsg); | ||
615 | xfree(failmsg); | ||
616 | out: | ||
617 | buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out)); | ||
618 | buffer_free(&out); | ||
619 | if (c->mux_pause <= 0) | ||
620 | fatal("%s: mux_pause %d", __func__, c->mux_pause); | ||
621 | c->mux_pause = 0; /* start processing messages again */ | ||
622 | } | ||
623 | |||
562 | static int | 624 | static int |
563 | process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | 625 | process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) |
564 | { | 626 | { |
@@ -594,15 +656,16 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
594 | ftype != MUX_FWD_DYNAMIC) { | 656 | ftype != MUX_FWD_DYNAMIC) { |
595 | logit("%s: invalid forwarding type %u", __func__, ftype); | 657 | logit("%s: invalid forwarding type %u", __func__, ftype); |
596 | invalid: | 658 | invalid: |
597 | xfree(fwd.listen_host); | 659 | if (fwd.listen_host) |
598 | xfree(fwd.connect_host); | 660 | xfree(fwd.listen_host); |
661 | if (fwd.connect_host) | ||
662 | xfree(fwd.connect_host); | ||
599 | buffer_put_int(r, MUX_S_FAILURE); | 663 | buffer_put_int(r, MUX_S_FAILURE); |
600 | buffer_put_int(r, rid); | 664 | buffer_put_int(r, rid); |
601 | buffer_put_cstring(r, "Invalid forwarding request"); | 665 | buffer_put_cstring(r, "Invalid forwarding request"); |
602 | return 0; | 666 | return 0; |
603 | } | 667 | } |
604 | /* XXX support rport0 forwarding with reply of port assigned */ | 668 | if (fwd.listen_port >= 65536) { |
605 | if (fwd.listen_port == 0 || fwd.listen_port >= 65536) { | ||
606 | logit("%s: invalid listen port %u", __func__, | 669 | logit("%s: invalid listen port %u", __func__, |
607 | fwd.listen_port); | 670 | fwd.listen_port); |
608 | goto invalid; | 671 | goto invalid; |
@@ -637,8 +700,17 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
637 | case MUX_FWD_REMOTE: | 700 | case MUX_FWD_REMOTE: |
638 | for (i = 0; i < options.num_remote_forwards; i++) { | 701 | for (i = 0; i < options.num_remote_forwards; i++) { |
639 | if (compare_forward(&fwd, | 702 | if (compare_forward(&fwd, |
640 | options.remote_forwards + i)) | 703 | options.remote_forwards + i)) { |
641 | goto exists; | 704 | if (fwd.listen_port != 0) |
705 | goto exists; | ||
706 | debug2("%s: found allocated port", | ||
707 | __func__); | ||
708 | buffer_put_int(r, MUX_S_REMOTE_PORT); | ||
709 | buffer_put_int(r, rid); | ||
710 | buffer_put_int(r, | ||
711 | options.remote_forwards[i].allocated_port); | ||
712 | goto out; | ||
713 | } | ||
642 | } | 714 | } |
643 | break; | 715 | break; |
644 | } | 716 | } |
@@ -655,9 +727,7 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
655 | } | 727 | } |
656 | 728 | ||
657 | if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { | 729 | if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { |
658 | if (options.num_local_forwards + 1 >= | 730 | if (channel_setup_local_fwd_listener(fwd.listen_host, |
659 | SSH_MAX_FORWARDS_PER_DIRECTION || | ||
660 | channel_setup_local_fwd_listener(fwd.listen_host, | ||
661 | fwd.listen_port, fwd.connect_host, fwd.connect_port, | 731 | fwd.listen_port, fwd.connect_host, fwd.connect_port, |
662 | options.gateway_ports) < 0) { | 732 | options.gateway_ports) < 0) { |
663 | fail: | 733 | fail: |
@@ -670,14 +740,22 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
670 | add_local_forward(&options, &fwd); | 740 | add_local_forward(&options, &fwd); |
671 | freefwd = 0; | 741 | freefwd = 0; |
672 | } else { | 742 | } else { |
673 | /* XXX wait for remote to confirm */ | 743 | struct mux_channel_confirm_ctx *fctx; |
674 | if (options.num_remote_forwards + 1 >= | 744 | |
675 | SSH_MAX_FORWARDS_PER_DIRECTION || | 745 | if (channel_request_remote_forwarding(fwd.listen_host, |
676 | channel_request_remote_forwarding(fwd.listen_host, | ||
677 | fwd.listen_port, fwd.connect_host, fwd.connect_port) < 0) | 746 | fwd.listen_port, fwd.connect_host, fwd.connect_port) < 0) |
678 | goto fail; | 747 | goto fail; |
679 | add_remote_forward(&options, &fwd); | 748 | add_remote_forward(&options, &fwd); |
749 | fctx = xcalloc(1, sizeof(*fctx)); | ||
750 | fctx->cid = c->self; | ||
751 | fctx->rid = rid; | ||
752 | fctx->fid = options.num_remote_forwards - 1; | ||
753 | client_register_global_confirm(mux_confirm_remote_forward, | ||
754 | fctx); | ||
680 | freefwd = 0; | 755 | freefwd = 0; |
756 | c->mux_pause = 1; /* wait for mux_confirm_remote_forward */ | ||
757 | /* delayed reply in mux_confirm_remote_forward */ | ||
758 | goto out; | ||
681 | } | 759 | } |
682 | buffer_put_int(r, MUX_S_OK); | 760 | buffer_put_int(r, MUX_S_OK); |
683 | buffer_put_int(r, rid); | 761 | buffer_put_int(r, rid); |
@@ -826,7 +904,7 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
826 | debug2("%s: channel_new: %d linked to control channel %d", | 904 | debug2("%s: channel_new: %d linked to control channel %d", |
827 | __func__, nc->self, nc->ctl_chan); | 905 | __func__, nc->self, nc->ctl_chan); |
828 | 906 | ||
829 | channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 0); | 907 | channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); |
830 | 908 | ||
831 | /* prepare reply */ | 909 | /* prepare reply */ |
832 | /* XXX defer until channel confirmed */ | 910 | /* XXX defer until channel confirmed */ |
@@ -849,7 +927,7 @@ mux_master_read_cb(Channel *c) | |||
849 | 927 | ||
850 | /* Setup ctx and */ | 928 | /* Setup ctx and */ |
851 | if (c->mux_ctx == NULL) { | 929 | if (c->mux_ctx == NULL) { |
852 | state = xcalloc(1, sizeof(state)); | 930 | state = xcalloc(1, sizeof(*state)); |
853 | c->mux_ctx = state; | 931 | c->mux_ctx = state; |
854 | channel_register_cleanup(c->self, | 932 | channel_register_cleanup(c->self, |
855 | mux_master_control_cleanup_cb, 0); | 933 | mux_master_control_cleanup_cb, 0); |
@@ -1000,26 +1078,43 @@ muxserver_listen(void) | |||
1000 | 1078 | ||
1001 | /* Callback on open confirmation in mux master for a mux client session. */ | 1079 | /* Callback on open confirmation in mux master for a mux client session. */ |
1002 | static void | 1080 | static void |
1003 | mux_session_confirm(int id, void *arg) | 1081 | mux_session_confirm(int id, int success, void *arg) |
1004 | { | 1082 | { |
1005 | struct mux_session_confirm_ctx *cctx = arg; | 1083 | struct mux_session_confirm_ctx *cctx = arg; |
1006 | const char *display; | 1084 | const char *display; |
1007 | Channel *c; | 1085 | Channel *c, *cc; |
1008 | int i; | 1086 | int i; |
1087 | Buffer reply; | ||
1009 | 1088 | ||
1010 | if (cctx == NULL) | 1089 | if (cctx == NULL) |
1011 | fatal("%s: cctx == NULL", __func__); | 1090 | fatal("%s: cctx == NULL", __func__); |
1012 | if ((c = channel_by_id(id)) == NULL) | 1091 | if ((c = channel_by_id(id)) == NULL) |
1013 | fatal("%s: no channel for id %d", __func__, id); | 1092 | fatal("%s: no channel for id %d", __func__, id); |
1093 | if ((cc = channel_by_id(c->ctl_chan)) == NULL) | ||
1094 | fatal("%s: channel %d lacks control channel %d", __func__, | ||
1095 | id, c->ctl_chan); | ||
1096 | |||
1097 | if (!success) { | ||
1098 | debug3("%s: sending failure reply", __func__); | ||
1099 | /* prepare reply */ | ||
1100 | buffer_init(&reply); | ||
1101 | buffer_put_int(&reply, MUX_S_FAILURE); | ||
1102 | buffer_put_int(&reply, cctx->rid); | ||
1103 | buffer_put_cstring(&reply, "Session open refused by peer"); | ||
1104 | goto done; | ||
1105 | } | ||
1014 | 1106 | ||
1015 | display = getenv("DISPLAY"); | 1107 | display = getenv("DISPLAY"); |
1016 | if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { | 1108 | if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { |
1017 | char *proto, *data; | 1109 | char *proto, *data; |
1110 | |||
1018 | /* Get reasonable local authentication information. */ | 1111 | /* Get reasonable local authentication information. */ |
1019 | client_x11_get_proto(display, options.xauth_location, | 1112 | client_x11_get_proto(display, options.xauth_location, |
1020 | options.forward_x11_trusted, &proto, &data); | 1113 | options.forward_x11_trusted, options.forward_x11_timeout, |
1114 | &proto, &data); | ||
1021 | /* Request forwarding with authentication spoofing. */ | 1115 | /* Request forwarding with authentication spoofing. */ |
1022 | debug("Requesting X11 forwarding with authentication spoofing."); | 1116 | debug("Requesting X11 forwarding with authentication " |
1117 | "spoofing."); | ||
1023 | x11_request_forwarding_with_spoofing(id, display, proto, data); | 1118 | x11_request_forwarding_with_spoofing(id, display, proto, data); |
1024 | /* XXX wait for reply */ | 1119 | /* XXX wait for reply */ |
1025 | } | 1120 | } |
@@ -1033,6 +1128,21 @@ mux_session_confirm(int id, void *arg) | |||
1033 | client_session2_setup(id, cctx->want_tty, cctx->want_subsys, | 1128 | client_session2_setup(id, cctx->want_tty, cctx->want_subsys, |
1034 | cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); | 1129 | cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); |
1035 | 1130 | ||
1131 | debug3("%s: sending success reply", __func__); | ||
1132 | /* prepare reply */ | ||
1133 | buffer_init(&reply); | ||
1134 | buffer_put_int(&reply, MUX_S_SESSION_OPENED); | ||
1135 | buffer_put_int(&reply, cctx->rid); | ||
1136 | buffer_put_int(&reply, c->self); | ||
1137 | |||
1138 | done: | ||
1139 | /* Send reply */ | ||
1140 | buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); | ||
1141 | buffer_free(&reply); | ||
1142 | |||
1143 | if (cc->mux_pause <= 0) | ||
1144 | fatal("%s: mux_pause %d", __func__, cc->mux_pause); | ||
1145 | cc->mux_pause = 0; /* start processing messages again */ | ||
1036 | c->open_confirm_ctx = NULL; | 1146 | c->open_confirm_ctx = NULL; |
1037 | buffer_free(&cctx->cmd); | 1147 | buffer_free(&cctx->cmd); |
1038 | xfree(cctx->term); | 1148 | xfree(cctx->term); |
@@ -1365,6 +1475,15 @@ mux_client_request_forward(int fd, u_int ftype, Forward *fwd) | |||
1365 | switch (type) { | 1475 | switch (type) { |
1366 | case MUX_S_OK: | 1476 | case MUX_S_OK: |
1367 | break; | 1477 | break; |
1478 | case MUX_S_REMOTE_PORT: | ||
1479 | fwd->allocated_port = buffer_get_int(&m); | ||
1480 | logit("Allocated port %u for remote forward to %s:%d", | ||
1481 | fwd->allocated_port, | ||
1482 | fwd->connect_host ? fwd->connect_host : "", | ||
1483 | fwd->connect_port); | ||
1484 | if (muxclient_command == SSHMUX_COMMAND_FORWARD) | ||
1485 | fprintf(stdout, "%u\n", fwd->allocated_port); | ||
1486 | break; | ||
1368 | case MUX_S_PERMISSION_DENIED: | 1487 | case MUX_S_PERMISSION_DENIED: |
1369 | e = buffer_get_string(&m, NULL); | 1488 | e = buffer_get_string(&m, NULL); |
1370 | buffer_free(&m); | 1489 | buffer_free(&m); |
@@ -1731,6 +1850,10 @@ muxclient(const char *path) | |||
1731 | mux_client_request_terminate(sock); | 1850 | mux_client_request_terminate(sock); |
1732 | fprintf(stderr, "Exit request sent.\r\n"); | 1851 | fprintf(stderr, "Exit request sent.\r\n"); |
1733 | exit(0); | 1852 | exit(0); |
1853 | case SSHMUX_COMMAND_FORWARD: | ||
1854 | if (mux_client_request_forwards(sock) != 0) | ||
1855 | fatal("%s: master forward request failed", __func__); | ||
1856 | exit(0); | ||
1734 | case SSHMUX_COMMAND_OPEN: | 1857 | case SSHMUX_COMMAND_OPEN: |
1735 | if (mux_client_request_forwards(sock) != 0) { | 1858 | if (mux_client_request_forwards(sock) != 0) { |
1736 | error("%s: master forward request failed", __func__); | 1859 | error("%s: master forward request failed", __func__); |