diff options
Diffstat (limited to 'mux.c')
-rw-r--r-- | mux.c | 60 |
1 files changed, 51 insertions, 9 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mux.c,v 1.21 2010/06/25 23:15:36 djm Exp $ */ | 1 | /* $OpenBSD: mux.c,v 1.24 2011/01/13 21:54:53 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 | * |
@@ -879,7 +879,7 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
879 | 879 | ||
880 | if (options.control_master == SSHCTL_MASTER_ASK || | 880 | if (options.control_master == SSHCTL_MASTER_ASK || |
881 | options.control_master == SSHCTL_MASTER_AUTO_ASK) { | 881 | options.control_master == SSHCTL_MASTER_AUTO_ASK) { |
882 | if (!ask_permission("Allow forward to to %s:%u? ", | 882 | if (!ask_permission("Allow forward to %s:%u? ", |
883 | chost, cport)) { | 883 | chost, cport)) { |
884 | debug2("%s: stdio fwd refused by user", __func__); | 884 | debug2("%s: stdio fwd refused by user", __func__); |
885 | /* prepare reply */ | 885 | /* prepare reply */ |
@@ -1026,6 +1026,9 @@ muxserver_listen(void) | |||
1026 | struct sockaddr_un addr; | 1026 | struct sockaddr_un addr; |
1027 | socklen_t sun_len; | 1027 | socklen_t sun_len; |
1028 | mode_t old_umask; | 1028 | mode_t old_umask; |
1029 | char *orig_control_path = options.control_path; | ||
1030 | char rbuf[16+1]; | ||
1031 | u_int i, r; | ||
1029 | 1032 | ||
1030 | if (options.control_path == NULL || | 1033 | if (options.control_path == NULL || |
1031 | options.control_master == SSHCTL_MASTER_NO) | 1034 | options.control_master == SSHCTL_MASTER_NO) |
@@ -1033,6 +1036,23 @@ muxserver_listen(void) | |||
1033 | 1036 | ||
1034 | debug("setting up multiplex master socket"); | 1037 | debug("setting up multiplex master socket"); |
1035 | 1038 | ||
1039 | /* | ||
1040 | * Use a temporary path before listen so we can pseudo-atomically | ||
1041 | * establish the listening socket in its final location to avoid | ||
1042 | * other processes racing in between bind() and listen() and hitting | ||
1043 | * an unready socket. | ||
1044 | */ | ||
1045 | for (i = 0; i < sizeof(rbuf) - 1; i++) { | ||
1046 | r = arc4random_uniform(26+26+10); | ||
1047 | rbuf[i] = (r < 26) ? 'a' + r : | ||
1048 | (r < 26*2) ? 'A' + r - 26 : | ||
1049 | '0' + r - 26 - 26; | ||
1050 | } | ||
1051 | rbuf[sizeof(rbuf) - 1] = '\0'; | ||
1052 | options.control_path = NULL; | ||
1053 | xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf); | ||
1054 | debug3("%s: temporary control path %s", __func__, options.control_path); | ||
1055 | |||
1036 | memset(&addr, '\0', sizeof(addr)); | 1056 | memset(&addr, '\0', sizeof(addr)); |
1037 | addr.sun_family = AF_UNIX; | 1057 | addr.sun_family = AF_UNIX; |
1038 | sun_len = offsetof(struct sockaddr_un, sun_path) + | 1058 | sun_len = offsetof(struct sockaddr_un, sun_path) + |
@@ -1051,6 +1071,7 @@ muxserver_listen(void) | |||
1051 | if (errno == EINVAL || errno == EADDRINUSE) { | 1071 | if (errno == EINVAL || errno == EADDRINUSE) { |
1052 | error("ControlSocket %s already exists, " | 1072 | error("ControlSocket %s already exists, " |
1053 | "disabling multiplexing", options.control_path); | 1073 | "disabling multiplexing", options.control_path); |
1074 | disable_mux_master: | ||
1054 | close(muxserver_sock); | 1075 | close(muxserver_sock); |
1055 | muxserver_sock = -1; | 1076 | muxserver_sock = -1; |
1056 | xfree(options.control_path); | 1077 | xfree(options.control_path); |
@@ -1065,12 +1086,29 @@ muxserver_listen(void) | |||
1065 | if (listen(muxserver_sock, 64) == -1) | 1086 | if (listen(muxserver_sock, 64) == -1) |
1066 | fatal("%s listen(): %s", __func__, strerror(errno)); | 1087 | fatal("%s listen(): %s", __func__, strerror(errno)); |
1067 | 1088 | ||
1089 | /* Now atomically "move" the mux socket into position */ | ||
1090 | if (link(options.control_path, orig_control_path) != 0) { | ||
1091 | if (errno != EEXIST) { | ||
1092 | fatal("%s: link mux listener %s => %s: %s", __func__, | ||
1093 | options.control_path, orig_control_path, | ||
1094 | strerror(errno)); | ||
1095 | } | ||
1096 | error("ControlSocket %s already exists, disabling multiplexing", | ||
1097 | orig_control_path); | ||
1098 | xfree(orig_control_path); | ||
1099 | unlink(options.control_path); | ||
1100 | goto disable_mux_master; | ||
1101 | } | ||
1102 | unlink(options.control_path); | ||
1103 | xfree(options.control_path); | ||
1104 | options.control_path = orig_control_path; | ||
1105 | |||
1068 | set_nonblock(muxserver_sock); | 1106 | set_nonblock(muxserver_sock); |
1069 | 1107 | ||
1070 | mux_listener_channel = channel_new("mux listener", | 1108 | mux_listener_channel = channel_new("mux listener", |
1071 | SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, | 1109 | SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, |
1072 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, | 1110 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
1073 | 0, addr.sun_path, 1); | 1111 | 0, options.control_path, 1); |
1074 | mux_listener_channel->mux_rcb = mux_master_read_cb; | 1112 | mux_listener_channel->mux_rcb = mux_master_read_cb; |
1075 | debug3("%s: mux listener channel %d fd %d", __func__, | 1113 | debug3("%s: mux listener channel %d fd %d", __func__, |
1076 | mux_listener_channel->self, mux_listener_channel->sock); | 1114 | mux_listener_channel->self, mux_listener_channel->sock); |
@@ -1492,7 +1530,7 @@ mux_client_request_forward(int fd, u_int ftype, Forward *fwd) | |||
1492 | case MUX_S_FAILURE: | 1530 | case MUX_S_FAILURE: |
1493 | e = buffer_get_string(&m, NULL); | 1531 | e = buffer_get_string(&m, NULL); |
1494 | buffer_free(&m); | 1532 | buffer_free(&m); |
1495 | error("%s: session request failed: %s", __func__, e); | 1533 | error("%s: forwarding request failed: %s", __func__, e); |
1496 | return -1; | 1534 | return -1; |
1497 | default: | 1535 | default: |
1498 | fatal("%s: unexpected response from master 0x%08x", | 1536 | fatal("%s: unexpected response from master 0x%08x", |
@@ -1611,12 +1649,12 @@ mux_client_request_session(int fd) | |||
1611 | case MUX_S_PERMISSION_DENIED: | 1649 | case MUX_S_PERMISSION_DENIED: |
1612 | e = buffer_get_string(&m, NULL); | 1650 | e = buffer_get_string(&m, NULL); |
1613 | buffer_free(&m); | 1651 | buffer_free(&m); |
1614 | error("Master refused forwarding request: %s", e); | 1652 | error("Master refused session request: %s", e); |
1615 | return -1; | 1653 | return -1; |
1616 | case MUX_S_FAILURE: | 1654 | case MUX_S_FAILURE: |
1617 | e = buffer_get_string(&m, NULL); | 1655 | e = buffer_get_string(&m, NULL); |
1618 | buffer_free(&m); | 1656 | buffer_free(&m); |
1619 | error("%s: forwarding request failed: %s", __func__, e); | 1657 | error("%s: session request failed: %s", __func__, e); |
1620 | return -1; | 1658 | return -1; |
1621 | default: | 1659 | default: |
1622 | buffer_free(&m); | 1660 | buffer_free(&m); |
@@ -1743,7 +1781,7 @@ mux_client_request_stdio_fwd(int fd) | |||
1743 | case MUX_S_PERMISSION_DENIED: | 1781 | case MUX_S_PERMISSION_DENIED: |
1744 | e = buffer_get_string(&m, NULL); | 1782 | e = buffer_get_string(&m, NULL); |
1745 | buffer_free(&m); | 1783 | buffer_free(&m); |
1746 | fatal("Master refused forwarding request: %s", e); | 1784 | fatal("Master refused stdio forwarding request: %s", e); |
1747 | case MUX_S_FAILURE: | 1785 | case MUX_S_FAILURE: |
1748 | e = buffer_get_string(&m, NULL); | 1786 | e = buffer_get_string(&m, NULL); |
1749 | buffer_free(&m); | 1787 | buffer_free(&m); |
@@ -1823,9 +1861,13 @@ muxclient(const char *path) | |||
1823 | fatal("Control socket connect(%.100s): %s", path, | 1861 | fatal("Control socket connect(%.100s): %s", path, |
1824 | strerror(errno)); | 1862 | strerror(errno)); |
1825 | } | 1863 | } |
1826 | if (errno == ENOENT) | 1864 | if (errno == ECONNREFUSED && |
1865 | options.control_master != SSHCTL_MASTER_NO) { | ||
1866 | debug("Stale control socket %.100s, unlinking", path); | ||
1867 | unlink(path); | ||
1868 | } else if (errno == ENOENT) { | ||
1827 | debug("Control socket \"%.100s\" does not exist", path); | 1869 | debug("Control socket \"%.100s\" does not exist", path); |
1828 | else { | 1870 | } else { |
1829 | error("Control socket connect(%.100s): %s", path, | 1871 | error("Control socket connect(%.100s): %s", path, |
1830 | strerror(errno)); | 1872 | strerror(errno)); |
1831 | } | 1873 | } |