version 1.21, 2010/06/25 23:15:36 |
version 1.22, 2010/09/20 07:19:27 |
|
|
{ |
{ |
struct sockaddr_un addr; |
struct sockaddr_un addr; |
mode_t old_umask; |
mode_t old_umask; |
|
char *orig_control_path = options.control_path; |
|
char rbuf[16+1]; |
|
u_int i, r; |
|
|
if (options.control_path == NULL || |
if (options.control_path == NULL || |
options.control_master == SSHCTL_MASTER_NO) |
options.control_master == SSHCTL_MASTER_NO) |
|
|
|
|
debug("setting up multiplex master socket"); |
debug("setting up multiplex master socket"); |
|
|
|
/* |
|
* Use a temporary path before listen so we can pseudo-atomically |
|
* establish the listening socket in its final location to avoid |
|
* other processes racing in between bind() and listen() and hitting |
|
* an unready socket. |
|
*/ |
|
for (i = 0; i < sizeof(rbuf) - 1; i++) { |
|
r = arc4random_uniform(26+26+10); |
|
rbuf[i] = (r < 26) ? 'a' + r : |
|
(r < 26*2) ? 'A' + r - 26 : |
|
'0' + r - 26 - 26; |
|
} |
|
rbuf[sizeof(rbuf) - 1] = '\0'; |
|
options.control_path = NULL; |
|
xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf); |
|
debug3("%s: temporary control path %s", __func__, options.control_path); |
|
|
memset(&addr, '\0', sizeof(addr)); |
memset(&addr, '\0', sizeof(addr)); |
addr.sun_family = AF_UNIX; |
addr.sun_family = AF_UNIX; |
addr.sun_len = offsetof(struct sockaddr_un, sun_path) + |
addr.sun_len = offsetof(struct sockaddr_un, sun_path) + |
|
|
if (errno == EINVAL || errno == EADDRINUSE) { |
if (errno == EINVAL || errno == EADDRINUSE) { |
error("ControlSocket %s already exists, " |
error("ControlSocket %s already exists, " |
"disabling multiplexing", options.control_path); |
"disabling multiplexing", options.control_path); |
|
disable_mux_master: |
close(muxserver_sock); |
close(muxserver_sock); |
muxserver_sock = -1; |
muxserver_sock = -1; |
xfree(options.control_path); |
xfree(options.control_path); |
|
|
if (listen(muxserver_sock, 64) == -1) |
if (listen(muxserver_sock, 64) == -1) |
fatal("%s listen(): %s", __func__, strerror(errno)); |
fatal("%s listen(): %s", __func__, strerror(errno)); |
|
|
|
/* Now atomically "move" the mux socket into position */ |
|
if (link(options.control_path, orig_control_path) != 0) { |
|
if (errno != EEXIST) { |
|
fatal("%s: link mux listener %s => %s: %s", __func__, |
|
options.control_path, orig_control_path, |
|
strerror(errno)); |
|
} |
|
error("ControlSocket %s already exists, disabling multiplexing", |
|
orig_control_path); |
|
xfree(orig_control_path); |
|
unlink(options.control_path); |
|
goto disable_mux_master; |
|
} |
|
unlink(options.control_path); |
|
xfree(options.control_path); |
|
options.control_path = orig_control_path; |
|
|
set_nonblock(muxserver_sock); |
set_nonblock(muxserver_sock); |
|
|
mux_listener_channel = channel_new("mux listener", |
mux_listener_channel = channel_new("mux listener", |
SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, |
SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
0, addr.sun_path, 1); |
0, options.control_path, 1); |
mux_listener_channel->mux_rcb = mux_master_read_cb; |
mux_listener_channel->mux_rcb = mux_master_read_cb; |
debug3("%s: mux listener channel %d fd %d", __func__, |
debug3("%s: mux listener channel %d fd %d", __func__, |
mux_listener_channel->self, mux_listener_channel->sock); |
mux_listener_channel->self, mux_listener_channel->sock); |
|
|
fatal("Control socket connect(%.100s): %s", path, |
fatal("Control socket connect(%.100s): %s", path, |
strerror(errno)); |
strerror(errno)); |
} |
} |
if (errno == ENOENT) |
if (errno == ECONNREFUSED && |
|
options.control_master != SSHCTL_MASTER_NO) { |
|
debug("Stale control socket %.100s, unlinking", path); |
|
unlink(path); |
|
} else if (errno == ENOENT) { |
debug("Control socket \"%.100s\" does not exist", path); |
debug("Control socket \"%.100s\" does not exist", path); |
else { |
} else { |
error("Control socket connect(%.100s): %s", path, |
error("Control socket connect(%.100s): %s", path, |
strerror(errno)); |
strerror(errno)); |
} |
} |