]> andersk Git - openssh.git/blobdiff - mux.c
- (dtucker) [sftp-common.c] Wrap include of util.h in an ifdef.
[openssh.git] / mux.c
diff --git a/mux.c b/mux.c
index 8b9105b0402e50988e186aed6a2f33bba975f363..239edd5f5e36737cb1aa5c7ba3c984c208b632c6 100644 (file)
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mux.c,v 1.1 2008/05/09 14:18:44 djm Exp $ */
+/* $OpenBSD: mux.c,v 1.9 2010/01/09 05:04:24 djm Exp $ */
 /*
  * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
  *
 
 #include "includes.h"
 
+/*
+ * TODO:
+ *   1. partial reads in muxserver_accept_control (maybe make channels
+ *      from accepted connections)
+ *   2. Better signalling from master to slave, especially passing of
+ *      error messages
+ *   3. Better fall-back from mux slave error to new connection.
+ *   3. Add/delete forwardings via slave
+ *   4. ExitOnForwardingFailure (after #3 obviously)
+ *   5. Maybe extension mechanisms for multi-X11/multi-agent forwarding
+ *   6. Document the mux mini-protocol somewhere.
+ *   7. Support ~^Z in mux slaves.
+ *   8. Inspect or control sessions in master.
+ *   9. If we ever support the "signal" channel request, send signals on
+ *      sessions in master.
+ */
+
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 
 /* from ssh.c */
 extern int tty_flag;
+extern int force_tty_flag;
 extern Options options;
 extern int stdin_null_flag;
 extern char *host;
-int subsystem_flag;
+extern int subsystem_flag;
 extern Buffer command;
 
+/* Context for session open confirmation callback */
+struct mux_session_confirm_ctx {
+       int want_tty;
+       int want_subsys;
+       int want_x_fwd;
+       int want_agent_fwd;
+       Buffer cmd;
+       char *term;
+       struct termios tio;
+       char **env;
+};
+
 /* fd to control socket */
 int muxserver_sock = -1;
 
@@ -115,10 +145,16 @@ muxserver_listen(void)
        old_umask = umask(0177);
        if (bind(muxserver_sock, (struct sockaddr *)&addr, addr_len) == -1) {
                muxserver_sock = -1;
-               if (errno == EINVAL || errno == EADDRINUSE)
-                       fatal("ControlSocket %s already exists",
-                           options.control_path);
-               else
+               if (errno == EINVAL || errno == EADDRINUSE) {
+                       error("ControlSocket %s already exists, "
+                           "disabling multiplexing", options.control_path);
+                       close(muxserver_sock);
+                       muxserver_sock = -1;
+                       xfree(options.control_path);
+                       options.control_path = NULL;
+                       options.control_master = SSHCTL_MASTER_NO;
+                       return;
+               } else
                        fatal("%s bind(): %s", __func__, strerror(errno));
        }
        umask(old_umask);
@@ -131,7 +167,7 @@ muxserver_listen(void)
 
 /* Callback on open confirmation in mux master for a mux client session. */
 static void
-client_extra_session2_setup(int id, void *arg)
+mux_session_confirm(int id, void *arg)
 {
        struct mux_session_confirm_ctx *cctx = arg;
        const char *display;
@@ -190,7 +226,7 @@ muxserver_accept_control(void)
        struct sockaddr_storage addr;
        struct mux_session_confirm_ctx *cctx;
        char *cmd;
-       u_int i, j, len, env_len, mux_command, flags;
+       u_int i, j, len, env_len, mux_command, flags, escape_char;
        uid_t euid;
        gid_t egid;
        int start_close = 0;
@@ -317,6 +353,7 @@ muxserver_accept_control(void)
        cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
        cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
        cctx->term = buffer_get_string(&m, &len);
+       escape_char = buffer_get_int(&m);
 
        cmd = buffer_get_string(&m, &len);
        buffer_init(&cctx->cmd);
@@ -402,14 +439,18 @@ muxserver_accept_control(void)
            new_fd[0], new_fd[1], new_fd[2], window, packetmax,
            CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
 
-       /* XXX */
        c->ctl_fd = client_fd;
+       if (cctx->want_tty && escape_char != 0xffffffff) {
+               channel_register_filter(c->self,
+                   client_simple_escape_filter, NULL,
+                   client_filter_cleanup,
+                   client_new_escape_filter_ctx((int)escape_char));
+       }
 
        debug3("%s: channel_new: %d", __func__, c->self);
 
        channel_send_open(c->self);
-       channel_register_open_confirm(c->self,
-           client_extra_session2_setup, cctx);
+       channel_register_open_confirm(c->self, mux_session_confirm, cctx);
        return 0;
 }
 
@@ -466,7 +507,7 @@ muxclient(const char *path)
        Buffer m;
        char *term;
        extern char **environ;
-       u_int  flags;
+       u_int allowed, flags;
 
        if (muxclient_command == 0)
                muxclient_command = SSHMUX_COMMAND_OPEN;
@@ -537,17 +578,38 @@ muxclient(const char *path)
        /* Send our command to server */
        buffer_put_int(&m, muxclient_command);
        buffer_put_int(&m, flags);
