]> andersk Git - openssh.git/commitdiff
- djm@cvs.openbsd.org 2008/06/12 03:40:52
authordtucker <dtucker>
Thu, 12 Jun 2008 18:49:33 +0000 (18:49 +0000)
committerdtucker <dtucker>
Thu, 12 Jun 2008 18:49:33 +0000 (18:49 +0000)
     [clientloop.h mux.c channels.c clientloop.c channels.h]
     Enable ~ escapes for multiplex slave sessions; give each channel
     its own escape state and hook the escape filters up to muxed
     channels. bz #1331
     Mux slaves do not currently support the ~^Z and ~& escapes.
     NB. this change cranks the mux protocol version, so a new ssh
     mux client will not be able to connect to a running old ssh
     mux master.
     ok dtucker@

ChangeLog
channels.c
channels.h
clientloop.c
clientloop.h
mux.c

index 31a61b2dc6cc984adbca1c5e758371dc4f8ddad1..15679c64b28b9b5d175ca4e5a5c22a1da389db86 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
      [key.c]
      use an odd number of rows and columns and a separate start marker, looks
      better; ok grunk@
+   - djm@cvs.openbsd.org 2008/06/12 03:40:52
+     [clientloop.h mux.c channels.c clientloop.c channels.h]
+     Enable ~ escapes for multiplex slave sessions; give each channel
+     its own escape state and hook the escape filters up to muxed
+     channels. bz #1331
+     Mux slaves do not currently support the ~^Z and ~& escapes.
+     NB. this change cranks the mux protocol version, so a new ssh
+     mux client will not be able to connect to a running old ssh
+     mux master.
+     ok dtucker@
 
 20080611
  - (djm) [channels.c configure.ac]
index 233c2247be8231cdd2ecf1aeaed9826263fa3de6..c539990f64bb1a23fed2c97539aace8fd5fa1860 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.278 2008/06/10 04:50:25 dtucker Exp $ */
+/* $OpenBSD: channels.c,v 1.279 2008/06/12 03:40:52 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -731,7 +731,7 @@ channel_cancel_cleanup(int id)
 
 void
 channel_register_filter(int id, channel_infilter_fn *ifn,
-    channel_outfilter_fn *ofn)
+    channel_outfilter_fn *ofn, void *ctx)
 {
        Channel *c = channel_lookup(id);
 
@@ -741,6 +741,7 @@ channel_register_filter(int id, channel_infilter_fn *ifn,
        }
        c->input_filter = ifn;
        c->output_filter = ofn;
+       c->filter_ctx = ctx;
 }
 
 void
index dc1f483ed37017e6722ca5df84839d6010439203..450321d43fe2ee847659fbd86ba99d08186098af 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.93 2008/06/10 04:50:25 dtucker Exp $ */
+/* $OpenBSD: channels.h,v 1.94 2008/06/12 03:40:52 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -131,6 +131,7 @@ struct Channel {
        /* filter */
        channel_infilter_fn     *input_filter;
        channel_outfilter_fn    *output_filter;
+       void                    *filter_ctx;
 
        /* keep boundaries */
        int                     datagram;
@@ -195,7 +196,7 @@ void         channel_request_start(int, char *, int);
 void    channel_register_cleanup(int, channel_callback_fn *, int);
 void    channel_register_open_confirm(int, channel_callback_fn *, void *);
 void    channel_register_filter(int, channel_infilter_fn *,
-    channel_outfilter_fn *);
+    channel_outfilter_fn *, void *);
 void    channel_register_status_confirm(int, channel_confirm_cb *,
     channel_confirm_abandon_cb *, void *);
 void    channel_cancel_cleanup(int);
index 3bc8bb8d05b5240364a4789af8e1b11f63f85d63..b45e7298a802ff2e8aefb2bfae549cb214be7a4e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.194 2008/05/19 20:53:52 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.195 2008/06/12 03:40:52 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -144,8 +144,8 @@ static int in_non_blocking_mode = 0;
 
 /* Common data for the client loop code. */
 static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
