View | Details | Raw Unified | Return to bug 1331 | Differences between
and this patch

Collapse All | Expand All

(-)channels.c (-1 / +2 lines)
Lines 726-732 channel_cancel_cleanup(int id) Link Here
726
726
727
void
727
void
728
channel_register_filter(int id, channel_infilter_fn *ifn,
728
channel_register_filter(int id, channel_infilter_fn *ifn,
729
    channel_outfilter_fn *ofn)
729
    channel_outfilter_fn *ofn, void *ctx)
730
{
730
{
731
	Channel *c = channel_lookup(id);
731
	Channel *c = channel_lookup(id);
732
732
Lines 736-741 channel_register_filter(int id, channel_ Link Here
736
	}
736
	}
737
	c->input_filter = ifn;
737
	c->input_filter = ifn;
738
	c->output_filter = ofn;
738
	c->output_filter = ofn;
739
	c->filter_ctx = ctx;
739
}
740
}
740
741
741
void
742
void
(-)channels.h (-1 / +2 lines)
Lines 130-135 struct Channel { Link Here
130
	/* filter */
130
	/* filter */
131
	channel_infilter_fn	*input_filter;
131
	channel_infilter_fn	*input_filter;
132
	channel_outfilter_fn	*output_filter;
132
	channel_outfilter_fn	*output_filter;
133
	void			*filter_ctx;
133
134
134
	/* keep boundaries */
135
	/* keep boundaries */
135
	int     		datagram;
136
	int     		datagram;
Lines 194-200 void channel_request_start(int, char *, Link Here
194
void	 channel_register_cleanup(int, channel_callback_fn *, int);
195
void	 channel_register_cleanup(int, channel_callback_fn *, int);
195
void	 channel_register_open_confirm(int, channel_callback_fn *, void *);
196
void	 channel_register_open_confirm(int, channel_callback_fn *, void *);
196
void	 channel_register_filter(int, channel_infilter_fn *,
197
void	 channel_register_filter(int, channel_infilter_fn *,
197
    channel_outfilter_fn *);
198
    channel_outfilter_fn *, void *);
198
void	 channel_register_status_confirm(int, channel_confirm_cb *,
199
void	 channel_register_status_confirm(int, channel_confirm_cb *,
199
    channel_confirm_abandon_cb *, void *);
200
    channel_confirm_abandon_cb *, void *);
200
void	 channel_cancel_cleanup(int);
201
void	 channel_cancel_cleanup(int);
(-)clientloop.c (-36 / +115 lines)
Lines 136-143 static int in_non_blocking_mode = 0; Link Here
136
136
137
/* Common data for the client loop code. */
137
/* Common data for the client loop code. */
138
static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
138
static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
139
static int escape_char;		/* Escape character. */
139
static int escape_char1;	/* Escape character. (proto1 only) */
140
static int escape_pending;	/* Last character was the escape character */
140
static int escape_pending1;	/* Last character was an escape (proto1 only) */
141
static int last_was_cr;		/* Last character was a newline. */
141
static int last_was_cr;		/* Last character was a newline. */
142
static int exit_status;		/* Used to store the exit status of the command. */
142
static int exit_status;		/* Used to store the exit status of the command. */
143
static int stdin_eof;		/* EOF has been encountered on standard error. */
143
static int stdin_eof;		/* EOF has been encountered on standard error. */
Lines 154-159 static int session_closed = 0; /* In SSH Link Here
154
static void client_init_dispatch(void);
154
static void client_init_dispatch(void);
155
int	session_ident = -1;
155
int	session_ident = -1;
156
156
157
/* Track escape per proto2 channel */
158
struct escape_filter_ctx {
159
	int escape_pending;
160
	int escape_char;
161
};
162
163
/* Context for channel confirmation replies */
157
struct channel_reply_ctx {
164
struct channel_reply_ctx {
158
	const char *request_type;
165
	const char *request_type;
159
	int id, do_close;
166
	int id, do_close;
Lines 377-384 client_check_initial_eof_on_stdin(void) Link Here
377
			 * and also process it as an escape character if
384
			 * and also process it as an escape character if
378
			 * appropriate.
385
			 * appropriate.
379
			 */
386
			 */
380
			if ((u_char) buf[0] == escape_char)
387
			if ((u_char) buf[0] == escape_char1)
381
				escape_pending = 1;
388
				escape_pending1 = 1;
382
			else
389
			else
383
				buffer_append(&stdin_buffer, buf, 1);
390
				buffer_append(&stdin_buffer, buf, 1);
384
		}
391
		}
Lines 805-813 out: Link Here
805
		xfree(fwd.connect_host);
812
		xfree(fwd.connect_host);
806
}
813
}
807
814
808
/* process the characters one by one */
815
/* 
816
 * Process the characters one by one, call with c==NULL for proto1 case.
817
 */