-       if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
-               fatal("%s: msg_send", __func__);
+       if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) {
+               error("%s: msg_send", __func__);
+ muxerr:
+               close(sock);
+               buffer_free(&m);
+               if (muxclient_command != SSHMUX_COMMAND_OPEN)
+                       cleanup_exit(255);
+               logit("Falling back to non-multiplexed connection");
+               xfree(options.control_path);
+               options.control_path = NULL;
+               options.control_master = SSHCTL_MASTER_NO;
+               return;
+       }
        buffer_clear(&m);
 
        /* Get authorisation status and PID of controlee */
-       if (ssh_msg_recv(sock, &m) == -1)
-               fatal("%s: msg_recv", __func__);
-       if (buffer_get_char(&m) != SSHMUX_VER)
-               fatal("%s: wrong version", __func__);
-       if (buffer_get_int(&m) != 1)
-               fatal("Connection to master denied");
+       if (ssh_msg_recv(sock, &m) == -1) {
+               error("%s: Did not receive reply from master", __func__);
+               goto muxerr;
+       }
+       if (buffer_get_char(&m) != SSHMUX_VER) {
+               error("%s: Master replied with wrong version", __func__);
+               goto muxerr;
+       }
+       if (buffer_get_int_ret(&allowed, &m) != 0) {
+               error("%s: bad server reply", __func__);
+               goto muxerr;
+       }
+       if (allowed != 1) {
+               error("Connection to master denied");
+               goto muxerr;
+       }
        muxserver_pid = buffer_get_int(&m);
 
        buffer_clear(&m);
@@ -561,42 +623,52 @@ muxclient(const char *path)
                fprintf(stderr, "Exit request sent.\r\n");
                exit(0);
        case SSHMUX_COMMAND_OPEN:
-               /* continue below */
+               buffer_put_cstring(&m, term ? term : "");
+               if (options.escape_char == SSH_ESCAPECHAR_NONE)
+                       buffer_put_int(&m, 0xffffffff);
+               else
+                       buffer_put_int(&m, options.escape_char);
+               buffer_append(&command, "\0", 1);
+               buffer_put_cstring(&m, buffer_ptr(&command));
+
+               if (options.num_send_env == 0 || environ == NULL) {
+                       buffer_put_int(&m, 0);
+               } else {
+                       /* Pass environment */
+                       num_env = 0;
+                       for (i = 0; environ[i] != NULL; i++) {
+                               if (env_permitted(environ[i]))
+                                       num_env++; /* Count */
+                       }
+                       buffer_put_int(&m, num_env);
+               for (i = 0; environ[i] != NULL && num_env >= 0; i++) {
+                               if (env_permitted(environ[i])) {
+                                       num_env--;
+                                       buffer_put_cstring(&m, environ[i]);
+                               }
+                       }
+               }
                break;
        default:
-               fatal("silly muxclient_command %d", muxclient_command);
+               fatal("unrecognised muxclient_command %d", muxclient_command);
        }
 
-       /* SSHMUX_COMMAND_OPEN */
-       buffer_put_cstring(&m, term ? term : "");
-       buffer_append(&command, "\0", 1);
-       buffer_put_cstring(&m, buffer_ptr(&command));
-
-       if (options.num_send_env == 0 || environ == NULL) {
-               buffer_put_int(&m, 0);
-       } else {
-               /* Pass environment */
-               num_env = 0;
-               for (i = 0; environ[i] != NULL; i++)
-                       if (env_permitted(environ[i]))
-                               num_env++; /* Count */
-
-               buffer_put_int(&m, num_env);
-
-               for (i = 0; environ[i] != NULL && num_env >= 0; i++)
-                       if (env_permitted(environ[i])) {
-                               num_env--;
-                               buffer_put_cstring(&m, environ[i]);
-                       }
+       if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) {
+               error("%s: msg_send", __func__);
+               goto muxerr;
        }
 
-       if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
-               fatal("%s: msg_send", __func__);
-
        if (mm_send_fd(sock, STDIN_FILENO) == -1 ||
            mm_send_fd(sock, STDOUT_FILENO) == -1 ||
-           mm_send_fd(sock, STDERR_FILENO) == -1)
-               fatal("%s: send fds failed", __func__);
+           mm_send_fd(sock, STDERR_FILENO) == -1) {
+               error("%s: send fds failed", __func__);
+               goto muxerr;
+       }
+
+       /*
+        * Mux errors are non-recoverable from this point as the master
+        * has ownership of the session now.
+        */
 
        /* Wait for reply, so master has a chance to gather ttymodes */
        buffer_clear(&m);
@@ -612,7 +684,7 @@ muxclient(const char *path)
        signal(SIGWINCH, control_client_sigrelay);
 
        if (tty_flag)
-               enter_raw_mode();
+               enter_raw_mode(force_tty_flag);
 
        /*
         * Stick around until the controlee closes the client_fd.
@@ -637,10 +709,10 @@ muxclient(const char *path)
        }
 
        close(sock);
-       leave_raw_mode();
+       leave_raw_mode(force_tty_flag);
        if (i > (int)sizeof(int))
                fatal("%s: master returned too much data (%d > %lu)",
-                   __func__, i, sizeof(int));
+                   __func__, i, (u_long)sizeof(int));
        if (muxclient_terminate) {
                debug2("Exiting on signal %d", muxclient_terminate);
                exitval[0] = 255;
This page took 1.08854 seconds and 4 git commands to generate.