-static int escape_char;                /* Escape character. */
-static int escape_pending;     /* Last character was the escape character */
+static int escape_char1;       /* Escape character. (proto1 only) */
+static int escape_pending1;    /* Last character was an escape (proto1 only) */
 static int last_was_cr;                /* Last character was a newline. */
 static int exit_status;                /* Used to store the exit status of the command. */
 static int stdin_eof;          /* EOF has been encountered on standard error. */
@@ -162,6 +162,13 @@ static int session_closed = 0;     /* In SSH2: login session closed. */
 static void client_init_dispatch(void);
 int    session_ident = -1;
 
+/* Track escape per proto2 channel */
+struct escape_filter_ctx {
+       int escape_pending;
+       int escape_char;
+};
+
+/* Context for channel confirmation replies */
 struct channel_reply_ctx {
        const char *request_type;
        int id, do_close;
@@ -385,8 +392,8 @@ client_check_initial_eof_on_stdin(void)
                         * and also process it as an escape character if
                         * appropriate.
                         */
-                       if ((u_char) buf[0] == escape_char)
-                               escape_pending = 1;
+                       if ((u_char) buf[0] == escape_char1)
+                               escape_pending1 = 1;
                        else
                                buffer_append(&stdin_buffer, buf, 1);
                }
@@ -813,9 +820,12 @@ out:
                xfree(fwd.connect_host);
 }
 
-/* process the characters one by one */
+/* 
+ * Process the characters one by one, call with c==NULL for proto1 case.
+ */
 static int