809
static int
818
static int
810
process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
819
process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
820
    char *buf, int len)
811
{
821
{
812
	char string[1024];
822
	char string[1024];
813
	pid_t pid;
823
	pid_t pid;
Lines 815-821 process_escapes(Buffer *bin, Buffer *bou Link Here
815
	u_int i;
825
	u_int i;
816
	u_char ch;
826
	u_char ch;
817
	char *s;
827
	char *s;
828
	int *escape_pendingp, escape_char;
829
	struct escape_filter_ctx *efc;
818
830
831
	if (c == NULL) {
832
		escape_pendingp = &escape_pending1;
833
		escape_char = escape_char1;
834
	} else {
835
		if (c->filter_ctx == NULL)
836
			return 0;
837
		efc = (struct escape_filter_ctx *)c->filter_ctx;
838
		escape_pendingp = &efc->escape_pending;
839
		escape_char = efc->escape_char;
840
	}
841
	
819
	if (len <= 0)
842
	if (len <= 0)
820
		return (0);
843
		return (0);
821
844
Lines 823-847 process_escapes(Buffer *bin, Buffer *bou Link Here
823
		/* Get one character at a time. */
846
		/* Get one character at a time. */
824
		ch = buf[i];
847
		ch = buf[i];
825
848
826
		if (escape_pending) {
849
		if (*escape_pendingp) {
827
			/* We have previously seen an escape character. */
850
			/* We have previously seen an escape character. */
828
			/* Clear the flag now. */
851
			/* Clear the flag now. */
829
			escape_pending = 0;
852
			*escape_pendingp = 0;
830
853
831
			/* Process the escaped character. */
854
			/* Process the escaped character. */
832
			switch (ch) {
855
			switch (ch) {
833
			case '.':
856
			case '.':
834
				/* Terminate the connection. */
857
				/* Terminate the connection. */
835
				snprintf(string, sizeof string, "%c.\r\n", escape_char);
858
				snprintf(string, sizeof string, "%c.\r\n",
859
				    escape_char);
836
				buffer_append(berr, string, strlen(string));
860
				buffer_append(berr, string, strlen(string));
837
861
838
				quit_pending = 1;
862
				if (c && c->ctl_fd != -1) {
863
					chan_read_failed(c);
864
					chan_write_failed(c);
865
				} else
866
					quit_pending = 1;
839
				return -1;
867
				return -1;
840
868
841
			case 'Z' - 64:
869
			case 'Z' - 64:
870
				/* XXX support this for mux clients */
871
				if (c && c->ctl_fd != -1) {
872
 noescape:
873
					snprintf(string, sizeof string,
874
					    "%c%c escape not available to "
875
					    "multiplexed sessions\r\n",
876
					    escape_char, ch);
877
					buffer_append(berr, string,
878
					    strlen(string));
879
					continue;
880
				}
842
				/* Suspend the program. */
881
				/* Suspend the program. */
843
				/* Print a message to that effect to the user. */
882
				/* Print a message to that effect to the user. */
844
				snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char);
883
				snprintf(string, sizeof string,
884
				    "%c^Z [suspend ssh]\r\n", escape_char);
845
				buffer_append(berr, string, strlen(string));
885
				buffer_append(berr, string, strlen(string));
846
886
847
				/* Restore terminal modes and suspend. */
887
				/* Restore terminal modes and suspend. */
Lines 873-878 process_escapes(Buffer *bin, Buffer *bou Link Here
873
				continue;
913
				continue;
874
914
875
			case '&':
915
			case '&':
916
				if (c && c->ctl_fd != -1)
917
					goto noescape;
876
				/*
918
				/*
877
				 * Detach the program (continue to serve connections,
919
				 * Detach the program (continue to serve connections,
878
				 * but put in background and no more new connections).
920
				 * but put in background and no more new connections).
Lines 921-947 process_escapes(Buffer *bin, Buffer *bou Link Here
921
				continue;
963
				continue;
922
964
923
			case '?':
965
			case '?':
924
				snprintf(string, sizeof string,
966
				if (c && c->ctl_fd != -1) {
967
					snprintf(string, sizeof string,
968
"%c?\r\n\
969
Supported escape sequences:\r\n\
970
  %c.  - terminate session\r\n\
971
  %cB  - send a BREAK to the remote system\r\n\
972
  %cC  - open a command line\r\n\
973
  %cR  - Request rekey (SSH protocol 2 only)\r\n\
974
  %c#  - list forwarded connections\r\n\
975
  %c?  - this message\r\n\
976
  %c%c  - send the escape character by typing it twice\r\n\
977
(Note that escapes are only recognized immediately after newline.)\r\n",
978
					    escape_char, escape_char,
979
					    escape_char, escape_char,
980
					    escape_char, escape_char,
981
					    escape_char, escape_char,
982
					    escape_char);
983
				} else {
984
					snprintf(string, sizeof string,
925
"%c?\r\n\
985
"%c?\r\n\
926
Supported escape sequences:\r\n\
986
Supported escape sequences:\r\n\
927
%c.  - terminate connection\r\n\
987
  %c.  - terminate connection (and any multiplexed sessions)\r\n\
928
%cB  - send a BREAK to the remote system\r\n\
988
  %cB  - send a BREAK to the remote system\r\n\
929
%cC  - open a command line\r\n\
989
  %cC  - open a command line\r\n\
930
%cR  - Request rekey (SSH protocol 2 only)\r\n\
990
  %cR  - Request rekey (SSH protocol 2 only)\r\n\
931
%c^Z - suspend ssh\r\n\
991
  %c^Z - suspend ssh\r\n\
932
%c#  - list forwarded connections\r\n\
992
  %c#  - list forwarded connections\r\n\
933
%c&  - background ssh (when waiting for connections to terminate)\r\n\
993
  %c&  - background ssh (when waiting for connections to terminate)\r\n\
934
%c?  - this message\r\n\
994
  %c?  - this message\r\n\
935
%c%c  - send the escape character by typing it twice\r\n\
995
  %c%c  - send the escape character by typing it twice\r\n\
936
(Note that escapes are only recognized immediately after newline.)\r\n",
996
(Note that escapes are only recognized immediately after newline.)\r\n",
937
				    escape_char, escape_char, escape_char, escape_char,
997
					    escape_char, escape_char,
938
				    escape_char, escape_char, escape_char, escape_char,
998
					    escape_char, escape_char,
939
				    escape_char, escape_char, escape_char);
999
					    escape_char, escape_char,
1000
					    escape_char, escape_char,
1001
					    escape_char, escape_char,
1002
					    escape_char);
1003
				}
940
				buffer_append(berr, string, strlen(string));
1004
				buffer_append(berr, string, strlen(string));
941
				continue;
1005
				continue;
942
1006
943
			case '#':
1007
			case '#':
944
				snprintf(string, sizeof string, "%c#\r\n", escape_char);
1008
				snprintf(string, sizeof string, "%c#\r\n",
1009
				    escape_char);
945
				buffer_append(berr, string, strlen(string));
1010
				buffer_append(berr, string, strlen(string));
946
				s = channel_open_message();
1011
				s = channel_open_message();
947
				buffer_append(berr, s, strlen(s));
1012
				buffer_append(berr, s, strlen(s));
Lines 967-973 Supported escape sequences:\r\n\ Link Here
967
			 */
1032
			 */
968
			if (last_was_cr && ch == escape_char) {
1033
			if (last_was_cr && ch == escape_char) {
969
				/* It is. Set the flag and continue to next character. */
1034
				/* It is. Set the flag and continue to next character. */
970
				escape_pending = 1;
1035
				*escape_pendingp = 1;
971
				continue;
1036
				continue;
972
			}
1037
			}
973
		}
1038
		}
Lines 1018-1024 client_process_input(fd_set *readset) Link Here
1018
				packet_start(SSH_CMSG_EOF);
1083
				packet_start(SSH_CMSG_EOF);
1019
				packet_send();
1084
				packet_send();
1020
			}
1085
			}
1021
		} else if (escape_char == SSH_ESCAPECHAR_NONE) {
1086
		} else if (escape_char1 == SSH_ESCAPECHAR_NONE) {
1022
			/*
1087
			/*
1023
			 * Normal successful read, and no escape character.
1088
			 * Normal successful read, and no escape character.
1024
			 * Just append the data to buffer.
1089
			 * Just append the data to buffer.
Lines 1029-1036 client_process_input(fd_set *readset) Link Here
1029
			 * Normal, successful read.  But we have an escape character
1094
			 * Normal, successful read.  But we have an escape character
1030
			 * and have to process the characters one by one.
1095
			 * and have to process the characters one by one.
1031
			 */
1096
			 */
1032
			if (process_escapes(&stdin_buffer, &stdout_buffer,
1097
			if (process_escapes(NULL, &stdin_buffer,
1033
			    &stderr_buffer, buf, len) == -1)
1098
			    &stdout_buffer, &stderr_buffer, buf, len) == -1)
1034
				return;
1099
				return;
1035
		}
1100
		}
1036
	}
1101
	}
