summaryrefslogtreecommitdiff
path: root/mux.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2010-09-24 22:07:55 +1000
committerDamien Miller <djm@mindrot.org>2010-09-24 22:07:55 +1000
commit603134e077e667b4819effb0e121803842df621f (patch)
tree6a4a91c923103d9b6408ab6ff2be4773884aecbc /mux.c
parent18e1cab1a112052580bbd3f35fbaec15661d098d (diff)
- djm@cvs.openbsd.org 2010/09/20 07:19:27
[mux.c] "atomically" create the listening mux socket by binding it on a temorary name and then linking it into position after listen() has succeeded. this allows the mux clients to determine that the server socket is either ready or stale without races. stale server sockets are now automatically removed ok deraadt
Diffstat (limited to 'mux.c')
-rw-r--r--mux.c50
1 files changed, 46 insertions, 4 deletions
diff --git a/mux.c b/mux.c
index 5c3857ee8..c010b614e 100644
--- a/mux.c
+++ b/mux.c
@@ -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.22 2010/09/20 07:19:27 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 *
@@ -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);
@@ -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 }