-process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
+process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
+    char *buf, int len)
 {
        char string[1024];
        pid_t pid;
@@ -823,7 +833,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
        u_int i;
        u_char ch;
        char *s;
+       int *escape_pendingp, escape_char;
+       struct escape_filter_ctx *efc;
 
+       if (c == NULL) {
+               escape_pendingp = &escape_pending1;
+               escape_char = escape_char1;
+       } else {
+               if (c->filter_ctx == NULL)
+                       return 0;
+               efc = (struct escape_filter_ctx *)c->filter_ctx;
+               escape_pendingp = &efc->escape_pending;
+               escape_char = efc->escape_char;
+       }
+       
        if (len <= 0)
                return (0);
 
@@ -831,25 +854,43 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
                /* Get one character at a time. */
                ch = buf[i];
 
-               if (escape_pending) {
+               if (*escape_pendingp) {
                        /* We have previously seen an escape character. */
                        /* Clear the flag now. */
-                       escape_pending = 0;
+                       *escape_pendingp = 0;
 
                        /* Process the escaped character. */
                        switch (ch) {
                        case '.':
                                /* Terminate the connection. */
-                               snprintf(string, sizeof string, "%c.\r\n", escape_char);
+                               snprintf(string, sizeof string, "%c.\r\n",
+                                   escape_char);
                                buffer_append(berr, string, strlen(string));
 
-                               quit_pending = 1;
+                               if (c && c->ctl_fd != -1) {
+                                       chan_read_failed(c);
+                                       chan_write_failed(c);
+                                       return 0;
+                               } else
+                                       quit_pending = 1;
                                return -1;
 
                        case 'Z' - 64:
+                               /* XXX support this for mux clients */
+                               if (c && c->ctl_fd != -1) {
+ noescape:
+                                       snprintf(string, sizeof string,
+                                           "%c%c escape not available to "
+                                           "multiplexed sessions\r\n",
+                                           escape_char, ch);
+                                       buffer_append(berr, string,
+                                           strlen(string));
+                                       continue;
+                               }
                                /* Suspend the program. */
                                /* Print a message to that effect to the user. */
-                               snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char);
+                               snprintf(string, sizeof string,
+                                   "%c^Z [suspend ssh]\r\n", escape_char);
                                buffer_append(berr, string, strlen(string));
 
                                /* Restore terminal modes and suspend. */
@@ -881,6 +922,8 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
                                continue;
 
                        case '&':
+                               if (c && c->ctl_fd != -1)
+                                       goto noescape;
                                /*
                                 * Detach the program (continue to serve connections,
                                 * but put in background and no more new connections).
@@ -929,27 +972,50 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
                                continue;
 
                        case '?':
-                               snprintf(string, sizeof string,
+                               if (c && c->ctl_fd != -1) {
+                                       snprintf(string, sizeof string,
 "%c?\r\n\
 Supported escape sequences:\r\n\
-%c.  - terminate connection\r\n\
-%cB  - send a BREAK to the remote system\r\n\
-%cC  - open a command line\r\n\
-%cR  - Request rekey (SSH protocol 2 only)\r\n\
-%c^Z - suspend ssh\r\n\
-%c#  - list forwarded connections\r\n\
-%c&  - background ssh (when waiting for connections to terminate)\r\n\
-%c?  - this message\r\n\
-%c%c  - send the escape character by typing it twice\r\n\
+  %c.  - terminate session\r\n\
+  %cB  - send a BREAK to the remote system\r\n\
+  %cC  - open a command line\r\n\
+  %cR  - Request rekey (SSH protocol 2 only)\r\n\
+  %c#  - list forwarded connections\r\n\
+  %c?  - this message\r\n\
+  %c%c  - send the escape character by typing it twice\r\n\
 (Note that escapes are only recognized immediately after newline.)\r\n",
-                                   escape_char, escape_char, escape_char, escape_char,
-                                   escape_char, escape_char, escape_char, escape_char,
-                                   escape_char, escape_char, escape_char);
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char);
+                               } else {
+                                       snprintf(string, sizeof string,
+"%c?\r\n\
+Supported escape sequences:\r\n\
+  %c.  - terminate connection (and any multiplexed sessions)\r\n\
+  %cB  - send a BREAK to the remote system\r\n\
+  %cC  - open a command line\r\n\
+  %cR  - Request rekey (SSH protocol 2 only)\r\n\
+  %c^Z - suspend ssh\r\n\
+  %c#  - list forwarded connections\r\n\
+  %c&  - background ssh (when waiting for connections to terminate)\r\n\
+  %c?  - this message\r\n\
+  %c%c  - send the escape character by typing it twice\r\n\
+(Note that escapes are only recognized immediately after newline.)\r\n",
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char);
+                               }
                                buffer_append(berr, string, strlen(string));
                                continue;
 
                        case '#':
-                               snprintf(string, sizeof string, "%c#\r\n", escape_char);
+                               snprintf(string, sizeof string, "%c#\r\n",
+                                   escape_char);
                                buffer_append(berr, string, strlen(string));
                                s = channel_open_message();
                                buffer_append(berr, s, strlen(s));
@@ -975,7 +1041,7 @@ Supported escape sequences:\r\n\
                         */
                        if (last_was_cr && ch == escape_char) {
                                /* It is. Set the flag and continue to next character. */
-                               escape_pending = 1;
+                               *escape_pendingp = 1;
                                continue;
                        }
                }
@@ -1026,7 +1092,7 @@ client_process_input(fd_set *readset)
                                packet_start(SSH_CMSG_EOF);
                                packet_send();
                        }
-               } else if (escape_char == SSH_ESCAPECHAR_NONE) {
+               } else if (escape_char1 == SSH_ESCAPECHAR_NONE) {
                        /*
                         * Normal successful read, and no escape character.
                         * Just append the data to buffer.
@@ -1037,8 +1103,8 @@ client_process_input(fd_set *readset)
                         * Normal, successful read.  But we have an escape character
                         * and have to process the characters one by one.
                         */
-                       if (process_escapes(&stdin_buffer, &stdout_buffer,
-                           &stderr_buffer, buf, len) == -1)
+                       if (process_escapes(NULL, &stdin_buffer,
+                           &stdout_buffer, &stderr_buffer, buf, len) == -1)
                                return;
                }
        }
@@ -1113,13 +1179,26 @@ client_process_buffered_input_packets(void)
 
 /* scan buf[] for '~' before sending data to the peer */
 
