summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarren Tucker <dtucker@zip.com.au>2008-06-13 04:49:33 +1000
committerDarren Tucker <dtucker@zip.com.au>2008-06-13 04:49:33 +1000
commit2fb66caca2c9e69c6a0584060114fcd52e59d5ff (patch)
treede895acfd51886da7e4ca547baea0b45e954c72e
parent267e28bb75e97755ab3bbe128b75623734f2b3fd (diff)
- 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@
-rw-r--r--ChangeLog12
-rw-r--r--channels.c5
-rw-r--r--channels.h5
-rw-r--r--clientloop.c154
-rw-r--r--clientloop.h22
-rw-r--r--mux.c93
6 files changed, 202 insertions, 89 deletions
diff --git a/ChangeLog b/ChangeLog
index 27a2a7abc..ca0d8ea57 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -68,6 +68,16 @@
68 [key.c] 68 [key.c]
69 use an odd number of rows and columns and a separate start marker, looks 69 use an odd number of rows and columns and a separate start marker, looks
70 better; ok grunk@ 70 better; ok grunk@
71 - djm@cvs.openbsd.org 2008/06/12 03:40:52
72 [clientloop.h mux.c channels.c clientloop.c channels.h]
73 Enable ~ escapes for multiplex slave sessions; give each channel
74 its own escape state and hook the escape filters up to muxed
75 channels. bz #1331
76 Mux slaves do not currently support the ~^Z and ~& escapes.
77 NB. this change cranks the mux protocol version, so a new ssh
78 mux client will not be able to connect to a running old ssh
79 mux master.
80 ok dtucker@
71 81
7220080611 8220080611
73 - (djm) [channels.c configure.ac] 83 - (djm) [channels.c configure.ac]
@@ -4230,4 +4240,4 @@
4230 OpenServer 6 and add osr5bigcrypt support so when someone migrates 4240 OpenServer 6 and add osr5bigcrypt support so when someone migrates
4231 passwords between UnixWare and OpenServer they will still work. OK dtucker@ 4241 passwords between UnixWare and OpenServer they will still work. OK dtucker@
4232 4242
4233$Id: ChangeLog,v 1.4976 2008/06/12 18:48:11 dtucker Exp $ 4243$Id: ChangeLog,v 1.4977 2008/06/12 18:49:33 dtucker Exp $
diff --git a/channels.c b/channels.c
index 233c2247b..c539990f6 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.278 2008/06/10 04:50:25 dtucker Exp $ */ 1/* $OpenBSD: channels.c,v 1.279 2008/06/12 03:40:52 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -731,7 +731,7 @@ channel_cancel_cleanup(int id)
731 731
732void 732void
733channel_register_filter(int id, channel_infilter_fn *ifn, 733channel_register_filter(int id, channel_infilter_fn *ifn,
734 channel_outfilter_fn *ofn) 734 channel_outfilter_fn *ofn, void *ctx)
735{ 735{
736 Channel *c = channel_lookup(id); 736 Channel *c = channel_lookup(id);
737 737
@@ -741,6 +741,7 @@ channel_register_filter(int id, channel_infilter_fn *ifn,
741 } 741 }
742 c->input_filter = ifn; 742 c->input_filter = ifn;
743 c->output_filter = ofn; 743 c->output_filter = ofn;
744 c->filter_ctx = ctx;
744} 745}
745 746
746void 747void
diff --git a/channels.h b/channels.h
index dc1f483ed..450321d43 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.h,v 1.93 2008/06/10 04:50:25 dtucker Exp $ */ 1/* $OpenBSD: channels.h,v 1.94 2008/06/12 03:40:52 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -131,6 +131,7 @@ struct Channel {
131 /* filter */ 131 /* filter */
132 channel_infilter_fn *input_filter; 132 channel_infilter_fn *input_filter;
133 channel_outfilter_fn *output_filter; 133 channel_outfilter_fn *output_filter;
134 void *filter_ctx;
134 135
135 /* keep boundaries */ 136 /* keep boundaries */
136 int datagram; 137 int datagram;
@@ -195,7 +196,7 @@ void channel_request_start(int, char *, int);
195void channel_register_cleanup(int, channel_callback_fn *, int); 196void channel_register_cleanup(int, channel_callback_fn *, int);
196void channel_register_open_confirm(int, channel_callback_fn *, void *); 197void channel_register_open_confirm(int, channel_callback_fn *, void *);
197void channel_register_filter(int, channel_infilter_fn *, 198void channel_register_filter(int, channel_infilter_fn *,
198 channel_outfilter_fn *); 199 channel_outfilter_fn *, void *);
199void channel_register_status_confirm(int, channel_confirm_cb *, 200void channel_register_status_confirm(int, channel_confirm_cb *,
200 channel_confirm_abandon_cb *, void *); 201 channel_confirm_abandon_cb *, void *);
201void channel_cancel_cleanup(int); 202void channel_cancel_cleanup(int);
diff --git a/clientloop.c b/clientloop.c
index 3bc8bb8d0..b45e7298a 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.c,v 1.194 2008/05/19 20:53:52 djm Exp $ */ 1/* $OpenBSD: clientloop.c,v 1.195 2008/06/12 03:40:52 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -144,8 +144,8 @@ static int in_non_blocking_mode = 0;
144 144
145/* Common data for the client loop code. */ 145/* Common data for the client loop code. */
146static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ 146static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
147static int escape_char; /* Escape character. */ 147static int escape_char1; /* Escape character. (proto1 only) */
148static int escape_pending; /* Last character was the escape character */ 148static int escape_pending1; /* Last character was an escape (proto1 only) */
149static int last_was_cr; /* Last character was a newline. */ 149static int last_was_cr; /* Last character was a newline. */
150static int exit_status; /* Used to store the exit status of the command. */ 150static int exit_status; /* Used to store the exit status of the command. */
151static int stdin_eof; /* EOF has been encountered on standard error. */ 151static int stdin_eof; /* EOF has been encountered on standard error. */
@@ -162,6 +162,13 @@ static int session_closed = 0; /* In SSH2: login session closed. */
162static void client_init_dispatch(void); 162static void client_init_dispatch(void);
163int session_ident = -1; 163int session_ident = -1;
164 164
165/* Track escape per proto2 channel */
166struct escape_filter_ctx {
167 int escape_pending;
168 int escape_char;
169};
170
171/* Context for channel confirmation replies */
165struct channel_reply_ctx { 172struct channel_reply_ctx {
166 const char *request_type; 173 const char *request_type;
167 int id, do_close; 174 int id, do_close;
@@ -385,8 +392,8 @@ client_check_initial_eof_on_stdin(void)
385 * and also process it as an escape character if 392 * and also process it as an escape character if
386 * appropriate. 393 * appropriate.
387 */ 394 */
388 if ((u_char) buf[0] == escape_char) 395 if ((u_char) buf[0] == escape_char1)
389 escape_pending = 1; 396 escape_pending1 = 1;
390 else 397 else
391 buffer_append(&stdin_buffer, buf, 1); 398 buffer_append(&stdin_buffer, buf, 1);
392 } 399 }
@@ -813,9 +820,12 @@ out:
813 xfree(fwd.connect_host); 820 xfree(fwd.connect_host);
814} 821}
815 822
816/* process the characters one by one */ 823/*
824 * Process the characters one by one, call with c==NULL for proto1 case.
825 */
817static int 826static int
818process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) 827process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
828 char *buf, int len)
819{ 829{
820 char string[1024]; 830 char string[1024];
821 pid_t pid; 831 pid_t pid;
@@ -823,7 +833,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
823 u_int i; 833 u_int i;
824 u_char ch; 834 u_char ch;
825 char *s; 835 char *s;
836 int *escape_pendingp, escape_char;
837 struct escape_filter_ctx *efc;
826 838
839 if (c == NULL) {
840 escape_pendingp = &escape_pending1;
841 escape_char = escape_char1;
842 } else {
843 if (c->filter_ctx == NULL)
844 return 0;
845 efc = (struct escape_filter_ctx *)c->filter_ctx;
846 escape_pendingp = &efc->escape_pending;
847 escape_char = efc->escape_char;
848 }
849
827 if (len <= 0) 850 if (len <= 0)
828 return (0); 851 return (0);
829 852
@@ -831,25 +854,43 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
831 /* Get one character at a time. */ 854 /* Get one character at a time. */
832 ch = buf[i]; 855 ch = buf[i];
833 856
834 if (escape_pending) { 857 if (*escape_pendingp) {
835 /* We have previously seen an escape character. */ 858 /* We have previously seen an escape character. */
836 /* Clear the flag now. */ 859 /* Clear the flag now. */
837 escape_pending = 0; 860 *escape_pendingp = 0;
838 861
839 /* Process the escaped character. */ 862 /* Process the escaped character. */
840 switch (ch) { 863 switch (ch) {
841 case '.': 864 case '.':
842 /* Terminate the connection. */ 865 /* Terminate the connection. */
843 snprintf(string, sizeof string, "%c.\r\n", escape_char); 866 snprintf(string, sizeof string, "%c.\r\n",
867 escape_char);
844 buffer_append(berr, string, strlen(string)); 868 buffer_append(berr, string, strlen(string));
845 869
846 quit_pending = 1; 870 if (c && c->ctl_fd != -1) {
871 chan_read_failed(c);
872 chan_write_failed(c);
873 return 0;
874 } else
875 quit_pending = 1;
847 return -1; 876 return -1;
848 877
849 case 'Z' - 64: 878 case 'Z' - 64:
879 /* XXX support this for mux clients */
880 if (c && c->ctl_fd != -1) {
881 noescape:
882 snprintf(string, sizeof string,
883 "%c%c escape not available to "
884 "multiplexed sessions\r\n",
885 escape_char, ch);
886 buffer_append(berr, string,
887 strlen(string));
888 continue;
889 }
850 /* Suspend the program. */ 890 /* Suspend the program. */
851 /* Print a message to that effect to the user. */ 891 /* Print a message to that effect to the user. */
852 snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); 892 snprintf(string, sizeof string,
893 "%c^Z [suspend ssh]\r\n", escape_char);
853 buffer_append(berr, string, strlen(string)); 894 buffer_append(berr, string, strlen(string));
854 895
855 /* Restore terminal modes and suspend. */ 896 /* Restore terminal modes and suspend. */
@@ -881,6 +922,8 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
881 continue; 922 continue;
882 923
883 case '&': 924 case '&':
925 if (c && c->ctl_fd != -1)
926 goto noescape;
884 /* 927 /*
885 * Detach the program (continue to serve connections, 928 * Detach the program (continue to serve connections,
886 * but put in background and no more new connections). 929 * 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)
929 continue; 972 continue;
930 973
931 case '?': 974 case '?':
932 snprintf(string, sizeof string, 975 if (c && c->ctl_fd != -1) {
976 snprintf(string, sizeof string,
933"%c?\r\n\ 977"%c?\r\n\
934Supported escape sequences:\r\n\ 978Supported escape sequences:\r\n\
935%c. - terminate connection\r\n\ 979 %c. - terminate session\r\n\
936%cB - send a BREAK to the remote system\r\n\ 980 %cB - send a BREAK to the remote system\r\n\
937%cC - open a command line\r\n\ 981 %cC - open a command line\r\n\
938%cR - Request rekey (SSH protocol 2 only)\r\n\ 982 %cR - Request rekey (SSH protocol 2 only)\r\n\
939%c^Z - suspend ssh\r\n\ 983 %c# - list forwarded connections\r\n\
940%c# - list forwarded connections\r\n\ 984 %c? - this message\r\n\
941%c& - background ssh (when waiting for connections to terminate)\r\n\ 985 %c%c - send the escape character by typing it twice\r\n\
942%c? - this message\r\n\
943%c%c - send the escape character by typing it twice\r\n\
944(Note that escapes are only recognized immediately after newline.)\r\n", 986(Note that escapes are only recognized immediately after newline.)\r\n",
945 escape_char, escape_char, escape_char, escape_char, 987 escape_char, escape_char,
946 escape_char, escape_char, escape_char, escape_char, 988 escape_char, escape_char,
947 escape_char, escape_char, escape_char); 989 escape_char, escape_char,
990 escape_char, escape_char,
991 escape_char);
992 } else {
993 snprintf(string, sizeof string,
994"%c?\r\n\
995Supported escape sequences:\r\n\
996 %c. - terminate connection (and any multiplexed sessions)\r\n\
997 %cB - send a BREAK to the remote system\r\n\
998 %cC - open a command line\r\n\
999 %cR - Request rekey (SSH protocol 2 only)\r\n\
1000 %c^Z - suspend ssh\r\n\
1001 %c# - list forwarded connections\r\n\
1002 %c& - background ssh (when waiting for connections to terminate)\r\n\
1003 %c? - this message\r\n\
1004 %c%c - send the escape character by typing it twice\r\n\
1005(Note that escapes are only recognized immediately after newline.)\r\n",
1006 escape_char, escape_char,
1007 escape_char, escape_char,
1008 escape_char, escape_char,
1009 escape_char, escape_char,
1010 escape_char, escape_char,
1011 escape_char);
1012 }
948 buffer_append(berr, string, strlen(string)); 1013 buffer_append(berr, string, strlen(string));
949 continue; 1014 continue;
950 1015
951 case '#': 1016 case '#':
952 snprintf(string, sizeof string, "%c#\r\n", escape_char); 1017 snprintf(string, sizeof string, "%c#\r\n",
1018 escape_char);
953 buffer_append(berr, string, strlen(string)); 1019 buffer_append(berr, string, strlen(string));
954 s = channel_open_message(); 1020 s = channel_open_message();
955 buffer_append(berr, s, strlen(s)); 1021 buffer_append(berr, s, strlen(s));
@@ -975,7 +1041,7 @@ Supported escape sequences:\r\n\
975 */ 1041 */
976 if (last_was_cr && ch == escape_char) { 1042 if (last_was_cr && ch == escape_char) {
977 /* It is. Set the flag and continue to next character. */ 1043 /* It is. Set the flag and continue to next character. */
978 escape_pending = 1; 1044 *escape_pendingp = 1;
979 continue; 1045 continue;
980 } 1046 }
981 } 1047 }
@@ -1026,7 +1092,7 @@ client_process_input(fd_set *readset)
1026 packet_start(SSH_CMSG_EOF); 1092 packet_start(SSH_CMSG_EOF);
1027 packet_send(); 1093 packet_send();
1028 } 1094 }
1029 } else if (escape_char == SSH_ESCAPECHAR_NONE) { 1095 } else if (escape_char1 == SSH_ESCAPECHAR_NONE) {
1030 /* 1096 /*
1031 * Normal successful read, and no escape character. 1097 * Normal successful read, and no escape character.
1032 * Just append the data to buffer. 1098 * Just append the data to buffer.
@@ -1037,8 +1103,8 @@ client_process_input(fd_set *readset)
1037 * Normal, successful read. But we have an escape character 1103 * Normal, successful read. But we have an escape character
1038 * and have to process the characters one by one. 1104 * and have to process the characters one by one.
1039 */ 1105 */
1040 if (process_escapes(&stdin_buffer, &stdout_buffer, 1106 if (process_escapes(NULL, &stdin_buffer,
1041 &stderr_buffer, buf, len) == -1) 1107 &stdout_buffer, &stderr_buffer, buf, len) == -1)
1042 return; 1108 return;
1043 } 1109 }
1044 } 1110 }
@@ -1113,13 +1179,26 @@ client_process_buffered_input_packets(void)
1113 1179
1114/* scan buf[] for '~' before sending data to the peer */ 1180/* scan buf[] for '~' before sending data to the peer */
1115 1181
1116static int 1182/* Helper: allocate a new escape_filter_ctx and fill in its escape char */
1117simple_escape_filter(Channel *c, char *buf, int len) 1183void *
1184client_new_escape_filter_ctx(int escape_char)
1185{
1186 struct escape_filter_ctx *ret;
1187
1188 ret = xmalloc(sizeof(*ret));
1189 ret->escape_pending = 0;
1190 ret->escape_char = escape_char;
1191 return (void *)ret;
1192}
1193
1194int
1195client_simple_escape_filter(Channel *c, char *buf, int len)
1118{ 1196{
1119 if (c->extended_usage != CHAN_EXTENDED_WRITE) 1197 if (c->extended_usage != CHAN_EXTENDED_WRITE)
1120 return 0; 1198 return 0;
1121 1199
1122 return process_escapes(&c->input, &c->output, &c->extended, buf, len); 1200 return process_escapes(c, &c->input, &c->output, &c->extended,
1201 buf, len);
1123} 1202}
1124 1203
1125static void 1204static void
@@ -1151,7 +1230,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1151 start_time = get_current_time(); 1230 start_time = get_current_time();
1152 1231
1153 /* Initialize variables. */ 1232 /* Initialize variables. */
1154 escape_pending = 0; 1233 escape_pending1 = 0;
1155 last_was_cr = 1; 1234 last_was_cr = 1;
1156 exit_status = -1; 1235 exit_status = -1;
1157 stdin_eof = 0; 1236 stdin_eof = 0;
@@ -1178,7 +1257,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1178 stdout_bytes = 0; 1257 stdout_bytes = 0;
1179 stderr_bytes = 0; 1258 stderr_bytes = 0;
1180 quit_pending = 0; 1259 quit_pending = 0;
1181 escape_char = escape_char_arg; 1260 escape_char1 = escape_char_arg;
1182 1261
1183 /* Initialize buffers. */ 1262 /* Initialize buffers. */
1184 buffer_init(&stdin_buffer); 1263 buffer_init(&stdin_buffer);
@@ -1206,9 +1285,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1206 1285
1207 if (compat20) { 1286 if (compat20) {
1208 session_ident = ssh2_chan_id; 1287 session_ident = ssh2_chan_id;
1209 if (escape_char != SSH_ESCAPECHAR_NONE) 1288 if (escape_char_arg != SSH_ESCAPECHAR_NONE)
1210 channel_register_filter(session_ident, 1289 channel_register_filter(session_ident,
1211 simple_escape_filter, NULL); 1290 client_simple_escape_filter, NULL,
1291 client_new_escape_filter_ctx(escape_char_arg));
1212 if (session_ident != -1) 1292 if (session_ident != -1)
1213 channel_register_cleanup(session_ident, 1293 channel_register_cleanup(session_ident,
1214 client_channel_closed, 0); 1294 client_channel_closed, 0);
diff --git a/clientloop.h b/clientloop.h
index 6f8e70123..cecbfb1a8 100644
--- a/clientloop.h
+++ b/clientloop.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.h,v 1.19 2008/05/09 14:18:44 djm Exp $ */ 1/* $OpenBSD: clientloop.h,v 1.20 2008/06/12 03:40:52 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -46,8 +46,12 @@ void client_session2_setup(int, int, int, const char *, struct termios *,
46 int, Buffer *, char **); 46 int, Buffer *, char **);
47int client_request_tun_fwd(int, int, int); 47int client_request_tun_fwd(int, int, int);
48 48
49/* Escape filter for protocol 2 sessions */
50void *client_new_escape_filter_ctx(int);
51int client_simple_escape_filter(Channel *, char *, int);
52
49/* Multiplexing protocol version */ 53/* Multiplexing protocol version */
50#define SSHMUX_VER 1 54#define SSHMUX_VER 2
51 55
52/* Multiplexing control protocol flags */ 56/* Multiplexing control protocol flags */
53#define SSHMUX_COMMAND_OPEN 1 /* Open new connection */ 57#define SSHMUX_COMMAND_OPEN 1 /* Open new connection */
@@ -59,20 +63,6 @@ int client_request_tun_fwd(int, int, int);
59#define SSHMUX_FLAG_X11_FWD (1<<2) /* Request X11 forwarding */ 63#define SSHMUX_FLAG_X11_FWD (1<<2) /* Request X11 forwarding */
60#define SSHMUX_FLAG_AGENT_FWD (1<<3) /* Request agent forwarding */ 64#define SSHMUX_FLAG_AGENT_FWD (1<<3) /* Request agent forwarding */
61 65
62/* Multiplexing routines */
63
64struct mux_session_confirm_ctx {
65 int want_tty;
66 int want_subsys;
67 int want_x_fwd;
68 int want_agent_fwd;
69 Buffer cmd;
70 char *term;
71 struct termios tio;
72 char **env;
73};
74
75/* mux.c */
76void muxserver_listen(void); 66void muxserver_listen(void);
77int muxserver_accept_control(void); 67int muxserver_accept_control(void);
78void muxclient(const char *); 68void muxclient(const char *);
diff --git a/mux.c b/mux.c
index 8b9105b04..efc3840cb 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: mux.c,v 1.1 2008/05/09 14:18:44 djm Exp $ */ 1/* $OpenBSD: mux.c,v 1.2 2008/06/12 03:40:52 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 *
@@ -19,6 +19,20 @@
19 19
20#include "includes.h" 20#include "includes.h"
21 21
22/*
23 * TODO:
24 * 1. partial reads in muxserver_accept_control (maybe make channels
25 * from accepted connections)
26 * 2. Better signalling from master to slave, especially passing of
27 * error messages
28 * 3. Better fall-back from mux slave error to new connection.
29 * 3. Add/delete forwardings via slave
30 * 4. ExitOnForwardingFailure (after #3 obviously)
31 * 5. Maybe extension mechanisms for multi-X11/multi-agent forwarding
32 * 6. Document the mux mini-protocol somewhere.
33 * 6. Support ~^Z in mux slaves.
34 */
35
22#include <sys/types.h> 36#include <sys/types.h>
23#include <sys/param.h> 37#include <sys/param.h>
24#include <sys/stat.h> 38#include <sys/stat.h>
@@ -71,6 +85,18 @@ extern char *host;
71int subsystem_flag; 85int subsystem_flag;
72extern Buffer command; 86extern Buffer command;
73 87
88/* Context for session open confirmation callback */
89struct mux_session_confirm_ctx {
90 int want_tty;
91 int want_subsys;
92 int want_x_fwd;
93 int want_agent_fwd;
94 Buffer cmd;
95 char *term;
96 struct termios tio;
97 char **env;
98};
99
74/* fd to control socket */ 100/* fd to control socket */
75int muxserver_sock = -1; 101int muxserver_sock = -1;
76 102
@@ -131,7 +157,7 @@ muxserver_listen(void)
131 157
132/* Callback on open confirmation in mux master for a mux client session. */ 158/* Callback on open confirmation in mux master for a mux client session. */
133static void 159static void
134client_extra_session2_setup(int id, void *arg) 160mux_session_confirm(int id, void *arg)
135{ 161{
136 struct mux_session_confirm_ctx *cctx = arg; 162 struct mux_session_confirm_ctx *cctx = arg;
137 const char *display; 163 const char *display;
@@ -190,7 +216,7 @@ muxserver_accept_control(void)
190 struct sockaddr_storage addr; 216 struct sockaddr_storage addr;
191 struct mux_session_confirm_ctx *cctx; 217 struct mux_session_confirm_ctx *cctx;
192 char *cmd; 218 char *cmd;
193 u_int i, j, len, env_len, mux_command, flags; 219 u_int i, j, len, env_len, mux_command, flags, escape_char;
194 uid_t euid; 220 uid_t euid;
195 gid_t egid; 221 gid_t egid;
196 int start_close = 0; 222 int start_close = 0;
@@ -317,6 +343,7 @@ muxserver_accept_control(void)
317 cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0; 343 cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
318 cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0; 344 cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
319 cctx->term = buffer_get_string(&m, &len); 345 cctx->term = buffer_get_string(&m, &len);
346 escape_char = buffer_get_int(&m);
320 347
321 cmd = buffer_get_string(&m, &len); 348 cmd = buffer_get_string(&m, &len);
322 buffer_init(&cctx->cmd); 349 buffer_init(&cctx->cmd);
@@ -402,14 +429,17 @@ muxserver_accept_control(void)
402 new_fd[0], new_fd[1], new_fd[2], window, packetmax, 429 new_fd[0], new_fd[1], new_fd[2], window, packetmax,
403 CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); 430 CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
404 431
405 /* XXX */
406 c->ctl_fd = client_fd; 432 c->ctl_fd = client_fd;
433 if (cctx->want_tty && escape_char != 0xffffffff) {
434 channel_register_filter(c->self,
435 client_simple_escape_filter, NULL,
436 client_new_escape_filter_ctx((int)escape_char));
437 }
407 438
408 debug3("%s: channel_new: %d", __func__, c->self); 439 debug3("%s: channel_new: %d", __func__, c->self);
409 440
410 channel_send_open(c->self); 441 channel_send_open(c->self);
411 channel_register_open_confirm(c->self, 442 channel_register_open_confirm(c->self, mux_session_confirm, cctx);
412 client_extra_session2_setup, cctx);
413 return 0; 443 return 0;
414} 444}
415 445
@@ -561,33 +591,34 @@ muxclient(const char *path)
561 fprintf(stderr, "Exit request sent.\r\n"); 591 fprintf(stderr, "Exit request sent.\r\n");
562 exit(0); 592 exit(0);
563 case SSHMUX_COMMAND_OPEN: 593 case SSHMUX_COMMAND_OPEN:
564 /* continue below */ 594 buffer_put_cstring(&m, term ? term : "");
595 if (options.escape_char == SSH_ESCAPECHAR_NONE)
596 buffer_put_int(&m, 0xffffffff);
597 else
598 buffer_put_int(&m, options.escape_char);
599 buffer_append(&command, "\0", 1);
600 buffer_put_cstring(&m, buffer_ptr(&command));
601
602 if (options.num_send_env == 0 || environ == NULL) {
603 buffer_put_int(&m, 0);
604 } else {
605 /* Pass environment */
606 num_env = 0;
607 for (i = 0; environ[i] != NULL; i++) {
608 if (env_permitted(environ[i]))
609 num_env++; /* Count */
610 }
611 buffer_put_int(&m, num_env);
612 for (i = 0; environ[i] != NULL && num_env >= 0; i++) {
613 if (env_permitted(environ[i])) {
614 num_env--;
615 buffer_put_cstring(&m, environ[i]);
616 }
617 }
618 }
565 break; 619 break;
566 default: 620 default:
567 fatal("silly muxclient_command %d", muxclient_command); 621 fatal("unrecognised muxclient_command %d", muxclient_command);
568 }
569
570 /* SSHMUX_COMMAND_OPEN */
571 buffer_put_cstring(&m, term ? term : "");
572 buffer_append(&command, "\0", 1);
573 buffer_put_cstring(&m, buffer_ptr(&command));
574
575 if (options.num_send_env == 0 || environ == NULL) {
576 buffer_put_int(&m, 0);
577 } else {
578 /* Pass environment */
579 num_env = 0;
580 for (i = 0; environ[i] != NULL; i++)
581 if (env_permitted(environ[i]))
582 num_env++; /* Count */
583
584 buffer_put_int(&m, num_env);
585
586 for (i = 0; environ[i] != NULL && num_env >= 0; i++)
587 if (env_permitted(environ[i])) {
588 num_env--;
589 buffer_put_cstring(&m, environ[i]);
590 }
591 } 622 }
592 623
593 if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) 624 if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)