Lines 1105-1117 client_process_buffered_input_packets(vo Link Here
1105
1170
1106
/* scan buf[] for '~' before sending data to the peer */
1171
/* scan buf[] for '~' before sending data to the peer */
1107
1172
1108
static int
1173
/* Helper: allocate a new escape_filter_ctx and fill in its escape char */
1109
simple_escape_filter(Channel *c, char *buf, int len)
1174
void *
1175
client_new_escape_filter_ctx(int escape_char)
1176
{
1177
	struct escape_filter_ctx *ret;
1178
1179
	ret = xmalloc(sizeof(*ret));
1180
	ret->escape_pending = 0;
1181
	ret->escape_char = escape_char;
1182
	return (void *)ret;
1183
}
1184
1185
int
1186
client_simple_escape_filter(Channel *c, char *buf, int len)
1110
{
1187
{
1111
	if (c->extended_usage != CHAN_EXTENDED_WRITE)
1188
	if (c->extended_usage != CHAN_EXTENDED_WRITE)
1112
		return 0;
1189
		return 0;
1113
1190
1114
	return process_escapes(&c->input, &c->output, &c->extended, buf, len);
1191
	return process_escapes(c, &c->input, &c->output, &c->extended,
1192
	    buf, len);
1115
}
1193
}
1116
1194
1117
static void
1195
static void
Lines 1143-1149 client_loop(int have_pty, int escape_cha Link Here
1143
	start_time = get_current_time();
1221
	start_time = get_current_time();
1144
1222
1145
	/* Initialize variables. */
1223
	/* Initialize variables. */
1146
	escape_pending = 0;
1224
	escape_pending1 = 0;
1147
	last_was_cr = 1;
1225
	last_was_cr = 1;
1148
	exit_status = -1;
1226
	exit_status = -1;
1149
	stdin_eof = 0;
1227
	stdin_eof = 0;
Lines 1170-1176 client_loop(int have_pty, int escape_cha Link Here
1170
	stdout_bytes = 0;
1248
	stdout_bytes = 0;
1171
	stderr_bytes = 0;
1249
	stderr_bytes = 0;
1172
	quit_pending = 0;
1250
	quit_pending = 0;
1173
	escape_char = escape_char_arg;
1251
	escape_char1 = escape_char_arg;
1174
1252
1175
	/* Initialize buffers. */
1253
	/* Initialize buffers. */
1176
	buffer_init(&stdin_buffer);
1254
	buffer_init(&stdin_buffer);
Lines 1198-1206 client_loop(int have_pty, int escape_cha Link Here
1198
1276
1199
	if (compat20) {
1277
	if (compat20) {
1200
		session_ident = ssh2_chan_id;
1278
		session_ident = ssh2_chan_id;
1201
		if (escape_char != SSH_ESCAPECHAR_NONE)
1279
		if (escape_char_arg != SSH_ESCAPECHAR_NONE)
1202
			channel_register_filter(session_ident,
1280
			channel_register_filter(session_ident,
1203
			    simple_escape_filter, NULL);
1281
			    client_simple_escape_filter, NULL,
1282
			    client_new_escape_filter_ctx(escape_char_arg));
1204
		if (session_ident != -1)
1283
		if (session_ident != -1)
1205
			channel_register_cleanup(session_ident,
1284
			channel_register_cleanup(session_ident,
1206
			    client_channel_closed, 0);
1285
			    client_channel_closed, 0);
(-)clientloop.h (-15 / +5 lines)
Lines 46-53 void client_session2_setup(int, int, in Link Here
46
	    int, Buffer *, char **);
46
	    int, Buffer *, char **);
47
int	 client_request_tun_fwd(int, int, int);
47
int	 client_request_tun_fwd(int, int, int);
48
48
49
/* Escape filter for protocol 2 sessions */
50
void	*client_new_escape_filter_ctx(int);
51
int	 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 */
Lines 59-78 int client_request_tun_fwd(int, int, in Link Here
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
64
struct 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 */
76
void	muxserver_listen(void);
66
void	muxserver_listen(void);
77
int	muxserver_accept_control(void);
67
int	muxserver_accept_control(void);
78
void	muxclient(const char *);
68
void	muxclient(const char *);
(-)mux.c (-27 / +45 lines)
Lines 60-65 extern char *host; Link Here
60
int subsystem_flag;
60
int subsystem_flag;
61
extern Buffer command;
61
extern Buffer command;
62
62
63
/* Context for session open confirmation callback */
64
struct 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
63
/* fd to control socket */
75
/* fd to control socket */
64
int muxserver_sock = -1;
76
int muxserver_sock = -1;
65
77
Lines 178-184 muxserver_accept_control(void) Link Here
178
	struct sockaddr_storage addr;
190
	struct sockaddr_storage addr;
179
	struct mux_session_confirm_ctx *cctx;
191
	struct mux_session_confirm_ctx *cctx;
180
	char *cmd;
192
	char *cmd;
181
	u_int i, j, len, env_len, mux_command, flags;
193
	u_int i, j, len, env_len, mux_command, flags, escape_char;
182
	uid_t euid;
194
	uid_t euid;
183
	gid_t egid;
195
	gid_t egid;
184
	int start_close = 0;
196
	int start_close = 0;
Lines 305-310 muxserver_accept_control(void) Link Here
305
	cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
317
	cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
306
	cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
318
	cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
307
	cctx->term = buffer_get_string(&m, &len);
319
	cctx->term = buffer_get_string(&m, &len);
320
	escape_char = buffer_get_int(&m);
308
321
309
	cmd = buffer_get_string(&m, &len);
322
	cmd = buffer_get_string(&m, &len);
310
	buffer_init(&cctx->cmd);
323
	buffer_init(&cctx->cmd);
Lines 390-397 muxserver_accept_control(void) Link Here
390
	    new_fd[0], new_fd[1], new_fd[2], window, packetmax,
403
	    new_fd[0], new_fd[1], new_fd[2], window, packetmax,
391
	    CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
404
	    CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
392
405
393
	/* XXX */
394
	c->ctl_fd = client_fd;
406
	c->ctl_fd = client_fd;
407
	if (cctx->want_tty && escape_char != 0xffffffff) {
408
		channel_register_filter(c->self,
409
		    client_simple_escape_filter, NULL,
410
		    client_new_escape_filter_ctx((int)escape_char));
411
	}
395
412
396
	debug3("%s: channel_new: %d", __func__, c->self);
413
	debug3("%s: channel_new: %d", __func__, c->self);
397
414
Lines 549-581 muxclient(const char *path) Link Here
549
		fprintf(stderr, "Exit request sent.\r\n");
566
		fprintf(stderr, "Exit request sent.\r\n");
550
		exit(0);
567
		exit(0);
551
	case SSHMUX_COMMAND_OPEN:
568
	case SSHMUX_COMMAND_OPEN:
552
		/* continue below */
569
		buffer_put_cstring(&m, term ? term : "");
570
		if (options.escape_char == SSH_ESCAPECHAR_NONE)
571
			buffer_put_int(&m, 0xffffffff);
572
		else
573
			buffer_put_int(&m, options.escape_char);
574
		buffer_append(&command, "\0", 1);
575
		buffer_put_cstring(&m, buffer_ptr(&command));
576
577
		if (options.num_send_env == 0 || environ == NULL) {
578
			buffer_put_int(&m, 0);
579
		} else {
580
			/* Pass environment */
581
			num_env = 0;
582
			for (i = 0; environ[i] != NULL; i++) {
583
				if (env_permitted(environ[i]))
584
					num_env++; /* Count */
585
			}
586
			buffer_put_int(&m, num_env);
587
		for (i = 0; environ[i] != NULL && num_env >= 0; i++) {
588
				if (env_permitted(environ[i])) {
589
					num_env--;
590
					buffer_put_cstring(&m, environ[i]);
591
				}
592
			}
593
		}
553
		break;
594
		break;
554
	default:
595
	default:
555
		fatal("silly muxclient_command %d", muxclient_command);
596
		fatal("unrecognised muxclient_command %d", muxclient_command);
556
	}
557
558
	/* SSHMUX_COMMAND_OPEN */
559
	buffer_put_cstring(&m, term ? term : "");
560
	buffer_append(&command, "\0", 1);
561
	buffer_put_cstring(&m, buffer_ptr(&command));
562
563
	if (options.num_send_env == 0 || environ == NULL) {
564
		buffer_put_int(&m, 0);
565
	} else {
566
		/* Pass environment */
567
		num_env = 0;
568
		for (i = 0; environ[i] != NULL; i++)
569
			if (env_permitted(environ[i]))
570
				num_env++; /* Count */
571
572
		buffer_put_int(&m, num_env);
573
574
		for (i = 0; environ[i] != NULL && num_env >= 0; i++)
575
			if (env_permitted(environ[i])) {
576
				num_env--;
577
				buffer_put_cstring(&m, environ[i]);
578
			}
579
	}
597
	}
580
598
581
	if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
599
	if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)

Return to bug 1331