-static int
-simple_escape_filter(Channel *c, char *buf, int len)
+/* Helper: allocate a new escape_filter_ctx and fill in its escape char */
+void *
+client_new_escape_filter_ctx(int escape_char)
+{
+       struct escape_filter_ctx *ret;
+
+       ret = xmalloc(sizeof(*ret));
+       ret->escape_pending = 0;
+       ret->escape_char = escape_char;
+       return (void *)ret;
+}
+
+int
+client_simple_escape_filter(Channel *c, char *buf, int len)
 {
        if (c->extended_usage != CHAN_EXTENDED_WRITE)
                return 0;
 
-       return process_escapes(&c->input, &c->output, &c->extended, buf, len);
+       return process_escapes(c, &c->input, &c->output, &c->extended,
+           buf, len);
 }
 
 static void
@@ -1151,7 +1230,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
        start_time = get_current_time();
 
        /* Initialize variables. */
-       escape_pending = 0;
+       escape_pending1 = 0;
        last_was_cr = 1;
        exit_status = -1;
        stdin_eof = 0;
@@ -1178,7 +1257,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
        stdout_bytes = 0;
        stderr_bytes = 0;
        quit_pending = 0;
-       escape_char = escape_char_arg;
+       escape_char1 = escape_char_arg;
 
        /* Initialize buffers. */
        buffer_init(&stdin_buffer);
@@ -1206,9 +1285,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
 
        if (compat20) {
                session_ident = ssh2_chan_id;
-               if (escape_char != SSH_ESCAPECHAR_NONE)
+               if (escape_char_arg != SSH_ESCAPECHAR_NONE)
                        channel_register_filter(session_ident,
-                           simple_escape_filter, NULL);
+                           client_simple_escape_filter, NULL,
+                           client_new_escape_filter_ctx(escape_char_arg));
                if (session_ident != -1)
                        channel_register_cleanup(session_ident,
                            client_channel_closed, 0);
index 6f8e701233b1ac334c68a771b4146a56c60f7c01..cecbfb1a87893e79ccfaa598c5c29e66c181bc27 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.h,v 1.19 2008/05/09 14:18:44 djm Exp $ */
+/* $OpenBSD: clientloop.h,v 1.20 2008/06/12 03:40:52 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -46,8 +46,12 @@ void  client_session2_setup(int, int, int, const char *, struct termios *,
            int, Buffer *, char **);
 int     client_request_tun_fwd(int, int, int);
 
+/* Escape filter for protocol 2 sessions */
+void   *client_new_escape_filter_ctx(int);
+int     client_simple_escape_filter(Channel *, char *, int);
+
 /* Multiplexing protocol version */
-#define SSHMUX_VER                     1
+#define SSHMUX_VER                     2
 
 /* Multiplexing control protocol flags */
 #define SSHMUX_COMMAND_OPEN            1       /* Open new connection */
@@ -59,20 +63,6 @@ int   client_request_tun_fwd(int, int, int);
 #define SSHMUX_FLAG_X11_FWD            (1<<2)  /* Request X11 forwarding */
 #define SSHMUX_FLAG_AGENT_FWD          (1<<3)  /* Request agent forwarding */
 
-/* Multiplexing routines */
-
-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;
-};
-
-/* mux.c */
 void   muxserver_listen(void);
 int    muxserver_accept_control(void);
 void   muxclient(const char *);
diff --git a/mux.c b/mux.c
index 8b9105b0402e50988e186aed6a2f33bba975f363..efc3840cbbf5b509729b124b9335f51d6f2f47d2 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.2 2008/06/12 03:40:52 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.
+ *   6. Support ~^Z in mux slaves.
+ */
+
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/stat.h>
@@ -71,6 +85,18 @@ extern char *host;
 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;
 
@@ -131,7 +157,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 +216,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 +343,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 +429,17 @@ 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_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;
 }
 
@@ -561,33 +591,34 @@ 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);
-       }
-
-       /* 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]);
-                       }
+               fatal("unrecognised muxclient_command %d", muxclient_command);
        }
 
        if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
This page took 0.138395 seconds and 5 git commands to generate.