diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 3885 |
1 files changed, 1971 insertions, 1914 deletions
diff --git a/channels.c b/channels.c index d030fcdd9..83442be06 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.357 2017/02/01 02:59:09 dtucker Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.375 2017/09/24 13:45:34 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 |
@@ -55,27 +55,27 @@ | |||
55 | 55 | ||
56 | #include <errno.h> | 56 | #include <errno.h> |
57 | #include <fcntl.h> | 57 | #include <fcntl.h> |
58 | #include <limits.h> | ||
58 | #include <netdb.h> | 59 | #include <netdb.h> |
60 | #include <stdarg.h> | ||
59 | #ifdef HAVE_STDINT_H | 61 | #ifdef HAVE_STDINT_H |
60 | #include <stdint.h> | 62 | #include <stdint.h> |
61 | #endif | 63 | #endif |
62 | #include <stdio.h> | 64 | #include <stdio.h> |
63 | #include <stdlib.h> | 65 | #include <stdlib.h> |
64 | #include <string.h> | 66 | #include <string.h> |
65 | #include <termios.h> | 67 | #include <termios.h> |
66 | #include <unistd.h> | 68 | #include <unistd.h> |
67 | #include <stdarg.h> | ||
68 | 69 | ||
69 | #include "openbsd-compat/sys-queue.h" | 70 | #include "openbsd-compat/sys-queue.h" |
70 | #include "xmalloc.h" | 71 | #include "xmalloc.h" |
71 | #include "ssh.h" | 72 | #include "ssh.h" |
72 | #include "ssh1.h" | ||
73 | #include "ssh2.h" | 73 | #include "ssh2.h" |
74 | #include "ssherr.h" | 74 | #include "ssherr.h" |
75 | #include "sshbuf.h" | ||
75 | #include "packet.h" | 76 | #include "packet.h" |
76 | #include "log.h" | 77 | #include "log.h" |
77 | #include "misc.h" | 78 | #include "misc.h" |
78 | #include "buffer.h" | ||
79 | #include "channels.h" | 79 | #include "channels.h" |
80 | #include "compat.h" | 80 | #include "compat.h" |
81 | #include "canohost.h" | 81 | #include "canohost.h" |
@@ -83,28 +83,19 @@ | |||
83 | #include "authfd.h" | 83 | #include "authfd.h" |
84 | #include "pathnames.h" | 84 | #include "pathnames.h" |
85 | 85 | ||
86 | /* -- channel core */ | 86 | /* -- agent forwarding */ |
87 | 87 | #define NUM_SOCKS 10 | |
88 | /* | ||
89 | * Pointer to an array containing all allocated channels. The array is | ||
90 | * dynamically extended as needed. | ||
91 | */ | ||
92 | static Channel **channels = NULL; | ||
93 | |||
94 | /* | ||
95 | * Size of the channel array. All slots of the array must always be | ||
96 | * initialized (at least the type field); unused slots set to NULL | ||
97 | */ | ||
98 | static u_int channels_alloc = 0; | ||
99 | 88 | ||
100 | /* | 89 | /* -- tcp forwarding */ |
101 | * Maximum file descriptor value used in any of the channels. This is | 90 | /* special-case port number meaning allow any port */ |
102 | * updated in channel_new. | 91 | #define FWD_PERMIT_ANY_PORT 0 |
103 | */ | ||
104 | static int channel_max_fd = 0; | ||
105 | 92 | ||
93 | /* special-case wildcard meaning allow any host */ | ||
94 | #define FWD_PERMIT_ANY_HOST "*" | ||
106 | 95 | ||
107 | /* -- tcp forwarding */ | 96 | /* -- X11 forwarding */ |
97 | /* Maximum number of fake X11 displays to try. */ | ||
98 | #define MAX_DISPLAYS 1000 | ||
108 | 99 | ||
109 | /* | 100 | /* |
110 | * Data structure for storing which hosts are permitted for forward requests. | 101 | * Data structure for storing which hosts are permitted for forward requests. |
@@ -124,101 +115,153 @@ typedef struct { | |||
124 | Channel *downstream; /* Downstream mux*/ | 115 | Channel *downstream; /* Downstream mux*/ |
125 | } ForwardPermission; | 116 | } ForwardPermission; |
126 | 117 | ||
127 | /* List of all permitted host/port pairs to connect by the user. */ | 118 | typedef void chan_fn(struct ssh *, Channel *c, |
128 | static ForwardPermission *permitted_opens = NULL; | 119 | fd_set *readset, fd_set *writeset); |
129 | |||
130 | /* List of all permitted host/port pairs to connect by the admin. */ | ||
131 | static ForwardPermission *permitted_adm_opens = NULL; | ||
132 | 120 | ||
133 | /* Number of permitted host/port pairs in the array permitted by the user. */ | 121 | /* Master structure for channels state */ |
134 | static int num_permitted_opens = 0; | 122 | struct ssh_channels { |
123 | /* | ||
124 | * Pointer to an array containing all allocated channels. The array | ||
125 | * is dynamically extended as needed. | ||
126 | */ | ||
127 | Channel **channels; | ||
135 | 128 | ||
136 | /* Number of permitted host/port pair in the array permitted by the admin. */ | 129 | /* |
137 | static int num_adm_permitted_opens = 0; | 130 | * Size of the channel array. All slots of the array must always be |
131 | * initialized (at least the type field); unused slots set to NULL | ||
132 | */ | ||
133 | u_int channels_alloc; | ||
138 | 134 | ||
139 | /* special-case port number meaning allow any port */ | 135 | /* |
140 | #define FWD_PERMIT_ANY_PORT 0 | 136 | * Maximum file descriptor value used in any of the channels. This is |
137 | * updated in channel_new. | ||
138 | */ | ||
139 | int channel_max_fd; | ||
141 | 140 | ||
142 | /* special-case wildcard meaning allow any host */ | 141 | /* |
143 | #define FWD_PERMIT_ANY_HOST "*" | 142 | * 'channel_pre*' are called just before select() to add any bits |
143 | * relevant to channels in the select bitmasks. | ||
144 | * | ||
145 | * 'channel_post*': perform any appropriate operations for | ||
146 | * channels which have events pending. | ||
147 | */ | ||
148 | chan_fn **channel_pre; | ||
149 | chan_fn **channel_post; | ||
144 | 150 | ||
145 | /* | 151 | /* -- tcp forwarding */ |
146 | * If this is true, all opens are permitted. This is the case on the server | ||
147 | * on which we have to trust the client anyway, and the user could do | ||
148 | * anything after logging in anyway. | ||
149 | */ | ||
150 | static int all_opens_permitted = 0; | ||
151 | 152 | ||
153 | /* List of all permitted host/port pairs to connect by the user. */ | ||
154 | ForwardPermission *permitted_opens; | ||
152 | 155 | ||
153 | /* -- X11 forwarding */ | 156 | /* List of all permitted host/port pairs to connect by the admin. */ |
157 | ForwardPermission *permitted_adm_opens; | ||
154 | 158 | ||
155 | /* Maximum number of fake X11 displays to try. */ | 159 | /* |
156 | #define MAX_DISPLAYS 1000 | 160 | * Number of permitted host/port pairs in the array permitted by |
161 | * the user. | ||
162 | */ | ||
163 | u_int num_permitted_opens; | ||
157 | 164 | ||
158 | /* Saved X11 local (client) display. */ | 165 | /* |
159 | static char *x11_saved_display = NULL; | 166 | * Number of permitted host/port pair in the array permitted by |
167 | * the admin. | ||
168 | */ | ||
169 | u_int num_adm_permitted_opens; | ||
160 | 170 | ||
161 | /* Saved X11 authentication protocol name. */ | 171 | /* |
162 | static char *x11_saved_proto = NULL; | 172 | * If this is true, all opens are permitted. This is the case on |
173 | * the server on which we have to trust the client anyway, and the | ||
174 | * user could do anything after logging in anyway. | ||
175 | */ | ||
176 | int all_opens_permitted; | ||
163 | 177 | ||
164 | /* Saved X11 authentication data. This is the real data. */ | 178 | /* -- X11 forwarding */ |
165 | static char *x11_saved_data = NULL; | ||
166 | static u_int x11_saved_data_len = 0; | ||
167 | 179 | ||
168 | /* Deadline after which all X11 connections are refused */ | 180 | /* Saved X11 local (client) display. */ |
169 | static u_int x11_refuse_time; | 181 | char *x11_saved_display; |
170 | 182 | ||
171 | /* | 183 | /* Saved X11 authentication protocol name. */ |
172 | * Fake X11 authentication data. This is what the server will be sending us; | 184 | char *x11_saved_proto; |
173 | * we should replace any occurrences of this by the real data. | ||
174 | */ | ||
175 | static u_char *x11_fake_data = NULL; | ||
176 | static u_int x11_fake_data_len; | ||
177 | 185 | ||
186 | /* Saved X11 authentication data. This is the real data. */ | ||
187 | char *x11_saved_data; | ||
188 | u_int x11_saved_data_len; | ||
178 | 189 | ||
179 | /* -- agent forwarding */ | 190 | /* Deadline after which all X11 connections are refused */ |
191 | u_int x11_refuse_time; | ||
180 | 192 | ||
181 | #define NUM_SOCKS 10 | 193 | /* |
194 | * Fake X11 authentication data. This is what the server will be | ||
195 | * sending us; we should replace any occurrences of this by the | ||
196 | * real data. | ||
197 | */ | ||
198 | u_char *x11_fake_data; | ||
199 | u_int x11_fake_data_len; | ||
182 | 200 | ||
183 | /* AF_UNSPEC or AF_INET or AF_INET6 */ | 201 | /* AF_UNSPEC or AF_INET or AF_INET6 */ |
184 | static int IPv4or6 = AF_UNSPEC; | 202 | int IPv4or6; |
203 | }; | ||
185 | 204 | ||
186 | /* helper */ | 205 | /* helper */ |
187 | static void port_open_helper(Channel *c, char *rtype); | 206 | static void port_open_helper(struct ssh *ssh, Channel *c, char *rtype); |
188 | static const char *channel_rfwd_bind_host(const char *listen_host); | 207 | static const char *channel_rfwd_bind_host(const char *listen_host); |
189 | 208 | ||
190 | /* non-blocking connect helpers */ | 209 | /* non-blocking connect helpers */ |
191 | static int connect_next(struct channel_connect *); | 210 | static int connect_next(struct channel_connect *); |
192 | static void channel_connect_ctx_free(struct channel_connect *); | 211 | static void channel_connect_ctx_free(struct channel_connect *); |
212 | static Channel *rdynamic_connect_prepare(struct ssh *, char *, char *); | ||
213 | static int rdynamic_connect_finish(struct ssh *, Channel *); | ||
214 | |||
215 | /* Setup helper */ | ||
216 | static void channel_handler_init(struct ssh_channels *sc); | ||
193 | 217 | ||
194 | /* -- channel core */ | 218 | /* -- channel core */ |
195 | 219 | ||
220 | void | ||
221 | channel_init_channels(struct ssh *ssh) | ||
222 | { | ||
223 | struct ssh_channels *sc; | ||
224 | |||
225 | if ((sc = calloc(1, sizeof(*sc))) == NULL || | ||
226 | (sc->channel_pre = calloc(SSH_CHANNEL_MAX_TYPE, | ||
227 | sizeof(*sc->channel_pre))) == NULL || | ||
228 | (sc->channel_post = calloc(SSH_CHANNEL_MAX_TYPE, | ||
229 | sizeof(*sc->channel_post))) == NULL) | ||
230 | fatal("%s: allocation failed", __func__); | ||
231 | sc->channels_alloc = 10; | ||
232 | sc->channels = xcalloc(sc->channels_alloc, sizeof(*sc->channels)); | ||
233 | sc->IPv4or6 = AF_UNSPEC; | ||
234 | channel_handler_init(sc); | ||
235 | |||
236 | ssh->chanctxt = sc; | ||
237 | } | ||
238 | |||
196 | Channel * | 239 | Channel * |
197 | channel_by_id(int id) | 240 | channel_by_id(struct ssh *ssh, int id) |
198 | { | 241 | { |
199 | Channel *c; | 242 | Channel *c; |
200 | 243 | ||
201 | if (id < 0 || (u_int)id >= channels_alloc) { | 244 | if (id < 0 || (u_int)id >= ssh->chanctxt->channels_alloc) { |
202 | logit("channel_by_id: %d: bad id", id); | 245 | logit("%s: %d: bad id", __func__, id); |
203 | return NULL; | 246 | return NULL; |
204 | } | 247 | } |
205 | c = channels[id]; | 248 | c = ssh->chanctxt->channels[id]; |
206 | if (c == NULL) { | 249 | if (c == NULL) { |
207 | logit("channel_by_id: %d: bad id: channel free", id); | 250 | logit("%s: %d: bad id: channel free", __func__, id); |
208 | return NULL; | 251 | return NULL; |
209 | } | 252 | } |
210 | return c; | 253 | return c; |
211 | } | 254 | } |
212 | 255 | ||
213 | Channel * | 256 | Channel * |
214 | channel_by_remote_id(int remote_id) | 257 | channel_by_remote_id(struct ssh *ssh, u_int remote_id) |
215 | { | 258 | { |
216 | Channel *c; | 259 | Channel *c; |
217 | u_int i; | 260 | u_int i; |
218 | 261 | ||
219 | for (i = 0; i < channels_alloc; i++) { | 262 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
220 | c = channels[i]; | 263 | c = ssh->chanctxt->channels[i]; |
221 | if (c != NULL && c->remote_id == remote_id) | 264 | if (c != NULL && c->have_remote_id && c->remote_id == remote_id) |
222 | return c; | 265 | return c; |
223 | } | 266 | } |
224 | return NULL; | 267 | return NULL; |
@@ -229,28 +272,28 @@ channel_by_remote_id(int remote_id) | |||
229 | * Private channels, like listening sockets, may not receive messages. | 272 | * Private channels, like listening sockets, may not receive messages. |
230 | */ | 273 | */ |
231 | Channel * | 274 | Channel * |
232 | channel_lookup(int id) | 275 | channel_lookup(struct ssh *ssh, int id) |
233 | { | 276 | { |
234 | Channel *c; | 277 | Channel *c; |
235 | 278 | ||
236 | if ((c = channel_by_id(id)) == NULL) | 279 | if ((c = channel_by_id(ssh, id)) == NULL) |
237 | return (NULL); | 280 | return NULL; |
238 | 281 | ||
239 | switch (c->type) { | 282 | switch (c->type) { |
240 | case SSH_CHANNEL_X11_OPEN: | 283 | case SSH_CHANNEL_X11_OPEN: |
241 | case SSH_CHANNEL_LARVAL: | 284 | case SSH_CHANNEL_LARVAL: |
242 | case SSH_CHANNEL_CONNECTING: | 285 | case SSH_CHANNEL_CONNECTING: |
243 | case SSH_CHANNEL_DYNAMIC: | 286 | case SSH_CHANNEL_DYNAMIC: |
287 | case SSH_CHANNEL_RDYNAMIC_OPEN: | ||
288 | case SSH_CHANNEL_RDYNAMIC_FINISH: | ||
244 | case SSH_CHANNEL_OPENING: | 289 | case SSH_CHANNEL_OPENING: |
245 | case SSH_CHANNEL_OPEN: | 290 | case SSH_CHANNEL_OPEN: |
246 | case SSH_CHANNEL_INPUT_DRAINING: | ||
247 | case SSH_CHANNEL_OUTPUT_DRAINING: | ||
248 | case SSH_CHANNEL_ABANDONED: | 291 | case SSH_CHANNEL_ABANDONED: |
249 | case SSH_CHANNEL_MUX_PROXY: | 292 | case SSH_CHANNEL_MUX_PROXY: |
250 | return (c); | 293 | return c; |
251 | } | 294 | } |
252 | logit("Non-public channel %d, type %d.", id, c->type); | 295 | logit("Non-public channel %d, type %d.", id, c->type); |
253 | return (NULL); | 296 | return NULL; |
254 | } | 297 | } |
255 | 298 | ||
256 | /* | 299 | /* |
@@ -258,13 +301,15 @@ channel_lookup(int id) | |||
258 | * when the channel consumer/producer is ready, e.g. shell exec'd | 301 | * when the channel consumer/producer is ready, e.g. shell exec'd |
259 | */ | 302 | */ |
260 | static void | 303 | static void |
261 | channel_register_fds(Channel *c, int rfd, int wfd, int efd, | 304 | channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd, |
262 | int extusage, int nonblock, int is_tty) | 305 | int extusage, int nonblock, int is_tty) |
263 | { | 306 | { |
307 | struct ssh_channels *sc = ssh->chanctxt; | ||
308 | |||
264 | /* Update the maximum file descriptor value. */ | 309 | /* Update the maximum file descriptor value. */ |
265 | channel_max_fd = MAXIMUM(channel_max_fd, rfd); | 310 | sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, rfd); |
266 | channel_max_fd = MAXIMUM(channel_max_fd, wfd); | 311 | sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, wfd); |
267 | channel_max_fd = MAXIMUM(channel_max_fd, efd); | 312 | sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, efd); |
268 | 313 | ||
269 | if (rfd != -1) | 314 | if (rfd != -1) |
270 | fcntl(rfd, F_SETFD, FD_CLOEXEC); | 315 | fcntl(rfd, F_SETFD, FD_CLOEXEC); |
@@ -302,192 +347,220 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, | |||
302 | * remote_name to be freed. | 347 | * remote_name to be freed. |
303 | */ | 348 | */ |
304 | Channel * | 349 | Channel * |
305 | channel_new(char *ctype, int type, int rfd, int wfd, int efd, | 350 | channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd, |
306 | u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) | 351 | u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) |
307 | { | 352 | { |
308 | int found; | 353 | struct ssh_channels *sc = ssh->chanctxt; |
309 | u_int i; | 354 | u_int i, found; |
310 | Channel *c; | 355 | Channel *c; |
311 | 356 | ||
312 | /* Do initial allocation if this is the first call. */ | ||
313 | if (channels_alloc == 0) { | ||
314 | channels_alloc = 10; | ||
315 | channels = xcalloc(channels_alloc, sizeof(Channel *)); | ||
316 | for (i = 0; i < channels_alloc; i++) | ||
317 | channels[i] = NULL; | ||
318 | } | ||
319 | /* Try to find a free slot where to put the new channel. */ | 357 | /* Try to find a free slot where to put the new channel. */ |
320 | for (found = -1, i = 0; i < channels_alloc; i++) | 358 | for (i = 0; i < sc->channels_alloc; i++) { |
321 | if (channels[i] == NULL) { | 359 | if (sc->channels[i] == NULL) { |
322 | /* Found a free slot. */ | 360 | /* Found a free slot. */ |
323 | found = (int)i; | 361 | found = i; |
324 | break; | 362 | break; |
325 | } | 363 | } |
326 | if (found < 0) { | 364 | } |
327 | /* There are no free slots. Take last+1 slot and expand the array. */ | 365 | if (i >= sc->channels_alloc) { |
328 | found = channels_alloc; | 366 | /* |
329 | if (channels_alloc > 10000) | 367 | * There are no free slots. Take last+1 slot and expand |
330 | fatal("channel_new: internal error: channels_alloc %d " | 368 | * the array. |
331 | "too big.", channels_alloc); | 369 | */ |
332 | channels = xreallocarray(channels, channels_alloc + 10, | 370 | found = sc->channels_alloc; |
333 | sizeof(Channel *)); | 371 | if (sc->channels_alloc > CHANNELS_MAX_CHANNELS) |
334 | channels_alloc += 10; | 372 | fatal("%s: internal error: channels_alloc %d too big", |
335 | debug2("channel: expanding %d", channels_alloc); | 373 | __func__, sc->channels_alloc); |
336 | for (i = found; i < channels_alloc; i++) | 374 | sc->channels = xrecallocarray(sc->channels, sc->channels_alloc, |
337 | channels[i] = NULL; | 375 | sc->channels_alloc + 10, sizeof(*sc->channels)); |
376 | sc->channels_alloc += 10; | ||
377 | debug2("channel: expanding %d", sc->channels_alloc); | ||
338 | } | 378 | } |
339 | /* Initialize and return new channel. */ | 379 | /* Initialize and return new channel. */ |
340 | c = channels[found] = xcalloc(1, sizeof(Channel)); | 380 | c = sc->channels[found] = xcalloc(1, sizeof(Channel)); |
341 | buffer_init(&c->input); | 381 | if ((c->input = sshbuf_new()) == NULL || |
342 | buffer_init(&c->output); | 382 | (c->output = sshbuf_new()) == NULL || |
343 | buffer_init(&c->extended); | 383 | (c->extended = sshbuf_new()) == NULL) |
344 | c->path = NULL; | 384 | fatal("%s: sshbuf_new failed", __func__); |
345 | c->listening_addr = NULL; | ||
346 | c->listening_port = 0; | ||
347 | c->ostate = CHAN_OUTPUT_OPEN; | 385 | c->ostate = CHAN_OUTPUT_OPEN; |
348 | c->istate = CHAN_INPUT_OPEN; | 386 | c->istate = CHAN_INPUT_OPEN; |
349 | c->flags = 0; | 387 | channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, 0); |
350 | channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0); | ||
351 | c->notbefore = 0; | ||
352 | c->self = found; | 388 | c->self = found; |
353 | c->type = type; | 389 | c->type = type; |
354 | c->ctype = ctype; | 390 | c->ctype = ctype; |
355 | c->local_window = window; | 391 | c->local_window = window; |
356 | c->local_window_max = window; | 392 | c->local_window_max = window; |
357 | c->local_consumed = 0; | ||
358 | c->local_maxpacket = maxpack; | 393 | c->local_maxpacket = maxpack; |
359 | c->remote_id = -1; | ||
360 | c->remote_name = xstrdup(remote_name); | 394 | c->remote_name = xstrdup(remote_name); |
361 | c->remote_window = 0; | ||
362 | c->remote_maxpacket = 0; | ||
363 | c->force_drain = 0; | ||
364 | c->single_connection = 0; | ||
365 | c->detach_user = NULL; | ||
366 | c->detach_close = 0; | ||
367 | c->open_confirm = NULL; | ||
368 | c->open_confirm_ctx = NULL; | ||
369 | c->input_filter = NULL; | ||
370 | c->output_filter = NULL; | ||
371 | c->filter_ctx = NULL; | ||
372 | c->filter_cleanup = NULL; | ||
373 | c->ctl_chan = -1; | 395 | c->ctl_chan = -1; |
374 | c->mux_rcb = NULL; | ||
375 | c->mux_ctx = NULL; | ||
376 | c->mux_pause = 0; | ||
377 | c->delayed = 1; /* prevent call to channel_post handler */ | 396 | c->delayed = 1; /* prevent call to channel_post handler */ |
378 | TAILQ_INIT(&c->status_confirms); | 397 | TAILQ_INIT(&c->status_confirms); |
379 | debug("channel %d: new [%s]", found, remote_name); | 398 | debug("channel %d: new [%s]", found, remote_name); |
380 | return c; | 399 | return c; |
381 | } | 400 | } |
382 | 401 | ||
383 | static int | 402 | static void |
384 | channel_find_maxfd(void) | 403 | channel_find_maxfd(struct ssh_channels *sc) |
385 | { | 404 | { |
386 | u_int i; | 405 | u_int i; |
387 | int max = 0; | 406 | int max = 0; |
388 | Channel *c; | 407 | Channel *c; |
389 | 408 | ||
390 | for (i = 0; i < channels_alloc; i++) { | 409 | for (i = 0; i < sc->channels_alloc; i++) { |
391 | c = channels[i]; | 410 | c = sc->channels[i]; |
392 | if (c != NULL) { | 411 | if (c != NULL) { |
393 | max = MAXIMUM(max, c->rfd); | 412 | max = MAXIMUM(max, c->rfd); |
394 | max = MAXIMUM(max, c->wfd); | 413 | max = MAXIMUM(max, c->wfd); |
395 | max = MAXIMUM(max, c->efd); | 414 | max = MAXIMUM(max, c->efd); |
396 | } | 415 | } |
397 | } | 416 | } |
398 | return max; | 417 | sc->channel_max_fd = max; |
399 | } | 418 | } |
400 | 419 | ||
401 | int | 420 | int |
402 | channel_close_fd(int *fdp) | 421 | channel_close_fd(struct ssh *ssh, int *fdp) |
403 | { | 422 | { |
423 | struct ssh_channels *sc = ssh->chanctxt; | ||
404 | int ret = 0, fd = *fdp; | 424 | int ret = 0, fd = *fdp; |
405 | 425 | ||
406 | if (fd != -1) { | 426 | if (fd != -1) { |
407 | ret = close(fd); | 427 | ret = close(fd); |
408 | *fdp = -1; | 428 | *fdp = -1; |
409 | if (fd == channel_max_fd) | 429 | if (fd == sc->channel_max_fd) |
410 | channel_max_fd = channel_find_maxfd(); | 430 | channel_find_maxfd(sc); |
411 | } | 431 | } |
412 | return ret; | 432 | return ret; |
413 | } | 433 | } |
414 | 434 | ||
415 | /* Close all channel fd/socket. */ | 435 | /* Close all channel fd/socket. */ |
416 | static void | 436 | static void |
417 | channel_close_fds(Channel *c) | 437 | channel_close_fds(struct ssh *ssh, Channel *c) |
438 | { | ||
439 | channel_close_fd(ssh, &c->sock); | ||
440 | channel_close_fd(ssh, &c->rfd); | ||
441 | channel_close_fd(ssh, &c->wfd); | ||
442 | channel_close_fd(ssh, &c->efd); | ||
443 | } | ||
444 | |||
445 | static void | ||
446 | fwd_perm_clear(ForwardPermission *fp) | ||
418 | { | 447 | { |
419 | channel_close_fd(&c->sock); | 448 | free(fp->host_to_connect); |
420 | channel_close_fd(&c->rfd); | 449 | free(fp->listen_host); |
421 | channel_close_fd(&c->wfd); | 450 | free(fp->listen_path); |
422 | channel_close_fd(&c->efd); | 451 | bzero(fp, sizeof(*fp)); |
452 | } | ||
453 | |||
454 | enum { FWDPERM_USER, FWDPERM_ADMIN }; | ||
455 | |||
456 | static int | ||
457 | fwd_perm_list_add(struct ssh *ssh, int which, | ||
458 | const char *host_to_connect, int port_to_connect, | ||
459 | const char *listen_host, const char *listen_path, int listen_port, | ||
460 | Channel *downstream) | ||
461 | { | ||
462 | ForwardPermission **fpl; | ||
463 | u_int n, *nfpl; | ||
464 | |||
465 | switch (which) { | ||
466 | case FWDPERM_USER: | ||
467 | fpl = &ssh->chanctxt->permitted_opens; | ||
468 | nfpl = &ssh->chanctxt->num_permitted_opens; | ||
469 | break; | ||
470 | case FWDPERM_ADMIN: | ||
471 | fpl = &ssh->chanctxt->permitted_adm_opens; | ||
472 | nfpl = &ssh->chanctxt->num_adm_permitted_opens; | ||
473 | break; | ||
474 | default: | ||
475 | fatal("%s: invalid list %d", __func__, which); | ||
476 | } | ||
477 | |||
478 | if (*nfpl >= INT_MAX) | ||
479 | fatal("%s: overflow", __func__); | ||
480 | |||
481 | *fpl = xrecallocarray(*fpl, *nfpl, *nfpl + 1, sizeof(**fpl)); | ||
482 | n = (*nfpl)++; | ||
483 | #define MAYBE_DUP(s) ((s == NULL) ? NULL : xstrdup(s)) | ||
484 | (*fpl)[n].host_to_connect = MAYBE_DUP(host_to_connect); | ||
485 | (*fpl)[n].port_to_connect = port_to_connect; | ||
486 | (*fpl)[n].listen_host = MAYBE_DUP(listen_host); | ||
487 | (*fpl)[n].listen_path = MAYBE_DUP(listen_path); | ||
488 | (*fpl)[n].listen_port = listen_port; | ||
489 | (*fpl)[n].downstream = downstream; | ||
490 | #undef MAYBE_DUP | ||
491 | return (int)n; | ||
492 | } | ||
493 | |||
494 | static void | ||
495 | mux_remove_remote_forwardings(struct ssh *ssh, Channel *c) | ||
496 | { | ||
497 | struct ssh_channels *sc = ssh->chanctxt; | ||
498 | ForwardPermission *fp; | ||
499 | int r; | ||
500 | u_int i; | ||
501 | |||
502 | for (i = 0; i < sc->num_permitted_opens; i++) { | ||
503 | fp = &sc->permitted_opens[i]; | ||
504 | if (fp->downstream != c) | ||
505 | continue; | ||
506 | |||
507 | /* cancel on the server, since mux client is gone */ | ||
508 | debug("channel %d: cleanup remote forward for %s:%u", | ||
509 | c->self, fp->listen_host, fp->listen_port); | ||
510 | if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || | ||
511 | (r = sshpkt_put_cstring(ssh, | ||
512 | "cancel-tcpip-forward")) != 0 || | ||
513 | (r = sshpkt_put_u8(ssh, 0)) != 0 || | ||
514 | (r = sshpkt_put_cstring(ssh, | ||
515 | channel_rfwd_bind_host(fp->listen_host))) != 0 || | ||
516 | (r = sshpkt_put_u32(ssh, fp->listen_port)) != 0 || | ||
517 | (r = sshpkt_send(ssh)) != 0) { | ||
518 | fatal("%s: channel %i: %s", __func__, | ||
519 | c->self, ssh_err(r)); | ||
520 | } | ||
521 | fwd_perm_clear(fp); /* unregister */ | ||
522 | } | ||
423 | } | 523 | } |
424 | 524 | ||
425 | /* Free the channel and close its fd/socket. */ | 525 | /* Free the channel and close its fd/socket. */ |
426 | void | 526 | void |
427 | channel_free(Channel *c) | 527 | channel_free(struct ssh *ssh, Channel *c) |
428 | { | 528 | { |
529 | struct ssh_channels *sc = ssh->chanctxt; | ||
429 | char *s; | 530 | char *s; |
430 | u_int i, n; | 531 | u_int i, n; |
431 | Channel *other; | 532 | Channel *other; |
432 | struct channel_confirm *cc; | 533 | struct channel_confirm *cc; |
433 | 534 | ||
434 | for (n = 0, i = 0; i < channels_alloc; i++) { | 535 | for (n = 0, i = 0; i < sc->channels_alloc; i++) { |
435 | if ((other = channels[i]) != NULL) { | 536 | if ((other = sc->channels[i]) == NULL) |
436 | n++; | 537 | continue; |
437 | 538 | n++; | |
438 | /* detach from mux client and prepare for closing */ | 539 | /* detach from mux client and prepare for closing */ |
439 | if (c->type == SSH_CHANNEL_MUX_CLIENT && | 540 | if (c->type == SSH_CHANNEL_MUX_CLIENT && |
440 | other->type == SSH_CHANNEL_MUX_PROXY && | 541 | other->type == SSH_CHANNEL_MUX_PROXY && |
441 | other->mux_ctx == c) { | 542 | other->mux_ctx == c) { |
442 | other->mux_ctx = NULL; | 543 | other->mux_ctx = NULL; |
443 | other->type = SSH_CHANNEL_OPEN; | 544 | other->type = SSH_CHANNEL_OPEN; |
444 | other->istate = CHAN_INPUT_CLOSED; | 545 | other->istate = CHAN_INPUT_CLOSED; |
445 | other->ostate = CHAN_OUTPUT_CLOSED; | 546 | other->ostate = CHAN_OUTPUT_CLOSED; |
446 | } | ||
447 | } | 547 | } |
448 | } | 548 | } |
449 | debug("channel %d: free: %s, nchannels %u", c->self, | 549 | debug("channel %d: free: %s, nchannels %u", c->self, |
450 | c->remote_name ? c->remote_name : "???", n); | 550 | c->remote_name ? c->remote_name : "???", n); |
451 | 551 | ||
452 | /* XXX more MUX cleanup: remove remote forwardings */ | 552 | if (c->type == SSH_CHANNEL_MUX_CLIENT) |
453 | if (c->type == SSH_CHANNEL_MUX_CLIENT) { | 553 | mux_remove_remote_forwardings(ssh, c); |
454 | for (i = 0; i < (u_int)num_permitted_opens; i++) { | ||
455 | if (permitted_opens[i].downstream != c) | ||
456 | continue; | ||
457 | /* cancel on the server, since mux client is gone */ | ||
458 | debug("channel %d: cleanup remote forward for %s:%u", | ||
459 | c->self, | ||
460 | permitted_opens[i].listen_host, | ||
461 | permitted_opens[i].listen_port); | ||
462 | packet_start(SSH2_MSG_GLOBAL_REQUEST); | ||
463 | packet_put_cstring("cancel-tcpip-forward"); | ||
464 | packet_put_char(0); | ||
465 | packet_put_cstring(channel_rfwd_bind_host( | ||
466 | permitted_opens[i].listen_host)); | ||
467 | packet_put_int(permitted_opens[i].listen_port); | ||
468 | packet_send(); | ||
469 | /* unregister */ | ||
470 | permitted_opens[i].listen_port = 0; | ||
471 | permitted_opens[i].port_to_connect = 0; | ||
472 | free(permitted_opens[i].host_to_connect); | ||
473 | permitted_opens[i].host_to_connect = NULL; | ||
474 | free(permitted_opens[i].listen_host); | ||
475 | permitted_opens[i].listen_host = NULL; | ||
476 | permitted_opens[i].listen_path = NULL; | ||
477 | permitted_opens[i].downstream = NULL; | ||
478 | } | ||
479 | } | ||
480 | 554 | ||
481 | s = channel_open_message(); | 555 | s = channel_open_message(ssh); |
482 | debug3("channel %d: status: %s", c->self, s); | 556 | debug3("channel %d: status: %s", c->self, s); |
483 | free(s); | 557 | free(s); |
484 | 558 | ||
485 | if (c->sock != -1) | 559 | channel_close_fds(ssh, c); |
486 | shutdown(c->sock, SHUT_RDWR); | 560 | sshbuf_free(c->input); |
487 | channel_close_fds(c); | 561 | sshbuf_free(c->output); |
488 | buffer_free(&c->input); | 562 | sshbuf_free(c->extended); |
489 | buffer_free(&c->output); | 563 | c->input = c->output = c->extended = NULL; |
490 | buffer_free(&c->extended); | ||
491 | free(c->remote_name); | 564 | free(c->remote_name); |
492 | c->remote_name = NULL; | 565 | c->remote_name = NULL; |
493 | free(c->path); | 566 | free(c->path); |
@@ -496,25 +569,26 @@ channel_free(Channel *c) | |||
496 | c->listening_addr = NULL; | 569 | c->listening_addr = NULL; |
497 | while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { | 570 | while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { |
498 | if (cc->abandon_cb != NULL) | 571 | if (cc->abandon_cb != NULL) |
499 | cc->abandon_cb(c, cc->ctx); | 572 | cc->abandon_cb(ssh, c, cc->ctx); |
500 | TAILQ_REMOVE(&c->status_confirms, cc, entry); | 573 | TAILQ_REMOVE(&c->status_confirms, cc, entry); |
501 | explicit_bzero(cc, sizeof(*cc)); | 574 | explicit_bzero(cc, sizeof(*cc)); |
502 | free(cc); | 575 | free(cc); |
503 | } | 576 | } |
504 | if (c->filter_cleanup != NULL && c->filter_ctx != NULL) | 577 | if (c->filter_cleanup != NULL && c->filter_ctx != NULL) |
505 | c->filter_cleanup(c->self, c->filter_ctx); | 578 | c->filter_cleanup(ssh, c->self, c->filter_ctx); |
506 | channels[c->self] = NULL; | 579 | sc->channels[c->self] = NULL; |
580 | explicit_bzero(c, sizeof(*c)); | ||
507 | free(c); | 581 | free(c); |
508 | } | 582 | } |
509 | 583 | ||
510 | void | 584 | void |
511 | channel_free_all(void) | 585 | channel_free_all(struct ssh *ssh) |
512 | { | 586 | { |
513 | u_int i; | 587 | u_int i; |
514 | 588 | ||
515 | for (i = 0; i < channels_alloc; i++) | 589 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) |
516 | if (channels[i] != NULL) | 590 | if (ssh->chanctxt->channels[i] != NULL) |
517 | channel_free(channels[i]); | 591 | channel_free(ssh, ssh->chanctxt->channels[i]); |
518 | } | 592 | } |
519 | 593 | ||
520 | /* | 594 | /* |
@@ -522,26 +596,26 @@ channel_free_all(void) | |||
522 | * descriptors after a fork. | 596 | * descriptors after a fork. |
523 | */ | 597 | */ |
524 | void | 598 | void |
525 | channel_close_all(void) | 599 | channel_close_all(struct ssh *ssh) |
526 | { | 600 | { |
527 | u_int i; | 601 | u_int i; |
528 | 602 | ||
529 | for (i = 0; i < channels_alloc; i++) | 603 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) |
530 | if (channels[i] != NULL) | 604 | if (ssh->chanctxt->channels[i] != NULL) |
531 | channel_close_fds(channels[i]); | 605 | channel_close_fds(ssh, ssh->chanctxt->channels[i]); |
532 | } | 606 | } |
533 | 607 | ||
534 | /* | 608 | /* |
535 | * Stop listening to channels. | 609 | * Stop listening to channels. |
536 | */ | 610 | */ |
537 | void | 611 | void |
538 | channel_stop_listening(void) | 612 | channel_stop_listening(struct ssh *ssh) |
539 | { | 613 | { |
540 | u_int i; | 614 | u_int i; |
541 | Channel *c; | 615 | Channel *c; |
542 | 616 | ||
543 | for (i = 0; i < channels_alloc; i++) { | 617 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
544 | c = channels[i]; | 618 | c = ssh->chanctxt->channels[i]; |
545 | if (c != NULL) { | 619 | if (c != NULL) { |
546 | switch (c->type) { | 620 | switch (c->type) { |
547 | case SSH_CHANNEL_AUTH_SOCKET: | 621 | case SSH_CHANNEL_AUTH_SOCKET: |
@@ -550,8 +624,8 @@ channel_stop_listening(void) | |||
550 | case SSH_CHANNEL_X11_LISTENER: | 624 | case SSH_CHANNEL_X11_LISTENER: |
551 | case SSH_CHANNEL_UNIX_LISTENER: | 625 | case SSH_CHANNEL_UNIX_LISTENER: |
552 | case SSH_CHANNEL_RUNIX_LISTENER: | 626 | case SSH_CHANNEL_RUNIX_LISTENER: |
553 | channel_close_fd(&c->sock); | 627 | channel_close_fd(ssh, &c->sock); |
554 | channel_free(c); | 628 | channel_free(ssh, c); |
555 | break; | 629 | break; |
556 | } | 630 | } |
557 | } | 631 | } |
@@ -563,28 +637,20 @@ channel_stop_listening(void) | |||
563 | * more channel is overfull. | 637 | * more channel is overfull. |
564 | */ | 638 | */ |
565 | int | 639 | int |
566 | channel_not_very_much_buffered_data(void) | 640 | channel_not_very_much_buffered_data(struct ssh *ssh) |
567 | { | 641 | { |
568 | u_int i; | 642 | u_int i; |
643 | u_int maxsize = ssh_packet_get_maxsize(ssh); | ||
569 | Channel *c; | 644 | Channel *c; |
570 | 645 | ||
571 | for (i = 0; i < channels_alloc; i++) { | 646 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
572 | c = channels[i]; | 647 | c = ssh->chanctxt->channels[i]; |
573 | if (c != NULL && c->type == SSH_CHANNEL_OPEN) { | 648 | if (c == NULL || c->type != SSH_CHANNEL_OPEN) |
574 | #if 0 | 649 | continue; |
575 | if (!compat20 && | 650 | if (sshbuf_len(c->output) > maxsize) { |
576 | buffer_len(&c->input) > packet_get_maxsize()) { | 651 | debug2("channel %d: big output buffer %zu > %u", |
577 | debug2("channel %d: big input buffer %d", | 652 | c->self, sshbuf_len(c->output), maxsize); |
578 | c->self, buffer_len(&c->input)); | 653 | return 0; |
579 | return 0; | ||
580 | } | ||
581 | #endif | ||
582 | if (buffer_len(&c->output) > packet_get_maxsize()) { | ||
583 | debug2("channel %d: big output buffer %u > %u", | ||
584 | c->self, buffer_len(&c->output), | ||
585 | packet_get_maxsize()); | ||
586 | return 0; | ||
587 | } | ||
588 | } | 654 | } |
589 | } | 655 | } |
590 | return 1; | 656 | return 1; |
@@ -592,13 +658,13 @@ channel_not_very_much_buffered_data(void) | |||
592 | 658 | ||
593 | /* Returns true if any channel is still open. */ | 659 | /* Returns true if any channel is still open. */ |
594 | int | 660 | int |
595 | channel_still_open(void) | 661 | channel_still_open(struct ssh *ssh) |
596 | { | 662 | { |
597 | u_int i; | 663 | u_int i; |
598 | Channel *c; | 664 | Channel *c; |
599 | 665 | ||
600 | for (i = 0; i < channels_alloc; i++) { | 666 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
601 | c = channels[i]; | 667 | c = ssh->chanctxt->channels[i]; |
602 | if (c == NULL) | 668 | if (c == NULL) |
603 | continue; | 669 | continue; |
604 | switch (c->type) { | 670 | switch (c->type) { |
@@ -609,6 +675,7 @@ channel_still_open(void) | |||
609 | case SSH_CHANNEL_CLOSED: | 675 | case SSH_CHANNEL_CLOSED: |
610 | case SSH_CHANNEL_AUTH_SOCKET: | 676 | case SSH_CHANNEL_AUTH_SOCKET: |
611 | case SSH_CHANNEL_DYNAMIC: | 677 | case SSH_CHANNEL_DYNAMIC: |
678 | case SSH_CHANNEL_RDYNAMIC_OPEN: | ||
612 | case SSH_CHANNEL_CONNECTING: | 679 | case SSH_CHANNEL_CONNECTING: |
613 | case SSH_CHANNEL_ZOMBIE: | 680 | case SSH_CHANNEL_ZOMBIE: |
614 | case SSH_CHANNEL_ABANDONED: | 681 | case SSH_CHANNEL_ABANDONED: |
@@ -616,22 +683,16 @@ channel_still_open(void) | |||
616 | case SSH_CHANNEL_RUNIX_LISTENER: | 683 | case SSH_CHANNEL_RUNIX_LISTENER: |
617 | continue; | 684 | continue; |
618 | case SSH_CHANNEL_LARVAL: | 685 | case SSH_CHANNEL_LARVAL: |
619 | if (!compat20) | ||
620 | fatal("cannot happen: SSH_CHANNEL_LARVAL"); | ||
621 | continue; | 686 | continue; |
622 | case SSH_CHANNEL_OPENING: | 687 | case SSH_CHANNEL_OPENING: |
623 | case SSH_CHANNEL_OPEN: | 688 | case SSH_CHANNEL_OPEN: |
689 | case SSH_CHANNEL_RDYNAMIC_FINISH: | ||
624 | case SSH_CHANNEL_X11_OPEN: | 690 | case SSH_CHANNEL_X11_OPEN: |
625 | case SSH_CHANNEL_MUX_CLIENT: | 691 | case SSH_CHANNEL_MUX_CLIENT: |
626 | case SSH_CHANNEL_MUX_PROXY: | 692 | case SSH_CHANNEL_MUX_PROXY: |
627 | return 1; | 693 | return 1; |
628 | case SSH_CHANNEL_INPUT_DRAINING: | ||
629 | case SSH_CHANNEL_OUTPUT_DRAINING: | ||
630 | if (!compat13) | ||
631 | fatal("cannot happen: OUT_DRAIN"); | ||
632 | return 1; | ||
633 | default: | 694 | default: |
634 | fatal("channel_still_open: bad channel type %d", c->type); | 695 | fatal("%s: bad channel type %d", __func__, c->type); |
635 | /* NOTREACHED */ | 696 | /* NOTREACHED */ |
636 | } | 697 | } |
637 | } | 698 | } |
@@ -640,18 +701,20 @@ channel_still_open(void) | |||
640 | 701 | ||
641 | /* Returns the id of an open channel suitable for keepaliving */ | 702 | /* Returns the id of an open channel suitable for keepaliving */ |
642 | int | 703 | int |
643 | channel_find_open(void) | 704 | channel_find_open(struct ssh *ssh) |
644 | { | 705 | { |
645 | u_int i; | 706 | u_int i; |
646 | Channel *c; | 707 | Channel *c; |
647 | 708 | ||
648 | for (i = 0; i < channels_alloc; i++) { | 709 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
649 | c = channels[i]; | 710 | c = ssh->chanctxt->channels[i]; |
650 | if (c == NULL || c->remote_id < 0) | 711 | if (c == NULL || !c->have_remote_id) |
651 | continue; | 712 | continue; |
652 | switch (c->type) { | 713 | switch (c->type) { |
653 | case SSH_CHANNEL_CLOSED: | 714 | case SSH_CHANNEL_CLOSED: |
654 | case SSH_CHANNEL_DYNAMIC: | 715 | case SSH_CHANNEL_DYNAMIC: |
716 | case SSH_CHANNEL_RDYNAMIC_OPEN: | ||
717 | case SSH_CHANNEL_RDYNAMIC_FINISH: | ||
655 | case SSH_CHANNEL_X11_LISTENER: | 718 | case SSH_CHANNEL_X11_LISTENER: |
656 | case SSH_CHANNEL_PORT_LISTENER: | 719 | case SSH_CHANNEL_PORT_LISTENER: |
657 | case SSH_CHANNEL_RPORT_LISTENER: | 720 | case SSH_CHANNEL_RPORT_LISTENER: |
@@ -670,13 +733,8 @@ channel_find_open(void) | |||
670 | case SSH_CHANNEL_OPEN: | 733 | case SSH_CHANNEL_OPEN: |
671 | case SSH_CHANNEL_X11_OPEN: | 734 | case SSH_CHANNEL_X11_OPEN: |
672 | return i; | 735 | return i; |
673 | case SSH_CHANNEL_INPUT_DRAINING: | ||
674 | case SSH_CHANNEL_OUTPUT_DRAINING: | ||
675 | if (!compat13) | ||
676 | fatal("cannot happen: OUT_DRAIN"); | ||
677 | return i; | ||
678 | default: | 736 | default: |
679 | fatal("channel_find_open: bad channel type %d", c->type); | 737 | fatal("%s: bad channel type %d", __func__, c->type); |
680 | /* NOTREACHED */ | 738 | /* NOTREACHED */ |
681 | } | 739 | } |
682 | } | 740 | } |
@@ -689,18 +747,21 @@ channel_find_open(void) | |||
689 | * newlines. | 747 | * newlines. |
690 | */ | 748 | */ |
691 | char * | 749 | char * |
692 | channel_open_message(void) | 750 | channel_open_message(struct ssh *ssh) |
693 | { | 751 | { |
694 | Buffer buffer; | 752 | struct sshbuf *buf; |
695 | Channel *c; | 753 | Channel *c; |
696 | char buf[1024], *cp; | ||
697 | u_int i; | 754 | u_int i; |
698 | 755 | int r; | |
699 | buffer_init(&buffer); | 756 | char *ret; |
700 | snprintf(buf, sizeof buf, "The following connections are open:\r\n"); | 757 | |
701 | buffer_append(&buffer, buf, strlen(buf)); | 758 | if ((buf = sshbuf_new()) == NULL) |
702 | for (i = 0; i < channels_alloc; i++) { | 759 | fatal("%s: sshbuf_new", __func__); |
703 | c = channels[i]; | 760 | if ((r = sshbuf_putf(buf, |
761 | "The following connections are open:\r\n")) != 0) | ||
762 | fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); | ||
763 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { | ||
764 | c = ssh->chanctxt->channels[i]; | ||
704 | if (c == NULL) | 765 | if (c == NULL) |
705 | continue; | 766 | continue; |
706 | switch (c->type) { | 767 | switch (c->type) { |
@@ -719,75 +780,95 @@ channel_open_message(void) | |||
719 | case SSH_CHANNEL_OPENING: | 780 | case SSH_CHANNEL_OPENING: |
720 | case SSH_CHANNEL_CONNECTING: | 781 | case SSH_CHANNEL_CONNECTING: |
721 | case SSH_CHANNEL_DYNAMIC: | 782 | case SSH_CHANNEL_DYNAMIC: |
783 | case SSH_CHANNEL_RDYNAMIC_OPEN: | ||
784 | case SSH_CHANNEL_RDYNAMIC_FINISH: | ||
722 | case SSH_CHANNEL_OPEN: | 785 | case SSH_CHANNEL_OPEN: |
723 | case SSH_CHANNEL_X11_OPEN: | 786 | case SSH_CHANNEL_X11_OPEN: |
724 | case SSH_CHANNEL_INPUT_DRAINING: | ||
725 | case SSH_CHANNEL_OUTPUT_DRAINING: | ||
726 | case SSH_CHANNEL_MUX_PROXY: | 787 | case SSH_CHANNEL_MUX_PROXY: |
727 | case SSH_CHANNEL_MUX_CLIENT: | 788 | case SSH_CHANNEL_MUX_CLIENT: |
728 | snprintf(buf, sizeof buf, | 789 | if ((r = sshbuf_putf(buf, " #%d %.300s " |
729 | " #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n", | 790 | "(t%d %s%u i%u/%zu o%u/%zu fd %d/%d cc %d)\r\n", |
730 | c->self, c->remote_name, | 791 | c->self, c->remote_name, |
731 | c->type, c->remote_id, | 792 | c->type, |
732 | c->istate, buffer_len(&c->input), | 793 | c->have_remote_id ? "r" : "nr", c->remote_id, |
733 | c->ostate, buffer_len(&c->output), | 794 | c->istate, sshbuf_len(c->input), |
734 | c->rfd, c->wfd, c->ctl_chan); | 795 | c->ostate, sshbuf_len(c->output), |
735 | buffer_append(&buffer, buf, strlen(buf)); | 796 | c->rfd, c->wfd, c->ctl_chan)) != 0) |
797 | fatal("%s: sshbuf_putf: %s", | ||
798 | __func__, ssh_err(r)); | ||
736 | continue; | 799 | continue; |
737 | default: | 800 | default: |
738 | fatal("channel_open_message: bad channel type %d", c->type); | 801 | fatal("%s: bad channel type %d", __func__, c->type); |
739 | /* NOTREACHED */ | 802 | /* NOTREACHED */ |
740 | } | 803 | } |
741 | } | 804 | } |
742 | buffer_append(&buffer, "\0", 1); | 805 | if ((ret = sshbuf_dup_string(buf)) == NULL) |
743 | cp = xstrdup((char *)buffer_ptr(&buffer)); | 806 | fatal("%s: sshbuf_dup_string", __func__); |
744 | buffer_free(&buffer); | 807 | sshbuf_free(buf); |
745 | return cp; | 808 | return ret; |
809 | } | ||
810 | |||
811 | static void | ||
812 | open_preamble(struct ssh *ssh, const char *where, Channel *c, const char *type) | ||
813 | { | ||
814 | int r; | ||
815 | |||
816 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN)) != 0 || | ||
817 | (r = sshpkt_put_cstring(ssh, type)) != 0 || | ||
818 | (r = sshpkt_put_u32(ssh, c->self)) != 0 || | ||
819 | (r = sshpkt_put_u32(ssh, c->local_window)) != 0 || | ||
820 | (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) { | ||
821 | fatal("%s: channel %i: open: %s", where, c->self, ssh_err(r)); | ||
822 | } | ||
746 | } | 823 | } |
747 | 824 | ||
748 | void | 825 | void |
749 | channel_send_open(int id) | 826 | channel_send_open(struct ssh *ssh, int id) |
750 | { | 827 | { |
751 | Channel *c = channel_lookup(id); | 828 | Channel *c = channel_lookup(ssh, id); |
829 | int r; | ||
752 | 830 | ||
753 | if (c == NULL) { | 831 | if (c == NULL) { |
754 | logit("channel_send_open: %d: bad id", id); | 832 | logit("channel_send_open: %d: bad id", id); |
755 | return; | 833 | return; |
756 | } | 834 | } |
757 | debug2("channel %d: send open", id); | 835 | debug2("channel %d: send open", id); |
758 | packet_start(SSH2_MSG_CHANNEL_OPEN); | 836 | open_preamble(ssh, __func__, c, c->ctype); |
759 | packet_put_cstring(c->ctype); | 837 | if ((r = sshpkt_send(ssh)) != 0) |
760 | packet_put_int(c->self); | 838 | fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r)); |
761 | packet_put_int(c->local_window); | ||
762 | packet_put_int(c->local_maxpacket); | ||
763 | packet_send(); | ||
764 | } | 839 | } |
765 | 840 | ||
766 | void | 841 | void |
767 | channel_request_start(int id, char *service, int wantconfirm) | 842 | channel_request_start(struct ssh *ssh, int id, char *service, int wantconfirm) |
768 | { | 843 | { |
769 | Channel *c = channel_lookup(id); | 844 | Channel *c = channel_lookup(ssh, id); |
845 | int r; | ||
770 | 846 | ||
771 | if (c == NULL) { | 847 | if (c == NULL) { |
772 | logit("channel_request_start: %d: unknown channel id", id); | 848 | logit("%s: %d: unknown channel id", __func__, id); |
773 | return; | 849 | return; |
774 | } | 850 | } |
851 | if (!c->have_remote_id) | ||
852 | fatal(":%s: channel %d: no remote id", __func__, c->self); | ||
853 | |||
775 | debug2("channel %d: request %s confirm %d", id, service, wantconfirm); | 854 | debug2("channel %d: request %s confirm %d", id, service, wantconfirm); |
776 | packet_start(SSH2_MSG_CHANNEL_REQUEST); | 855 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 || |
777 | packet_put_int(c->remote_id); | 856 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
778 | packet_put_cstring(service); | 857 | (r = sshpkt_put_cstring(ssh, service)) != 0 || |
779 | packet_put_char(wantconfirm); | 858 | (r = sshpkt_put_u8(ssh, wantconfirm)) != 0) { |
859 | fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r)); | ||
860 | } | ||
780 | } | 861 | } |
781 | 862 | ||
782 | void | 863 | void |
783 | channel_register_status_confirm(int id, channel_confirm_cb *cb, | 864 | channel_register_status_confirm(struct ssh *ssh, int id, |
784 | channel_confirm_abandon_cb *abandon_cb, void *ctx) | 865 | channel_confirm_cb *cb, channel_confirm_abandon_cb *abandon_cb, void *ctx) |
785 | { | 866 | { |
786 | struct channel_confirm *cc; | 867 | struct channel_confirm *cc; |
787 | Channel *c; | 868 | Channel *c; |
788 | 869 | ||
789 | if ((c = channel_lookup(id)) == NULL) | 870 | if ((c = channel_lookup(ssh, id)) == NULL) |
790 | fatal("channel_register_expect: %d: bad id", id); | 871 | fatal("%s: %d: bad id", __func__, id); |
791 | 872 | ||
792 | cc = xcalloc(1, sizeof(*cc)); | 873 | cc = xcalloc(1, sizeof(*cc)); |
793 | cc->cb = cb; | 874 | cc->cb = cb; |
@@ -797,12 +878,13 @@ channel_register_status_confirm(int id, channel_confirm_cb *cb, | |||
797 | } | 878 | } |
798 | 879 | ||
799 | void | 880 | void |
800 | channel_register_open_confirm(int id, channel_open_fn *fn, void *ctx) | 881 | channel_register_open_confirm(struct ssh *ssh, int id, |
882 | channel_open_fn *fn, void *ctx) | ||
801 | { | 883 | { |
802 | Channel *c = channel_lookup(id); | 884 | Channel *c = channel_lookup(ssh, id); |
803 | 885 | ||
804 | if (c == NULL) { | 886 | if (c == NULL) { |
805 | logit("channel_register_open_confirm: %d: bad id", id); | 887 | logit("%s: %d: bad id", __func__, id); |
806 | return; | 888 | return; |
807 | } | 889 | } |
808 | c->open_confirm = fn; | 890 | c->open_confirm = fn; |
@@ -810,12 +892,13 @@ channel_register_open_confirm(int id, channel_open_fn *fn, void *ctx) | |||
810 | } | 892 | } |
811 | 893 | ||
812 | void | 894 | void |
813 | channel_register_cleanup(int id, channel_callback_fn *fn, int do_close) | 895 | channel_register_cleanup(struct ssh *ssh, int id, |
896 | channel_callback_fn *fn, int do_close) | ||
814 | { | 897 | { |
815 | Channel *c = channel_by_id(id); | 898 | Channel *c = channel_by_id(ssh, id); |
816 | 899 | ||
817 | if (c == NULL) { | 900 | if (c == NULL) { |
818 | logit("channel_register_cleanup: %d: bad id", id); | 901 | logit("%s: %d: bad id", __func__, id); |
819 | return; | 902 | return; |
820 | } | 903 | } |
821 | c->detach_user = fn; | 904 | c->detach_user = fn; |
@@ -823,12 +906,12 @@ channel_register_cleanup(int id, channel_callback_fn *fn, int do_close) | |||
823 | } | 906 | } |
824 | 907 | ||
825 | void | 908 | void |
826 | channel_cancel_cleanup(int id) | 909 | channel_cancel_cleanup(struct ssh *ssh, int id) |
827 | { | 910 | { |
828 | Channel *c = channel_by_id(id); | 911 | Channel *c = channel_by_id(ssh, id); |
829 | 912 | ||
830 | if (c == NULL) { | 913 | if (c == NULL) { |
831 | logit("channel_cancel_cleanup: %d: bad id", id); | 914 | logit("%s: %d: bad id", __func__, id); |
832 | return; | 915 | return; |
833 | } | 916 | } |
834 | c->detach_user = NULL; | 917 | c->detach_user = NULL; |
@@ -836,13 +919,13 @@ channel_cancel_cleanup(int id) | |||
836 | } | 919 | } |
837 | 920 | ||
838 | void | 921 | void |
839 | channel_register_filter(int id, channel_infilter_fn *ifn, | 922 | channel_register_filter(struct ssh *ssh, int id, channel_infilter_fn *ifn, |
840 | channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx) | 923 | channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx) |
841 | { | 924 | { |
842 | Channel *c = channel_lookup(id); | 925 | Channel *c = channel_lookup(ssh, id); |
843 | 926 | ||
844 | if (c == NULL) { | 927 | if (c == NULL) { |
845 | logit("channel_register_filter: %d: bad id", id); | 928 | logit("%s: %d: bad id", __func__, id); |
846 | return; | 929 | return; |
847 | } | 930 | } |
848 | c->input_filter = ifn; | 931 | c->input_filter = ifn; |
@@ -852,118 +935,80 @@ channel_register_filter(int id, channel_infilter_fn *ifn, | |||
852 | } | 935 | } |
853 | 936 | ||
854 | void | 937 | void |
855 | channel_set_fds(int id, int rfd, int wfd, int efd, | 938 | channel_set_fds(struct ssh *ssh, int id, int rfd, int wfd, int efd, |
856 | int extusage, int nonblock, int is_tty, u_int window_max) | 939 | int extusage, int nonblock, int is_tty, u_int window_max) |
857 | { | 940 | { |
858 | Channel *c = channel_lookup(id); | 941 | Channel *c = channel_lookup(ssh, id); |
942 | int r; | ||
859 | 943 | ||
860 | if (c == NULL || c->type != SSH_CHANNEL_LARVAL) | 944 | if (c == NULL || c->type != SSH_CHANNEL_LARVAL) |
861 | fatal("channel_activate for non-larval channel %d.", id); | 945 | fatal("channel_activate for non-larval channel %d.", id); |
862 | channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, is_tty); | 946 | if (!c->have_remote_id) |
947 | fatal(":%s: channel %d: no remote id", __func__, c->self); | ||
948 | |||
949 | channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, is_tty); | ||
863 | c->type = SSH_CHANNEL_OPEN; | 950 | c->type = SSH_CHANNEL_OPEN; |
864 | c->local_window = c->local_window_max = window_max; | 951 | c->local_window = c->local_window_max = window_max; |
865 | packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); | ||
866 | packet_put_int(c->remote_id); | ||
867 | packet_put_int(c->local_window); | ||
868 | packet_send(); | ||
869 | } | ||
870 | 952 | ||
871 | /* | 953 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 || |
872 | * 'channel_pre*' are called just before select() to add any bits relevant to | 954 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
873 | * channels in the select bitmasks. | 955 | (r = sshpkt_put_u32(ssh, c->local_window)) != 0 || |
874 | */ | 956 | (r = sshpkt_send(ssh)) != 0) |
875 | /* | 957 | fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r)); |
876 | * 'channel_post*': perform any appropriate operations for channels which | 958 | } |
877 | * have events pending. | ||
878 | */ | ||
879 | typedef void chan_fn(Channel *c, fd_set *readset, fd_set *writeset); | ||
880 | chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE]; | ||
881 | chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE]; | ||
882 | 959 | ||
883 | /* ARGSUSED */ | ||
884 | static void | 960 | static void |
885 | channel_pre_listener(Channel *c, fd_set *readset, fd_set *writeset) | 961 | channel_pre_listener(struct ssh *ssh, Channel *c, |
962 | fd_set *readset, fd_set *writeset) | ||
886 | { | 963 | { |
887 | FD_SET(c->sock, readset); | 964 | FD_SET(c->sock, readset); |
888 | } | 965 | } |
889 | 966 | ||
890 | /* ARGSUSED */ | ||
891 | static void | 967 | static void |
892 | channel_pre_connecting(Channel *c, fd_set *readset, fd_set *writeset) | 968 | channel_pre_connecting(struct ssh *ssh, Channel *c, |
969 | fd_set *readset, fd_set *writeset) | ||
893 | { | 970 | { |
894 | debug3("channel %d: waiting for connection", c->self); | 971 | debug3("channel %d: waiting for connection", c->self); |
895 | FD_SET(c->sock, writeset); | 972 | FD_SET(c->sock, writeset); |
896 | } | 973 | } |
897 | 974 | ||
898 | static void | 975 | static void |
899 | channel_pre_open_13(Channel *c, fd_set *readset, fd_set *writeset) | 976 | channel_pre_open(struct ssh *ssh, Channel *c, |
977 | fd_set *readset, fd_set *writeset) | ||
900 | { | 978 | { |
901 | if (buffer_len(&c->input) < packet_get_maxsize()) | ||
902 | FD_SET(c->sock, readset); | ||
903 | if (buffer_len(&c->output) > 0) | ||
904 | FD_SET(c->sock, writeset); | ||
905 | } | ||
906 | |||
907 | static void | ||
908 | channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset) | ||
909 | { | ||
910 | u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); | ||
911 | |||
912 | if (c->istate == CHAN_INPUT_OPEN && | 979 | if (c->istate == CHAN_INPUT_OPEN && |
913 | limit > 0 && | 980 | c->remote_window > 0 && |
914 | buffer_len(&c->input) < limit && | 981 | sshbuf_len(c->input) < c->remote_window && |
915 | buffer_check_alloc(&c->input, CHAN_RBUF)) | 982 | sshbuf_check_reserve(c->input, CHAN_RBUF) == 0) |
916 | FD_SET(c->rfd, readset); | 983 | FD_SET(c->rfd, readset); |
917 | if (c->ostate == CHAN_OUTPUT_OPEN || | 984 | if (c->ostate == CHAN_OUTPUT_OPEN || |
918 | c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { | 985 | c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { |
919 | if (buffer_len(&c->output) > 0) { | 986 | if (sshbuf_len(c->output) > 0) { |
920 | FD_SET(c->wfd, writeset); | 987 | FD_SET(c->wfd, writeset); |
921 | } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { | 988 | } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { |
922 | if (CHANNEL_EFD_OUTPUT_ACTIVE(c)) | 989 | if (CHANNEL_EFD_OUTPUT_ACTIVE(c)) |
923 | debug2("channel %d: obuf_empty delayed efd %d/(%d)", | 990 | debug2("channel %d: " |
924 | c->self, c->efd, buffer_len(&c->extended)); | 991 | "obuf_empty delayed efd %d/(%zu)", c->self, |
992 | c->efd, sshbuf_len(c->extended)); | ||
925 | else | 993 | else |
926 | chan_obuf_empty(c); | 994 | chan_obuf_empty(ssh, c); |
927 | } | 995 | } |
928 | } | 996 | } |
929 | /** XXX check close conditions, too */ | 997 | /** XXX check close conditions, too */ |
930 | if (compat20 && c->efd != -1 && | 998 | if (c->efd != -1 && !(c->istate == CHAN_INPUT_CLOSED && |
931 | !(c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED)) { | 999 | c->ostate == CHAN_OUTPUT_CLOSED)) { |
932 | if (c->extended_usage == CHAN_EXTENDED_WRITE && | 1000 | if (c->extended_usage == CHAN_EXTENDED_WRITE && |
933 | buffer_len(&c->extended) > 0) | 1001 | sshbuf_len(c->extended) > 0) |
934 | FD_SET(c->efd, writeset); | 1002 | FD_SET(c->efd, writeset); |
935 | else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) && | 1003 | else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) && |
936 | (c->extended_usage == CHAN_EXTENDED_READ || | 1004 | (c->extended_usage == CHAN_EXTENDED_READ || |
937 | c->extended_usage == CHAN_EXTENDED_IGNORE) && | 1005 | c->extended_usage == CHAN_EXTENDED_IGNORE) && |
938 | buffer_len(&c->extended) < c->remote_window) | 1006 | sshbuf_len(c->extended) < c->remote_window) |
939 | FD_SET(c->efd, readset); | 1007 | FD_SET(c->efd, readset); |
940 | } | 1008 | } |
941 | /* XXX: What about efd? races? */ | 1009 | /* XXX: What about efd? races? */ |
942 | } | 1010 | } |
943 | 1011 | ||
944 | /* ARGSUSED */ | ||
945 | static void | ||
946 | channel_pre_input_draining(Channel *c, fd_set *readset, fd_set *writeset) | ||
947 | { | ||
948 | if (buffer_len(&c->input) == 0) { | ||
949 | packet_start(SSH_MSG_CHANNEL_CLOSE); | ||
950 | packet_put_int(c->remote_id); | ||
951 | packet_send(); | ||
952 | c->type = SSH_CHANNEL_CLOSED; | ||
953 | debug2("channel %d: closing after input drain.", c->self); | ||
954 | } | ||
955 | } | ||
956 | |||
957 | /* ARGSUSED */ | ||
958 | static void | ||
959 | channel_pre_output_draining(Channel *c, fd_set *readset, fd_set *writeset) | ||
960 | { | ||
961 | if (buffer_len(&c->output) == 0) | ||
962 | chan_mark_dead(c); | ||
963 | else | ||
964 | FD_SET(c->sock, writeset); | ||
965 | } | ||
966 | |||
967 | /* | 1012 | /* |
968 | * This is a special state for X11 authentication spoofing. An opened X11 | 1013 | * This is a special state for X11 authentication spoofing. An opened X11 |
969 | * connection (when authentication spoofing is being done) remains in this | 1014 | * connection (when authentication spoofing is being done) remains in this |
@@ -974,24 +1019,26 @@ channel_pre_output_draining(Channel *c, fd_set *readset, fd_set *writeset) | |||
974 | * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok | 1019 | * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok |
975 | */ | 1020 | */ |
976 | static int | 1021 | static int |
977 | x11_open_helper(Buffer *b) | 1022 | x11_open_helper(struct ssh *ssh, struct sshbuf *b) |
978 | { | 1023 | { |
1024 | struct ssh_channels *sc = ssh->chanctxt; | ||
979 | u_char *ucp; | 1025 | u_char *ucp; |
980 | u_int proto_len, data_len; | 1026 | u_int proto_len, data_len; |
981 | 1027 | ||
982 | /* Is this being called after the refusal deadline? */ | 1028 | /* Is this being called after the refusal deadline? */ |
983 | if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) { | 1029 | if (sc->x11_refuse_time != 0 && |
1030 | (u_int)monotime() >= sc->x11_refuse_time) { | ||
984 | verbose("Rejected X11 connection after ForwardX11Timeout " | 1031 | verbose("Rejected X11 connection after ForwardX11Timeout " |
985 | "expired"); | 1032 | "expired"); |
986 | return -1; | 1033 | return -1; |
987 | } | 1034 | } |
988 | 1035 | ||
989 | /* Check if the fixed size part of the packet is in buffer. */ | 1036 | /* Check if the fixed size part of the packet is in buffer. */ |
990 | if (buffer_len(b) < 12) | 1037 | if (sshbuf_len(b) < 12) |
991 | return 0; | 1038 | return 0; |
992 | 1039 | ||
993 | /* Parse the lengths of variable-length fields. */ | 1040 | /* Parse the lengths of variable-length fields. */ |
994 | ucp = buffer_ptr(b); | 1041 | ucp = sshbuf_mutable_ptr(b); |
995 | if (ucp[0] == 0x42) { /* Byte order MSB first. */ | 1042 | if (ucp[0] == 0x42) { /* Byte order MSB first. */ |
996 | proto_len = 256 * ucp[6] + ucp[7]; | 1043 | proto_len = 256 * ucp[6] + ucp[7]; |
997 | data_len = 256 * ucp[8] + ucp[9]; | 1044 | data_len = 256 * ucp[8] + ucp[9]; |
@@ -1005,27 +1052,27 @@ x11_open_helper(Buffer *b) | |||
1005 | } | 1052 | } |
1006 | 1053 | ||
1007 | /* Check if the whole packet is in buffer. */ | 1054 | /* Check if the whole packet is in buffer. */ |
1008 | if (buffer_len(b) < | 1055 | if (sshbuf_len(b) < |
1009 | 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) | 1056 | 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) |
1010 | return 0; | 1057 | return 0; |
1011 | 1058 | ||
1012 | /* Check if authentication protocol matches. */ | 1059 | /* Check if authentication protocol matches. */ |
1013 | if (proto_len != strlen(x11_saved_proto) || | 1060 | if (proto_len != strlen(sc->x11_saved_proto) || |
1014 | memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { | 1061 | memcmp(ucp + 12, sc->x11_saved_proto, proto_len) != 0) { |
1015 | debug2("X11 connection uses different authentication protocol."); | 1062 | debug2("X11 connection uses different authentication protocol."); |
1016 | return -1; | 1063 | return -1; |
1017 | } | 1064 | } |
1018 | /* Check if authentication data matches our fake data. */ | 1065 | /* Check if authentication data matches our fake data. */ |
1019 | if (data_len != x11_fake_data_len || | 1066 | if (data_len != sc->x11_fake_data_len || |
1020 | timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3), | 1067 | timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3), |
1021 | x11_fake_data, x11_fake_data_len) != 0) { | 1068 | sc->x11_fake_data, sc->x11_fake_data_len) != 0) { |
1022 | debug2("X11 auth data does not match fake data."); | 1069 | debug2("X11 auth data does not match fake data."); |
1023 | return -1; | 1070 | return -1; |
1024 | } | 1071 | } |
1025 | /* Check fake data length */ | 1072 | /* Check fake data length */ |
1026 | if (x11_fake_data_len != x11_saved_data_len) { | 1073 | if (sc->x11_fake_data_len != sc->x11_saved_data_len) { |
1027 | error("X11 fake_data_len %d != saved_data_len %d", | 1074 | error("X11 fake_data_len %d != saved_data_len %d", |
1028 | x11_fake_data_len, x11_saved_data_len); | 1075 | sc->x11_fake_data_len, sc->x11_saved_data_len); |
1029 | return -1; | 1076 | return -1; |
1030 | } | 1077 | } |
1031 | /* | 1078 | /* |
@@ -1034,90 +1081,63 @@ x11_open_helper(Buffer *b) | |||
1034 | * data. | 1081 | * data. |
1035 | */ | 1082 | */ |
1036 | memcpy(ucp + 12 + ((proto_len + 3) & ~3), | 1083 | memcpy(ucp + 12 + ((proto_len + 3) & ~3), |
1037 | x11_saved_data, x11_saved_data_len); | 1084 | sc->x11_saved_data, sc->x11_saved_data_len); |
1038 | return 1; | 1085 | return 1; |
1039 | } | 1086 | } |
1040 | 1087 | ||
1041 | static void | 1088 | static void |
1042 | channel_pre_x11_open_13(Channel *c, fd_set *readset, fd_set *writeset) | 1089 | channel_pre_x11_open(struct ssh *ssh, Channel *c, |
1090 | fd_set *readset, fd_set *writeset) | ||
1043 | { | 1091 | { |
1044 | int ret = x11_open_helper(&c->output); | 1092 | int ret = x11_open_helper(ssh, c->output); |
1045 | |||
1046 | if (ret == 1) { | ||
1047 | /* Start normal processing for the channel. */ | ||
1048 | c->type = SSH_CHANNEL_OPEN; | ||
1049 | channel_pre_open_13(c, readset, writeset); | ||
1050 | } else if (ret == -1) { | ||
1051 | /* | ||
1052 | * We have received an X11 connection that has bad | ||
1053 | * authentication information. | ||
1054 | */ | ||
1055 | logit("X11 connection rejected because of wrong authentication."); | ||
1056 | buffer_clear(&c->input); | ||
1057 | buffer_clear(&c->output); | ||
1058 | channel_close_fd(&c->sock); | ||
1059 | c->sock = -1; | ||
1060 | c->type = SSH_CHANNEL_CLOSED; | ||
1061 | packet_start(SSH_MSG_CHANNEL_CLOSE); | ||
1062 | packet_put_int(c->remote_id); | ||
1063 | packet_send(); | ||
1064 | } | ||
1065 | } | ||
1066 | |||
1067 | static void | ||
1068 | channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset) | ||
1069 | { | ||
1070 | int ret = x11_open_helper(&c->output); | ||
1071 | 1093 | ||
1072 | /* c->force_drain = 1; */ | 1094 | /* c->force_drain = 1; */ |
1073 | 1095 | ||
1074 | if (ret == 1) { | 1096 | if (ret == 1) { |
1075 | c->type = SSH_CHANNEL_OPEN; | 1097 | c->type = SSH_CHANNEL_OPEN; |
1076 | channel_pre_open(c, readset, writeset); | 1098 | channel_pre_open(ssh, c, readset, writeset); |
1077 | } else if (ret == -1) { | 1099 | } else if (ret == -1) { |
1078 | logit("X11 connection rejected because of wrong authentication."); | 1100 | logit("X11 connection rejected because of wrong authentication."); |
1079 | debug2("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); | 1101 | debug2("X11 rejected %d i%d/o%d", |
1080 | chan_read_failed(c); | 1102 | c->self, c->istate, c->ostate); |
1081 | buffer_clear(&c->input); | 1103 | chan_read_failed(ssh, c); |
1082 | chan_ibuf_empty(c); | 1104 | sshbuf_reset(c->input); |
1083 | buffer_clear(&c->output); | 1105 | chan_ibuf_empty(ssh, c); |
1084 | /* for proto v1, the peer will send an IEOF */ | 1106 | sshbuf_reset(c->output); |
1085 | if (compat20) | 1107 | chan_write_failed(ssh, c); |
1086 | chan_write_failed(c); | ||
1087 | else | ||
1088 | c->type = SSH_CHANNEL_OPEN; | ||
1089 | debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); | 1108 | debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); |
1090 | } | 1109 | } |
1091 | } | 1110 | } |
1092 | 1111 | ||
1093 | static void | 1112 | static void |
1094 | channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset) | 1113 | channel_pre_mux_client(struct ssh *ssh, |
1114 | Channel *c, fd_set *readset, fd_set *writeset) | ||
1095 | { | 1115 | { |
1096 | if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause && | 1116 | if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause && |
1097 | buffer_check_alloc(&c->input, CHAN_RBUF)) | 1117 | sshbuf_check_reserve(c->input, CHAN_RBUF) == 0) |
1098 | FD_SET(c->rfd, readset); | 1118 | FD_SET(c->rfd, readset); |
1099 | if (c->istate == CHAN_INPUT_WAIT_DRAIN) { | 1119 | if (c->istate == CHAN_INPUT_WAIT_DRAIN) { |
1100 | /* clear buffer immediately (discard any partial packet) */ | 1120 | /* clear buffer immediately (discard any partial packet) */ |
1101 | buffer_clear(&c->input); | 1121 | sshbuf_reset(c->input); |
1102 | chan_ibuf_empty(c); | 1122 | chan_ibuf_empty(ssh, c); |
1103 | /* Start output drain. XXX just kill chan? */ | 1123 | /* Start output drain. XXX just kill chan? */ |
1104 | chan_rcvd_oclose(c); | 1124 | chan_rcvd_oclose(ssh, c); |
1105 | } | 1125 | } |
1106 | if (c->ostate == CHAN_OUTPUT_OPEN || | 1126 | if (c->ostate == CHAN_OUTPUT_OPEN || |
1107 | c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { | 1127 | c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { |
1108 | if (buffer_len(&c->output) > 0) | 1128 | if (sshbuf_len(c->output) > 0) |
1109 | FD_SET(c->wfd, writeset); | 1129 | FD_SET(c->wfd, writeset); |
1110 | else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) | 1130 | else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) |
1111 | chan_obuf_empty(c); | 1131 | chan_obuf_empty(ssh, c); |
1112 | } | 1132 | } |
1113 | } | 1133 | } |
1114 | 1134 | ||
1115 | /* try to decode a socks4 header */ | 1135 | /* try to decode a socks4 header */ |
1116 | /* ARGSUSED */ | ||
1117 | static int | 1136 | static int |
1118 | channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | 1137 | channel_decode_socks4(Channel *c, struct sshbuf *input, struct sshbuf *output) |
1119 | { | 1138 | { |
1120 | char *p, *host; | 1139 | const u_char *p; |
1140 | char *host; | ||
1121 | u_int len, have, i, found, need; | 1141 | u_int len, have, i, found, need; |
1122 | char username[256]; | 1142 | char username[256]; |
1123 | struct { | 1143 | struct { |
@@ -1126,14 +1146,15 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | |||
1126 | u_int16_t dest_port; | 1146 | u_int16_t dest_port; |
1127 | struct in_addr dest_addr; | 1147 | struct in_addr dest_addr; |
1128 | } s4_req, s4_rsp; | 1148 | } s4_req, s4_rsp; |
1149 | int r; | ||
1129 | 1150 | ||
1130 | debug2("channel %d: decode socks4", c->self); | 1151 | debug2("channel %d: decode socks4", c->self); |
1131 | 1152 | ||
1132 | have = buffer_len(&c->input); | 1153 | have = sshbuf_len(input); |
1133 | len = sizeof(s4_req); | 1154 | len = sizeof(s4_req); |
1134 | if (have < len) | 1155 | if (have < len) |
1135 | return 0; | 1156 | return 0; |
1136 | p = (char *)buffer_ptr(&c->input); | 1157 | p = sshbuf_ptr(input); |
1137 | 1158 | ||
1138 | need = 1; | 1159 | need = 1; |
1139 | /* SOCKS4A uses an invalid IP address 0.0.0.x */ | 1160 | /* SOCKS4A uses an invalid IP address 0.0.0.x */ |
@@ -1158,46 +1179,55 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | |||
1158 | } | 1179 | } |
1159 | if (found < need) | 1180 | if (found < need) |
1160 | return 0; | 1181 | return 0; |
1161 | buffer_get(&c->input, (char *)&s4_req.version, 1); | 1182 | if ((r = sshbuf_get(input, &s4_req.version, 1)) != 0 || |
1162 | buffer_get(&c->input, (char *)&s4_req.command, 1); | 1183 | (r = sshbuf_get(input, &s4_req.command, 1)) != 0 || |
1163 | buffer_get(&c->input, (char *)&s4_req.dest_port, 2); | 1184 | (r = sshbuf_get(input, &s4_req.dest_port, 2)) != 0 || |
1164 | buffer_get(&c->input, (char *)&s4_req.dest_addr, 4); | 1185 | (r = sshbuf_get(input, &s4_req.dest_addr, 4)) != 0) { |
1165 | have = buffer_len(&c->input); | 1186 | debug("channels %d: decode socks4: %s", c->self, ssh_err(r)); |
1166 | p = (char *)buffer_ptr(&c->input); | 1187 | return -1; |
1167 | if (memchr(p, '\0', have) == NULL) | 1188 | } |
1168 | fatal("channel %d: decode socks4: user not nul terminated", | 1189 | have = sshbuf_len(input); |
1190 | p = sshbuf_ptr(input); | ||
1191 | if (memchr(p, '\0', have) == NULL) { | ||
1192 | error("channel %d: decode socks4: user not nul terminated", | ||
1169 | c->self); | 1193 | c->self); |
1194 | return -1; | ||
1195 | } | ||
1170 | len = strlen(p); | 1196 | len = strlen(p); |
1171 | debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); | 1197 | debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); |
1172 | len++; /* trailing '\0' */ | 1198 | len++; /* trailing '\0' */ |
1173 | if (len > have) | ||
1174 | fatal("channel %d: decode socks4: len %d > have %d", | ||
1175 | c->self, len, have); | ||
1176 | strlcpy(username, p, sizeof(username)); | 1199 | strlcpy(username, p, sizeof(username)); |
1177 | buffer_consume(&c->input, len); | 1200 | if ((r = sshbuf_consume(input, len)) != 0) { |
1178 | 1201 | fatal("%s: channel %d: consume: %s", __func__, | |
1202 | c->self, ssh_err(r)); | ||
1203 | } | ||
1179 | free(c->path); | 1204 | free(c->path); |
1180 | c->path = NULL; | 1205 | c->path = NULL; |
1181 | if (need == 1) { /* SOCKS4: one string */ | 1206 | if (need == 1) { /* SOCKS4: one string */ |
1182 | host = inet_ntoa(s4_req.dest_addr); | 1207 | host = inet_ntoa(s4_req.dest_addr); |
1183 | c->path = xstrdup(host); | 1208 | c->path = xstrdup(host); |
1184 | } else { /* SOCKS4A: two strings */ | 1209 | } else { /* SOCKS4A: two strings */ |
1185 | have = buffer_len(&c->input); | 1210 | have = sshbuf_len(input); |
1186 | p = (char *)buffer_ptr(&c->input); | 1211 | p = sshbuf_ptr(input); |
1212 | if (memchr(p, '\0', have) == NULL) { | ||
1213 | error("channel %d: decode socks4a: host not nul " | ||
1214 | "terminated", c->self); | ||
1215 | return -1; | ||
1216 | } | ||
1187 | len = strlen(p); | 1217 | len = strlen(p); |
1188 | debug2("channel %d: decode socks4a: host %s/%d", | 1218 | debug2("channel %d: decode socks4a: host %s/%d", |
1189 | c->self, p, len); | 1219 | c->self, p, len); |
1190 | len++; /* trailing '\0' */ | 1220 | len++; /* trailing '\0' */ |
1191 | if (len > have) | ||
1192 | fatal("channel %d: decode socks4a: len %d > have %d", | ||
1193 | c->self, len, have); | ||
1194 | if (len > NI_MAXHOST) { | 1221 | if (len > NI_MAXHOST) { |
1195 | error("channel %d: hostname \"%.100s\" too long", | 1222 | error("channel %d: hostname \"%.100s\" too long", |
1196 | c->self, p); | 1223 | c->self, p); |
1197 | return -1; | 1224 | return -1; |
1198 | } | 1225 | } |
1199 | c->path = xstrdup(p); | 1226 | c->path = xstrdup(p); |
1200 | buffer_consume(&c->input, len); | 1227 | if ((r = sshbuf_consume(input, len)) != 0) { |
1228 | fatal("%s: channel %d: consume: %s", __func__, | ||
1229 | c->self, ssh_err(r)); | ||
1230 | } | ||
1201 | } | 1231 | } |
1202 | c->host_port = ntohs(s4_req.dest_port); | 1232 | c->host_port = ntohs(s4_req.dest_port); |
1203 | 1233 | ||
@@ -1213,7 +1243,10 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | |||
1213 | s4_rsp.command = 90; /* cd: req granted */ | 1243 | s4_rsp.command = 90; /* cd: req granted */ |
1214 | s4_rsp.dest_port = 0; /* ignored */ | 1244 | s4_rsp.dest_port = 0; /* ignored */ |
1215 | s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ | 1245 | s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ |
1216 | buffer_append(&c->output, &s4_rsp, sizeof(s4_rsp)); | 1246 | if ((r = sshbuf_put(output, &s4_rsp, sizeof(s4_rsp))) != 0) { |
1247 | fatal("%s: channel %d: append reply: %s", __func__, | ||
1248 | c->self, ssh_err(r)); | ||
1249 | } | ||
1217 | return 1; | 1250 | return 1; |
1218 | } | 1251 | } |
1219 | 1252 | ||
@@ -1226,10 +1259,10 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | |||
1226 | #define SSH_SOCKS5_CONNECT 0x01 | 1259 | #define SSH_SOCKS5_CONNECT 0x01 |
1227 | #define SSH_SOCKS5_SUCCESS 0x00 | 1260 | #define SSH_SOCKS5_SUCCESS 0x00 |
1228 | 1261 | ||
1229 | /* ARGSUSED */ | ||
1230 | static int | 1262 | static int |
1231 | channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) | 1263 | channel_decode_socks5(Channel *c, struct sshbuf *input, struct sshbuf *output) |
1232 | { | 1264 | { |
1265 | /* XXX use get/put_u8 instead of trusting struct padding */ | ||
1233 | struct { | 1266 | struct { |
1234 | u_int8_t version; | 1267 | u_int8_t version; |
1235 | u_int8_t command; | 1268 | u_int8_t command; |
@@ -1238,14 +1271,15 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) | |||
1238 | } s5_req, s5_rsp; | 1271 | } s5_req, s5_rsp; |
1239 | u_int16_t dest_port; | 1272 | u_int16_t dest_port; |
1240 | char dest_addr[255+1], ntop[INET6_ADDRSTRLEN]; | 1273 | char dest_addr[255+1], ntop[INET6_ADDRSTRLEN]; |
1241 | u_char *p; | 1274 | const u_char *p; |
1242 | u_int have, need, i, found, nmethods, addrlen, af; | 1275 | u_int have, need, i, found, nmethods, addrlen, af; |
1276 | int r; | ||
1243 | 1277 | ||
1244 | debug2("channel %d: decode socks5", c->self); | 1278 | debug2("channel %d: decode socks5", c->self); |
1245 | p = buffer_ptr(&c->input); | 1279 | p = sshbuf_ptr(input); |
1246 | if (p[0] != 0x05) | 1280 | if (p[0] != 0x05) |
1247 | return -1; | 1281 | return -1; |
1248 | have = buffer_len(&c->input); | 1282 | have = sshbuf_len(input); |
1249 | if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { | 1283 | if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { |
1250 | /* format: ver | nmethods | methods */ | 1284 | /* format: ver | nmethods | methods */ |
1251 | if (have < 2) | 1285 | if (have < 2) |
@@ -1265,10 +1299,16 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) | |||
1265 | c->self); | 1299 | c->self); |
1266 | return -1; | 1300 | return -1; |
1267 | } | 1301 | } |
1268 | buffer_consume(&c->input, nmethods + 2); | 1302 | if ((r = sshbuf_consume(input, nmethods + 2)) != 0) { |
1269 | buffer_put_char(&c->output, 0x05); /* version */ | 1303 | fatal("%s: channel %d: consume: %s", __func__, |
1270 | buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH); /* method */ | 1304 | c->self, ssh_err(r)); |
1271 | FD_SET(c->sock, writeset); | 1305 | } |
1306 | /* version, method */ | ||
1307 | if ((r = sshbuf_put_u8(output, 0x05)) != 0 || | ||
1308 | (r = sshbuf_put_u8(output, SSH_SOCKS5_NOAUTH)) != 0) { | ||
1309 | fatal("%s: channel %d: append reply: %s", __func__, | ||
1310 | c->self, ssh_err(r)); | ||
1311 | } | ||
1272 | c->flags |= SSH_SOCKS5_AUTHDONE; | 1312 | c->flags |= SSH_SOCKS5_AUTHDONE; |
1273 | debug2("channel %d: socks5 auth done", c->self); | 1313 | debug2("channel %d: socks5 auth done", c->self); |
1274 | return 0; /* need more */ | 1314 | return 0; /* need more */ |
@@ -1305,11 +1345,22 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) | |||
1305 | need++; | 1345 | need++; |
1306 | if (have < need) | 1346 | if (have < need) |
1307 | return 0; | 1347 | return 0; |
1308 | buffer_consume(&c->input, sizeof(s5_req)); | 1348 | if ((r = sshbuf_consume(input, sizeof(s5_req))) != 0) { |
1309 | if (s5_req.atyp == SSH_SOCKS5_DOMAIN) | 1349 | fatal("%s: channel %d: consume: %s", __func__, |
1310 | buffer_consume(&c->input, 1); /* host string length */ | 1350 | c->self, ssh_err(r)); |
1311 | buffer_get(&c->input, &dest_addr, addrlen); | 1351 | } |
1312 | buffer_get(&c->input, (char *)&dest_port, 2); | 1352 | if (s5_req.atyp == SSH_SOCKS5_DOMAIN) { |
1353 | /* host string length */ | ||
1354 | if ((r = sshbuf_consume(input, 1)) != 0) { | ||
1355 | fatal("%s: channel %d: consume: %s", __func__, | ||
1356 | c->self, ssh_err(r)); | ||
1357 | } | ||
1358 | } | ||
1359 | if ((r = sshbuf_get(input, &dest_addr, addrlen)) != 0 || | ||
1360 | (r = sshbuf_get(input, &dest_port, 2)) != 0) { | ||
1361 | debug("channel %d: parse addr/port: %s", c->self, ssh_err(r)); | ||
1362 | return -1; | ||
1363 | } | ||
1313 | dest_addr[addrlen] = '\0'; | 1364 | dest_addr[addrlen] = '\0'; |
1314 | free(c->path); | 1365 | free(c->path); |
1315 | c->path = NULL; | 1366 | c->path = NULL; |
@@ -1336,22 +1387,23 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) | |||
1336 | s5_rsp.atyp = SSH_SOCKS5_IPV4; | 1387 | s5_rsp.atyp = SSH_SOCKS5_IPV4; |
1337 | dest_port = 0; /* ignored */ | 1388 | dest_port = 0; /* ignored */ |
1338 | 1389 | ||
1339 | buffer_append(&c->output, &s5_rsp, sizeof(s5_rsp)); | 1390 | if ((r = sshbuf_put(output, &s5_rsp, sizeof(s5_rsp))) != 0 || |
1340 | buffer_put_int(&c->output, ntohl(INADDR_ANY)); /* bind address */ | 1391 | (r = sshbuf_put_u32(output, ntohl(INADDR_ANY))) != 0 || |
1341 | buffer_append(&c->output, &dest_port, sizeof(dest_port)); | 1392 | (r = sshbuf_put(output, &dest_port, sizeof(dest_port))) != 0) |
1393 | fatal("%s: channel %d: append reply: %s", __func__, | ||
1394 | c->self, ssh_err(r)); | ||
1342 | return 1; | 1395 | return 1; |
1343 | } | 1396 | } |
1344 | 1397 | ||
1345 | Channel * | 1398 | Channel * |
1346 | channel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect, | 1399 | channel_connect_stdio_fwd(struct ssh *ssh, |
1347 | int in, int out) | 1400 | const char *host_to_connect, u_short port_to_connect, int in, int out) |
1348 | { | 1401 | { |
1349 | Channel *c; | 1402 | Channel *c; |
1350 | 1403 | ||
1351 | debug("channel_connect_stdio_fwd %s:%d", host_to_connect, | 1404 | debug("%s %s:%d", __func__, host_to_connect, port_to_connect); |
1352 | port_to_connect); | ||
1353 | 1405 | ||
1354 | c = channel_new("stdio-forward", SSH_CHANNEL_OPENING, in, out, | 1406 | c = channel_new(ssh, "stdio-forward", SSH_CHANNEL_OPENING, in, out, |
1355 | -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, | 1407 | -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
1356 | 0, "stdio-forward", /*nonblock*/0); | 1408 | 0, "stdio-forward", /*nonblock*/0); |
1357 | 1409 | ||
@@ -1360,23 +1412,24 @@ channel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect, | |||
1360 | c->listening_port = 0; | 1412 | c->listening_port = 0; |
1361 | c->force_drain = 1; | 1413 | c->force_drain = 1; |
1362 | 1414 | ||
1363 | channel_register_fds(c, in, out, -1, 0, 1, 0); | 1415 | channel_register_fds(ssh, c, in, out, -1, 0, 1, 0); |
1364 | port_open_helper(c, "direct-tcpip"); | 1416 | port_open_helper(ssh, c, "direct-tcpip"); |
1365 | 1417 | ||
1366 | return c; | 1418 | return c; |
1367 | } | 1419 | } |
1368 | 1420 | ||
1369 | /* dynamic port forwarding */ | 1421 | /* dynamic port forwarding */ |
1370 | static void | 1422 | static void |
1371 | channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset) | 1423 | channel_pre_dynamic(struct ssh *ssh, Channel *c, |
1424 | fd_set *readset, fd_set *writeset) | ||
1372 | { | 1425 | { |
1373 | u_char *p; | 1426 | const u_char *p; |
1374 | u_int have; | 1427 | u_int have; |
1375 | int ret; | 1428 | int ret; |
1376 | 1429 | ||
1377 | have = buffer_len(&c->input); | 1430 | have = sshbuf_len(c->input); |
1378 | debug2("channel %d: pre_dynamic: have %d", c->self, have); | 1431 | debug2("channel %d: pre_dynamic: have %d", c->self, have); |
1379 | /* buffer_dump(&c->input); */ | 1432 | /* sshbuf_dump(c->input, stderr); */ |
1380 | /* check if the fixed size part of the packet is in buffer. */ | 1433 | /* check if the fixed size part of the packet is in buffer. */ |
1381 | if (have < 3) { | 1434 | if (have < 3) { |
1382 | /* need more */ | 1435 | /* need more */ |
@@ -1384,105 +1437,174 @@ channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset) | |||
1384 | return; | 1437 | return; |
1385 | } | 1438 | } |
1386 | /* try to guess the protocol */ | 1439 | /* try to guess the protocol */ |
1387 | p = buffer_ptr(&c->input); | 1440 | p = sshbuf_ptr(c->input); |
1441 | /* XXX sshbuf_peek_u8? */ | ||
1388 | switch (p[0]) { | 1442 | switch (p[0]) { |
1389 | case 0x04: | 1443 | case 0x04: |
1390 | ret = channel_decode_socks4(c, readset, writeset); | 1444 | ret = channel_decode_socks4(c, c->input, c->output); |
1391 | break; | 1445 | break; |
1392 | case 0x05: | 1446 | case 0x05: |
1393 | ret = channel_decode_socks5(c, readset, writeset); | 1447 | ret = channel_decode_socks5(c, c->input, c->output); |
1394 | break; | 1448 | break; |
1395 | default: | 1449 | default: |
1396 | ret = -1; | 1450 | ret = -1; |
1397 | break; | 1451 | break; |
1398 | } | 1452 | } |
1399 | if (ret < 0) { | 1453 | if (ret < 0) { |
1400 | chan_mark_dead(c); | 1454 | chan_mark_dead(ssh, c); |
1401 | } else if (ret == 0) { | 1455 | } else if (ret == 0) { |
1402 | debug2("channel %d: pre_dynamic: need more", c->self); | 1456 | debug2("channel %d: pre_dynamic: need more", c->self); |
1403 | /* need more */ | 1457 | /* need more */ |
1404 | FD_SET(c->sock, readset); | 1458 | FD_SET(c->sock, readset); |
1459 | if (sshbuf_len(c->output)) | ||
1460 | FD_SET(c->sock, writeset); | ||
1405 | } else { | 1461 | } else { |
1406 | /* switch to the next state */ | 1462 | /* switch to the next state */ |
1407 | c->type = SSH_CHANNEL_OPENING; | 1463 | c->type = SSH_CHANNEL_OPENING; |
1408 | port_open_helper(c, "direct-tcpip"); | 1464 | port_open_helper(ssh, c, "direct-tcpip"); |
1465 | } | ||
1466 | } | ||
1467 | |||
1468 | /* simulate read-error */ | ||
1469 | static void | ||
1470 | rdynamic_close(struct ssh *ssh, Channel *c) | ||
1471 | { | ||
1472 | c->type = SSH_CHANNEL_OPEN; | ||
1473 | chan_read_failed(ssh, c); | ||
1474 | sshbuf_reset(c->input); | ||
1475 | chan_ibuf_empty(ssh, c); | ||
1476 | sshbuf_reset(c->output); | ||
1477 | chan_write_failed(ssh, c); | ||
1478 | } | ||
1479 | |||
1480 | /* reverse dynamic port forwarding */ | ||
1481 | static void | ||
1482 | channel_before_prepare_select_rdynamic(struct ssh *ssh, Channel *c) | ||
1483 | { | ||
1484 | const u_char *p; | ||
1485 | u_int have, len; | ||
1486 | int r, ret; | ||
1487 | |||
1488 | have = sshbuf_len(c->output); | ||
1489 | debug2("channel %d: pre_rdynamic: have %d", c->self, have); | ||
1490 | /* sshbuf_dump(c->output, stderr); */ | ||
1491 | /* EOF received */ | ||
1492 | if (c->flags & CHAN_EOF_RCVD) { | ||
1493 | if ((r = sshbuf_consume(c->output, have)) != 0) { | ||
1494 | fatal("%s: channel %d: consume: %s", | ||
1495 | __func__, c->self, ssh_err(r)); | ||
1496 | } | ||
1497 | rdynamic_close(ssh, c); | ||
1498 | return; | ||
1499 | } | ||
1500 | /* check if the fixed size part of the packet is in buffer. */ | ||
1501 | if (have < 3) | ||
1502 | return; | ||
1503 | /* try to guess the protocol */ | ||
1504 | p = sshbuf_ptr(c->output); | ||
1505 | switch (p[0]) { | ||
1506 | case 0x04: | ||
1507 | /* switch input/output for reverse forwarding */ | ||
1508 | ret = channel_decode_socks4(c, c->output, c->input); | ||
1509 | break; | ||
1510 | case 0x05: | ||
1511 | ret = channel_decode_socks5(c, c->output, c->input); | ||
1512 | break; | ||
1513 | default: | ||
1514 | ret = -1; | ||
1515 | break; | ||
1516 | } | ||
1517 | if (ret < 0) { | ||
1518 | rdynamic_close(ssh, c); | ||
1519 | } else if (ret == 0) { | ||
1520 | debug2("channel %d: pre_rdynamic: need more", c->self); | ||
1521 | /* send socks request to peer */ | ||
1522 | len = sshbuf_len(c->input); | ||
1523 | if (len > 0 && len < c->remote_window) { | ||
1524 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 || | ||
1525 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | ||
1526 | (r = sshpkt_put_stringb(ssh, c->input)) != 0 || | ||
1527 | (r = sshpkt_send(ssh)) != 0) { | ||
1528 | fatal("%s: channel %i: rdynamic: %s", __func__, | ||
1529 | c->self, ssh_err(r)); | ||
1530 | } | ||
1531 | if ((r = sshbuf_consume(c->input, len)) != 0) { | ||
1532 | fatal("%s: channel %d: consume: %s", | ||
1533 | __func__, c->self, ssh_err(r)); | ||
1534 | } | ||
1535 | c->remote_window -= len; | ||
1536 | } | ||
1537 | } else if (rdynamic_connect_finish(ssh, c) < 0) { | ||
1538 | /* the connect failed */ | ||
1539 | rdynamic_close(ssh, c); | ||
1409 | } | 1540 | } |
1410 | } | 1541 | } |
1411 | 1542 | ||
1412 | /* This is our fake X11 server socket. */ | 1543 | /* This is our fake X11 server socket. */ |
1413 | /* ARGSUSED */ | ||
1414 | static void | 1544 | static void |
1415 | channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset) | 1545 | channel_post_x11_listener(struct ssh *ssh, Channel *c, |
1546 | fd_set *readset, fd_set *writeset) | ||
1416 | { | 1547 | { |
1417 | Channel *nc; | 1548 | Channel *nc; |
1418 | struct sockaddr_storage addr; | 1549 | struct sockaddr_storage addr; |
1419 | int newsock, oerrno; | 1550 | int r, newsock, oerrno, remote_port; |
1420 | socklen_t addrlen; | 1551 | socklen_t addrlen; |
1421 | char buf[16384], *remote_ipaddr; | 1552 | char buf[16384], *remote_ipaddr; |
1422 | int remote_port; | 1553 | |
1423 | 1554 | if (!FD_ISSET(c->sock, readset)) | |
1424 | if (FD_ISSET(c->sock, readset)) { | 1555 | return; |
1425 | debug("X11 connection requested."); | 1556 | |
1426 | addrlen = sizeof(addr); | 1557 | debug("X11 connection requested."); |
1427 | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | 1558 | addrlen = sizeof(addr); |
1428 | if (c->single_connection) { | 1559 | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); |
1429 | oerrno = errno; | 1560 | if (c->single_connection) { |
1430 | debug2("single_connection: closing X11 listener."); | 1561 | oerrno = errno; |
1431 | channel_close_fd(&c->sock); | 1562 | debug2("single_connection: closing X11 listener."); |
1432 | chan_mark_dead(c); | 1563 | channel_close_fd(ssh, &c->sock); |
1433 | errno = oerrno; | 1564 | chan_mark_dead(ssh, c); |
1434 | } | 1565 | errno = oerrno; |
1435 | if (newsock < 0) { | 1566 | } |
1436 | if (errno != EINTR && errno != EWOULDBLOCK && | 1567 | if (newsock < 0) { |
1437 | errno != ECONNABORTED) | 1568 | if (errno != EINTR && errno != EWOULDBLOCK && |
1438 | error("accept: %.100s", strerror(errno)); | 1569 | errno != ECONNABORTED) |
1439 | if (errno == EMFILE || errno == ENFILE) | 1570 | error("accept: %.100s", strerror(errno)); |
1440 | c->notbefore = monotime() + 1; | 1571 | if (errno == EMFILE || errno == ENFILE) |
1441 | return; | 1572 | c->notbefore = monotime() + 1; |
1442 | } | 1573 | return; |
1443 | set_nodelay(newsock); | ||
1444 | remote_ipaddr = get_peer_ipaddr(newsock); | ||
1445 | remote_port = get_peer_port(newsock); | ||
1446 | snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", | ||
1447 | remote_ipaddr, remote_port); | ||
1448 | |||
1449 | nc = channel_new("accepted x11 socket", | ||
1450 | SSH_CHANNEL_OPENING, newsock, newsock, -1, | ||
1451 | c->local_window_max, c->local_maxpacket, 0, buf, 1); | ||
1452 | if (compat20) { | ||
1453 | packet_start(SSH2_MSG_CHANNEL_OPEN); | ||
1454 | packet_put_cstring("x11"); | ||
1455 | packet_put_int(nc->self); | ||
1456 | packet_put_int(nc->local_window_max); | ||
1457 | packet_put_int(nc->local_maxpacket); | ||
1458 | /* originator ipaddr and port */ | ||
1459 | packet_put_cstring(remote_ipaddr); | ||
1460 | if (datafellows & SSH_BUG_X11FWD) { | ||
1461 | debug2("ssh2 x11 bug compat mode"); | ||
1462 | } else { | ||
1463 | packet_put_int(remote_port); | ||
1464 | } | ||
1465 | packet_send(); | ||
1466 | } else { | ||
1467 | packet_start(SSH_SMSG_X11_OPEN); | ||
1468 | packet_put_int(nc->self); | ||
1469 | if (packet_get_protocol_flags() & | ||
1470 | SSH_PROTOFLAG_HOST_IN_FWD_OPEN) | ||
1471 | packet_put_cstring(buf); | ||
1472 | packet_send(); | ||
1473 | } | ||
1474 | free(remote_ipaddr); | ||
1475 | } | 1574 | } |
1575 | set_nodelay(newsock); | ||
1576 | remote_ipaddr = get_peer_ipaddr(newsock); | ||
1577 | remote_port = get_peer_port(newsock); | ||
1578 | snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", | ||
1579 | remote_ipaddr, remote_port); | ||
1580 | |||
1581 | nc = channel_new(ssh, "accepted x11 socket", | ||
1582 | SSH_CHANNEL_OPENING, newsock, newsock, -1, | ||
1583 | c->local_window_max, c->local_maxpacket, 0, buf, 1); | ||
1584 | open_preamble(ssh, __func__, nc, "x11"); | ||
1585 | if ((r = sshpkt_put_cstring(ssh, remote_ipaddr)) != 0) { | ||
1586 | fatal("%s: channel %i: reply %s", __func__, | ||
1587 | c->self, ssh_err(r)); | ||
1588 | } | ||
1589 | if ((datafellows & SSH_BUG_X11FWD) != 0) | ||
1590 | debug2("channel %d: ssh2 x11 bug compat mode", nc->self); | ||
1591 | else if ((r = sshpkt_put_u32(ssh, remote_port)) != 0) { | ||
1592 | fatal("%s: channel %i: reply %s", __func__, | ||
1593 | c->self, ssh_err(r)); | ||
1594 | } | ||
1595 | if ((r = sshpkt_send(ssh)) != 0) | ||
1596 | fatal("%s: channel %i: send %s", __func__, c->self, ssh_err(r)); | ||
1597 | free(remote_ipaddr); | ||
1476 | } | 1598 | } |
1477 | 1599 | ||
1478 | static void | 1600 | static void |
1479 | port_open_helper(Channel *c, char *rtype) | 1601 | port_open_helper(struct ssh *ssh, Channel *c, char *rtype) |
1480 | { | 1602 | { |
1481 | char buf[1024]; | ||
1482 | char *local_ipaddr = get_local_ipaddr(c->sock); | 1603 | char *local_ipaddr = get_local_ipaddr(c->sock); |
1483 | int local_port = c->sock == -1 ? 65536 : get_local_port(c->sock); | 1604 | int local_port = c->sock == -1 ? 65536 : get_local_port(c->sock); |
1484 | char *remote_ipaddr = get_peer_ipaddr(c->sock); | 1605 | char *remote_ipaddr = get_peer_ipaddr(c->sock); |
1485 | int remote_port = get_peer_port(c->sock); | 1606 | int remote_port = get_peer_port(c->sock); |
1607 | int r; | ||
1486 | 1608 | ||
1487 | if (remote_port == -1) { | 1609 | if (remote_port == -1) { |
1488 | /* Fake addr/port to appease peers that validate it (Tectia) */ | 1610 | /* Fake addr/port to appease peers that validate it (Tectia) */ |
@@ -1491,55 +1613,57 @@ port_open_helper(Channel *c, char *rtype) | |||
1491 | remote_port = 65535; | 1613 | remote_port = 65535; |
1492 | } | 1614 | } |
1493 | 1615 | ||
1494 | snprintf(buf, sizeof buf, | 1616 | free(c->remote_name); |
1617 | xasprintf(&c->remote_name, | ||
1495 | "%s: listening port %d for %.100s port %d, " | 1618 | "%s: listening port %d for %.100s port %d, " |
1496 | "connect from %.200s port %d to %.100s port %d", | 1619 | "connect from %.200s port %d to %.100s port %d", |
1497 | rtype, c->listening_port, c->path, c->host_port, | 1620 | rtype, c->listening_port, c->path, c->host_port, |
1498 | remote_ipaddr, remote_port, local_ipaddr, local_port); | 1621 | remote_ipaddr, remote_port, local_ipaddr, local_port); |
1499 | 1622 | ||
1500 | free(c->remote_name); | 1623 | open_preamble(ssh, __func__, c, rtype); |
1501 | c->remote_name = xstrdup(buf); | 1624 | if (strcmp(rtype, "direct-tcpip") == 0) { |
1502 | 1625 | /* target host, port */ | |
1503 | if (compat20) { | 1626 | if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 || |
1504 | packet_start(SSH2_MSG_CHANNEL_OPEN); | 1627 | (r = sshpkt_put_u32(ssh, c->host_port)) != 0) { |
1505 | packet_put_cstring(rtype); | 1628 | fatal("%s: channel %i: reply %s", __func__, |
1506 | packet_put_int(c->self); | 1629 | c->self, ssh_err(r)); |
1507 | packet_put_int(c->local_window_max); | ||
1508 | packet_put_int(c->local_maxpacket); | ||
1509 | if (strcmp(rtype, "direct-tcpip") == 0) { | ||
1510 | /* target host, port */ | ||
1511 | packet_put_cstring(c->path); | ||
1512 | packet_put_int(c->host_port); | ||
1513 | } else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) { | ||
1514 | /* target path */ | ||
1515 | packet_put_cstring(c->path); | ||
1516 | } else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { | ||
1517 | /* listen path */ | ||
1518 | packet_put_cstring(c->path); | ||
1519 | } else { | ||
1520 | /* listen address, port */ | ||
1521 | packet_put_cstring(c->path); | ||
1522 | packet_put_int(local_port); | ||
1523 | } | 1630 | } |
1524 | if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { | 1631 | } else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) { |
1525 | /* reserved for future owner/mode info */ | 1632 | /* target path */ |
1526 | packet_put_cstring(""); | 1633 | if ((r = sshpkt_put_cstring(ssh, c->path)) != 0) { |
1527 | } else { | 1634 | fatal("%s: channel %i: reply %s", __func__, |
1528 | /* originator host and port */ | 1635 | c->self, ssh_err(r)); |
1529 | packet_put_cstring(remote_ipaddr); | 1636 | } |
1530 | packet_put_int((u_int)remote_port); | 1637 | } else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { |
1638 | /* listen path */ | ||
1639 | if ((r = sshpkt_put_cstring(ssh, c->path)) != 0) { | ||
1640 | fatal("%s: channel %i: reply %s", __func__, | ||
1641 | c->self, ssh_err(r)); | ||
1531 | } | 1642 | } |
1532 | packet_send(); | ||
1533 | } else { | 1643 | } else { |
1534 | packet_start(SSH_MSG_PORT_OPEN); | 1644 | /* listen address, port */ |
1535 | packet_put_int(c->self); | 1645 | if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 || |
1536 | packet_put_cstring(c->path); | 1646 | (r = sshpkt_put_u32(ssh, local_port)) != 0) { |
1537 | packet_put_int(c->host_port); | 1647 | fatal("%s: channel %i: reply %s", __func__, |
1538 | if (packet_get_protocol_flags() & | 1648 | c->self, ssh_err(r)); |
1539 | SSH_PROTOFLAG_HOST_IN_FWD_OPEN) | 1649 | } |
1540 | packet_put_cstring(c->remote_name); | ||
1541 | packet_send(); | ||
1542 | } | 1650 | } |
1651 | if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { | ||
1652 | /* reserved for future owner/mode info */ | ||
1653 | if ((r = sshpkt_put_cstring(ssh, "")) != 0) { | ||
1654 | fatal("%s: channel %i: reply %s", __func__, | ||
1655 | c->self, ssh_err(r)); | ||
1656 | } | ||
1657 | } else { | ||
1658 | /* originator host and port */ | ||
1659 | if ((r = sshpkt_put_cstring(ssh, remote_ipaddr)) != 0 || | ||
1660 | (r = sshpkt_put_u32(ssh, (u_int)remote_port)) != 0) { | ||
1661 | fatal("%s: channel %i: reply %s", __func__, | ||
1662 | c->self, ssh_err(r)); | ||
1663 | } | ||
1664 | } | ||
1665 | if ((r = sshpkt_send(ssh)) != 0) | ||
1666 | fatal("%s: channel %i: send %s", __func__, c->self, ssh_err(r)); | ||
1543 | free(remote_ipaddr); | 1667 | free(remote_ipaddr); |
1544 | free(local_ipaddr); | 1668 | free(local_ipaddr); |
1545 | } | 1669 | } |
@@ -1558,17 +1682,17 @@ channel_set_reuseaddr(int fd) | |||
1558 | } | 1682 | } |
1559 | 1683 | ||
1560 | void | 1684 | void |
1561 | channel_set_x11_refuse_time(u_int refuse_time) | 1685 | channel_set_x11_refuse_time(struct ssh *ssh, u_int refuse_time) |
1562 | { | 1686 | { |
1563 | x11_refuse_time = refuse_time; | 1687 | ssh->chanctxt->x11_refuse_time = refuse_time; |
1564 | } | 1688 | } |
1565 | 1689 | ||
1566 | /* | 1690 | /* |
1567 | * This socket is listening for connections to a forwarded TCP/IP port. | 1691 | * This socket is listening for connections to a forwarded TCP/IP port. |
1568 | */ | 1692 | */ |
1569 | /* ARGSUSED */ | ||
1570 | static void | 1693 | static void |
1571 | channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset) | 1694 | channel_post_port_listener(struct ssh *ssh, Channel *c, |
1695 | fd_set *readset, fd_set *writeset) | ||
1572 | { | 1696 | { |
1573 | Channel *nc; | 1697 | Channel *nc; |
1574 | struct sockaddr_storage addr; | 1698 | struct sockaddr_storage addr; |
@@ -1576,360 +1700,406 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
1576 | socklen_t addrlen; | 1700 | socklen_t addrlen; |
1577 | char *rtype; | 1701 | char *rtype; |
1578 | 1702 | ||
1579 | if (FD_ISSET(c->sock, readset)) { | 1703 | if (!FD_ISSET(c->sock, readset)) |
1580 | debug("Connection to port %d forwarding " | 1704 | return; |
1581 | "to %.100s port %d requested.", | ||
1582 | c->listening_port, c->path, c->host_port); | ||
1583 | |||
1584 | if (c->type == SSH_CHANNEL_RPORT_LISTENER) { | ||
1585 | nextstate = SSH_CHANNEL_OPENING; | ||
1586 | rtype = "forwarded-tcpip"; | ||
1587 | } else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) { | ||
1588 | nextstate = SSH_CHANNEL_OPENING; | ||
1589 | rtype = "forwarded-streamlocal@openssh.com"; | ||
1590 | } else if (c->host_port == PORT_STREAMLOCAL) { | ||
1591 | nextstate = SSH_CHANNEL_OPENING; | ||
1592 | rtype = "direct-streamlocal@openssh.com"; | ||
1593 | } else if (c->host_port == 0) { | ||
1594 | nextstate = SSH_CHANNEL_DYNAMIC; | ||
1595 | rtype = "dynamic-tcpip"; | ||
1596 | } else { | ||
1597 | nextstate = SSH_CHANNEL_OPENING; | ||
1598 | rtype = "direct-tcpip"; | ||
1599 | } | ||
1600 | 1705 | ||
1601 | addrlen = sizeof(addr); | 1706 | debug("Connection to port %d forwarding to %.100s port %d requested.", |
1602 | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | 1707 | c->listening_port, c->path, c->host_port); |
1603 | if (newsock < 0) { | 1708 | |
1604 | if (errno != EINTR && errno != EWOULDBLOCK && | 1709 | if (c->type == SSH_CHANNEL_RPORT_LISTENER) { |
1605 | errno != ECONNABORTED) | 1710 | nextstate = SSH_CHANNEL_OPENING; |
1606 | error("accept: %.100s", strerror(errno)); | 1711 | rtype = "forwarded-tcpip"; |
1607 | if (errno == EMFILE || errno == ENFILE) | 1712 | } else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) { |
1608 | c->notbefore = monotime() + 1; | 1713 | nextstate = SSH_CHANNEL_OPENING; |
1609 | return; | 1714 | rtype = "forwarded-streamlocal@openssh.com"; |
1610 | } | 1715 | } else if (c->host_port == PORT_STREAMLOCAL) { |
1611 | if (c->host_port != PORT_STREAMLOCAL) | 1716 | nextstate = SSH_CHANNEL_OPENING; |
1612 | set_nodelay(newsock); | 1717 | rtype = "direct-streamlocal@openssh.com"; |
1613 | nc = channel_new(rtype, nextstate, newsock, newsock, -1, | 1718 | } else if (c->host_port == 0) { |
1614 | c->local_window_max, c->local_maxpacket, 0, rtype, 1); | 1719 | nextstate = SSH_CHANNEL_DYNAMIC; |
1615 | nc->listening_port = c->listening_port; | 1720 | rtype = "dynamic-tcpip"; |
1616 | nc->host_port = c->host_port; | 1721 | } else { |
1617 | if (c->path != NULL) | 1722 | nextstate = SSH_CHANNEL_OPENING; |
1618 | nc->path = xstrdup(c->path); | 1723 | rtype = "direct-tcpip"; |
1619 | 1724 | } | |
1620 | if (nextstate != SSH_CHANNEL_DYNAMIC) | 1725 | |
1621 | port_open_helper(nc, rtype); | 1726 | addrlen = sizeof(addr); |
1727 | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | ||
1728 | if (newsock < 0) { | ||
1729 | if (errno != EINTR && errno != EWOULDBLOCK && | ||
1730 | errno != ECONNABORTED) | ||
1731 | error("accept: %.100s", strerror(errno)); | ||
1732 | if (errno == EMFILE || errno == ENFILE) | ||
1733 | c->notbefore = monotime() + 1; | ||
1734 | return; | ||
1622 | } | 1735 | } |
1736 | if (c->host_port != PORT_STREAMLOCAL) | ||
1737 | set_nodelay(newsock); | ||
1738 | nc = channel_new(ssh, rtype, nextstate, newsock, newsock, -1, | ||
1739 | c->local_window_max, c->local_maxpacket, 0, rtype, 1); | ||
1740 | nc->listening_port = c->listening_port; | ||
1741 | nc->host_port = c->host_port; | ||
1742 | if (c->path != NULL) | ||
1743 | nc->path = xstrdup(c->path); | ||
1744 | |||
1745 | if (nextstate != SSH_CHANNEL_DYNAMIC) | ||
1746 | port_open_helper(ssh, nc, rtype); | ||
1623 | } | 1747 | } |
1624 | 1748 | ||
1625 | /* | 1749 | /* |
1626 | * This is the authentication agent socket listening for connections from | 1750 | * This is the authentication agent socket listening for connections from |
1627 | * clients. | 1751 | * clients. |
1628 | */ | 1752 | */ |
1629 | /* ARGSUSED */ | ||
1630 | static void | 1753 | static void |
1631 | channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset) | 1754 | channel_post_auth_listener(struct ssh *ssh, Channel *c, |
1755 | fd_set *readset, fd_set *writeset) | ||
1632 | { | 1756 | { |
1633 | Channel *nc; | 1757 | Channel *nc; |
1634 | int newsock; | 1758 | int r, newsock; |
1635 | struct sockaddr_storage addr; | 1759 | struct sockaddr_storage addr; |
1636 | socklen_t addrlen; | 1760 | socklen_t addrlen; |
1637 | 1761 | ||
1638 | if (FD_ISSET(c->sock, readset)) { | 1762 | if (!FD_ISSET(c->sock, readset)) |
1639 | addrlen = sizeof(addr); | 1763 | return; |
1640 | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | 1764 | |
1641 | if (newsock < 0) { | 1765 | addrlen = sizeof(addr); |
1642 | error("accept from auth socket: %.100s", | 1766 | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); |
1643 | strerror(errno)); | 1767 | if (newsock < 0) { |
1644 | if (errno == EMFILE || errno == ENFILE) | 1768 | error("accept from auth socket: %.100s", strerror(errno)); |
1645 | c->notbefore = monotime() + 1; | 1769 | if (errno == EMFILE || errno == ENFILE) |
1646 | return; | 1770 | c->notbefore = monotime() + 1; |
1647 | } | 1771 | return; |
1648 | nc = channel_new("accepted auth socket", | ||
1649 | SSH_CHANNEL_OPENING, newsock, newsock, -1, | ||
1650 | c->local_window_max, c->local_maxpacket, | ||
1651 | 0, "accepted auth socket", 1); | ||
1652 | if (compat20) { | ||
1653 | packet_start(SSH2_MSG_CHANNEL_OPEN); | ||
1654 | packet_put_cstring("auth-agent@openssh.com"); | ||
1655 | packet_put_int(nc->self); | ||
1656 | packet_put_int(c->local_window_max); | ||
1657 | packet_put_int(c->local_maxpacket); | ||
1658 | } else { | ||
1659 | packet_start(SSH_SMSG_AGENT_OPEN); | ||
1660 | packet_put_int(nc->self); | ||
1661 | } | ||
1662 | packet_send(); | ||
1663 | } | 1772 | } |
1773 | nc = channel_new(ssh, "accepted auth socket", | ||
1774 | SSH_CHANNEL_OPENING, newsock, newsock, -1, | ||
1775 | c->local_window_max, c->local_maxpacket, | ||
1776 | 0, "accepted auth socket", 1); | ||
1777 | open_preamble(ssh, __func__, nc, "auth-agent@openssh.com"); | ||
1778 | if ((r = sshpkt_send(ssh)) != 0) | ||
1779 | fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r)); | ||
1664 | } | 1780 | } |
1665 | 1781 | ||
1666 | /* ARGSUSED */ | ||
1667 | static void | 1782 | static void |
1668 | channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset) | 1783 | channel_post_connecting(struct ssh *ssh, Channel *c, |
1784 | fd_set *readset, fd_set *writeset) | ||
1669 | { | 1785 | { |
1670 | int err = 0, sock; | 1786 | int err = 0, sock, isopen, r; |
1671 | socklen_t sz = sizeof(err); | 1787 | socklen_t sz = sizeof(err); |
1672 | 1788 | ||
1673 | if (FD_ISSET(c->sock, writeset)) { | 1789 | if (!FD_ISSET(c->sock, writeset)) |
1674 | if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) { | 1790 | return; |
1675 | err = errno; | 1791 | if (!c->have_remote_id) |
1676 | error("getsockopt SO_ERROR failed"); | 1792 | fatal(":%s: channel %d: no remote id", __func__, c->self); |
1793 | /* for rdynamic the OPEN_CONFIRMATION has been sent already */ | ||
1794 | isopen = (c->type == SSH_CHANNEL_RDYNAMIC_FINISH); | ||
1795 | if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) { | ||
1796 | err = errno; | ||
1797 | error("getsockopt SO_ERROR failed"); | ||
1798 | } | ||
1799 | if (err == 0) { | ||
1800 | debug("channel %d: connected to %s port %d", | ||
1801 | c->self, c->connect_ctx.host, c->connect_ctx.port); | ||
1802 | channel_connect_ctx_free(&c->connect_ctx); | ||
1803 | c->type = SSH_CHANNEL_OPEN; | ||
1804 | if (isopen) { | ||
1805 | /* no message necessary */ | ||
1806 | } else { | ||
1807 | if ((r = sshpkt_start(ssh, | ||
1808 | SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 || | ||
1809 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | ||
1810 | (r = sshpkt_put_u32(ssh, c->self)) != 0 || | ||
1811 | (r = sshpkt_put_u32(ssh, c->local_window)) != 0 || | ||
1812 | (r = sshpkt_put_u32(ssh, c->local_maxpacket)) | ||
1813 | != 0) | ||
1814 | fatal("%s: channel %i: confirm: %s", __func__, | ||
1815 | c->self, ssh_err(r)); | ||
1816 | if ((r = sshpkt_send(ssh)) != 0) | ||
1817 | fatal("%s: channel %i: %s", __func__, c->self, | ||
1818 | ssh_err(r)); | ||
1677 | } | 1819 | } |
1678 | if (err == 0) { | 1820 | } else { |
1679 | debug("channel %d: connected to %s port %d", | 1821 | debug("channel %d: connection failed: %s", |
1680 | c->self, c->connect_ctx.host, c->connect_ctx.port); | 1822 | c->self, strerror(err)); |
1681 | channel_connect_ctx_free(&c->connect_ctx); | 1823 | /* Try next address, if any */ |
1682 | c->type = SSH_CHANNEL_OPEN; | 1824 | if ((sock = connect_next(&c->connect_ctx)) > 0) { |
1683 | if (compat20) { | 1825 | close(c->sock); |
1684 | packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); | 1826 | c->sock = c->rfd = c->wfd = sock; |
1685 | packet_put_int(c->remote_id); | 1827 | channel_find_maxfd(ssh->chanctxt); |
1686 | packet_put_int(c->self); | 1828 | return; |
1687 | packet_put_int(c->local_window); | 1829 | } |
1688 | packet_put_int(c->local_maxpacket); | 1830 | /* Exhausted all addresses */ |
1689 | } else { | 1831 | error("connect_to %.100s port %d: failed.", |
1690 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); | 1832 | c->connect_ctx.host, c->connect_ctx.port); |
1691 | packet_put_int(c->remote_id); | 1833 | channel_connect_ctx_free(&c->connect_ctx); |
1692 | packet_put_int(c->self); | 1834 | if (isopen) { |
1693 | } | 1835 | rdynamic_close(ssh, c); |
1694 | } else { | 1836 | } else { |
1695 | debug("channel %d: connection failed: %s", | 1837 | if ((r = sshpkt_start(ssh, |
1696 | c->self, strerror(err)); | 1838 | SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 || |
1697 | /* Try next address, if any */ | 1839 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
1698 | if ((sock = connect_next(&c->connect_ctx)) > 0) { | 1840 | (r = sshpkt_put_u32(ssh, SSH2_OPEN_CONNECT_FAILED)) |
1699 | close(c->sock); | 1841 | != 0) |
1700 | c->sock = c->rfd = c->wfd = sock; | 1842 | fatal("%s: channel %i: failure: %s", __func__, |
1701 | channel_max_fd = channel_find_maxfd(); | 1843 | c->self, ssh_err(r)); |
1702 | return; | 1844 | if ((datafellows & SSH_BUG_OPENFAILURE) == 0 && |
1703 | } | 1845 | ((r = sshpkt_put_cstring(ssh, strerror(err))) != 0 || |
1704 | /* Exhausted all addresses */ | 1846 | (r = sshpkt_put_cstring(ssh, "")) != 0)) |
1705 | error("connect_to %.100s port %d: failed.", | 1847 | fatal("%s: channel %i: failure: %s", __func__, |
1706 | c->connect_ctx.host, c->connect_ctx.port); | 1848 | c->self, ssh_err(r)); |
1707 | channel_connect_ctx_free(&c->connect_ctx); | 1849 | if ((r = sshpkt_send(ssh)) != 0) |
1708 | if (compat20) { | 1850 | fatal("%s: channel %i: %s", __func__, c->self, |
1709 | packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); | 1851 | ssh_err(r)); |
1710 | packet_put_int(c->remote_id); | 1852 | chan_mark_dead(ssh, c); |
1711 | packet_put_int(SSH2_OPEN_CONNECT_FAILED); | ||
1712 | if (!(datafellows & SSH_BUG_OPENFAILURE)) { | ||
1713 | packet_put_cstring(strerror(err)); | ||
1714 | packet_put_cstring(""); | ||
1715 | } | ||
1716 | } else { | ||
1717 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | ||
1718 | packet_put_int(c->remote_id); | ||
1719 | } | ||
1720 | chan_mark_dead(c); | ||
1721 | } | 1853 | } |
1722 | packet_send(); | ||
1723 | } | 1854 | } |
1724 | } | 1855 | } |
1725 | 1856 | ||
1726 | /* ARGSUSED */ | ||
1727 | static int | 1857 | static int |
1728 | channel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset) | 1858 | channel_handle_rfd(struct ssh *ssh, Channel *c, |
1859 | fd_set *readset, fd_set *writeset) | ||
1729 | { | 1860 | { |
1730 | char buf[CHAN_RBUF]; | 1861 | char buf[CHAN_RBUF]; |
1731 | int len, force; | 1862 | ssize_t len; |
1863 | int r, force; | ||
1732 | 1864 | ||
1733 | force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED; | 1865 | force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED; |
1734 | if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) { | 1866 | |
1735 | errno = 0; | 1867 | if (c->rfd == -1 || (!force && !FD_ISSET(c->rfd, readset))) |
1736 | len = read(c->rfd, buf, sizeof(buf)); | 1868 | return 1; |
1737 | if (len < 0 && (errno == EINTR || | 1869 | |
1738 | ((errno == EAGAIN || errno == EWOULDBLOCK) && !force))) | 1870 | errno = 0; |
1739 | return 1; | 1871 | len = read(c->rfd, buf, sizeof(buf)); |
1872 | if (len < 0 && (errno == EINTR || | ||
1873 | ((errno == EAGAIN || errno == EWOULDBLOCK) && !force))) | ||
1874 | return 1; | ||
1740 | #ifndef PTY_ZEROREAD | 1875 | #ifndef PTY_ZEROREAD |
1741 | if (len <= 0) { | 1876 | if (len <= 0) { |
1742 | #else | 1877 | #else |
1743 | if ((!c->isatty && len <= 0) || | 1878 | if ((!c->isatty && len <= 0) || |
1744 | (c->isatty && (len < 0 || (len == 0 && errno != 0)))) { | 1879 | (c->isatty && (len < 0 || (len == 0 && errno != 0)))) { |
1745 | #endif | 1880 | #endif |
1746 | debug2("channel %d: read<=0 rfd %d len %d", | 1881 | debug2("channel %d: read<=0 rfd %d len %zd", |
1747 | c->self, c->rfd, len); | 1882 | c->self, c->rfd, len); |
1748 | if (c->type != SSH_CHANNEL_OPEN) { | 1883 | if (c->type != SSH_CHANNEL_OPEN) { |
1749 | debug2("channel %d: not open", c->self); | 1884 | debug2("channel %d: not open", c->self); |
1750 | chan_mark_dead(c); | 1885 | chan_mark_dead(ssh, c); |
1751 | return -1; | ||
1752 | } else if (compat13) { | ||
1753 | buffer_clear(&c->output); | ||
1754 | c->type = SSH_CHANNEL_INPUT_DRAINING; | ||
1755 | debug2("channel %d: input draining.", c->self); | ||
1756 | } else { | ||
1757 | chan_read_failed(c); | ||
1758 | } | ||
1759 | return -1; | 1886 | return -1; |
1760 | } | ||
1761 | if (c->input_filter != NULL) { | ||
1762 | if (c->input_filter(c, buf, len) == -1) { | ||
1763 | debug2("channel %d: filter stops", c->self); | ||
1764 | chan_read_failed(c); | ||
1765 | } | ||
1766 | } else if (c->datagram) { | ||
1767 | buffer_put_string(&c->input, buf, len); | ||
1768 | } else { | 1887 | } else { |
1769 | buffer_append(&c->input, buf, len); | 1888 | chan_read_failed(ssh, c); |
1889 | } | ||
1890 | return -1; | ||
1891 | } | ||
1892 | if (c->input_filter != NULL) { | ||
1893 | if (c->input_filter(ssh, c, buf, len) == -1) { | ||
1894 | debug2("channel %d: filter stops", c->self); | ||
1895 | chan_read_failed(ssh, c); | ||
1770 | } | 1896 | } |
1897 | } else if (c->datagram) { | ||
1898 | if ((r = sshbuf_put_string(c->input, buf, len)) != 0) | ||
1899 | fatal("%s: channel %d: put datagram: %s", __func__, | ||
1900 | c->self, ssh_err(r)); | ||
1901 | } else if ((r = sshbuf_put(c->input, buf, len)) != 0) { | ||
1902 | fatal("%s: channel %d: put data: %s", __func__, | ||
1903 | c->self, ssh_err(r)); | ||
1771 | } | 1904 | } |
1772 | return 1; | 1905 | return 1; |
1773 | } | 1906 | } |
1774 | 1907 | ||
1775 | /* ARGSUSED */ | ||
1776 | static int | 1908 | static int |
1777 | channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset) | 1909 | channel_handle_wfd(struct ssh *ssh, Channel *c, |
1910 | fd_set *readset, fd_set *writeset) | ||
1778 | { | 1911 | { |
1779 | struct termios tio; | 1912 | struct termios tio; |
1780 | u_char *data = NULL, *buf; | 1913 | u_char *data = NULL, *buf; /* XXX const; need filter API change */ |
1781 | u_int dlen, olen = 0; | 1914 | size_t dlen, olen = 0; |
1782 | int len; | 1915 | int r, len; |
1916 | |||
1917 | if (c->wfd == -1 || !FD_ISSET(c->wfd, writeset) || | ||
1918 | sshbuf_len(c->output) == 0) | ||
1919 | return 1; | ||
1783 | 1920 | ||
1784 | /* Send buffered output data to the socket. */ | 1921 | /* Send buffered output data to the socket. */ |
1785 | if (c->wfd != -1 && | 1922 | olen = sshbuf_len(c->output); |
1786 | FD_ISSET(c->wfd, writeset) && | 1923 | if (c->output_filter != NULL) { |
1787 | buffer_len(&c->output) > 0) { | 1924 | if ((buf = c->output_filter(ssh, c, &data, &dlen)) == NULL) { |
1788 | olen = buffer_len(&c->output); | 1925 | debug2("channel %d: filter stops", c->self); |
1789 | if (c->output_filter != NULL) { | 1926 | if (c->type != SSH_CHANNEL_OPEN) |
1790 | if ((buf = c->output_filter(c, &data, &dlen)) == NULL) { | 1927 | chan_mark_dead(ssh, c); |
1791 | debug2("channel %d: filter stops", c->self); | 1928 | else |
1792 | if (c->type != SSH_CHANNEL_OPEN) | 1929 | chan_write_failed(ssh, c); |
1793 | chan_mark_dead(c); | 1930 | return -1; |
1794 | else | ||
1795 | chan_write_failed(c); | ||
1796 | return -1; | ||
1797 | } | ||
1798 | } else if (c->datagram) { | ||
1799 | buf = data = buffer_get_string(&c->output, &dlen); | ||
1800 | } else { | ||
1801 | buf = data = buffer_ptr(&c->output); | ||
1802 | dlen = buffer_len(&c->output); | ||
1803 | } | 1931 | } |
1932 | } else if (c->datagram) { | ||
1933 | if ((r = sshbuf_get_string(c->output, &data, &dlen)) != 0) | ||
1934 | fatal("%s: channel %d: get datagram: %s", __func__, | ||
1935 | c->self, ssh_err(r)); | ||
1936 | buf = data; | ||
1937 | } else { | ||
1938 | buf = data = sshbuf_mutable_ptr(c->output); | ||
1939 | dlen = sshbuf_len(c->output); | ||
1940 | } | ||
1941 | |||
1942 | if (c->datagram) { | ||
1943 | /* ignore truncated writes, datagrams might get lost */ | ||
1944 | len = write(c->wfd, buf, dlen); | ||
1945 | free(data); | ||
1946 | if (len < 0 && (errno == EINTR || errno == EAGAIN || | ||
1947 | errno == EWOULDBLOCK)) | ||
1948 | return 1; | ||
1949 | if (len <= 0) | ||
1950 | goto write_fail; | ||
1951 | goto out; | ||
1952 | } | ||
1804 | 1953 | ||
1805 | if (c->datagram) { | ||
1806 | /* ignore truncated writes, datagrams might get lost */ | ||
1807 | len = write(c->wfd, buf, dlen); | ||
1808 | free(data); | ||
1809 | if (len < 0 && (errno == EINTR || errno == EAGAIN || | ||
1810 | errno == EWOULDBLOCK)) | ||
1811 | return 1; | ||
1812 | if (len <= 0) { | ||
1813 | if (c->type != SSH_CHANNEL_OPEN) | ||
1814 | chan_mark_dead(c); | ||
1815 | else | ||
1816 | chan_write_failed(c); | ||
1817 | return -1; | ||
1818 | } | ||
1819 | goto out; | ||
1820 | } | ||
1821 | #ifdef _AIX | 1954 | #ifdef _AIX |
1822 | /* XXX: Later AIX versions can't push as much data to tty */ | 1955 | /* XXX: Later AIX versions can't push as much data to tty */ |
1823 | if (compat20 && c->wfd_isatty) | 1956 | if (c->wfd_isatty) |
1824 | dlen = MIN(dlen, 8*1024); | 1957 | dlen = MIN(dlen, 8*1024); |
1825 | #endif | 1958 | #endif |
1826 | 1959 | ||
1827 | len = write(c->wfd, buf, dlen); | 1960 | len = write(c->wfd, buf, dlen); |
1828 | if (len < 0 && | 1961 | if (len < 0 && |
1829 | (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) | 1962 | (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) |
1830 | return 1; | 1963 | return 1; |
1831 | if (len <= 0) { | 1964 | if (len <= 0) { |
1832 | if (c->type != SSH_CHANNEL_OPEN) { | 1965 | write_fail: |
1833 | debug2("channel %d: not open", c->self); | 1966 | if (c->type != SSH_CHANNEL_OPEN) { |
1834 | chan_mark_dead(c); | 1967 | debug2("channel %d: not open", c->self); |
1835 | return -1; | 1968 | chan_mark_dead(ssh, c); |
1836 | } else if (compat13) { | ||
1837 | buffer_clear(&c->output); | ||
1838 | debug2("channel %d: input draining.", c->self); | ||
1839 | c->type = SSH_CHANNEL_INPUT_DRAINING; | ||
1840 | } else { | ||
1841 | chan_write_failed(c); | ||
1842 | } | ||
1843 | return -1; | 1969 | return -1; |
1970 | } else { | ||
1971 | chan_write_failed(ssh, c); | ||
1844 | } | 1972 | } |
1973 | return -1; | ||
1974 | } | ||
1845 | #ifndef BROKEN_TCGETATTR_ICANON | 1975 | #ifndef BROKEN_TCGETATTR_ICANON |
1846 | if (compat20 && c->isatty && dlen >= 1 && buf[0] != '\r') { | 1976 | if (c->isatty && dlen >= 1 && buf[0] != '\r') { |
1847 | if (tcgetattr(c->wfd, &tio) == 0 && | 1977 | if (tcgetattr(c->wfd, &tio) == 0 && |
1848 | !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { | 1978 | !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { |
1849 | /* | 1979 | /* |
1850 | * Simulate echo to reduce the impact of | 1980 | * Simulate echo to reduce the impact of |
1851 | * traffic analysis. We need to match the | 1981 | * traffic analysis. We need to match the |
1852 | * size of a SSH2_MSG_CHANNEL_DATA message | 1982 | * size of a SSH2_MSG_CHANNEL_DATA message |
1853 | * (4 byte channel id + buf) | 1983 | * (4 byte channel id + buf) |
1854 | */ | 1984 | */ |
1855 | packet_send_ignore(4 + len); | 1985 | if ((r = sshpkt_msg_ignore(ssh, 4+len)) != 0 || |
1856 | packet_send(); | 1986 | (r = sshpkt_send(ssh)) != 0) |
1857 | } | 1987 | fatal("%s: channel %d: ignore: %s", |
1988 | __func__, c->self, ssh_err(r)); | ||
1858 | } | 1989 | } |
1859 | #endif | 1990 | } |
1860 | buffer_consume(&c->output, len); | 1991 | #endif /* BROKEN_TCGETATTR_ICANON */ |
1992 | if ((r = sshbuf_consume(c->output, len)) != 0) { | ||
1993 | fatal("%s: channel %d: consume: %s", | ||
1994 | __func__, c->self, ssh_err(r)); | ||
1861 | } | 1995 | } |
1862 | out: | 1996 | out: |
1863 | if (compat20 && olen > 0) | 1997 | c->local_consumed += olen - sshbuf_len(c->output); |
1864 | c->local_consumed += olen - buffer_len(&c->output); | 1998 | |
1865 | return 1; | 1999 | return 1; |
1866 | } | 2000 | } |
1867 | 2001 | ||
1868 | static int | 2002 | static int |
1869 | channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset) | 2003 | channel_handle_efd_write(struct ssh *ssh, Channel *c, |
2004 | fd_set *readset, fd_set *writeset) | ||
2005 | { | ||
2006 | int r; | ||
2007 | ssize_t len; | ||
2008 | |||
2009 | if (!FD_ISSET(c->efd, writeset) || sshbuf_len(c->extended) == 0) | ||
2010 | return 1; | ||
2011 | |||
2012 | len = write(c->efd, sshbuf_ptr(c->extended), | ||
2013 | sshbuf_len(c->extended)); | ||
2014 | debug2("channel %d: written %zd to efd %d", c->self, len, c->efd); | ||
2015 | if (len < 0 && (errno == EINTR || errno == EAGAIN || | ||
2016 | errno == EWOULDBLOCK)) | ||
2017 | return 1; | ||
2018 | if (len <= 0) { | ||
2019 | debug2("channel %d: closing write-efd %d", c->self, c->efd); | ||
2020 | channel_close_fd(ssh, &c->efd); | ||
2021 | } else { | ||
2022 | if ((r = sshbuf_consume(c->extended, len)) != 0) { | ||
2023 | fatal("%s: channel %d: consume: %s", | ||
2024 | __func__, c->self, ssh_err(r)); | ||
2025 | } | ||
2026 | c->local_consumed += len; | ||
2027 | } | ||
2028 | return 1; | ||
2029 | } | ||
2030 | |||
2031 | static int | ||
2032 | channel_handle_efd_read(struct ssh *ssh, Channel *c, | ||
2033 | fd_set *readset, fd_set *writeset) | ||
1870 | { | 2034 | { |
1871 | char buf[CHAN_RBUF]; | 2035 | char buf[CHAN_RBUF]; |
1872 | int len; | 2036 | int r; |
2037 | ssize_t len; | ||
1873 | 2038 | ||
1874 | /** XXX handle drain efd, too */ | 2039 | if (!c->detach_close && !FD_ISSET(c->efd, readset)) |
1875 | if (c->efd != -1) { | 2040 | return 1; |
1876 | if (c->extended_usage == CHAN_EXTENDED_WRITE && | 2041 | |
1877 | FD_ISSET(c->efd, writeset) && | 2042 | len = read(c->efd, buf, sizeof(buf)); |
1878 | buffer_len(&c->extended) > 0) { | 2043 | debug2("channel %d: read %zd from efd %d", c->self, len, c->efd); |
1879 | len = write(c->efd, buffer_ptr(&c->extended), | 2044 | if (len < 0 && (errno == EINTR || ((errno == EAGAIN || |
1880 | buffer_len(&c->extended)); | 2045 | errno == EWOULDBLOCK) && !c->detach_close))) |
1881 | debug2("channel %d: written %d to efd %d", | 2046 | return 1; |
1882 | c->self, len, c->efd); | 2047 | if (len <= 0) { |
1883 | if (len < 0 && (errno == EINTR || errno == EAGAIN || | 2048 | debug2("channel %d: closing read-efd %d", |
1884 | errno == EWOULDBLOCK)) | 2049 | c->self, c->efd); |
1885 | return 1; | 2050 | channel_close_fd(ssh, &c->efd); |
1886 | if (len <= 0) { | 2051 | } else { |
1887 | debug2("channel %d: closing write-efd %d", | 2052 | if (c->extended_usage == CHAN_EXTENDED_IGNORE) { |
1888 | c->self, c->efd); | 2053 | debug3("channel %d: discard efd", |
1889 | channel_close_fd(&c->efd); | 2054 | c->self); |
1890 | } else { | 2055 | } else if ((r = sshbuf_put(c->extended, buf, len)) != 0) { |
1891 | buffer_consume(&c->extended, len); | 2056 | fatal("%s: channel %d: append: %s", |
1892 | c->local_consumed += len; | 2057 | __func__, c->self, ssh_err(r)); |
1893 | } | ||
1894 | } else if (c->efd != -1 && | ||
1895 | (c->extended_usage == CHAN_EXTENDED_READ || | ||
1896 | c->extended_usage == CHAN_EXTENDED_IGNORE) && | ||
1897 | (c->detach_close || FD_ISSET(c->efd, readset))) { | ||
1898 | len = read(c->efd, buf, sizeof(buf)); | ||
1899 | debug2("channel %d: read %d from efd %d", | ||
1900 | c->self, len, c->efd); | ||
1901 | if (len < 0 && (errno == EINTR || ((errno == EAGAIN || | ||
1902 | errno == EWOULDBLOCK) && !c->detach_close))) | ||
1903 | return 1; | ||
1904 | if (len <= 0) { | ||
1905 | debug2("channel %d: closing read-efd %d", | ||
1906 | c->self, c->efd); | ||
1907 | channel_close_fd(&c->efd); | ||
1908 | } else { | ||
1909 | if (c->extended_usage == CHAN_EXTENDED_IGNORE) { | ||
1910 | debug3("channel %d: discard efd", | ||
1911 | c->self); | ||
1912 | } else | ||
1913 | buffer_append(&c->extended, buf, len); | ||
1914 | } | ||
1915 | } | 2058 | } |
1916 | } | 2059 | } |
1917 | return 1; | 2060 | return 1; |
1918 | } | 2061 | } |
1919 | 2062 | ||
1920 | static int | 2063 | static int |
1921 | channel_check_window(Channel *c) | 2064 | channel_handle_efd(struct ssh *ssh, Channel *c, |
2065 | fd_set *readset, fd_set *writeset) | ||
1922 | { | 2066 | { |
2067 | if (c->efd == -1) | ||
2068 | return 1; | ||
2069 | |||
2070 | /** XXX handle drain efd, too */ | ||
2071 | |||
2072 | if (c->extended_usage == CHAN_EXTENDED_WRITE) | ||
2073 | return channel_handle_efd_write(ssh, c, readset, writeset); | ||
2074 | else if (c->extended_usage == CHAN_EXTENDED_READ || | ||
2075 | c->extended_usage == CHAN_EXTENDED_IGNORE) | ||
2076 | return channel_handle_efd_read(ssh, c, readset, writeset); | ||
2077 | |||
2078 | return 1; | ||
2079 | } | ||
2080 | |||
2081 | static int | ||
2082 | channel_check_window(struct ssh *ssh, Channel *c) | ||
2083 | { | ||
2084 | int r; | ||
2085 | |||
1923 | if (c->type == SSH_CHANNEL_OPEN && | 2086 | if (c->type == SSH_CHANNEL_OPEN && |
1924 | !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && | 2087 | !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && |
1925 | ((c->local_window_max - c->local_window > | 2088 | ((c->local_window_max - c->local_window > |
1926 | c->local_maxpacket*3) || | 2089 | c->local_maxpacket*3) || |
1927 | c->local_window < c->local_window_max/2) && | 2090 | c->local_window < c->local_window_max/2) && |
1928 | c->local_consumed > 0) { | 2091 | c->local_consumed > 0) { |
1929 | packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); | 2092 | if (!c->have_remote_id) |
1930 | packet_put_int(c->remote_id); | 2093 | fatal(":%s: channel %d: no remote id", |
1931 | packet_put_int(c->local_consumed); | 2094 | __func__, c->self); |
1932 | packet_send(); | 2095 | if ((r = sshpkt_start(ssh, |
2096 | SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 || | ||
2097 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | ||
2098 | (r = sshpkt_put_u32(ssh, c->local_consumed)) != 0 || | ||
2099 | (r = sshpkt_send(ssh)) != 0) { | ||
2100 | fatal("%s: channel %i: %s", __func__, | ||
2101 | c->self, ssh_err(r)); | ||
2102 | } | ||
1933 | debug2("channel %d: window %d sent adjust %d", | 2103 | debug2("channel %d: window %d sent adjust %d", |
1934 | c->self, c->local_window, | 2104 | c->self, c->local_window, |
1935 | c->local_consumed); | 2105 | c->local_consumed); |
@@ -1940,90 +2110,112 @@ channel_check_window(Channel *c) | |||
1940 | } | 2110 | } |
1941 | 2111 | ||
1942 | static void | 2112 | static void |
1943 | channel_post_open(Channel *c, fd_set *readset, fd_set *writeset) | 2113 | channel_post_open(struct ssh *ssh, Channel *c, |
2114 | fd_set *readset, fd_set *writeset) | ||
1944 | { | 2115 | { |
1945 | channel_handle_rfd(c, readset, writeset); | 2116 | channel_handle_rfd(ssh, c, readset, writeset); |
1946 | channel_handle_wfd(c, readset, writeset); | 2117 | channel_handle_wfd(ssh, c, readset, writeset); |
1947 | if (!compat20) | 2118 | channel_handle_efd(ssh, c, readset, writeset); |
1948 | return; | 2119 | channel_check_window(ssh, c); |
1949 | channel_handle_efd(c, readset, writeset); | ||
1950 | channel_check_window(c); | ||
1951 | } | 2120 | } |
1952 | 2121 | ||
1953 | static u_int | 2122 | static u_int |
1954 | read_mux(Channel *c, u_int need) | 2123 | read_mux(struct ssh *ssh, Channel *c, u_int need) |
1955 | { | 2124 | { |
1956 | char buf[CHAN_RBUF]; | 2125 | char buf[CHAN_RBUF]; |
1957 | int len; | 2126 | ssize_t len; |
1958 | u_int rlen; | 2127 | u_int rlen; |
2128 | int r; | ||
1959 | 2129 | ||
1960 | if (buffer_len(&c->input) < need) { | 2130 | if (sshbuf_len(c->input) < need) { |
1961 | rlen = need - buffer_len(&c->input); | 2131 | rlen = need - sshbuf_len(c->input); |
1962 | len = read(c->rfd, buf, MINIMUM(rlen, CHAN_RBUF)); | 2132 | len = read(c->rfd, buf, MINIMUM(rlen, CHAN_RBUF)); |
1963 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | 2133 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) |
1964 | return buffer_len(&c->input); | 2134 | return sshbuf_len(c->input); |
1965 | if (len <= 0) { | 2135 | if (len <= 0) { |
1966 | debug2("channel %d: ctl read<=0 rfd %d len %d", | 2136 | debug2("channel %d: ctl read<=0 rfd %d len %zd", |
1967 | c->self, c->rfd, len); | 2137 | c->self, c->rfd, len); |
1968 | chan_read_failed(c); | 2138 | chan_read_failed(ssh, c); |
1969 | return 0; | 2139 | return 0; |
1970 | } else | 2140 | } else if ((r = sshbuf_put(c->input, buf, len)) != 0) { |
1971 | buffer_append(&c->input, buf, len); | 2141 | fatal("%s: channel %d: append: %s", |
2142 | __func__, c->self, ssh_err(r)); | ||
2143 | } | ||
1972 | } | 2144 | } |
1973 | return buffer_len(&c->input); | 2145 | return sshbuf_len(c->input); |
1974 | } | 2146 | } |
1975 | 2147 | ||
1976 | static void | 2148 | static void |
1977 | channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset) | 2149 | channel_post_mux_client_read(struct ssh *ssh, Channel *c, |
2150 | fd_set *readset, fd_set *writeset) | ||
1978 | { | 2151 | { |
1979 | u_int need; | 2152 | u_int need; |
1980 | ssize_t len; | ||
1981 | 2153 | ||
1982 | if (!compat20) | 2154 | if (c->rfd == -1 || !FD_ISSET(c->rfd, readset)) |
1983 | fatal("%s: entered with !compat20", __func__); | 2155 | return; |
2156 | if (c->istate != CHAN_INPUT_OPEN && c->istate != CHAN_INPUT_WAIT_DRAIN) | ||
2157 | return; | ||
2158 | if (c->mux_pause) | ||
2159 | return; | ||
1984 | 2160 | ||
1985 | if (c->rfd != -1 && !c->mux_pause && FD_ISSET(c->rfd, readset) && | 2161 | /* |
1986 | (c->istate == CHAN_INPUT_OPEN || | 2162 | * Don't not read past the precise end of packets to |
1987 | c->istate == CHAN_INPUT_WAIT_DRAIN)) { | 2163 | * avoid disrupting fd passing. |
1988 | /* | 2164 | */ |
1989 | * Don't not read past the precise end of packets to | 2165 | if (read_mux(ssh, c, 4) < 4) /* read header */ |
1990 | * avoid disrupting fd passing. | 2166 | return; |
1991 | */ | 2167 | /* XXX sshbuf_peek_u32 */ |
1992 | if (read_mux(c, 4) < 4) /* read header */ | 2168 | need = PEEK_U32(sshbuf_ptr(c->input)); |
1993 | return; | ||
1994 | need = get_u32(buffer_ptr(&c->input)); | ||
1995 | #define CHANNEL_MUX_MAX_PACKET (256 * 1024) | 2169 | #define CHANNEL_MUX_MAX_PACKET (256 * 1024) |
1996 | if (need > CHANNEL_MUX_MAX_PACKET) { | 2170 | if (need > CHANNEL_MUX_MAX_PACKET) { |
1997 | debug2("channel %d: packet too big %u > %u", | 2171 | debug2("channel %d: packet too big %u > %u", |
1998 | c->self, CHANNEL_MUX_MAX_PACKET, need); | 2172 | c->self, CHANNEL_MUX_MAX_PACKET, need); |
1999 | chan_rcvd_oclose(c); | 2173 | chan_rcvd_oclose(ssh, c); |
2000 | return; | 2174 | return; |
2001 | } | 2175 | } |
2002 | if (read_mux(c, need + 4) < need + 4) /* read body */ | 2176 | if (read_mux(ssh, c, need + 4) < need + 4) /* read body */ |
2003 | return; | 2177 | return; |
2004 | if (c->mux_rcb(c) != 0) { | 2178 | if (c->mux_rcb(ssh, c) != 0) { |
2005 | debug("channel %d: mux_rcb failed", c->self); | 2179 | debug("channel %d: mux_rcb failed", c->self); |
2006 | chan_mark_dead(c); | 2180 | chan_mark_dead(ssh, c); |
2007 | return; | 2181 | return; |
2008 | } | ||
2009 | } | 2182 | } |
2183 | } | ||
2010 | 2184 | ||
2011 | if (c->wfd != -1 && FD_ISSET(c->wfd, writeset) && | 2185 | static void |
2012 | buffer_len(&c->output) > 0) { | 2186 | channel_post_mux_client_write(struct ssh *ssh, Channel *c, |
2013 | len = write(c->wfd, buffer_ptr(&c->output), | 2187 | fd_set *readset, fd_set *writeset) |
2014 | buffer_len(&c->output)); | 2188 | { |
2015 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | 2189 | ssize_t len; |
2016 | return; | 2190 | int r; |
2017 | if (len <= 0) { | 2191 | |
2018 | chan_mark_dead(c); | 2192 | if (c->wfd == -1 || !FD_ISSET(c->wfd, writeset) || |
2019 | return; | 2193 | sshbuf_len(c->output) == 0) |
2020 | } | 2194 | return; |
2021 | buffer_consume(&c->output, len); | 2195 | |
2196 | len = write(c->wfd, sshbuf_ptr(c->output), sshbuf_len(c->output)); | ||
2197 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | ||
2198 | return; | ||
2199 | if (len <= 0) { | ||
2200 | chan_mark_dead(ssh, c); | ||
2201 | return; | ||
2022 | } | 2202 | } |
2203 | if ((r = sshbuf_consume(c->output, len)) != 0) | ||
2204 | fatal("%s: channel %d: consume: %s", __func__, | ||
2205 | c->self, ssh_err(r)); | ||
2206 | } | ||
2207 | |||
2208 | static void | ||
2209 | channel_post_mux_client(struct ssh *ssh, Channel *c, | ||
2210 | fd_set *readset, fd_set *writeset) | ||
2211 | { | ||
2212 | channel_post_mux_client_read(ssh, c, readset, writeset); | ||
2213 | channel_post_mux_client_write(ssh, c, readset, writeset); | ||
2023 | } | 2214 | } |
2024 | 2215 | ||
2025 | static void | 2216 | static void |
2026 | channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset) | 2217 | channel_post_mux_listener(struct ssh *ssh, Channel *c, |
2218 | fd_set *readset, fd_set *writeset) | ||
2027 | { | 2219 | { |
2028 | Channel *nc; | 2220 | Channel *nc; |
2029 | struct sockaddr_storage addr; | 2221 | struct sockaddr_storage addr; |
@@ -2062,166 +2254,100 @@ channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
2062 | close(newsock); | 2254 | close(newsock); |
2063 | return; | 2255 | return; |
2064 | } | 2256 | } |
2065 | nc = channel_new("multiplex client", SSH_CHANNEL_MUX_CLIENT, | 2257 | nc = channel_new(ssh, "multiplex client", SSH_CHANNEL_MUX_CLIENT, |
2066 | newsock, newsock, -1, c->local_window_max, | 2258 | newsock, newsock, -1, c->local_window_max, |
2067 | c->local_maxpacket, 0, "mux-control", 1); | 2259 | c->local_maxpacket, 0, "mux-control", 1); |
2068 | nc->mux_rcb = c->mux_rcb; | 2260 | nc->mux_rcb = c->mux_rcb; |
2069 | debug3("%s: new mux channel %d fd %d", __func__, | 2261 | debug3("%s: new mux channel %d fd %d", __func__, nc->self, nc->sock); |
2070 | nc->self, nc->sock); | ||
2071 | /* establish state */ | 2262 | /* establish state */ |
2072 | nc->mux_rcb(nc); | 2263 | nc->mux_rcb(ssh, nc); |
2073 | /* mux state transitions must not elicit protocol messages */ | 2264 | /* mux state transitions must not elicit protocol messages */ |
2074 | nc->flags |= CHAN_LOCAL; | 2265 | nc->flags |= CHAN_LOCAL; |
2075 | } | 2266 | } |
2076 | 2267 | ||
2077 | /* ARGSUSED */ | ||
2078 | static void | 2268 | static void |
2079 | channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset) | 2269 | channel_handler_init(struct ssh_channels *sc) |
2080 | { | 2270 | { |
2081 | int len; | 2271 | chan_fn **pre, **post; |
2082 | 2272 | ||
2083 | /* Send buffered output data to the socket. */ | 2273 | if ((pre = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*pre))) == NULL || |
2084 | if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) { | 2274 | (post = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*post))) == NULL) |
2085 | len = write(c->sock, buffer_ptr(&c->output), | 2275 | fatal("%s: allocation failed", __func__); |
2086 | buffer_len(&c->output)); | 2276 | |
2087 | if (len <= 0) | 2277 | pre[SSH_CHANNEL_OPEN] = &channel_pre_open; |
2088 | buffer_clear(&c->output); | 2278 | pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; |
2089 | else | 2279 | pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; |
2090 | buffer_consume(&c->output, len); | 2280 | pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; |
2091 | } | 2281 | pre[SSH_CHANNEL_UNIX_LISTENER] = &channel_pre_listener; |
2092 | } | 2282 | pre[SSH_CHANNEL_RUNIX_LISTENER] = &channel_pre_listener; |
2093 | 2283 | pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; | |
2094 | static void | 2284 | pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
2095 | channel_handler_init_20(void) | 2285 | pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; |
2096 | { | 2286 | pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; |
2097 | channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open; | 2287 | pre[SSH_CHANNEL_RDYNAMIC_FINISH] = &channel_pre_connecting; |
2098 | channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; | 2288 | pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener; |
2099 | channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; | 2289 | pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client; |
2100 | channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; | 2290 | |
2101 | channel_pre[SSH_CHANNEL_UNIX_LISTENER] = &channel_pre_listener; | 2291 | post[SSH_CHANNEL_OPEN] = &channel_post_open; |
2102 | channel_pre[SSH_CHANNEL_RUNIX_LISTENER] = &channel_pre_listener; | 2292 | post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; |
2103 | channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; | 2293 | post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; |
2104 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; | 2294 | post[SSH_CHANNEL_UNIX_LISTENER] = &channel_post_port_listener; |
2105 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; | 2295 | post[SSH_CHANNEL_RUNIX_LISTENER] = &channel_post_port_listener; |
2106 | channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; | 2296 | post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; |
2107 | channel_pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener; | 2297 | post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
2108 | channel_pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client; | 2298 | post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
2109 | 2299 | post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; | |
2110 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; | 2300 | post[SSH_CHANNEL_RDYNAMIC_FINISH] = &channel_post_connecting; |
2111 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; | 2301 | post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener; |
2112 | channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; | 2302 | post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client; |
2113 | channel_post[SSH_CHANNEL_UNIX_LISTENER] = &channel_post_port_listener; | 2303 | |
2114 | channel_post[SSH_CHANNEL_RUNIX_LISTENER] = &channel_post_port_listener; | 2304 | sc->channel_pre = pre; |
2115 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; | 2305 | sc->channel_post = post; |
2116 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | ||
2117 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | ||
2118 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; | ||
2119 | channel_post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener; | ||
2120 | channel_post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client; | ||
2121 | } | ||
2122 | |||
2123 | static void | ||
2124 | channel_handler_init_13(void) | ||
2125 | { | ||
2126 | channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13; | ||
2127 | channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open_13; | ||
2128 | channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; | ||
2129 | channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; | ||
2130 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; | ||
2131 | channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining; | ||
2132 | channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining; | ||
2133 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; | ||
2134 | channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; | ||
2135 | |||
2136 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; | ||
2137 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; | ||
2138 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; | ||
2139 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | ||
2140 | channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; | ||
2141 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | ||
2142 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; | ||
2143 | } | ||
2144 | |||
2145 | static void | ||
2146 | channel_handler_init_15(void) | ||
2147 | { | ||
2148 | channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open; | ||
2149 | channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; | ||
2150 | channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; | ||
2151 | channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; | ||
2152 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; | ||
2153 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; | ||
2154 | channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; | ||
2155 | |||
2156 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; | ||
2157 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; | ||
2158 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | ||
2159 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; | ||
2160 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | ||
2161 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; | ||
2162 | } | ||
2163 | |||
2164 | static void | ||
2165 | channel_handler_init(void) | ||
2166 | { | ||
2167 | int i; | ||
2168 | |||
2169 | for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) { | ||
2170 | channel_pre[i] = NULL; | ||
2171 | channel_post[i] = NULL; | ||
2172 | } | ||
2173 | if (compat20) | ||
2174 | channel_handler_init_20(); | ||
2175 | else if (compat13) | ||
2176 | channel_handler_init_13(); | ||
2177 | else | ||
2178 | channel_handler_init_15(); | ||
2179 | } | 2306 | } |
2180 | 2307 | ||
2181 | /* gc dead channels */ | 2308 | /* gc dead channels */ |
2182 | static void | 2309 | static void |
2183 | channel_garbage_collect(Channel *c) | 2310 | channel_garbage_collect(struct ssh *ssh, Channel *c) |
2184 | { | 2311 | { |
2185 | if (c == NULL) | 2312 | if (c == NULL) |
2186 | return; | 2313 | return; |
2187 | if (c->detach_user != NULL) { | 2314 | if (c->detach_user != NULL) { |
2188 | if (!chan_is_dead(c, c->detach_close)) | 2315 | if (!chan_is_dead(ssh, c, c->detach_close)) |
2189 | return; | 2316 | return; |
2190 | debug2("channel %d: gc: notify user", c->self); | 2317 | debug2("channel %d: gc: notify user", c->self); |
2191 | c->detach_user(c->self, NULL); | 2318 | c->detach_user(ssh, c->self, NULL); |
2192 | /* if we still have a callback */ | 2319 | /* if we still have a callback */ |
2193 | if (c->detach_user != NULL) | 2320 | if (c->detach_user != NULL) |
2194 | return; | 2321 | return; |
2195 | debug2("channel %d: gc: user detached", c->self); | 2322 | debug2("channel %d: gc: user detached", c->self); |
2196 | } | 2323 | } |
2197 | if (!chan_is_dead(c, 1)) | 2324 | if (!chan_is_dead(ssh, c, 1)) |
2198 | return; | 2325 | return; |
2199 | debug2("channel %d: garbage collecting", c->self); | 2326 | debug2("channel %d: garbage collecting", c->self); |
2200 | channel_free(c); | 2327 | channel_free(ssh, c); |
2201 | } | 2328 | } |
2202 | 2329 | ||
2330 | enum channel_table { CHAN_PRE, CHAN_POST }; | ||
2331 | |||
2203 | static void | 2332 | static void |
2204 | channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset, | 2333 | channel_handler(struct ssh *ssh, int table, |
2205 | time_t *unpause_secs) | 2334 | fd_set *readset, fd_set *writeset, time_t *unpause_secs) |
2206 | { | 2335 | { |
2207 | static int did_init = 0; | 2336 | struct ssh_channels *sc = ssh->chanctxt; |
2337 | chan_fn **ftab = table == CHAN_PRE ? sc->channel_pre : sc->channel_post; | ||
2208 | u_int i, oalloc; | 2338 | u_int i, oalloc; |
2209 | Channel *c; | 2339 | Channel *c; |
2210 | time_t now; | 2340 | time_t now; |
2211 | 2341 | ||
2212 | if (!did_init) { | ||
2213 | channel_handler_init(); | ||
2214 | did_init = 1; | ||
2215 | } | ||
2216 | now = monotime(); | 2342 | now = monotime(); |
2217 | if (unpause_secs != NULL) | 2343 | if (unpause_secs != NULL) |
2218 | *unpause_secs = 0; | 2344 | *unpause_secs = 0; |
2219 | for (i = 0, oalloc = channels_alloc; i < oalloc; i++) { | 2345 | for (i = 0, oalloc = sc->channels_alloc; i < oalloc; i++) { |
2220 | c = channels[i]; | 2346 | c = sc->channels[i]; |
2221 | if (c == NULL) | 2347 | if (c == NULL) |
2222 | continue; | 2348 | continue; |
2223 | if (c->delayed) { | 2349 | if (c->delayed) { |
2224 | if (ftab == channel_pre) | 2350 | if (table == CHAN_PRE) |
2225 | c->delayed = 0; | 2351 | c->delayed = 0; |
2226 | else | 2352 | else |
2227 | continue; | 2353 | continue; |
@@ -2231,7 +2357,7 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset, | |||
2231 | * Run handlers that are not paused. | 2357 | * Run handlers that are not paused. |
2232 | */ | 2358 | */ |
2233 | if (c->notbefore <= now) | 2359 | if (c->notbefore <= now) |
2234 | (*ftab[c->type])(c, readset, writeset); | 2360 | (*ftab[c->type])(ssh, c, readset, writeset); |
2235 | else if (unpause_secs != NULL) { | 2361 | else if (unpause_secs != NULL) { |
2236 | /* | 2362 | /* |
2237 | * Collect the time that the earliest | 2363 | * Collect the time that the earliest |
@@ -2245,7 +2371,7 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset, | |||
2245 | *unpause_secs = c->notbefore - now; | 2371 | *unpause_secs = c->notbefore - now; |
2246 | } | 2372 | } |
2247 | } | 2373 | } |
2248 | channel_garbage_collect(c); | 2374 | channel_garbage_collect(ssh, c); |
2249 | } | 2375 | } |
2250 | if (unpause_secs != NULL && *unpause_secs != 0) | 2376 | if (unpause_secs != NULL && *unpause_secs != 0) |
2251 | debug3("%s: first channel unpauses in %d seconds", | 2377 | debug3("%s: first channel unpauses in %d seconds", |
@@ -2253,16 +2379,39 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset, | |||
2253 | } | 2379 | } |
2254 | 2380 | ||
2255 | /* | 2381 | /* |
2382 | * Create sockets before allocating the select bitmasks. | ||
2383 | * This is necessary for things that need to happen after reading | ||
2384 | * the network-input but before channel_prepare_select(). | ||
2385 | */ | ||
2386 | static void | ||
2387 | channel_before_prepare_select(struct ssh *ssh) | ||
2388 | { | ||
2389 | struct ssh_channels *sc = ssh->chanctxt; | ||
2390 | Channel *c; | ||
2391 | u_int i, oalloc; | ||
2392 | |||
2393 | for (i = 0, oalloc = sc->channels_alloc; i < oalloc; i++) { | ||
2394 | c = sc->channels[i]; | ||
2395 | if (c == NULL) | ||
2396 | continue; | ||
2397 | if (c->type == SSH_CHANNEL_RDYNAMIC_OPEN) | ||
2398 | channel_before_prepare_select_rdynamic(ssh, c); | ||
2399 | } | ||
2400 | } | ||
2401 | |||
2402 | /* | ||
2256 | * Allocate/update select bitmasks and add any bits relevant to channels in | 2403 | * Allocate/update select bitmasks and add any bits relevant to channels in |
2257 | * select bitmasks. | 2404 | * select bitmasks. |
2258 | */ | 2405 | */ |
2259 | void | 2406 | void |
2260 | channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | 2407 | channel_prepare_select(struct ssh *ssh, fd_set **readsetp, fd_set **writesetp, |
2261 | u_int *nallocp, time_t *minwait_secs, int rekeying) | 2408 | int *maxfdp, u_int *nallocp, time_t *minwait_secs) |
2262 | { | 2409 | { |
2263 | u_int n, sz, nfdset; | 2410 | u_int n, sz, nfdset; |
2264 | 2411 | ||
2265 | n = MAXIMUM(*maxfdp, channel_max_fd); | 2412 | channel_before_prepare_select(ssh); /* might update channel_max_fd */ |
2413 | |||
2414 | n = MAXIMUM(*maxfdp, ssh->chanctxt->channel_max_fd); | ||
2266 | 2415 | ||
2267 | nfdset = howmany(n+1, NFDBITS); | 2416 | nfdset = howmany(n+1, NFDBITS); |
2268 | /* Explicitly test here, because xrealloc isn't always called */ | 2417 | /* Explicitly test here, because xrealloc isn't always called */ |
@@ -2280,8 +2429,8 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
2280 | memset(*readsetp, 0, sz); | 2429 | memset(*readsetp, 0, sz); |
2281 | memset(*writesetp, 0, sz); | 2430 | memset(*writesetp, 0, sz); |
2282 | 2431 | ||
2283 | if (!rekeying) | 2432 | if (!ssh_packet_is_rekeying(ssh)) |
2284 | channel_handler(channel_pre, *readsetp, *writesetp, | 2433 | channel_handler(ssh, CHAN_PRE, *readsetp, *writesetp, |
2285 | minwait_secs); | 2434 | minwait_secs); |
2286 | } | 2435 | } |
2287 | 2436 | ||
@@ -2290,21 +2439,136 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
2290 | * events pending. | 2439 | * events pending. |
2291 | */ | 2440 | */ |
2292 | void | 2441 | void |
2293 | channel_after_select(fd_set *readset, fd_set *writeset) | 2442 | channel_after_select(struct ssh *ssh, fd_set *readset, fd_set *writeset) |
2294 | { | 2443 | { |
2295 | channel_handler(channel_post, readset, writeset, NULL); | 2444 | channel_handler(ssh, CHAN_POST, readset, writeset, NULL); |
2296 | } | 2445 | } |
2297 | 2446 | ||
2447 | /* | ||
2448 | * Enqueue data for channels with open or draining c->input. | ||
2449 | */ | ||
2450 | static void | ||
2451 | channel_output_poll_input_open(struct ssh *ssh, Channel *c) | ||
2452 | { | ||
2453 | size_t len, plen; | ||
2454 | const u_char *pkt; | ||
2455 | int r; | ||
2456 | |||
2457 | if ((len = sshbuf_len(c->input)) == 0) { | ||
2458 | if (c->istate == CHAN_INPUT_WAIT_DRAIN) { | ||
2459 | /* | ||
2460 | * input-buffer is empty and read-socket shutdown: | ||
2461 | * tell peer, that we will not send more data: | ||
2462 | * send IEOF. | ||
2463 | * hack for extended data: delay EOF if EFD still | ||
2464 | * in use. | ||
2465 | */ | ||
2466 | if (CHANNEL_EFD_INPUT_ACTIVE(c)) | ||
2467 | debug2("channel %d: " | ||
2468 | "ibuf_empty delayed efd %d/(%zu)", | ||
2469 | c->self, c->efd, sshbuf_len(c->extended)); | ||
2470 | else | ||
2471 | chan_ibuf_empty(ssh, c); | ||
2472 | } | ||
2473 | return; | ||
2474 | } | ||
2475 | |||
2476 | if (!c->have_remote_id) | ||
2477 | fatal(":%s: channel %d: no remote id", __func__, c->self); | ||
2478 | |||
2479 | if (c->datagram) { | ||
2480 | /* Check datagram will fit; drop if not */ | ||
2481 | if ((r = sshbuf_get_string_direct(c->input, &pkt, &plen)) != 0) | ||
2482 | fatal("%s: channel %d: get datagram: %s", __func__, | ||
2483 | c->self, ssh_err(r)); | ||
2484 | /* | ||
2485 | * XXX this does tail-drop on the datagram queue which is | ||
2486 | * usually suboptimal compared to head-drop. Better to have | ||
2487 | * backpressure at read time? (i.e. read + discard) | ||
2488 | */ | ||
2489 | if (plen > c->remote_window || plen > c->remote_maxpacket) { | ||
2490 | debug("channel %d: datagram too big", c->self); | ||
2491 | return; | ||
2492 | } | ||
2493 | /* Enqueue it */ | ||
2494 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 || | ||
2495 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | ||
2496 | (r = sshpkt_put_string(ssh, pkt, plen)) != 0 || | ||
2497 | (r = sshpkt_send(ssh)) != 0) { | ||
2498 | fatal("%s: channel %i: datagram: %s", __func__, | ||
2499 | c->self, ssh_err(r)); | ||
2500 | } | ||
2501 | c->remote_window -= plen; | ||
2502 | return; | ||
2503 | } | ||
2504 | |||
2505 | /* Enqueue packet for buffered data. */ | ||
2506 | if (len > c->remote_window) | ||
2507 | len = c->remote_window; | ||
2508 | if (len > c->remote_maxpacket) | ||
2509 | len = c->remote_maxpacket; | ||
2510 | if (len == 0) | ||
2511 | return; | ||
2512 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 || | ||
2513 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | ||
2514 | (r = sshpkt_put_string(ssh, sshbuf_ptr(c->input), len)) != 0 || | ||
2515 | (r = sshpkt_send(ssh)) != 0) { | ||
2516 | fatal("%s: channel %i: data: %s", __func__, | ||
2517 | c->self, ssh_err(r)); | ||
2518 | } | ||
2519 | if ((r = sshbuf_consume(c->input, len)) != 0) | ||
2520 | fatal("%s: channel %i: consume: %s", __func__, | ||
2521 | c->self, ssh_err(r)); | ||
2522 | c->remote_window -= len; | ||
2523 | } | ||
2524 | |||
2525 | /* | ||
2526 | * Enqueue data for channels with open c->extended in read mode. | ||
2527 | */ | ||
2528 | static void | ||
2529 | channel_output_poll_extended_read(struct ssh *ssh, Channel *c) | ||
2530 | { | ||
2531 | size_t len; | ||
2532 | int r; | ||
2533 | |||
2534 | if ((len = sshbuf_len(c->extended)) == 0) | ||
2535 | return; | ||
2536 | |||
2537 | debug2("channel %d: rwin %u elen %zu euse %d", c->self, | ||
2538 | c->remote_window, sshbuf_len(c->extended), c->extended_usage); | ||
2539 | if (len > c->remote_window) | ||
2540 | len = c->remote_window; | ||
2541 | if (len > c->remote_maxpacket) | ||
2542 | len = c->remote_maxpacket; | ||
2543 | if (len == 0) | ||
2544 | return; | ||
2545 | if (!c->have_remote_id) | ||
2546 | fatal(":%s: channel %d: no remote id", __func__, c->self); | ||
2547 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EXTENDED_DATA)) != 0 || | ||
2548 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | ||
2549 | (r = sshpkt_put_u32(ssh, SSH2_EXTENDED_DATA_STDERR)) != 0 || | ||
2550 | (r = sshpkt_put_string(ssh, sshbuf_ptr(c->extended), len)) != 0 || | ||
2551 | (r = sshpkt_send(ssh)) != 0) { | ||
2552 | fatal("%s: channel %i: data: %s", __func__, | ||
2553 | c->self, ssh_err(r)); | ||
2554 | } | ||
2555 | if ((r = sshbuf_consume(c->extended, len)) != 0) | ||
2556 | fatal("%s: channel %i: consume: %s", __func__, | ||
2557 | c->self, ssh_err(r)); | ||
2558 | c->remote_window -= len; | ||
2559 | debug2("channel %d: sent ext data %zu", c->self, len); | ||
2560 | } | ||
2298 | 2561 | ||
2299 | /* If there is data to send to the connection, enqueue some of it now. */ | 2562 | /* If there is data to send to the connection, enqueue some of it now. */ |
2300 | void | 2563 | void |
2301 | channel_output_poll(void) | 2564 | channel_output_poll(struct ssh *ssh) |
2302 | { | 2565 | { |
2566 | struct ssh_channels *sc = ssh->chanctxt; | ||
2303 | Channel *c; | 2567 | Channel *c; |
2304 | u_int i, len; | 2568 | u_int i; |
2305 | 2569 | ||
2306 | for (i = 0; i < channels_alloc; i++) { | 2570 | for (i = 0; i < sc->channels_alloc; i++) { |
2307 | c = channels[i]; | 2571 | c = sc->channels[i]; |
2308 | if (c == NULL) | 2572 | if (c == NULL) |
2309 | continue; | 2573 | continue; |
2310 | 2574 | ||
@@ -2312,113 +2576,23 @@ channel_output_poll(void) | |||
2312 | * We are only interested in channels that can have buffered | 2576 | * We are only interested in channels that can have buffered |
2313 | * incoming data. | 2577 | * incoming data. |
2314 | */ | 2578 | */ |
2315 | if (compat13) { | 2579 | if (c->type != SSH_CHANNEL_OPEN) |
2316 | if (c->type != SSH_CHANNEL_OPEN && | 2580 | continue; |
2317 | c->type != SSH_CHANNEL_INPUT_DRAINING) | 2581 | if ((c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { |
2318 | continue; | ||
2319 | } else { | ||
2320 | if (c->type != SSH_CHANNEL_OPEN) | ||
2321 | continue; | ||
2322 | } | ||
2323 | if (compat20 && | ||
2324 | (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { | ||
2325 | /* XXX is this true? */ | 2582 | /* XXX is this true? */ |
2326 | debug3("channel %d: will not send data after close", c->self); | 2583 | debug3("channel %d: will not send data after close", |
2584 | c->self); | ||
2327 | continue; | 2585 | continue; |
2328 | } | 2586 | } |
2329 | 2587 | ||
2330 | /* Get the amount of buffered data for this channel. */ | 2588 | /* Get the amount of buffered data for this channel. */ |
2331 | if ((c->istate == CHAN_INPUT_OPEN || | 2589 | if (c->istate == CHAN_INPUT_OPEN || |
2332 | c->istate == CHAN_INPUT_WAIT_DRAIN) && | 2590 | c->istate == CHAN_INPUT_WAIT_DRAIN) |
2333 | (len = buffer_len(&c->input)) > 0) { | 2591 | channel_output_poll_input_open(ssh, c); |
2334 | if (c->datagram) { | ||
2335 | if (len > 0) { | ||
2336 | u_char *data; | ||
2337 | u_int dlen; | ||
2338 | |||
2339 | data = buffer_get_string(&c->input, | ||
2340 | &dlen); | ||
2341 | if (dlen > c->remote_window || | ||
2342 | dlen > c->remote_maxpacket) { | ||
2343 | debug("channel %d: datagram " | ||
2344 | "too big for channel", | ||
2345 | c->self); | ||
2346 | free(data); | ||
2347 | continue; | ||
2348 | } | ||
2349 | packet_start(SSH2_MSG_CHANNEL_DATA); | ||
2350 | packet_put_int(c->remote_id); | ||
2351 | packet_put_string(data, dlen); | ||
2352 | packet_send(); | ||
2353 | c->remote_window -= dlen; | ||
2354 | free(data); | ||
2355 | } | ||
2356 | continue; | ||
2357 | } | ||
2358 | /* | ||
2359 | * Send some data for the other side over the secure | ||
2360 | * connection. | ||
2361 | */ | ||
2362 | if (compat20) { | ||
2363 | if (len > c->remote_window) | ||
2364 | len = c->remote_window; | ||
2365 | if (len > c->remote_maxpacket) | ||
2366 | len = c->remote_maxpacket; | ||
2367 | } else { | ||
2368 | if (packet_is_interactive()) { | ||
2369 | if (len > 1024) | ||
2370 | len = 512; | ||
2371 | } else { | ||
2372 | /* Keep the packets at reasonable size. */ | ||
2373 | if (len > packet_get_maxsize()/2) | ||
2374 | len = packet_get_maxsize()/2; | ||
2375 | } | ||
2376 | } | ||
2377 | if (len > 0) { | ||
2378 | packet_start(compat20 ? | ||
2379 | SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA); | ||
2380 | packet_put_int(c->remote_id); | ||
2381 | packet_put_string(buffer_ptr(&c->input), len); | ||
2382 | packet_send(); | ||
2383 | buffer_consume(&c->input, len); | ||
2384 | c->remote_window -= len; | ||
2385 | } | ||
2386 | } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) { | ||
2387 | if (compat13) | ||
2388 | fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); | ||
2389 | /* | ||
2390 | * input-buffer is empty and read-socket shutdown: | ||
2391 | * tell peer, that we will not send more data: send IEOF. | ||
2392 | * hack for extended data: delay EOF if EFD still in use. | ||
2393 | */ | ||
2394 | if (CHANNEL_EFD_INPUT_ACTIVE(c)) | ||
2395 | debug2("channel %d: ibuf_empty delayed efd %d/(%d)", | ||
2396 | c->self, c->efd, buffer_len(&c->extended)); | ||
2397 | else | ||
2398 | chan_ibuf_empty(c); | ||
2399 | } | ||
2400 | /* Send extended data, i.e. stderr */ | 2592 | /* Send extended data, i.e. stderr */ |
2401 | if (compat20 && | 2593 | if (!(c->flags & CHAN_EOF_SENT) && |
2402 | !(c->flags & CHAN_EOF_SENT) && | 2594 | c->extended_usage == CHAN_EXTENDED_READ) |
2403 | c->remote_window > 0 && | 2595 | channel_output_poll_extended_read(ssh, c); |
2404 | (len = buffer_len(&c->extended)) > 0 && | ||
2405 | c->extended_usage == CHAN_EXTENDED_READ) { | ||
2406 | debug2("channel %d: rwin %u elen %u euse %d", | ||
2407 | c->self, c->remote_window, buffer_len(&c->extended), | ||
2408 | c->extended_usage); | ||
2409 | if (len > c->remote_window) | ||
2410 | len = c->remote_window; | ||
2411 | if (len > c->remote_maxpacket) | ||
2412 | len = c->remote_maxpacket; | ||
2413 | packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA); | ||
2414 | packet_put_int(c->remote_id); | ||
2415 | packet_put_int(SSH2_EXTENDED_DATA_STDERR); | ||
2416 | packet_put_string(buffer_ptr(&c->extended), len); | ||
2417 | packet_send(); | ||
2418 | buffer_consume(&c->extended, len); | ||
2419 | c->remote_window -= len; | ||
2420 | debug2("channel %d: sent ext data %d", c->self, len); | ||
2421 | } | ||
2422 | } | 2596 | } |
2423 | } | 2597 | } |
2424 | 2598 | ||
@@ -2463,20 +2637,19 @@ channel_output_poll(void) | |||
2463 | * on channel creation. | 2637 | * on channel creation. |
2464 | */ | 2638 | */ |
2465 | int | 2639 | int |
2466 | channel_proxy_downstream(Channel *downstream) | 2640 | channel_proxy_downstream(struct ssh *ssh, Channel *downstream) |
2467 | { | 2641 | { |
2468 | Channel *c = NULL; | 2642 | Channel *c = NULL; |
2469 | struct ssh *ssh = active_state; | ||
2470 | struct sshbuf *original = NULL, *modified = NULL; | 2643 | struct sshbuf *original = NULL, *modified = NULL; |
2471 | const u_char *cp; | 2644 | const u_char *cp; |
2472 | char *ctype = NULL, *listen_host = NULL; | 2645 | char *ctype = NULL, *listen_host = NULL; |
2473 | u_char type; | 2646 | u_char type; |
2474 | size_t have; | 2647 | size_t have; |
2475 | int ret = -1, r, idx; | 2648 | int ret = -1, r; |
2476 | u_int id, remote_id, listen_port; | 2649 | u_int id, remote_id, listen_port; |
2477 | 2650 | ||
2478 | /* sshbuf_dump(&downstream->input, stderr); */ | 2651 | /* sshbuf_dump(downstream->input, stderr); */ |
2479 | if ((r = sshbuf_get_string_direct(&downstream->input, &cp, &have)) | 2652 | if ((r = sshbuf_get_string_direct(downstream->input, &cp, &have)) |
2480 | != 0) { | 2653 | != 0) { |
2481 | error("%s: malformed message: %s", __func__, ssh_err(r)); | 2654 | error("%s: malformed message: %s", __func__, ssh_err(r)); |
2482 | return -1; | 2655 | return -1; |
@@ -2505,7 +2678,7 @@ channel_proxy_downstream(Channel *downstream) | |||
2505 | error("%s: parse error %s", __func__, ssh_err(r)); | 2678 | error("%s: parse error %s", __func__, ssh_err(r)); |
2506 | goto out; | 2679 | goto out; |
2507 | } | 2680 | } |
2508 | c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY, | 2681 | c = channel_new(ssh, "mux proxy", SSH_CHANNEL_MUX_PROXY, |
2509 | -1, -1, -1, 0, 0, 0, ctype, 1); | 2682 | -1, -1, -1, 0, 0, 0, ctype, 1); |
2510 | c->mux_ctx = downstream; /* point to mux client */ | 2683 | c->mux_ctx = downstream; /* point to mux client */ |
2511 | c->mux_downstream_id = id; /* original downstream id */ | 2684 | c->mux_downstream_id = id; /* original downstream id */ |
@@ -2513,7 +2686,7 @@ channel_proxy_downstream(Channel *downstream) | |||
2513 | (r = sshbuf_put_u32(modified, c->self)) != 0 || | 2686 | (r = sshbuf_put_u32(modified, c->self)) != 0 || |
2514 | (r = sshbuf_putb(modified, original)) != 0) { | 2687 | (r = sshbuf_putb(modified, original)) != 0) { |
2515 | error("%s: compose error %s", __func__, ssh_err(r)); | 2688 | error("%s: compose error %s", __func__, ssh_err(r)); |
2516 | channel_free(c); | 2689 | channel_free(ssh, c); |
2517 | goto out; | 2690 | goto out; |
2518 | } | 2691 | } |
2519 | break; | 2692 | break; |
@@ -2532,16 +2705,17 @@ channel_proxy_downstream(Channel *downstream) | |||
2532 | error("%s: parse error %s", __func__, ssh_err(r)); | 2705 | error("%s: parse error %s", __func__, ssh_err(r)); |
2533 | goto out; | 2706 | goto out; |
2534 | } | 2707 | } |
2535 | c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY, | 2708 | c = channel_new(ssh, "mux proxy", SSH_CHANNEL_MUX_PROXY, |
2536 | -1, -1, -1, 0, 0, 0, "mux-down-connect", 1); | 2709 | -1, -1, -1, 0, 0, 0, "mux-down-connect", 1); |
2537 | c->mux_ctx = downstream; /* point to mux client */ | 2710 | c->mux_ctx = downstream; /* point to mux client */ |
2538 | c->mux_downstream_id = id; | 2711 | c->mux_downstream_id = id; |
2539 | c->remote_id = remote_id; | 2712 | c->remote_id = remote_id; |
2713 | c->have_remote_id = 1; | ||
2540 | if ((r = sshbuf_put_u32(modified, remote_id)) != 0 || | 2714 | if ((r = sshbuf_put_u32(modified, remote_id)) != 0 || |
2541 | (r = sshbuf_put_u32(modified, c->self)) != 0 || | 2715 | (r = sshbuf_put_u32(modified, c->self)) != 0 || |
2542 | (r = sshbuf_putb(modified, original)) != 0) { | 2716 | (r = sshbuf_putb(modified, original)) != 0) { |
2543 | error("%s: compose error %s", __func__, ssh_err(r)); | 2717 | error("%s: compose error %s", __func__, ssh_err(r)); |
2544 | channel_free(c); | 2718 | channel_free(ssh, c); |
2545 | goto out; | 2719 | goto out; |
2546 | } | 2720 | } |
2547 | break; | 2721 | break; |
@@ -2570,23 +2744,17 @@ channel_proxy_downstream(Channel *downstream) | |||
2570 | goto out; | 2744 | goto out; |
2571 | } | 2745 | } |
2572 | /* Record that connection to this host/port is permitted. */ | 2746 | /* Record that connection to this host/port is permitted. */ |
2573 | permitted_opens = xreallocarray(permitted_opens, | 2747 | fwd_perm_list_add(ssh, FWDPERM_USER, "<mux>", -1, |
2574 | num_permitted_opens + 1, sizeof(*permitted_opens)); | 2748 | listen_host, NULL, (int)listen_port, downstream); |
2575 | idx = num_permitted_opens++; | ||
2576 | permitted_opens[idx].host_to_connect = xstrdup("<mux>"); | ||
2577 | permitted_opens[idx].port_to_connect = -1; | ||
2578 | permitted_opens[idx].listen_host = listen_host; | ||
2579 | permitted_opens[idx].listen_port = (int)listen_port; | ||
2580 | permitted_opens[idx].downstream = downstream; | ||
2581 | listen_host = NULL; | 2749 | listen_host = NULL; |
2582 | break; | 2750 | break; |
2583 | case SSH2_MSG_CHANNEL_CLOSE: | 2751 | case SSH2_MSG_CHANNEL_CLOSE: |
2584 | if (have < 4) | 2752 | if (have < 4) |
2585 | break; | 2753 | break; |
2586 | remote_id = PEEK_U32(cp); | 2754 | remote_id = PEEK_U32(cp); |
2587 | if ((c = channel_by_remote_id(remote_id)) != NULL) { | 2755 | if ((c = channel_by_remote_id(ssh, remote_id)) != NULL) { |
2588 | if (c->flags & CHAN_CLOSE_RCVD) | 2756 | if (c->flags & CHAN_CLOSE_RCVD) |
2589 | channel_free(c); | 2757 | channel_free(ssh, c); |
2590 | else | 2758 | else |
2591 | c->flags |= CHAN_CLOSE_SENT; | 2759 | c->flags |= CHAN_CLOSE_SENT; |
2592 | } | 2760 | } |
@@ -2623,9 +2791,8 @@ channel_proxy_downstream(Channel *downstream) | |||
2623 | * replaces local (proxy) channel ID with downstream channel ID. | 2791 | * replaces local (proxy) channel ID with downstream channel ID. |
2624 | */ | 2792 | */ |
2625 | int | 2793 | int |
2626 | channel_proxy_upstream(Channel *c, int type, u_int32_t seq, void *ctxt) | 2794 | channel_proxy_upstream(Channel *c, int type, u_int32_t seq, struct ssh *ssh) |
2627 | { | 2795 | { |
2628 | struct ssh *ssh = active_state; | ||
2629 | struct sshbuf *b = NULL; | 2796 | struct sshbuf *b = NULL; |
2630 | Channel *downstream; | 2797 | Channel *downstream; |
2631 | const u_char *cp = NULL; | 2798 | const u_char *cp = NULL; |
@@ -2674,7 +2841,7 @@ channel_proxy_upstream(Channel *c, int type, u_int32_t seq, void *ctxt) | |||
2674 | (r = sshbuf_put_u8(b, type)) != 0 || | 2841 | (r = sshbuf_put_u8(b, type)) != 0 || |
2675 | (r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 || | 2842 | (r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 || |
2676 | (r = sshbuf_put(b, cp, len)) != 0 || | 2843 | (r = sshbuf_put(b, cp, len)) != 0 || |
2677 | (r = sshbuf_put_stringb(&downstream->output, b)) != 0) { | 2844 | (r = sshbuf_put_stringb(downstream->output, b)) != 0) { |
2678 | error("%s: compose for muxclient %s", __func__, ssh_err(r)); | 2845 | error("%s: compose for muxclient %s", __func__, ssh_err(r)); |
2679 | goto out; | 2846 | goto out; |
2680 | } | 2847 | } |
@@ -2687,12 +2854,14 @@ channel_proxy_upstream(Channel *c, int type, u_int32_t seq, void *ctxt) | |||
2687 | switch (type) { | 2854 | switch (type) { |
2688 | case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: | 2855 | case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: |
2689 | /* record remote_id for SSH2_MSG_CHANNEL_CLOSE */ | 2856 | /* record remote_id for SSH2_MSG_CHANNEL_CLOSE */ |
2690 | if (cp && len > 4) | 2857 | if (cp && len > 4) { |
2691 | c->remote_id = PEEK_U32(cp); | 2858 | c->remote_id = PEEK_U32(cp); |
2859 | c->have_remote_id = 1; | ||
2860 | } | ||
2692 | break; | 2861 | break; |
2693 | case SSH2_MSG_CHANNEL_CLOSE: | 2862 | case SSH2_MSG_CHANNEL_CLOSE: |
2694 | if (c->flags & CHAN_CLOSE_SENT) | 2863 | if (c->flags & CHAN_CLOSE_SENT) |
2695 | channel_free(c); | 2864 | channel_free(ssh, c); |
2696 | else | 2865 | else |
2697 | c->flags |= CHAN_CLOSE_RCVD; | 2866 | c->flags |= CHAN_CLOSE_RCVD; |
2698 | break; | 2867 | break; |
@@ -2703,257 +2872,221 @@ channel_proxy_upstream(Channel *c, int type, u_int32_t seq, void *ctxt) | |||
2703 | 2872 | ||
2704 | /* -- protocol input */ | 2873 | /* -- protocol input */ |
2705 | 2874 | ||
2706 | /* ARGSUSED */ | 2875 | /* Parse a channel ID from the current packet */ |
2876 | static int | ||
2877 | channel_parse_id(struct ssh *ssh, const char *where, const char *what) | ||
2878 | { | ||
2879 | u_int32_t id; | ||
2880 | int r; | ||
2881 | |||
2882 | if ((r = sshpkt_get_u32(ssh, &id)) != 0) { | ||
2883 | error("%s: parse id: %s", where, ssh_err(r)); | ||
2884 | ssh_packet_disconnect(ssh, "Invalid %s message", what); | ||
2885 | } | ||
2886 | if (id > INT_MAX) { | ||
2887 | error("%s: bad channel id %u: %s", where, id, ssh_err(r)); | ||
2888 | ssh_packet_disconnect(ssh, "Invalid %s channel id", what); | ||
2889 | } | ||
2890 | return (int)id; | ||
2891 | } | ||
2892 | |||
2893 | /* Lookup a channel from an ID in the current packet */ | ||
2894 | static Channel * | ||
2895 | channel_from_packet_id(struct ssh *ssh, const char *where, const char *what) | ||
2896 | { | ||
2897 | int id = channel_parse_id(ssh, where, what); | ||
2898 | Channel *c; | ||
2899 | |||
2900 | if ((c = channel_lookup(ssh, id)) == NULL) { | ||
2901 | ssh_packet_disconnect(ssh, | ||
2902 | "%s packet referred to nonexistent channel %d", what, id); | ||
2903 | } | ||
2904 | return c; | ||
2905 | } | ||
2906 | |||
2707 | int | 2907 | int |
2708 | channel_input_data(int type, u_int32_t seq, void *ctxt) | 2908 | channel_input_data(int type, u_int32_t seq, struct ssh *ssh) |
2709 | { | 2909 | { |
2710 | int id; | ||
2711 | const u_char *data; | 2910 | const u_char *data; |
2712 | u_int data_len, win_len; | 2911 | size_t data_len, win_len; |
2713 | Channel *c; | 2912 | Channel *c = channel_from_packet_id(ssh, __func__, "data"); |
2913 | int r; | ||
2714 | 2914 | ||
2715 | /* Get the channel number and verify it. */ | 2915 | if (channel_proxy_upstream(c, type, seq, ssh)) |
2716 | id = packet_get_int(); | ||
2717 | c = channel_lookup(id); | ||
2718 | if (c == NULL) | ||
2719 | packet_disconnect("Received data for nonexistent channel %d.", id); | ||
2720 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2721 | return 0; | 2916 | return 0; |
2722 | 2917 | ||
2723 | /* Ignore any data for non-open channels (might happen on close) */ | 2918 | /* Ignore any data for non-open channels (might happen on close) */ |
2724 | if (c->type != SSH_CHANNEL_OPEN && | 2919 | if (c->type != SSH_CHANNEL_OPEN && |
2920 | c->type != SSH_CHANNEL_RDYNAMIC_OPEN && | ||
2921 | c->type != SSH_CHANNEL_RDYNAMIC_FINISH && | ||
2725 | c->type != SSH_CHANNEL_X11_OPEN) | 2922 | c->type != SSH_CHANNEL_X11_OPEN) |
2726 | return 0; | 2923 | return 0; |
2727 | 2924 | ||
2728 | /* Get the data. */ | 2925 | /* Get the data. */ |
2729 | data = packet_get_string_ptr(&data_len); | 2926 | if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0) |
2927 | fatal("%s: channel %d: get data: %s", __func__, | ||
2928 | c->self, ssh_err(r)); | ||
2929 | ssh_packet_check_eom(ssh); | ||
2930 | |||
2730 | win_len = data_len; | 2931 | win_len = data_len; |
2731 | if (c->datagram) | 2932 | if (c->datagram) |
2732 | win_len += 4; /* string length header */ | 2933 | win_len += 4; /* string length header */ |
2733 | 2934 | ||
2734 | /* | 2935 | /* |
2735 | * Ignore data for protocol > 1.3 if output end is no longer open. | 2936 | * The sending side reduces its window as it sends data, so we |
2736 | * For protocol 2 the sending side is reducing its window as it sends | 2937 | * must 'fake' consumption of the data in order to ensure that window |
2737 | * data, so we must 'fake' consumption of the data in order to ensure | 2938 | * updates are sent back. Otherwise the connection might deadlock. |
2738 | * that window updates are sent back. Otherwise the connection might | ||
2739 | * deadlock. | ||
2740 | */ | 2939 | */ |
2741 | if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) { | 2940 | if (c->ostate != CHAN_OUTPUT_OPEN) { |
2742 | if (compat20) { | 2941 | c->local_window -= win_len; |
2743 | c->local_window -= win_len; | 2942 | c->local_consumed += win_len; |
2744 | c->local_consumed += win_len; | ||
2745 | } | ||
2746 | return 0; | 2943 | return 0; |
2747 | } | 2944 | } |
2748 | 2945 | ||
2749 | if (compat20) { | 2946 | if (win_len > c->local_maxpacket) { |
2750 | if (win_len > c->local_maxpacket) { | 2947 | logit("channel %d: rcvd big packet %zu, maxpack %u", |
2751 | logit("channel %d: rcvd big packet %d, maxpack %d", | 2948 | c->self, win_len, c->local_maxpacket); |
2752 | c->self, win_len, c->local_maxpacket); | 2949 | return 0; |
2753 | } | ||
2754 | if (win_len > c->local_window) { | ||
2755 | logit("channel %d: rcvd too much data %d, win %d", | ||
2756 | c->self, win_len, c->local_window); | ||
2757 | return 0; | ||
2758 | } | ||
2759 | c->local_window -= win_len; | ||
2760 | } | 2950 | } |
2761 | if (c->datagram) | 2951 | if (win_len > c->local_window) { |
2762 | buffer_put_string(&c->output, data, data_len); | 2952 | logit("channel %d: rcvd too much data %zu, win %u", |
2763 | else | 2953 | c->self, win_len, c->local_window); |
2764 | buffer_append(&c->output, data, data_len); | 2954 | return 0; |
2765 | packet_check_eom(); | 2955 | } |
2956 | c->local_window -= win_len; | ||
2957 | |||
2958 | if (c->datagram) { | ||
2959 | if ((r = sshbuf_put_string(c->output, data, data_len)) != 0) | ||
2960 | fatal("%s: channel %d: append datagram: %s", | ||
2961 | __func__, c->self, ssh_err(r)); | ||
2962 | } else if ((r = sshbuf_put(c->output, data, data_len)) != 0) | ||
2963 | fatal("%s: channel %d: append data: %s", | ||
2964 | __func__, c->self, ssh_err(r)); | ||
2965 | |||
2766 | return 0; | 2966 | return 0; |
2767 | } | 2967 | } |
2768 | 2968 | ||
2769 | /* ARGSUSED */ | ||
2770 | int | 2969 | int |
2771 | channel_input_extended_data(int type, u_int32_t seq, void *ctxt) | 2970 | channel_input_extended_data(int type, u_int32_t seq, struct ssh *ssh) |
2772 | { | 2971 | { |
2773 | int id; | 2972 | const u_char *data; |
2774 | char *data; | 2973 | size_t data_len; |
2775 | u_int data_len, tcode; | 2974 | u_int32_t tcode; |
2776 | Channel *c; | 2975 | Channel *c = channel_from_packet_id(ssh, __func__, "extended data"); |
2777 | 2976 | int r; | |
2778 | /* Get the channel number and verify it. */ | ||
2779 | id = packet_get_int(); | ||
2780 | c = channel_lookup(id); | ||
2781 | 2977 | ||
2782 | if (c == NULL) | 2978 | if (channel_proxy_upstream(c, type, seq, ssh)) |
2783 | packet_disconnect("Received extended_data for bad channel %d.", id); | ||
2784 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2785 | return 0; | 2979 | return 0; |
2786 | if (c->type != SSH_CHANNEL_OPEN) { | 2980 | if (c->type != SSH_CHANNEL_OPEN) { |
2787 | logit("channel %d: ext data for non open", id); | 2981 | logit("channel %d: ext data for non open", c->self); |
2788 | return 0; | 2982 | return 0; |
2789 | } | 2983 | } |
2790 | if (c->flags & CHAN_EOF_RCVD) { | 2984 | if (c->flags & CHAN_EOF_RCVD) { |
2791 | if (datafellows & SSH_BUG_EXTEOF) | 2985 | if (datafellows & SSH_BUG_EXTEOF) |
2792 | debug("channel %d: accepting ext data after eof", id); | 2986 | debug("channel %d: accepting ext data after eof", |
2987 | c->self); | ||
2793 | else | 2988 | else |
2794 | packet_disconnect("Received extended_data after EOF " | 2989 | ssh_packet_disconnect(ssh, "Received extended_data " |
2795 | "on channel %d.", id); | 2990 | "after EOF on channel %d.", c->self); |
2991 | } | ||
2992 | |||
2993 | if ((r = sshpkt_get_u32(ssh, &tcode)) != 0) { | ||
2994 | error("%s: parse tcode: %s", __func__, ssh_err(r)); | ||
2995 | ssh_packet_disconnect(ssh, "Invalid extended_data message"); | ||
2796 | } | 2996 | } |
2797 | tcode = packet_get_int(); | ||
2798 | if (c->efd == -1 || | 2997 | if (c->efd == -1 || |
2799 | c->extended_usage != CHAN_EXTENDED_WRITE || | 2998 | c->extended_usage != CHAN_EXTENDED_WRITE || |
2800 | tcode != SSH2_EXTENDED_DATA_STDERR) { | 2999 | tcode != SSH2_EXTENDED_DATA_STDERR) { |
2801 | logit("channel %d: bad ext data", c->self); | 3000 | logit("channel %d: bad ext data", c->self); |
2802 | return 0; | 3001 | return 0; |
2803 | } | 3002 | } |
2804 | data = packet_get_string(&data_len); | 3003 | if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0) { |
2805 | packet_check_eom(); | 3004 | error("%s: parse data: %s", __func__, ssh_err(r)); |
3005 | ssh_packet_disconnect(ssh, "Invalid extended_data message"); | ||
3006 | } | ||
3007 | ssh_packet_check_eom(ssh); | ||
3008 | |||
2806 | if (data_len > c->local_window) { | 3009 | if (data_len > c->local_window) { |
2807 | logit("channel %d: rcvd too much extended_data %d, win %d", | 3010 | logit("channel %d: rcvd too much extended_data %zu, win %u", |
2808 | c->self, data_len, c->local_window); | 3011 | c->self, data_len, c->local_window); |
2809 | free(data); | ||
2810 | return 0; | 3012 | return 0; |
2811 | } | 3013 | } |
2812 | debug2("channel %d: rcvd ext data %d", c->self, data_len); | 3014 | debug2("channel %d: rcvd ext data %zu", c->self, data_len); |
3015 | /* XXX sshpkt_getb? */ | ||
3016 | if ((r = sshbuf_put(c->extended, data, data_len)) != 0) | ||
3017 | error("%s: append: %s", __func__, ssh_err(r)); | ||
2813 | c->local_window -= data_len; | 3018 | c->local_window -= data_len; |
2814 | buffer_append(&c->extended, data, data_len); | ||
2815 | free(data); | ||
2816 | return 0; | 3019 | return 0; |
2817 | } | 3020 | } |
2818 | 3021 | ||
2819 | /* ARGSUSED */ | ||
2820 | int | 3022 | int |
2821 | channel_input_ieof(int type, u_int32_t seq, void *ctxt) | 3023 | channel_input_ieof(int type, u_int32_t seq, struct ssh *ssh) |
2822 | { | 3024 | { |
2823 | int id; | 3025 | Channel *c = channel_from_packet_id(ssh, __func__, "ieof"); |
2824 | Channel *c; | ||
2825 | 3026 | ||
2826 | id = packet_get_int(); | 3027 | ssh_packet_check_eom(ssh); |
2827 | packet_check_eom(); | 3028 | |
2828 | c = channel_lookup(id); | 3029 | if (channel_proxy_upstream(c, type, seq, ssh)) |
2829 | if (c == NULL) | ||
2830 | packet_disconnect("Received ieof for nonexistent channel %d.", id); | ||
2831 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2832 | return 0; | 3030 | return 0; |
2833 | chan_rcvd_ieof(c); | 3031 | chan_rcvd_ieof(ssh, c); |
2834 | 3032 | ||
2835 | /* XXX force input close */ | 3033 | /* XXX force input close */ |
2836 | if (c->force_drain && c->istate == CHAN_INPUT_OPEN) { | 3034 | if (c->force_drain && c->istate == CHAN_INPUT_OPEN) { |
2837 | debug("channel %d: FORCE input drain", c->self); | 3035 | debug("channel %d: FORCE input drain", c->self); |
2838 | c->istate = CHAN_INPUT_WAIT_DRAIN; | 3036 | c->istate = CHAN_INPUT_WAIT_DRAIN; |
2839 | if (buffer_len(&c->input) == 0) | 3037 | if (sshbuf_len(c->input) == 0) |
2840 | chan_ibuf_empty(c); | 3038 | chan_ibuf_empty(ssh, c); |
2841 | } | ||
2842 | return 0; | ||
2843 | } | ||
2844 | |||
2845 | /* ARGSUSED */ | ||
2846 | int | ||
2847 | channel_input_close(int type, u_int32_t seq, void *ctxt) | ||
2848 | { | ||
2849 | int id; | ||
2850 | Channel *c; | ||
2851 | |||
2852 | id = packet_get_int(); | ||
2853 | packet_check_eom(); | ||
2854 | c = channel_lookup(id); | ||
2855 | if (c == NULL) | ||
2856 | packet_disconnect("Received close for nonexistent channel %d.", id); | ||
2857 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2858 | return 0; | ||
2859 | /* | ||
2860 | * Send a confirmation that we have closed the channel and no more | ||
2861 | * data is coming for it. | ||
2862 | */ | ||
2863 | packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); | ||
2864 | packet_put_int(c->remote_id); | ||
2865 | packet_send(); | ||
2866 | |||
2867 | /* | ||
2868 | * If the channel is in closed state, we have sent a close request, | ||
2869 | * and the other side will eventually respond with a confirmation. | ||
2870 | * Thus, we cannot free the channel here, because then there would be | ||
2871 | * no-one to receive the confirmation. The channel gets freed when | ||
2872 | * the confirmation arrives. | ||
2873 | */ | ||
2874 | if (c->type != SSH_CHANNEL_CLOSED) { | ||
2875 | /* | ||
2876 | * Not a closed channel - mark it as draining, which will | ||
2877 | * cause it to be freed later. | ||
2878 | */ | ||
2879 | buffer_clear(&c->input); | ||
2880 | c->type = SSH_CHANNEL_OUTPUT_DRAINING; | ||
2881 | } | 3039 | } |
2882 | return 0; | 3040 | return 0; |
2883 | } | 3041 | } |
2884 | 3042 | ||
2885 | /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ | ||
2886 | /* ARGSUSED */ | ||
2887 | int | 3043 | int |
2888 | channel_input_oclose(int type, u_int32_t seq, void *ctxt) | 3044 | channel_input_oclose(int type, u_int32_t seq, struct ssh *ssh) |
2889 | { | 3045 | { |
2890 | int id = packet_get_int(); | 3046 | Channel *c = channel_from_packet_id(ssh, __func__, "oclose"); |
2891 | Channel *c = channel_lookup(id); | ||
2892 | 3047 | ||
2893 | if (c == NULL) | 3048 | if (channel_proxy_upstream(c, type, seq, ssh)) |
2894 | packet_disconnect("Received oclose for nonexistent channel %d.", id); | ||
2895 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2896 | return 0; | ||
2897 | packet_check_eom(); | ||
2898 | chan_rcvd_oclose(c); | ||
2899 | return 0; | ||
2900 | } | ||
2901 | |||
2902 | /* ARGSUSED */ | ||
2903 | int | ||
2904 | channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt) | ||
2905 | { | ||
2906 | int id = packet_get_int(); | ||
2907 | Channel *c = channel_lookup(id); | ||
2908 | |||
2909 | if (c == NULL) | ||
2910 | packet_disconnect("Received close confirmation for " | ||
2911 | "out-of-range channel %d.", id); | ||
2912 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2913 | return 0; | 3049 | return 0; |
2914 | packet_check_eom(); | 3050 | ssh_packet_check_eom(ssh); |
2915 | if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED) | 3051 | chan_rcvd_oclose(ssh, c); |
2916 | packet_disconnect("Received close confirmation for " | ||
2917 | "non-closed channel %d (type %d).", id, c->type); | ||
2918 | channel_free(c); | ||
2919 | return 0; | 3052 | return 0; |
2920 | } | 3053 | } |
2921 | 3054 | ||
2922 | /* ARGSUSED */ | ||
2923 | int | 3055 | int |
2924 | channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) | 3056 | channel_input_open_confirmation(int type, u_int32_t seq, struct ssh *ssh) |
2925 | { | 3057 | { |
2926 | int id, remote_id; | 3058 | Channel *c = channel_from_packet_id(ssh, __func__, "open confirmation"); |
2927 | Channel *c; | 3059 | u_int32_t remote_window, remote_maxpacket; |
2928 | 3060 | int r; | |
2929 | id = packet_get_int(); | ||
2930 | c = channel_lookup(id); | ||
2931 | 3061 | ||
2932 | if (c==NULL) | 3062 | if (channel_proxy_upstream(c, type, seq, ssh)) |
2933 | packet_disconnect("Received open confirmation for " | ||
2934 | "unknown channel %d.", id); | ||
2935 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2936 | return 0; | 3063 | return 0; |
2937 | if (c->type != SSH_CHANNEL_OPENING) | 3064 | if (c->type != SSH_CHANNEL_OPENING) |
2938 | packet_disconnect("Received open confirmation for " | 3065 | packet_disconnect("Received open confirmation for " |
2939 | "non-opening channel %d.", id); | 3066 | "non-opening channel %d.", c->self); |
2940 | remote_id = packet_get_int(); | 3067 | /* |
2941 | /* Record the remote channel number and mark that the channel is now open. */ | 3068 | * Record the remote channel number and mark that the channel |
2942 | c->remote_id = remote_id; | 3069 | * is now open. |
2943 | c->type = SSH_CHANNEL_OPEN; | 3070 | */ |
3071 | if ((r = sshpkt_get_u32(ssh, &c->remote_id)) != 0 || | ||
3072 | (r = sshpkt_get_u32(ssh, &remote_window)) != 0 || | ||
3073 | (r = sshpkt_get_u32(ssh, &remote_maxpacket)) != 0) { | ||
3074 | error("%s: window/maxpacket: %s", __func__, ssh_err(r)); | ||
3075 | packet_disconnect("Invalid open confirmation message"); | ||
3076 | } | ||
3077 | ssh_packet_check_eom(ssh); | ||
2944 | 3078 | ||
2945 | if (compat20) { | 3079 | c->have_remote_id = 1; |
2946 | c->remote_window = packet_get_int(); | 3080 | c->remote_window = remote_window; |
2947 | c->remote_maxpacket = packet_get_int(); | 3081 | c->remote_maxpacket = remote_maxpacket; |
2948 | if (c->open_confirm) { | 3082 | c->type = SSH_CHANNEL_OPEN; |
2949 | debug2("callback start"); | 3083 | if (c->open_confirm) { |
2950 | c->open_confirm(c->self, 1, c->open_confirm_ctx); | 3084 | debug2("%s: channel %d: callback start", __func__, c->self); |
2951 | debug2("callback done"); | 3085 | c->open_confirm(ssh, c->self, 1, c->open_confirm_ctx); |
2952 | } | 3086 | debug2("%s: channel %d: callback done", __func__, c->self); |
2953 | debug2("channel %d: open confirm rwindow %u rmax %u", c->self, | ||
2954 | c->remote_window, c->remote_maxpacket); | ||
2955 | } | 3087 | } |
2956 | packet_check_eom(); | 3088 | debug2("channel %d: open confirm rwindow %u rmax %u", c->self, |
3089 | c->remote_window, c->remote_maxpacket); | ||
2957 | return 0; | 3090 | return 0; |
2958 | } | 3091 | } |
2959 | 3092 | ||
@@ -2973,134 +3106,97 @@ reason2txt(int reason) | |||
2973 | return "unknown reason"; | 3106 | return "unknown reason"; |
2974 | } | 3107 | } |
2975 | 3108 | ||
2976 | /* ARGSUSED */ | ||
2977 | int | 3109 | int |
2978 | channel_input_open_failure(int type, u_int32_t seq, void *ctxt) | 3110 | channel_input_open_failure(int type, u_int32_t seq, struct ssh *ssh) |
2979 | { | 3111 | { |
2980 | int id, reason; | 3112 | Channel *c = channel_from_packet_id(ssh, __func__, "open failure"); |
2981 | char *msg = NULL, *lang = NULL; | 3113 | u_int32_t reason; |
2982 | Channel *c; | 3114 | char *msg = NULL; |
2983 | 3115 | int r; | |
2984 | id = packet_get_int(); | ||
2985 | c = channel_lookup(id); | ||
2986 | 3116 | ||
2987 | if (c==NULL) | 3117 | if (channel_proxy_upstream(c, type, seq, ssh)) |
2988 | packet_disconnect("Received open failure for " | ||
2989 | "unknown channel %d.", id); | ||
2990 | if (channel_proxy_upstream(c, type, seq, ctxt)) | ||
2991 | return 0; | 3118 | return 0; |
2992 | if (c->type != SSH_CHANNEL_OPENING) | 3119 | if (c->type != SSH_CHANNEL_OPENING) |
2993 | packet_disconnect("Received open failure for " | 3120 | packet_disconnect("Received open failure for " |
2994 | "non-opening channel %d.", id); | 3121 | "non-opening channel %d.", c->self); |
2995 | if (compat20) { | 3122 | if ((r = sshpkt_get_u32(ssh, &reason)) != 0) { |
2996 | reason = packet_get_int(); | 3123 | error("%s: reason: %s", __func__, ssh_err(r)); |
2997 | if (!(datafellows & SSH_BUG_OPENFAILURE)) { | 3124 | packet_disconnect("Invalid open failure message"); |
2998 | msg = packet_get_string(NULL); | 3125 | } |
2999 | lang = packet_get_string(NULL); | 3126 | if ((datafellows & SSH_BUG_OPENFAILURE) == 0) { |
3000 | } | 3127 | /* skip language */ |
3001 | logit("channel %d: open failed: %s%s%s", id, | 3128 | if ((r = sshpkt_get_cstring(ssh, &msg, NULL)) != 0 || |
3002 | reason2txt(reason), msg ? ": ": "", msg ? msg : ""); | 3129 | (r = sshpkt_get_string_direct(ssh, NULL, NULL)) != 0) { |
3003 | free(msg); | 3130 | error("%s: message/lang: %s", __func__, ssh_err(r)); |
3004 | free(lang); | 3131 | packet_disconnect("Invalid open failure message"); |
3005 | if (c->open_confirm) { | ||
3006 | debug2("callback start"); | ||
3007 | c->open_confirm(c->self, 0, c->open_confirm_ctx); | ||
3008 | debug2("callback done"); | ||
3009 | } | 3132 | } |
3010 | } | 3133 | } |
3011 | packet_check_eom(); | 3134 | ssh_packet_check_eom(ssh); |
3135 | logit("channel %d: open failed: %s%s%s", c->self, | ||
3136 | reason2txt(reason), msg ? ": ": "", msg ? msg : ""); | ||
3137 | free(msg); | ||
3138 | if (c->open_confirm) { | ||
3139 | debug2("%s: channel %d: callback start", __func__, c->self); | ||
3140 | c->open_confirm(ssh, c->self, 0, c->open_confirm_ctx); | ||
3141 | debug2("%s: channel %d: callback done", __func__, c->self); | ||
3142 | } | ||
3012 | /* Schedule the channel for cleanup/deletion. */ | 3143 | /* Schedule the channel for cleanup/deletion. */ |
3013 | chan_mark_dead(c); | 3144 | chan_mark_dead(ssh, c); |
3014 | return 0; | 3145 | return 0; |
3015 | } | 3146 | } |
3016 | 3147 | ||
3017 | /* ARGSUSED */ | ||
3018 | int | 3148 | int |
3019 | channel_input_window_adjust(int type, u_int32_t seq, void *ctxt) | 3149 | channel_input_window_adjust(int type, u_int32_t seq, struct ssh *ssh) |
3020 | { | 3150 | { |
3151 | int id = channel_parse_id(ssh, __func__, "window adjust"); | ||
3021 | Channel *c; | 3152 | Channel *c; |
3022 | int id; | 3153 | u_int32_t adjust; |
3023 | u_int adjust, tmp; | 3154 | u_int new_rwin; |
3024 | 3155 | int r; | |
3025 | if (!compat20) | ||
3026 | return 0; | ||
3027 | |||
3028 | /* Get the channel number and verify it. */ | ||
3029 | id = packet_get_int(); | ||
3030 | c = channel_lookup(id); | ||
3031 | 3156 | ||
3032 | if (c == NULL) { | 3157 | if ((c = channel_lookup(ssh, id)) == NULL) { |
3033 | logit("Received window adjust for non-open channel %d.", id); | 3158 | logit("Received window adjust for non-open channel %d.", id); |
3034 | return 0; | 3159 | return 0; |
3035 | } | 3160 | } |
3036 | if (channel_proxy_upstream(c, type, seq, ctxt)) | 3161 | |
3162 | if (channel_proxy_upstream(c, type, seq, ssh)) | ||
3037 | return 0; | 3163 | return 0; |
3038 | adjust = packet_get_int(); | 3164 | if ((r = sshpkt_get_u32(ssh, &adjust)) != 0) { |
3039 | packet_check_eom(); | 3165 | error("%s: adjust: %s", __func__, ssh_err(r)); |
3040 | debug2("channel %d: rcvd adjust %u", id, adjust); | 3166 | packet_disconnect("Invalid window adjust message"); |
3041 | if ((tmp = c->remote_window + adjust) < c->remote_window) | 3167 | } |
3168 | ssh_packet_check_eom(ssh); | ||
3169 | debug2("channel %d: rcvd adjust %u", c->self, adjust); | ||
3170 | if ((new_rwin = c->remote_window + adjust) < c->remote_window) { | ||
3042 | fatal("channel %d: adjust %u overflows remote window %u", | 3171 | fatal("channel %d: adjust %u overflows remote window %u", |
3043 | id, adjust, c->remote_window); | 3172 | c->self, adjust, c->remote_window); |
3044 | c->remote_window = tmp; | ||
3045 | return 0; | ||
3046 | } | ||
3047 | |||
3048 | /* ARGSUSED */ | ||
3049 | int | ||
3050 | channel_input_port_open(int type, u_int32_t seq, void *ctxt) | ||
3051 | { | ||
3052 | Channel *c = NULL; | ||
3053 | u_short host_port; | ||
3054 | char *host, *originator_string; | ||
3055 | int remote_id; | ||
3056 | |||
3057 | remote_id = packet_get_int(); | ||
3058 | host = packet_get_string(NULL); | ||
3059 | host_port = packet_get_int(); | ||
3060 | |||
3061 | if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) { | ||
3062 | originator_string = packet_get_string(NULL); | ||
3063 | } else { | ||
3064 | originator_string = xstrdup("unknown (remote did not supply name)"); | ||
3065 | } | 3173 | } |
3066 | packet_check_eom(); | 3174 | c->remote_window = new_rwin; |
3067 | c = channel_connect_to_port(host, host_port, | ||
3068 | "connected socket", originator_string, NULL, NULL); | ||
3069 | free(originator_string); | ||
3070 | free(host); | ||
3071 | if (c == NULL) { | ||
3072 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | ||
3073 | packet_put_int(remote_id); | ||
3074 | packet_send(); | ||
3075 | } else | ||
3076 | c->remote_id = remote_id; | ||
3077 | return 0; | 3175 | return 0; |
3078 | } | 3176 | } |
3079 | 3177 | ||
3080 | /* ARGSUSED */ | ||
3081 | int | 3178 | int |
3082 | channel_input_status_confirm(int type, u_int32_t seq, void *ctxt) | 3179 | channel_input_status_confirm(int type, u_int32_t seq, struct ssh *ssh) |
3083 | { | 3180 | { |
3181 | int id = channel_parse_id(ssh, __func__, "status confirm"); | ||
3084 | Channel *c; | 3182 | Channel *c; |
3085 | struct channel_confirm *cc; | 3183 | struct channel_confirm *cc; |
3086 | int id; | ||
3087 | 3184 | ||
3088 | /* Reset keepalive timeout */ | 3185 | /* Reset keepalive timeout */ |
3089 | packet_set_alive_timeouts(0); | 3186 | packet_set_alive_timeouts(0); |
3090 | 3187 | ||
3091 | id = packet_get_int(); | 3188 | debug2("%s: type %d id %d", __func__, type, id); |
3092 | debug2("channel_input_status_confirm: type %d id %d", type, id); | ||
3093 | 3189 | ||
3094 | if ((c = channel_lookup(id)) == NULL) { | 3190 | if ((c = channel_lookup(ssh, id)) == NULL) { |
3095 | logit("channel_input_status_confirm: %d: unknown", id); | 3191 | logit("%s: %d: unknown", __func__, id); |
3096 | return 0; | 3192 | return 0; |
3097 | } | 3193 | } |
3098 | if (channel_proxy_upstream(c, type, seq, ctxt)) | 3194 | if (channel_proxy_upstream(c, type, seq, ssh)) |
3099 | return 0; | 3195 | return 0; |
3100 | packet_check_eom(); | 3196 | ssh_packet_check_eom(ssh); |
3101 | if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) | 3197 | if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) |
3102 | return 0; | 3198 | return 0; |
3103 | cc->cb(type, c, cc->ctx); | 3199 | cc->cb(ssh, type, c, cc->ctx); |
3104 | TAILQ_REMOVE(&c->status_confirms, cc, entry); | 3200 | TAILQ_REMOVE(&c->status_confirms, cc, entry); |
3105 | explicit_bzero(cc, sizeof(*cc)); | 3201 | explicit_bzero(cc, sizeof(*cc)); |
3106 | free(cc); | 3202 | free(cc); |
@@ -3110,9 +3206,9 @@ channel_input_status_confirm(int type, u_int32_t seq, void *ctxt) | |||
3110 | /* -- tcp forwarding */ | 3206 | /* -- tcp forwarding */ |
3111 | 3207 | ||
3112 | void | 3208 | void |
3113 | channel_set_af(int af) | 3209 | channel_set_af(struct ssh *ssh, int af) |
3114 | { | 3210 | { |
3115 | IPv4or6 = af; | 3211 | ssh->chanctxt->IPv4or6 = af; |
3116 | } | 3212 | } |
3117 | 3213 | ||
3118 | 3214 | ||
@@ -3180,8 +3276,9 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, | |||
3180 | } | 3276 | } |
3181 | 3277 | ||
3182 | static int | 3278 | static int |
3183 | channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd, | 3279 | channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type, |
3184 | int *allocated_listen_port, struct ForwardOptions *fwd_opts) | 3280 | struct Forward *fwd, int *allocated_listen_port, |
3281 | struct ForwardOptions *fwd_opts) | ||
3185 | { | 3282 | { |
3186 | Channel *c; | 3283 | Channel *c; |
3187 | int sock, r, success = 0, wildcard = 0, is_client; | 3284 | int sock, r, success = 0, wildcard = 0, is_client; |
@@ -3218,7 +3315,7 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd, | |||
3218 | * set to NULL and hints.ai_flags is not AI_PASSIVE | 3315 | * set to NULL and hints.ai_flags is not AI_PASSIVE |
3219 | */ | 3316 | */ |
3220 | memset(&hints, 0, sizeof(hints)); | 3317 | memset(&hints, 0, sizeof(hints)); |
3221 | hints.ai_family = IPv4or6; | 3318 | hints.ai_family = ssh->chanctxt->IPv4or6; |
3222 | hints.ai_flags = wildcard ? AI_PASSIVE : 0; | 3319 | hints.ai_flags = wildcard ? AI_PASSIVE : 0; |
3223 | hints.ai_socktype = SOCK_STREAM; | 3320 | hints.ai_socktype = SOCK_STREAM; |
3224 | snprintf(strport, sizeof strport, "%d", fwd->listen_port); | 3321 | snprintf(strport, sizeof strport, "%d", fwd->listen_port); |
@@ -3252,12 +3349,14 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd, | |||
3252 | * If allocating a port for -R forwards, then use the | 3349 | * If allocating a port for -R forwards, then use the |
3253 | * same port for all address families. | 3350 | * same port for all address families. |
3254 | */ | 3351 | */ |
3255 | if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 && | 3352 | if (type == SSH_CHANNEL_RPORT_LISTENER && |
3256 | allocated_listen_port != NULL && *allocated_listen_port > 0) | 3353 | fwd->listen_port == 0 && allocated_listen_port != NULL && |
3354 | *allocated_listen_port > 0) | ||
3257 | *lport_p = htons(*allocated_listen_port); | 3355 | *lport_p = htons(*allocated_listen_port); |
3258 | 3356 | ||
3259 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), | 3357 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
3260 | strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { | 3358 | strport, sizeof(strport), |
3359 | NI_NUMERICHOST|NI_NUMERICSERV) != 0) { | ||
3261 | error("%s: getnameinfo failed", __func__); | 3360 | error("%s: getnameinfo failed", __func__); |
3262 | continue; | 3361 | continue; |
3263 | } | 3362 | } |
@@ -3278,7 +3377,10 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd, | |||
3278 | 3377 | ||
3279 | /* Bind the socket to the address. */ | 3378 | /* Bind the socket to the address. */ |
3280 | if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { | 3379 | if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
3281 | /* address can be in use ipv6 address is already bound */ | 3380 | /* |
3381 | * address can be in if use ipv6 address is | ||
3382 | * already bound | ||
3383 | */ | ||
3282 | if (!ai->ai_next) | 3384 | if (!ai->ai_next) |
3283 | error("bind: %.100s", strerror(errno)); | 3385 | error("bind: %.100s", strerror(errno)); |
3284 | else | 3386 | else |
@@ -3298,7 +3400,8 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd, | |||
3298 | * fwd->listen_port == 0 requests a dynamically allocated port - | 3400 | * fwd->listen_port == 0 requests a dynamically allocated port - |
3299 | * record what we got. | 3401 | * record what we got. |
3300 | */ | 3402 | */ |
3301 | if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 && | 3403 | if (type == SSH_CHANNEL_RPORT_LISTENER && |
3404 | fwd->listen_port == 0 && | ||
3302 | allocated_listen_port != NULL && | 3405 | allocated_listen_port != NULL && |
3303 | *allocated_listen_port == 0) { | 3406 | *allocated_listen_port == 0) { |
3304 | *allocated_listen_port = get_local_port(sock); | 3407 | *allocated_listen_port = get_local_port(sock); |
@@ -3307,7 +3410,7 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd, | |||
3307 | } | 3410 | } |
3308 | 3411 | ||
3309 | /* Allocate a channel number for the socket. */ | 3412 | /* Allocate a channel number for the socket. */ |
3310 | c = channel_new("port listener", type, sock, sock, -1, | 3413 | c = channel_new(ssh, "port listener", type, sock, sock, -1, |
3311 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, | 3414 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
3312 | 0, "port listener", 1); | 3415 | 0, "port listener", 1); |
3313 | c->path = xstrdup(host); | 3416 | c->path = xstrdup(host); |
@@ -3328,8 +3431,8 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd, | |||
3328 | } | 3431 | } |
3329 | 3432 | ||
3330 | static int | 3433 | static int |
3331 | channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd, | 3434 | channel_setup_fwd_listener_streamlocal(struct ssh *ssh, int type, |
3332 | struct ForwardOptions *fwd_opts) | 3435 | struct Forward *fwd, struct ForwardOptions *fwd_opts) |
3333 | { | 3436 | { |
3334 | struct sockaddr_un sunaddr; | 3437 | struct sockaddr_un sunaddr; |
3335 | const char *path; | 3438 | const char *path; |
@@ -3391,7 +3494,7 @@ channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd, | |||
3391 | debug("Local forwarding listening on path %s.", fwd->listen_path); | 3494 | debug("Local forwarding listening on path %s.", fwd->listen_path); |
3392 | 3495 | ||
3393 | /* Allocate a channel number for the socket. */ | 3496 | /* Allocate a channel number for the socket. */ |
3394 | c = channel_new("unix listener", type, sock, sock, -1, | 3497 | c = channel_new(ssh, "unix listener", type, sock, sock, -1, |
3395 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, | 3498 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
3396 | 0, "unix listener", 1); | 3499 | 0, "unix listener", 1); |
3397 | c->path = xstrdup(path); | 3500 | c->path = xstrdup(path); |
@@ -3402,66 +3505,71 @@ channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd, | |||
3402 | } | 3505 | } |
3403 | 3506 | ||
3404 | static int | 3507 | static int |
3405 | channel_cancel_rport_listener_tcpip(const char *host, u_short port) | 3508 | channel_cancel_rport_listener_tcpip(struct ssh *ssh, |
3509 | const char *host, u_short port) | ||
3406 | { | 3510 | { |
3407 | u_int i; | 3511 | u_int i; |
3408 | int found = 0; | 3512 | int found = 0; |
3409 | 3513 | ||
3410 | for (i = 0; i < channels_alloc; i++) { | 3514 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
3411 | Channel *c = channels[i]; | 3515 | Channel *c = ssh->chanctxt->channels[i]; |
3412 | if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER) | 3516 | if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER) |
3413 | continue; | 3517 | continue; |
3414 | if (strcmp(c->path, host) == 0 && c->listening_port == port) { | 3518 | if (strcmp(c->path, host) == 0 && c->listening_port == port) { |
3415 | debug2("%s: close channel %d", __func__, i); | 3519 | debug2("%s: close channel %d", __func__, i); |
3416 | channel_free(c); | 3520 | channel_free(ssh, c); |
3417 | found = 1; | 3521 | found = 1; |
3418 | } | 3522 | } |
3419 | } | 3523 | } |
3420 | 3524 | ||
3421 | return (found); | 3525 | return found; |
3422 | } | 3526 | } |
3423 | 3527 | ||
3424 | static int | 3528 | static int |
3425 | channel_cancel_rport_listener_streamlocal(const char *path) | 3529 | channel_cancel_rport_listener_streamlocal(struct ssh *ssh, const char *path) |
3426 | { | 3530 | { |
3427 | u_int i; | 3531 | u_int i; |
3428 | int found = 0; | 3532 | int found = 0; |
3429 | 3533 | ||
3430 | for (i = 0; i < channels_alloc; i++) { | 3534 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
3431 | Channel *c = channels[i]; | 3535 | Channel *c = ssh->chanctxt->channels[i]; |
3432 | if (c == NULL || c->type != SSH_CHANNEL_RUNIX_LISTENER) | 3536 | if (c == NULL || c->type != SSH_CHANNEL_RUNIX_LISTENER) |
3433 | continue; | 3537 | continue; |
3434 | if (c->path == NULL) | 3538 | if (c->path == NULL) |
3435 | continue; | 3539 | continue; |
3436 | if (strcmp(c->path, path) == 0) { | 3540 | if (strcmp(c->path, path) == 0) { |
3437 | debug2("%s: close channel %d", __func__, i); | 3541 | debug2("%s: close channel %d", __func__, i); |
3438 | channel_free(c); | 3542 | channel_free(ssh, c); |
3439 | found = 1; | 3543 | found = 1; |
3440 | } | 3544 | } |
3441 | } | 3545 | } |
3442 | 3546 | ||
3443 | return (found); | 3547 | return found; |
3444 | } | 3548 | } |
3445 | 3549 | ||
3446 | int | 3550 | int |
3447 | channel_cancel_rport_listener(struct Forward *fwd) | 3551 | channel_cancel_rport_listener(struct ssh *ssh, struct Forward *fwd) |
3448 | { | 3552 | { |
3449 | if (fwd->listen_path != NULL) | 3553 | if (fwd->listen_path != NULL) { |
3450 | return channel_cancel_rport_listener_streamlocal(fwd->listen_path); | 3554 | return channel_cancel_rport_listener_streamlocal(ssh, |
3451 | else | 3555 | fwd->listen_path); |
3452 | return channel_cancel_rport_listener_tcpip(fwd->listen_host, fwd->listen_port); | 3556 | } else { |
3557 | return channel_cancel_rport_listener_tcpip(ssh, | ||
3558 | fwd->listen_host, fwd->listen_port); | ||
3559 | } | ||
3453 | } | 3560 | } |
3454 | 3561 | ||
3455 | static int | 3562 | static int |
3456 | channel_cancel_lport_listener_tcpip(const char *lhost, u_short lport, | 3563 | channel_cancel_lport_listener_tcpip(struct ssh *ssh, |
3457 | int cport, struct ForwardOptions *fwd_opts) | 3564 | const char *lhost, u_short lport, int cport, |
3565 | struct ForwardOptions *fwd_opts) | ||
3458 | { | 3566 | { |
3459 | u_int i; | 3567 | u_int i; |
3460 | int found = 0; | 3568 | int found = 0; |
3461 | const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, fwd_opts); | 3569 | const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, fwd_opts); |
3462 | 3570 | ||
3463 | for (i = 0; i < channels_alloc; i++) { | 3571 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
3464 | Channel *c = channels[i]; | 3572 | Channel *c = ssh->chanctxt->channels[i]; |
3465 | if (c == NULL || c->type != SSH_CHANNEL_PORT_LISTENER) | 3573 | if (c == NULL || c->type != SSH_CHANNEL_PORT_LISTENER) |
3466 | continue; | 3574 | continue; |
3467 | if (c->listening_port != lport) | 3575 | if (c->listening_port != lport) |
@@ -3479,16 +3587,16 @@ channel_cancel_lport_listener_tcpip(const char *lhost, u_short lport, | |||
3479 | continue; | 3587 | continue; |
3480 | if (addr == NULL || strcmp(c->listening_addr, addr) == 0) { | 3588 | if (addr == NULL || strcmp(c->listening_addr, addr) == 0) { |
3481 | debug2("%s: close channel %d", __func__, i); | 3589 | debug2("%s: close channel %d", __func__, i); |
3482 | channel_free(c); | 3590 | channel_free(ssh, c); |
3483 | found = 1; | 3591 | found = 1; |
3484 | } | 3592 | } |
3485 | } | 3593 | } |
3486 | 3594 | ||
3487 | return (found); | 3595 | return found; |
3488 | } | 3596 | } |
3489 | 3597 | ||
3490 | static int | 3598 | static int |
3491 | channel_cancel_lport_listener_streamlocal(const char *path) | 3599 | channel_cancel_lport_listener_streamlocal(struct ssh *ssh, const char *path) |
3492 | { | 3600 | { |
3493 | u_int i; | 3601 | u_int i; |
3494 | int found = 0; | 3602 | int found = 0; |
@@ -3498,54 +3606,59 @@ channel_cancel_lport_listener_streamlocal(const char *path) | |||
3498 | return 0; | 3606 | return 0; |
3499 | } | 3607 | } |
3500 | 3608 | ||
3501 | for (i = 0; i < channels_alloc; i++) { | 3609 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
3502 | Channel *c = channels[i]; | 3610 | Channel *c = ssh->chanctxt->channels[i]; |
3503 | if (c == NULL || c->type != SSH_CHANNEL_UNIX_LISTENER) | 3611 | if (c == NULL || c->type != SSH_CHANNEL_UNIX_LISTENER) |
3504 | continue; | 3612 | continue; |
3505 | if (c->listening_addr == NULL) | 3613 | if (c->listening_addr == NULL) |
3506 | continue; | 3614 | continue; |
3507 | if (strcmp(c->listening_addr, path) == 0) { | 3615 | if (strcmp(c->listening_addr, path) == 0) { |
3508 | debug2("%s: close channel %d", __func__, i); | 3616 | debug2("%s: close channel %d", __func__, i); |
3509 | channel_free(c); | 3617 | channel_free(ssh, c); |
3510 | found = 1; | 3618 | found = 1; |
3511 | } | 3619 | } |
3512 | } | 3620 | } |
3513 | 3621 | ||
3514 | return (found); | 3622 | return found; |
3515 | } | 3623 | } |
3516 | 3624 | ||
3517 | int | 3625 | int |
3518 | channel_cancel_lport_listener(struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts) | 3626 | channel_cancel_lport_listener(struct ssh *ssh, |
3627 | struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts) | ||
3519 | { | 3628 | { |
3520 | if (fwd->listen_path != NULL) | 3629 | if (fwd->listen_path != NULL) { |
3521 | return channel_cancel_lport_listener_streamlocal(fwd->listen_path); | 3630 | return channel_cancel_lport_listener_streamlocal(ssh, |
3522 | else | 3631 | fwd->listen_path); |
3523 | return channel_cancel_lport_listener_tcpip(fwd->listen_host, fwd->listen_port, cport, fwd_opts); | 3632 | } else { |
3633 | return channel_cancel_lport_listener_tcpip(ssh, | ||
3634 | fwd->listen_host, fwd->listen_port, cport, fwd_opts); | ||
3635 | } | ||
3524 | } | 3636 | } |
3525 | 3637 | ||
3526 | /* protocol local port fwd, used by ssh (and sshd in v1) */ | 3638 | /* protocol local port fwd, used by ssh */ |
3527 | int | 3639 | int |
3528 | channel_setup_local_fwd_listener(struct Forward *fwd, struct ForwardOptions *fwd_opts) | 3640 | channel_setup_local_fwd_listener(struct ssh *ssh, |
3641 | struct Forward *fwd, struct ForwardOptions *fwd_opts) | ||
3529 | { | 3642 | { |
3530 | if (fwd->listen_path != NULL) { | 3643 | if (fwd->listen_path != NULL) { |
3531 | return channel_setup_fwd_listener_streamlocal( | 3644 | return channel_setup_fwd_listener_streamlocal(ssh, |
3532 | SSH_CHANNEL_UNIX_LISTENER, fwd, fwd_opts); | 3645 | SSH_CHANNEL_UNIX_LISTENER, fwd, fwd_opts); |
3533 | } else { | 3646 | } else { |
3534 | return channel_setup_fwd_listener_tcpip(SSH_CHANNEL_PORT_LISTENER, | 3647 | return channel_setup_fwd_listener_tcpip(ssh, |
3535 | fwd, NULL, fwd_opts); | 3648 | SSH_CHANNEL_PORT_LISTENER, fwd, NULL, fwd_opts); |
3536 | } | 3649 | } |
3537 | } | 3650 | } |
3538 | 3651 | ||
3539 | /* protocol v2 remote port fwd, used by sshd */ | 3652 | /* protocol v2 remote port fwd, used by sshd */ |
3540 | int | 3653 | int |
3541 | channel_setup_remote_fwd_listener(struct Forward *fwd, | 3654 | channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd, |
3542 | int *allocated_listen_port, struct ForwardOptions *fwd_opts) | 3655 | int *allocated_listen_port, struct ForwardOptions *fwd_opts) |
3543 | { | 3656 | { |
3544 | if (fwd->listen_path != NULL) { | 3657 | if (fwd->listen_path != NULL) { |
3545 | return channel_setup_fwd_listener_streamlocal( | 3658 | return channel_setup_fwd_listener_streamlocal(ssh, |
3546 | SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts); | 3659 | SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts); |
3547 | } else { | 3660 | } else { |
3548 | return channel_setup_fwd_listener_tcpip( | 3661 | return channel_setup_fwd_listener_tcpip(ssh, |
3549 | SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port, | 3662 | SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port, |
3550 | fwd_opts); | 3663 | fwd_opts); |
3551 | } | 3664 | } |
@@ -3579,81 +3692,61 @@ channel_rfwd_bind_host(const char *listen_host) | |||
3579 | * channel_update_permitted_opens(). | 3692 | * channel_update_permitted_opens(). |
3580 | */ | 3693 | */ |
3581 | int | 3694 | int |
3582 | channel_request_remote_forwarding(struct Forward *fwd) | 3695 | channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd) |
3583 | { | 3696 | { |
3584 | int type, success = 0, idx = -1; | 3697 | int r, success = 0, idx = -1; |
3698 | char *host_to_connect, *listen_host, *listen_path; | ||
3699 | int port_to_connect, listen_port; | ||
3585 | 3700 | ||
3586 | /* Send the forward request to the remote side. */ | 3701 | /* Send the forward request to the remote side. */ |
3587 | if (compat20) { | 3702 | if (fwd->listen_path != NULL) { |
3588 | packet_start(SSH2_MSG_GLOBAL_REQUEST); | 3703 | if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
3589 | if (fwd->listen_path != NULL) { | 3704 | (r = sshpkt_put_cstring(ssh, |
3590 | packet_put_cstring("streamlocal-forward@openssh.com"); | 3705 | "streamlocal-forward@openssh.com")) != 0 || |
3591 | packet_put_char(1); /* boolean: want reply */ | 3706 | (r = sshpkt_put_u8(ssh, 1)) != 0 || /* want reply */ |
3592 | packet_put_cstring(fwd->listen_path); | 3707 | (r = sshpkt_put_cstring(ssh, fwd->listen_path)) != 0 || |
3593 | } else { | 3708 | (r = sshpkt_send(ssh)) != 0 || |
3594 | packet_put_cstring("tcpip-forward"); | 3709 | (r = ssh_packet_write_wait(ssh)) != 0) |
3595 | packet_put_char(1); /* boolean: want reply */ | 3710 | fatal("%s: request streamlocal: %s", |
3596 | packet_put_cstring(channel_rfwd_bind_host(fwd->listen_host)); | 3711 | __func__, ssh_err(r)); |
3597 | packet_put_int(fwd->listen_port); | ||
3598 | } | ||
3599 | packet_send(); | ||
3600 | packet_write_wait(); | ||
3601 | /* Assume that server accepts the request */ | ||
3602 | success = 1; | ||
3603 | } else if (fwd->listen_path == NULL) { | ||
3604 | packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); | ||
3605 | packet_put_int(fwd->listen_port); | ||
3606 | packet_put_cstring(fwd->connect_host); | ||
3607 | packet_put_int(fwd->connect_port); | ||
3608 | packet_send(); | ||
3609 | packet_write_wait(); | ||
3610 | |||
3611 | /* Wait for response from the remote side. */ | ||
3612 | type = packet_read(); | ||
3613 | switch (type) { | ||
3614 | case SSH_SMSG_SUCCESS: | ||
3615 | success = 1; | ||
3616 | break; | ||
3617 | case SSH_SMSG_FAILURE: | ||
3618 | break; | ||
3619 | default: | ||
3620 | /* Unknown packet */ | ||
3621 | packet_disconnect("Protocol error for port forward request:" | ||
3622 | "received packet type %d.", type); | ||
3623 | } | ||
3624 | } else { | 3712 | } else { |
3625 | logit("Warning: Server does not support remote stream local forwarding."); | 3713 | if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
3626 | } | 3714 | (r = sshpkt_put_cstring(ssh, "tcpip-forward")) != 0 || |
3715 | (r = sshpkt_put_u8(ssh, 1)) != 0 || /* want reply */ | ||
3716 | (r = sshpkt_put_cstring(ssh, | ||
3717 | channel_rfwd_bind_host(fwd->listen_host))) != 0 || | ||
3718 | (r = sshpkt_put_u32(ssh, fwd->listen_port)) != 0 || | ||
3719 | (r = sshpkt_send(ssh)) != 0 || | ||
3720 | (r = ssh_packet_write_wait(ssh)) != 0) | ||
3721 | fatal("%s: request tcpip-forward: %s", | ||
3722 | __func__, ssh_err(r)); | ||
3723 | } | ||
3724 | /* Assume that server accepts the request */ | ||
3725 | success = 1; | ||
3627 | if (success) { | 3726 | if (success) { |
3628 | /* Record that connection to this host/port is permitted. */ | 3727 | /* Record that connection to this host/port is permitted. */ |
3629 | permitted_opens = xreallocarray(permitted_opens, | 3728 | host_to_connect = listen_host = listen_path = NULL; |
3630 | num_permitted_opens + 1, sizeof(*permitted_opens)); | 3729 | port_to_connect = listen_port = 0; |
3631 | idx = num_permitted_opens++; | ||
3632 | if (fwd->connect_path != NULL) { | 3730 | if (fwd->connect_path != NULL) { |
3633 | permitted_opens[idx].host_to_connect = | 3731 | host_to_connect = xstrdup(fwd->connect_path); |
3634 | xstrdup(fwd->connect_path); | 3732 | port_to_connect = PORT_STREAMLOCAL; |
3635 | permitted_opens[idx].port_to_connect = | ||
3636 | PORT_STREAMLOCAL; | ||
3637 | } else { | 3733 | } else { |
3638 | permitted_opens[idx].host_to_connect = | 3734 | host_to_connect = xstrdup(fwd->connect_host); |
3639 | xstrdup(fwd->connect_host); | 3735 | port_to_connect = fwd->connect_port; |
3640 | permitted_opens[idx].port_to_connect = | ||
3641 | fwd->connect_port; | ||
3642 | } | 3736 | } |
3643 | if (fwd->listen_path != NULL) { | 3737 | if (fwd->listen_path != NULL) { |
3644 | permitted_opens[idx].listen_host = NULL; | 3738 | listen_path = xstrdup(fwd->listen_path); |
3645 | permitted_opens[idx].listen_path = | 3739 | listen_port = PORT_STREAMLOCAL; |
3646 | xstrdup(fwd->listen_path); | ||
3647 | permitted_opens[idx].listen_port = PORT_STREAMLOCAL; | ||
3648 | } else { | 3740 | } else { |
3649 | permitted_opens[idx].listen_host = | 3741 | if (fwd->listen_host != NULL) |
3650 | fwd->listen_host ? xstrdup(fwd->listen_host) : NULL; | 3742 | listen_host = xstrdup(fwd->listen_host); |
3651 | permitted_opens[idx].listen_path = NULL; | 3743 | listen_port = fwd->listen_port; |
3652 | permitted_opens[idx].listen_port = fwd->listen_port; | ||
3653 | } | 3744 | } |
3654 | permitted_opens[idx].downstream = NULL; | 3745 | idx = fwd_perm_list_add(ssh, FWDPERM_USER, |
3746 | host_to_connect, port_to_connect, | ||
3747 | listen_host, listen_path, listen_port, NULL); | ||
3655 | } | 3748 | } |
3656 | return (idx); | 3749 | return idx; |
3657 | } | 3750 | } |
3658 | 3751 | ||
3659 | static int | 3752 | static int |
@@ -3718,36 +3811,33 @@ open_listen_match_streamlocal(ForwardPermission *allowed_open, | |||
3718 | * local side. | 3811 | * local side. |
3719 | */ | 3812 | */ |
3720 | static int | 3813 | static int |
3721 | channel_request_rforward_cancel_tcpip(const char *host, u_short port) | 3814 | channel_request_rforward_cancel_tcpip(struct ssh *ssh, |
3815 | const char *host, u_short port) | ||
3722 | { | 3816 | { |
3723 | int i; | 3817 | struct ssh_channels *sc = ssh->chanctxt; |
3724 | 3818 | int r; | |
3725 | if (!compat20) | 3819 | u_int i; |
3726 | return -1; | 3820 | ForwardPermission *fp; |
3727 | 3821 | ||
3728 | for (i = 0; i < num_permitted_opens; i++) { | 3822 | for (i = 0; i < sc->num_permitted_opens; i++) { |
3729 | if (open_listen_match_tcpip(&permitted_opens[i], host, port, 0)) | 3823 | fp = &sc->permitted_opens[i]; |
3824 | if (open_listen_match_tcpip(fp, host, port, 0)) | ||
3730 | break; | 3825 | break; |
3826 | fp = NULL; | ||
3731 | } | 3827 | } |
3732 | if (i >= num_permitted_opens) { | 3828 | if (fp == NULL) { |
3733 | debug("%s: requested forward not found", __func__); | 3829 | debug("%s: requested forward not found", __func__); |
3734 | return -1; | 3830 | return -1; |
3735 | } | 3831 | } |
3736 | packet_start(SSH2_MSG_GLOBAL_REQUEST); | 3832 | if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
3737 | packet_put_cstring("cancel-tcpip-forward"); | 3833 | (r = sshpkt_put_cstring(ssh, "cancel-tcpip-forward")) != 0 || |
3738 | packet_put_char(0); | 3834 | (r = sshpkt_put_u8(ssh, 0)) != 0 || /* want reply */ |
3739 | packet_put_cstring(channel_rfwd_bind_host(host)); | 3835 | (r = sshpkt_put_cstring(ssh, channel_rfwd_bind_host(host))) != 0 || |
3740 | packet_put_int(port); | 3836 | (r = sshpkt_put_u32(ssh, port)) != 0 || |
3741 | packet_send(); | 3837 | (r = sshpkt_send(ssh)) != 0) |
3742 | 3838 | fatal("%s: send cancel: %s", __func__, ssh_err(r)); | |
3743 | permitted_opens[i].listen_port = 0; | 3839 | |
3744 | permitted_opens[i].port_to_connect = 0; | 3840 | fwd_perm_clear(fp); /* unregister */ |
3745 | free(permitted_opens[i].host_to_connect); | ||
3746 | permitted_opens[i].host_to_connect = NULL; | ||
3747 | free(permitted_opens[i].listen_host); | ||
3748 | permitted_opens[i].listen_host = NULL; | ||
3749 | permitted_opens[i].listen_path = NULL; | ||
3750 | permitted_opens[i].downstream = NULL; | ||
3751 | 3841 | ||
3752 | return 0; | 3842 | return 0; |
3753 | } | 3843 | } |
@@ -3757,35 +3847,32 @@ channel_request_rforward_cancel_tcpip(const char *host, u_short port) | |||
3757 | * path from local side. | 3847 | * path from local side. |
3758 | */ | 3848 | */ |
3759 | static int | 3849 | static int |
3760 | channel_request_rforward_cancel_streamlocal(const char *path) | 3850 | channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path) |
3761 | { | 3851 | { |
3762 | int i; | 3852 | struct ssh_channels *sc = ssh->chanctxt; |
3763 | 3853 | int r; | |
3764 | if (!compat20) | 3854 | u_int i; |
3765 | return -1; | 3855 | ForwardPermission *fp; |
3766 | 3856 | ||
3767 | for (i = 0; i < num_permitted_opens; i++) { | 3857 | for (i = 0; i < sc->num_permitted_opens; i++) { |
3768 | if (open_listen_match_streamlocal(&permitted_opens[i], path)) | 3858 | fp = &sc->permitted_opens[i]; |
3859 | if (open_listen_match_streamlocal(fp, path)) | ||
3769 | break; | 3860 | break; |
3861 | fp = NULL; | ||
3770 | } | 3862 | } |
3771 | if (i >= num_permitted_opens) { | 3863 | if (fp == NULL) { |
3772 | debug("%s: requested forward not found", __func__); | 3864 | debug("%s: requested forward not found", __func__); |
3773 | return -1; | 3865 | return -1; |
3774 | } | 3866 | } |
3775 | packet_start(SSH2_MSG_GLOBAL_REQUEST); | 3867 | if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
3776 | packet_put_cstring("cancel-streamlocal-forward@openssh.com"); | 3868 | (r = sshpkt_put_cstring(ssh, |
3777 | packet_put_char(0); | 3869 | "cancel-streamlocal-forward@openssh.com")) != 0 || |
3778 | packet_put_cstring(path); | 3870 | (r = sshpkt_put_u8(ssh, 0)) != 0 || /* want reply */ |
3779 | packet_send(); | 3871 | (r = sshpkt_put_cstring(ssh, path)) != 0 || |
3780 | 3872 | (r = sshpkt_send(ssh)) != 0) | |
3781 | permitted_opens[i].listen_port = 0; | 3873 | fatal("%s: send cancel: %s", __func__, ssh_err(r)); |
3782 | permitted_opens[i].port_to_connect = 0; | 3874 | |
3783 | free(permitted_opens[i].host_to_connect); | 3875 | fwd_perm_clear(fp); /* unregister */ |
3784 | permitted_opens[i].host_to_connect = NULL; | ||
3785 | permitted_opens[i].listen_host = NULL; | ||
3786 | free(permitted_opens[i].listen_path); | ||
3787 | permitted_opens[i].listen_path = NULL; | ||
3788 | permitted_opens[i].downstream = NULL; | ||
3789 | 3876 | ||
3790 | return 0; | 3877 | return 0; |
3791 | } | 3878 | } |
@@ -3794,14 +3881,15 @@ channel_request_rforward_cancel_streamlocal(const char *path) | |||
3794 | * Request cancellation of remote forwarding of a connection from local side. | 3881 | * Request cancellation of remote forwarding of a connection from local side. |
3795 | */ | 3882 | */ |
3796 | int | 3883 | int |
3797 | channel_request_rforward_cancel(struct Forward *fwd) | 3884 | channel_request_rforward_cancel(struct ssh *ssh, struct Forward *fwd) |
3798 | { | 3885 | { |
3799 | if (fwd->listen_path != NULL) { | 3886 | if (fwd->listen_path != NULL) { |
3800 | return (channel_request_rforward_cancel_streamlocal( | 3887 | return channel_request_rforward_cancel_streamlocal(ssh, |
3801 | fwd->listen_path)); | 3888 | fwd->listen_path); |
3802 | } else { | 3889 | } else { |
3803 | return (channel_request_rforward_cancel_tcpip(fwd->listen_host, | 3890 | return channel_request_rforward_cancel_tcpip(ssh, |
3804 | fwd->listen_port ? fwd->listen_port : fwd->allocated_port)); | 3891 | fwd->listen_host, |
3892 | fwd->listen_port ? fwd->listen_port : fwd->allocated_port); | ||
3805 | } | 3893 | } |
3806 | } | 3894 | } |
3807 | 3895 | ||
@@ -3811,28 +3899,20 @@ channel_request_rforward_cancel(struct Forward *fwd) | |||
3811 | * anyway, and the server has no way to know but to trust the client anyway. | 3899 | * anyway, and the server has no way to know but to trust the client anyway. |
3812 | */ | 3900 | */ |
3813 | void | 3901 | void |
3814 | channel_permit_all_opens(void) | 3902 | channel_permit_all_opens(struct ssh *ssh) |
3815 | { | 3903 | { |
3816 | if (num_permitted_opens == 0) | 3904 | if (ssh->chanctxt->num_permitted_opens == 0) |
3817 | all_opens_permitted = 1; | 3905 | ssh->chanctxt->all_opens_permitted = 1; |
3818 | } | 3906 | } |
3819 | 3907 | ||
3820 | void | 3908 | void |
3821 | channel_add_permitted_opens(char *host, int port) | 3909 | channel_add_permitted_opens(struct ssh *ssh, char *host, int port) |
3822 | { | 3910 | { |
3823 | debug("allow port forwarding to host %s port %d", host, port); | 3911 | struct ssh_channels *sc = ssh->chanctxt; |
3824 | 3912 | ||
3825 | permitted_opens = xreallocarray(permitted_opens, | 3913 | debug("allow port forwarding to host %s port %d", host, port); |
3826 | num_permitted_opens + 1, sizeof(*permitted_opens)); | 3914 | fwd_perm_list_add(ssh, FWDPERM_USER, host, port, NULL, NULL, 0, NULL); |
3827 | permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); | 3915 | sc->all_opens_permitted = 0; |
3828 | permitted_opens[num_permitted_opens].port_to_connect = port; | ||
3829 | permitted_opens[num_permitted_opens].listen_host = NULL; | ||
3830 | permitted_opens[num_permitted_opens].listen_path = NULL; | ||
3831 | permitted_opens[num_permitted_opens].listen_port = 0; | ||
3832 | permitted_opens[num_permitted_opens].downstream = NULL; | ||
3833 | num_permitted_opens++; | ||
3834 | |||
3835 | all_opens_permitted = 0; | ||
3836 | } | 3916 | } |
3837 | 3917 | ||
3838 | /* | 3918 | /* |
@@ -3841,105 +3921,61 @@ channel_add_permitted_opens(char *host, int port) | |||
3841 | * passed then they entry will be invalidated. | 3921 | * passed then they entry will be invalidated. |
3842 | */ | 3922 | */ |
3843 | void | 3923 | void |
3844 | channel_update_permitted_opens(int idx, int newport) | 3924 | channel_update_permitted_opens(struct ssh *ssh, int idx, int newport) |
3845 | { | 3925 | { |
3846 | if (idx < 0 || idx >= num_permitted_opens) { | 3926 | struct ssh_channels *sc = ssh->chanctxt; |
3847 | debug("channel_update_permitted_opens: index out of range:" | 3927 | |
3848 | " %d num_permitted_opens %d", idx, num_permitted_opens); | 3928 | if (idx < 0 || (u_int)idx >= sc->num_permitted_opens) { |
3929 | debug("%s: index out of range: %d num_permitted_opens %d", | ||
3930 | __func__, idx, sc->num_permitted_opens); | ||
3849 | return; | 3931 | return; |
3850 | } | 3932 | } |
3851 | debug("%s allowed port %d for forwarding to host %s port %d", | 3933 | debug("%s allowed port %d for forwarding to host %s port %d", |
3852 | newport > 0 ? "Updating" : "Removing", | 3934 | newport > 0 ? "Updating" : "Removing", |
3853 | newport, | 3935 | newport, |
3854 | permitted_opens[idx].host_to_connect, | 3936 | sc->permitted_opens[idx].host_to_connect, |
3855 | permitted_opens[idx].port_to_connect); | 3937 | sc->permitted_opens[idx].port_to_connect); |
3856 | if (newport >= 0) { | 3938 | if (newport <= 0) |
3857 | permitted_opens[idx].listen_port = | 3939 | fwd_perm_clear(&sc->permitted_opens[idx]); |
3940 | else { | ||
3941 | sc->permitted_opens[idx].listen_port = | ||
3858 | (datafellows & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport; | 3942 | (datafellows & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport; |
3859 | } else { | ||
3860 | permitted_opens[idx].listen_port = 0; | ||
3861 | permitted_opens[idx].port_to_connect = 0; | ||
3862 | free(permitted_opens[idx].host_to_connect); | ||
3863 | permitted_opens[idx].host_to_connect = NULL; | ||
3864 | free(permitted_opens[idx].listen_host); | ||
3865 | permitted_opens[idx].listen_host = NULL; | ||
3866 | free(permitted_opens[idx].listen_path); | ||
3867 | permitted_opens[idx].listen_path = NULL; | ||
3868 | } | 3943 | } |
3869 | } | 3944 | } |
3870 | 3945 | ||
3871 | int | 3946 | int |
3872 | channel_add_adm_permitted_opens(char *host, int port) | 3947 | channel_add_adm_permitted_opens(struct ssh *ssh, char *host, int port) |
3873 | { | 3948 | { |
3874 | debug("config allows port forwarding to host %s port %d", host, port); | 3949 | debug("config allows port forwarding to host %s port %d", host, port); |
3875 | 3950 | return fwd_perm_list_add(ssh, FWDPERM_ADMIN, host, port, | |
3876 | permitted_adm_opens = xreallocarray(permitted_adm_opens, | 3951 | NULL, NULL, 0, NULL); |
3877 | num_adm_permitted_opens + 1, sizeof(*permitted_adm_opens)); | ||
3878 | permitted_adm_opens[num_adm_permitted_opens].host_to_connect | ||
3879 | = xstrdup(host); | ||
3880 | permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; | ||
3881 | permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL; | ||
3882 | permitted_adm_opens[num_adm_permitted_opens].listen_path = NULL; | ||
3883 | permitted_adm_opens[num_adm_permitted_opens].listen_port = 0; | ||
3884 | return ++num_adm_permitted_opens; | ||
3885 | } | 3952 | } |
3886 | 3953 | ||
3887 | void | 3954 | void |
3888 | channel_disable_adm_local_opens(void) | 3955 | channel_disable_adm_local_opens(struct ssh *ssh) |
3889 | { | 3956 | { |
3890 | channel_clear_adm_permitted_opens(); | 3957 | channel_clear_adm_permitted_opens(ssh); |
3891 | permitted_adm_opens = xcalloc(sizeof(*permitted_adm_opens), 1); | 3958 | fwd_perm_list_add(ssh, FWDPERM_ADMIN, NULL, 0, NULL, NULL, 0, NULL); |
3892 | permitted_adm_opens[num_adm_permitted_opens].host_to_connect = NULL; | ||
3893 | num_adm_permitted_opens = 1; | ||
3894 | } | 3959 | } |
3895 | 3960 | ||
3896 | void | 3961 | void |
3897 | channel_clear_permitted_opens(void) | 3962 | channel_clear_permitted_opens(struct ssh *ssh) |
3898 | { | 3963 | { |
3899 | int i; | 3964 | struct ssh_channels *sc = ssh->chanctxt; |
3900 | 3965 | ||
3901 | for (i = 0; i < num_permitted_opens; i++) { | 3966 | sc->permitted_opens = xrecallocarray(sc->permitted_opens, |
3902 | free(permitted_opens[i].host_to_connect); | 3967 | sc->num_permitted_opens, 0, sizeof(*sc->permitted_opens)); |
3903 | free(permitted_opens[i].listen_host); | 3968 | sc->num_permitted_opens = 0; |
3904 | free(permitted_opens[i].listen_path); | ||
3905 | } | ||
3906 | free(permitted_opens); | ||
3907 | permitted_opens = NULL; | ||
3908 | num_permitted_opens = 0; | ||
3909 | } | 3969 | } |
3910 | 3970 | ||
3911 | void | 3971 | void |
3912 | channel_clear_adm_permitted_opens(void) | 3972 | channel_clear_adm_permitted_opens(struct ssh *ssh) |
3913 | { | 3973 | { |
3914 | int i; | 3974 | struct ssh_channels *sc = ssh->chanctxt; |
3915 | 3975 | ||
3916 | for (i = 0; i < num_adm_permitted_opens; i++) { | 3976 | sc->permitted_adm_opens = xrecallocarray(sc->permitted_adm_opens, |
3917 | free(permitted_adm_opens[i].host_to_connect); | 3977 | sc->num_adm_permitted_opens, 0, sizeof(*sc->permitted_adm_opens)); |
3918 | free(permitted_adm_opens[i].listen_host); | 3978 | sc->num_adm_permitted_opens = 0; |
3919 | free(permitted_adm_opens[i].listen_path); | ||
3920 | } | ||
3921 | free(permitted_adm_opens); | ||
3922 | permitted_adm_opens = NULL; | ||
3923 | num_adm_permitted_opens = 0; | ||
3924 | } | ||
3925 | |||
3926 | void | ||
3927 | channel_print_adm_permitted_opens(void) | ||
3928 | { | ||
3929 | int i; | ||
3930 | |||
3931 | printf("permitopen"); | ||
3932 | if (num_adm_permitted_opens == 0) { | ||
3933 | printf(" any\n"); | ||
3934 | return; | ||
3935 | } | ||
3936 | for (i = 0; i < num_adm_permitted_opens; i++) | ||
3937 | if (permitted_adm_opens[i].host_to_connect == NULL) | ||
3938 | printf(" none"); | ||
3939 | else | ||
3940 | printf(" %s:%d", permitted_adm_opens[i].host_to_connect, | ||
3941 | permitted_adm_opens[i].port_to_connect); | ||
3942 | printf("\n"); | ||
3943 | } | 3979 | } |
3944 | 3980 | ||
3945 | /* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */ | 3981 | /* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */ |
@@ -3961,7 +3997,8 @@ connect_next(struct channel_connect *cctx) | |||
3961 | { | 3997 | { |
3962 | int sock, saved_errno; | 3998 | int sock, saved_errno; |
3963 | struct sockaddr_un *sunaddr; | 3999 | struct sockaddr_un *sunaddr; |
3964 | char ntop[NI_MAXHOST], strport[MAXIMUM(NI_MAXSERV,sizeof(sunaddr->sun_path))]; | 4000 | char ntop[NI_MAXHOST]; |
4001 | char strport[MAXIMUM(NI_MAXSERV, sizeof(sunaddr->sun_path))]; | ||
3965 | 4002 | ||
3966 | for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { | 4003 | for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { |
3967 | switch (cctx->ai->ai_family) { | 4004 | switch (cctx->ai->ai_family) { |
@@ -4027,21 +4064,18 @@ channel_connect_ctx_free(struct channel_connect *cctx) | |||
4027 | } | 4064 | } |
4028 | 4065 | ||
4029 | /* | 4066 | /* |
4030 | * Return CONNECTING channel to remote host:port or local socket path, | 4067 | * Return connecting socket to remote host:port or local socket path, |
4031 | * passing back the failure reason if appropriate. | 4068 | * passing back the failure reason if appropriate. |
4032 | */ | 4069 | */ |
4033 | static Channel * | 4070 | static int |
4034 | connect_to_reason(const char *name, int port, char *ctype, char *rname, | 4071 | connect_to_helper(struct ssh *ssh, const char *name, int port, int socktype, |
4035 | int *reason, const char **errmsg) | 4072 | char *ctype, char *rname, struct channel_connect *cctx, |
4073 | int *reason, const char **errmsg) | ||
4036 | { | 4074 | { |
4037 | struct addrinfo hints; | 4075 | struct addrinfo hints; |
4038 | int gaierr; | 4076 | int gaierr; |
4039 | int sock = -1; | 4077 | int sock = -1; |
4040 | char strport[NI_MAXSERV]; | 4078 | char strport[NI_MAXSERV]; |
4041 | struct channel_connect cctx; | ||
4042 | Channel *c; | ||
4043 | |||
4044 | memset(&cctx, 0, sizeof(cctx)); | ||
4045 | 4079 | ||
4046 | if (port == PORT_STREAMLOCAL) { | 4080 | if (port == PORT_STREAMLOCAL) { |
4047 | struct sockaddr_un *sunaddr; | 4081 | struct sockaddr_un *sunaddr; |
@@ -4049,7 +4083,7 @@ connect_to_reason(const char *name, int port, char *ctype, char *rname, | |||
4049 | 4083 | ||
4050 | if (strlen(name) > sizeof(sunaddr->sun_path)) { | 4084 | if (strlen(name) > sizeof(sunaddr->sun_path)) { |
4051 | error("%.100s: %.100s", name, strerror(ENAMETOOLONG)); | 4085 | error("%.100s: %.100s", name, strerror(ENAMETOOLONG)); |
4052 | return (NULL); | 4086 | return -1; |
4053 | } | 4087 | } |
4054 | 4088 | ||
4055 | /* | 4089 | /* |
@@ -4062,18 +4096,18 @@ connect_to_reason(const char *name, int port, char *ctype, char *rname, | |||
4062 | ai->ai_addr = (struct sockaddr *)(ai + 1); | 4096 | ai->ai_addr = (struct sockaddr *)(ai + 1); |
4063 | ai->ai_addrlen = sizeof(*sunaddr); | 4097 | ai->ai_addrlen = sizeof(*sunaddr); |
4064 | ai->ai_family = AF_UNIX; | 4098 | ai->ai_family = AF_UNIX; |
4065 | ai->ai_socktype = SOCK_STREAM; | 4099 | ai->ai_socktype = socktype; |
4066 | ai->ai_protocol = PF_UNSPEC; | 4100 | ai->ai_protocol = PF_UNSPEC; |
4067 | sunaddr = (struct sockaddr_un *)ai->ai_addr; | 4101 | sunaddr = (struct sockaddr_un *)ai->ai_addr; |
4068 | sunaddr->sun_family = AF_UNIX; | 4102 | sunaddr->sun_family = AF_UNIX; |
4069 | strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path)); | 4103 | strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path)); |
4070 | cctx.aitop = ai; | 4104 | cctx->aitop = ai; |
4071 | } else { | 4105 | } else { |
4072 | memset(&hints, 0, sizeof(hints)); | 4106 | memset(&hints, 0, sizeof(hints)); |
4073 | hints.ai_family = IPv4or6; | 4107 | hints.ai_family = ssh->chanctxt->IPv4or6; |
4074 | hints.ai_socktype = SOCK_STREAM; | 4108 | hints.ai_socktype = socktype; |
4075 | snprintf(strport, sizeof strport, "%d", port); | 4109 | snprintf(strport, sizeof strport, "%d", port); |
4076 | if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop)) | 4110 | if ((gaierr = getaddrinfo(name, strport, &hints, &cctx->aitop)) |
4077 | != 0) { | 4111 | != 0) { |
4078 | if (errmsg != NULL) | 4112 | if (errmsg != NULL) |
4079 | *errmsg = ssh_gai_strerror(gaierr); | 4113 | *errmsg = ssh_gai_strerror(gaierr); |
@@ -4081,31 +4115,46 @@ connect_to_reason(const char *name, int port, char *ctype, char *rname, | |||
4081 | *reason = SSH2_OPEN_CONNECT_FAILED; | 4115 | *reason = SSH2_OPEN_CONNECT_FAILED; |
4082 | error("connect_to %.100s: unknown host (%s)", name, | 4116 | error("connect_to %.100s: unknown host (%s)", name, |
4083 | ssh_gai_strerror(gaierr)); | 4117 | ssh_gai_strerror(gaierr)); |
4084 | return NULL; | 4118 | return -1; |
4085 | } | 4119 | } |
4086 | } | 4120 | } |
4087 | 4121 | ||
4088 | cctx.host = xstrdup(name); | 4122 | cctx->host = xstrdup(name); |
4089 | cctx.port = port; | 4123 | cctx->port = port; |
4090 | cctx.ai = cctx.aitop; | 4124 | cctx->ai = cctx->aitop; |
4091 | 4125 | ||
4092 | if ((sock = connect_next(&cctx)) == -1) { | 4126 | if ((sock = connect_next(cctx)) == -1) { |
4093 | error("connect to %.100s port %d failed: %s", | 4127 | error("connect to %.100s port %d failed: %s", |
4094 | name, port, strerror(errno)); | 4128 | name, port, strerror(errno)); |
4095 | channel_connect_ctx_free(&cctx); | 4129 | return -1; |
4096 | return NULL; | ||
4097 | } | 4130 | } |
4098 | c = channel_new(ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1, | 4131 | |
4099 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); | 4132 | return sock; |
4100 | c->connect_ctx = cctx; | ||
4101 | return c; | ||
4102 | } | 4133 | } |
4103 | 4134 | ||
4104 | /* Return CONNECTING channel to remote host:port or local socket path */ | 4135 | /* Return CONNECTING channel to remote host:port or local socket path */ |
4105 | static Channel * | 4136 | static Channel * |
4106 | connect_to(const char *name, int port, char *ctype, char *rname) | 4137 | connect_to(struct ssh *ssh, const char *host, int port, |
4138 | char *ctype, char *rname) | ||
4107 | { | 4139 | { |
4108 | return connect_to_reason(name, port, ctype, rname, NULL, NULL); | 4140 | struct channel_connect cctx; |
4141 | Channel *c; | ||
4142 | int sock; | ||
4143 | |||
4144 | memset(&cctx, 0, sizeof(cctx)); | ||
4145 | sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname, | ||
4146 | &cctx, NULL, NULL); | ||
4147 | if (sock == -1) { | ||
4148 | channel_connect_ctx_free(&cctx); | ||
4149 | return NULL; | ||
4150 | } | ||
4151 | c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1, | ||
4152 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); | ||
4153 | c->host_port = port; | ||
4154 | c->path = xstrdup(host); | ||
4155 | c->connect_ctx = cctx; | ||
4156 | |||
4157 | return c; | ||
4109 | } | 4158 | } |
4110 | 4159 | ||
4111 | /* | 4160 | /* |
@@ -4113,19 +4162,24 @@ connect_to(const char *name, int port, char *ctype, char *rname) | |||
4113 | * that needs to deal with this connection. | 4162 | * that needs to deal with this connection. |
4114 | */ | 4163 | */ |
4115 | Channel * | 4164 | Channel * |
4116 | channel_connect_by_listen_address(const char *listen_host, | 4165 | channel_connect_by_listen_address(struct ssh *ssh, const char *listen_host, |
4117 | u_short listen_port, char *ctype, char *rname) | 4166 | u_short listen_port, char *ctype, char *rname) |
4118 | { | 4167 | { |
4119 | int i; | 4168 | struct ssh_channels *sc = ssh->chanctxt; |
4120 | 4169 | u_int i; | |
4121 | for (i = 0; i < num_permitted_opens; i++) { | 4170 | ForwardPermission *fp; |
4122 | if (open_listen_match_tcpip(&permitted_opens[i], listen_host, | 4171 | |
4123 | listen_port, 1)) { | 4172 | for (i = 0; i < sc->num_permitted_opens; i++) { |
4124 | if (permitted_opens[i].downstream) | 4173 | fp = &sc->permitted_opens[i]; |
4125 | return permitted_opens[i].downstream; | 4174 | if (open_listen_match_tcpip(fp, listen_host, listen_port, 1)) { |
4126 | return connect_to( | 4175 | if (fp->downstream) |
4127 | permitted_opens[i].host_to_connect, | 4176 | return fp->downstream; |
4128 | permitted_opens[i].port_to_connect, ctype, rname); | 4177 | if (fp->port_to_connect == 0) |
4178 | return rdynamic_connect_prepare(ssh, | ||
4179 | ctype, rname); | ||
4180 | return connect_to(ssh, | ||
4181 | fp->host_to_connect, fp->port_to_connect, | ||
4182 | ctype, rname); | ||
4129 | } | 4183 | } |
4130 | } | 4184 | } |
4131 | error("WARNING: Server requests forwarding for unknown listen_port %d", | 4185 | error("WARNING: Server requests forwarding for unknown listen_port %d", |
@@ -4134,15 +4188,19 @@ channel_connect_by_listen_address(const char *listen_host, | |||
4134 | } | 4188 | } |
4135 | 4189 | ||
4136 | Channel * | 4190 | Channel * |
4137 | channel_connect_by_listen_path(const char *path, char *ctype, char *rname) | 4191 | channel_connect_by_listen_path(struct ssh *ssh, const char *path, |
4192 | char *ctype, char *rname) | ||
4138 | { | 4193 | { |
4139 | int i; | 4194 | struct ssh_channels *sc = ssh->chanctxt; |
4140 | 4195 | u_int i; | |
4141 | for (i = 0; i < num_permitted_opens; i++) { | 4196 | ForwardPermission *fp; |
4142 | if (open_listen_match_streamlocal(&permitted_opens[i], path)) { | 4197 | |
4143 | return connect_to( | 4198 | for (i = 0; i < sc->num_permitted_opens; i++) { |
4144 | permitted_opens[i].host_to_connect, | 4199 | fp = &sc->permitted_opens[i]; |
4145 | permitted_opens[i].port_to_connect, ctype, rname); | 4200 | if (open_listen_match_streamlocal(fp, path)) { |
4201 | return connect_to(ssh, | ||
4202 | fp->host_to_connect, fp->port_to_connect, | ||
4203 | ctype, rname); | ||
4146 | } | 4204 | } |
4147 | } | 4205 | } |
4148 | error("WARNING: Server requests forwarding for unknown path %.100s", | 4206 | error("WARNING: Server requests forwarding for unknown path %.100s", |
@@ -4152,27 +4210,36 @@ channel_connect_by_listen_path(const char *path, char *ctype, char *rname) | |||
4152 | 4210 | ||
4153 | /* Check if connecting to that port is permitted and connect. */ | 4211 | /* Check if connecting to that port is permitted and connect. */ |
4154 | Channel * | 4212 | Channel * |
4155 | channel_connect_to_port(const char *host, u_short port, char *ctype, | 4213 | channel_connect_to_port(struct ssh *ssh, const char *host, u_short port, |
4156 | char *rname, int *reason, const char **errmsg) | 4214 | char *ctype, char *rname, int *reason, const char **errmsg) |
4157 | { | 4215 | { |
4158 | int i, permit, permit_adm = 1; | 4216 | struct ssh_channels *sc = ssh->chanctxt; |
4217 | struct channel_connect cctx; | ||
4218 | Channel *c; | ||
4219 | u_int i, permit, permit_adm = 1; | ||
4220 | int sock; | ||
4221 | ForwardPermission *fp; | ||
4159 | 4222 | ||
4160 | permit = all_opens_permitted; | 4223 | permit = sc->all_opens_permitted; |
4161 | if (!permit) { | 4224 | if (!permit) { |
4162 | for (i = 0; i < num_permitted_opens; i++) | 4225 | for (i = 0; i < sc->num_permitted_opens; i++) { |
4163 | if (open_match(&permitted_opens[i], host, port)) { | 4226 | fp = &sc->permitted_opens[i]; |
4227 | if (open_match(fp, host, port)) { | ||
4164 | permit = 1; | 4228 | permit = 1; |
4165 | break; | 4229 | break; |
4166 | } | 4230 | } |
4231 | } | ||
4167 | } | 4232 | } |
4168 | 4233 | ||
4169 | if (num_adm_permitted_opens > 0) { | 4234 | if (sc->num_adm_permitted_opens > 0) { |
4170 | permit_adm = 0; | 4235 | permit_adm = 0; |
4171 | for (i = 0; i < num_adm_permitted_opens; i++) | 4236 | for (i = 0; i < sc->num_adm_permitted_opens; i++) { |
4172 | if (open_match(&permitted_adm_opens[i], host, port)) { | 4237 | fp = &sc->permitted_adm_opens[i]; |
4238 | if (open_match(fp, host, port)) { | ||
4173 | permit_adm = 1; | 4239 | permit_adm = 1; |
4174 | break; | 4240 | break; |
4175 | } | 4241 | } |
4242 | } | ||
4176 | } | 4243 | } |
4177 | 4244 | ||
4178 | if (!permit || !permit_adm) { | 4245 | if (!permit || !permit_adm) { |
@@ -4182,31 +4249,53 @@ channel_connect_to_port(const char *host, u_short port, char *ctype, | |||
4182 | *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED; | 4249 | *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED; |
4183 | return NULL; | 4250 | return NULL; |
4184 | } | 4251 | } |
4185 | return connect_to_reason(host, port, ctype, rname, reason, errmsg); | 4252 | |
4253 | memset(&cctx, 0, sizeof(cctx)); | ||
4254 | sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname, | ||
4255 | &cctx, reason, errmsg); | ||
4256 | if (sock == -1) { | ||
4257 | channel_connect_ctx_free(&cctx); | ||
4258 | return NULL; | ||
4259 | } | ||
4260 | |||
4261 | c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1, | ||
4262 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); | ||
4263 | c->host_port = port; | ||
4264 | c->path = xstrdup(host); | ||
4265 | c->connect_ctx = cctx; | ||
4266 | |||
4267 | return c; | ||
4186 | } | 4268 | } |
4187 | 4269 | ||
4188 | /* Check if connecting to that path is permitted and connect. */ | 4270 | /* Check if connecting to that path is permitted and connect. */ |
4189 | Channel * | 4271 | Channel * |
4190 | channel_connect_to_path(const char *path, char *ctype, char *rname) | 4272 | channel_connect_to_path(struct ssh *ssh, const char *path, |
4273 | char *ctype, char *rname) | ||
4191 | { | 4274 | { |
4192 | int i, permit, permit_adm = 1; | 4275 | struct ssh_channels *sc = ssh->chanctxt; |
4276 | u_int i, permit, permit_adm = 1; | ||
4277 | ForwardPermission *fp; | ||
4193 | 4278 | ||
4194 | permit = all_opens_permitted; | 4279 | permit = sc->all_opens_permitted; |
4195 | if (!permit) { | 4280 | if (!permit) { |
4196 | for (i = 0; i < num_permitted_opens; i++) | 4281 | for (i = 0; i < sc->num_permitted_opens; i++) { |
4197 | if (open_match(&permitted_opens[i], path, PORT_STREAMLOCAL)) { | 4282 | fp = &sc->permitted_opens[i]; |
4283 | if (open_match(fp, path, PORT_STREAMLOCAL)) { | ||
4198 | permit = 1; | 4284 | permit = 1; |
4199 | break; | 4285 | break; |
4200 | } | 4286 | } |
4287 | } | ||
4201 | } | 4288 | } |
4202 | 4289 | ||
4203 | if (num_adm_permitted_opens > 0) { | 4290 | if (sc->num_adm_permitted_opens > 0) { |
4204 | permit_adm = 0; | 4291 | permit_adm = 0; |
4205 | for (i = 0; i < num_adm_permitted_opens; i++) | 4292 | for (i = 0; i < sc->num_adm_permitted_opens; i++) { |
4206 | if (open_match(&permitted_adm_opens[i], path, PORT_STREAMLOCAL)) { | 4293 | fp = &sc->permitted_adm_opens[i]; |
4294 | if (open_match(fp, path, PORT_STREAMLOCAL)) { | ||
4207 | permit_adm = 1; | 4295 | permit_adm = 1; |
4208 | break; | 4296 | break; |
4209 | } | 4297 | } |
4298 | } | ||
4210 | } | 4299 | } |
4211 | 4300 | ||
4212 | if (!permit || !permit_adm) { | 4301 | if (!permit || !permit_adm) { |
@@ -4214,30 +4303,82 @@ channel_connect_to_path(const char *path, char *ctype, char *rname) | |||
4214 | "but the request was denied.", path); | 4303 | "but the request was denied.", path); |
4215 | return NULL; | 4304 | return NULL; |
4216 | } | 4305 | } |
4217 | return connect_to(path, PORT_STREAMLOCAL, ctype, rname); | 4306 | return connect_to(ssh, path, PORT_STREAMLOCAL, ctype, rname); |
4218 | } | 4307 | } |
4219 | 4308 | ||
4220 | void | 4309 | void |
4221 | channel_send_window_changes(void) | 4310 | channel_send_window_changes(struct ssh *ssh) |
4222 | { | 4311 | { |
4223 | u_int i; | 4312 | struct ssh_channels *sc = ssh->chanctxt; |
4224 | struct winsize ws; | 4313 | struct winsize ws; |
4314 | int r; | ||
4315 | u_int i; | ||
4225 | 4316 | ||
4226 | for (i = 0; i < channels_alloc; i++) { | 4317 | for (i = 0; i < sc->channels_alloc; i++) { |
4227 | if (channels[i] == NULL || !channels[i]->client_tty || | 4318 | if (sc->channels[i] == NULL || !sc->channels[i]->client_tty || |
4228 | channels[i]->type != SSH_CHANNEL_OPEN) | 4319 | sc->channels[i]->type != SSH_CHANNEL_OPEN) |
4229 | continue; | 4320 | continue; |
4230 | if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0) | 4321 | if (ioctl(sc->channels[i]->rfd, TIOCGWINSZ, &ws) < 0) |
4231 | continue; | 4322 | continue; |
4232 | channel_request_start(i, "window-change", 0); | 4323 | channel_request_start(ssh, i, "window-change", 0); |
4233 | packet_put_int((u_int)ws.ws_col); | 4324 | if ((r = sshpkt_put_u32(ssh, (u_int)ws.ws_col)) != 0 || |
4234 | packet_put_int((u_int)ws.ws_row); | 4325 | (r = sshpkt_put_u32(ssh, (u_int)ws.ws_row)) != 0 || |
4235 | packet_put_int((u_int)ws.ws_xpixel); | 4326 | (r = sshpkt_put_u32(ssh, (u_int)ws.ws_xpixel)) != 0 || |
4236 | packet_put_int((u_int)ws.ws_ypixel); | 4327 | (r = sshpkt_put_u32(ssh, (u_int)ws.ws_ypixel)) != 0 || |
4237 | packet_send(); | 4328 | (r = sshpkt_send(ssh)) != 0) |
4329 | fatal("%s: channel %u: send window-change: %s", | ||
4330 | __func__, i, ssh_err(r)); | ||
4238 | } | 4331 | } |
4239 | } | 4332 | } |
4240 | 4333 | ||
4334 | /* Return RDYNAMIC_OPEN channel: channel allows SOCKS, but is not connected */ | ||
4335 | static Channel * | ||
4336 | rdynamic_connect_prepare(struct ssh *ssh, char *ctype, char *rname) | ||
4337 | { | ||
4338 | Channel *c; | ||
4339 | int r; | ||
4340 | |||
4341 | c = channel_new(ssh, ctype, SSH_CHANNEL_RDYNAMIC_OPEN, -1, -1, -1, | ||
4342 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); | ||
4343 | c->host_port = 0; | ||
4344 | c->path = NULL; | ||
4345 | |||
4346 | /* | ||
4347 | * We need to open the channel before we have a FD, | ||
4348 | * so that we can get SOCKS header from peer. | ||
4349 | */ | ||
4350 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 || | ||
4351 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | ||
4352 | (r = sshpkt_put_u32(ssh, c->self)) != 0 || | ||
4353 | (r = sshpkt_put_u32(ssh, c->local_window)) != 0 || | ||
4354 | (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) { | ||
4355 | fatal("%s: channel %i: confirm: %s", __func__, | ||
4356 | c->self, ssh_err(r)); | ||
4357 | } | ||
4358 | return c; | ||
4359 | } | ||
4360 | |||
4361 | /* Return CONNECTING socket to remote host:port or local socket path */ | ||
4362 | static int | ||
4363 | rdynamic_connect_finish(struct ssh *ssh, Channel *c) | ||
4364 | { | ||
4365 | struct channel_connect cctx; | ||
4366 | int sock; | ||
4367 | |||
4368 | memset(&cctx, 0, sizeof(cctx)); | ||
4369 | sock = connect_to_helper(ssh, c->path, c->host_port, SOCK_STREAM, NULL, | ||
4370 | NULL, &cctx, NULL, NULL); | ||
4371 | if (sock == -1) | ||
4372 | channel_connect_ctx_free(&cctx); | ||
4373 | else { | ||
4374 | /* similar to SSH_CHANNEL_CONNECTING but we've already sent the open */ | ||
4375 | c->type = SSH_CHANNEL_RDYNAMIC_FINISH; | ||
4376 | c->connect_ctx = cctx; | ||
4377 | channel_register_fds(ssh, c, sock, sock, -1, 0, 1, 0); | ||
4378 | } | ||
4379 | return sock; | ||
4380 | } | ||
4381 | |||
4241 | /* -- X11 forwarding */ | 4382 | /* -- X11 forwarding */ |
4242 | 4383 | ||
4243 | /* | 4384 | /* |
@@ -4246,8 +4387,9 @@ channel_send_window_changes(void) | |||
4246 | * stored in display_numberp , or -1 if an error occurs. | 4387 | * stored in display_numberp , or -1 if an error occurs. |
4247 | */ | 4388 | */ |
4248 | int | 4389 | int |
4249 | x11_create_display_inet(int x11_display_offset, int x11_use_localhost, | 4390 | x11_create_display_inet(struct ssh *ssh, int x11_display_offset, |
4250 | int single_connection, u_int *display_numberp, int **chanids) | 4391 | int x11_use_localhost, int single_connection, |
4392 | u_int *display_numberp, int **chanids) | ||
4251 | { | 4393 | { |
4252 | Channel *nc = NULL; | 4394 | Channel *nc = NULL; |
4253 | int display_number, sock; | 4395 | int display_number, sock; |
@@ -4264,16 +4406,18 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, | |||
4264 | display_number++) { | 4406 | display_number++) { |
4265 | port = 6000 + display_number; | 4407 | port = 6000 + display_number; |
4266 | memset(&hints, 0, sizeof(hints)); | 4408 | memset(&hints, 0, sizeof(hints)); |
4267 | hints.ai_family = IPv4or6; | 4409 | hints.ai_family = ssh->chanctxt->IPv4or6; |
4268 | hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE; | 4410 | hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE; |
4269 | hints.ai_socktype = SOCK_STREAM; | 4411 | hints.ai_socktype = SOCK_STREAM; |
4270 | snprintf(strport, sizeof strport, "%d", port); | 4412 | snprintf(strport, sizeof strport, "%d", port); |
4271 | if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) { | 4413 | if ((gaierr = getaddrinfo(NULL, strport, |
4414 | &hints, &aitop)) != 0) { | ||
4272 | error("getaddrinfo: %.100s", ssh_gai_strerror(gaierr)); | 4415 | error("getaddrinfo: %.100s", ssh_gai_strerror(gaierr)); |
4273 | return -1; | 4416 | return -1; |
4274 | } | 4417 | } |
4275 | for (ai = aitop; ai; ai = ai->ai_next) { | 4418 | for (ai = aitop; ai; ai = ai->ai_next) { |
4276 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) | 4419 | if (ai->ai_family != AF_INET && |
4420 | ai->ai_family != AF_INET6) | ||
4277 | continue; | 4421 | continue; |
4278 | sock = socket(ai->ai_family, ai->ai_socktype, | 4422 | sock = socket(ai->ai_family, ai->ai_socktype, |
4279 | ai->ai_protocol); | 4423 | ai->ai_protocol); |
@@ -4297,12 +4441,11 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, | |||
4297 | if (x11_use_localhost) | 4441 | if (x11_use_localhost) |
4298 | channel_set_reuseaddr(sock); | 4442 | channel_set_reuseaddr(sock); |
4299 | if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { | 4443 | if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
4300 | debug2("bind port %d: %.100s", port, strerror(errno)); | 4444 | debug2("%s: bind port %d: %.100s", __func__, |
4445 | port, strerror(errno)); | ||
4301 | close(sock); | 4446 | close(sock); |
4302 | 4447 | for (n = 0; n < num_socks; n++) | |
4303 | for (n = 0; n < num_socks; n++) { | ||
4304 | close(socks[n]); | 4448 | close(socks[n]); |
4305 | } | ||
4306 | num_socks = 0; | 4449 | num_socks = 0; |
4307 | break; | 4450 | break; |
4308 | } | 4451 | } |
@@ -4332,7 +4475,7 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, | |||
4332 | *chanids = xcalloc(num_socks + 1, sizeof(**chanids)); | 4475 | *chanids = xcalloc(num_socks + 1, sizeof(**chanids)); |
4333 | for (n = 0; n < num_socks; n++) { | 4476 | for (n = 0; n < num_socks; n++) { |
4334 | sock = socks[n]; | 4477 | sock = socks[n]; |
4335 | nc = channel_new("x11 listener", | 4478 | nc = channel_new(ssh, "x11 listener", |
4336 | SSH_CHANNEL_X11_LISTENER, sock, sock, -1, | 4479 | SSH_CHANNEL_X11_LISTENER, sock, sock, -1, |
4337 | CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, | 4480 | CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, |
4338 | 0, "X11 inet listener", 1); | 4481 | 0, "X11 inet listener", 1); |
@@ -4343,7 +4486,7 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, | |||
4343 | 4486 | ||
4344 | /* Return the display number for the DISPLAY environment variable. */ | 4487 | /* Return the display number for the DISPLAY environment variable. */ |
4345 | *display_numberp = display_number; | 4488 | *display_numberp = display_number; |
4346 | return (0); | 4489 | return 0; |
4347 | } | 4490 | } |
4348 | 4491 | ||
4349 | static int | 4492 | static int |
@@ -4401,7 +4544,7 @@ is_path_to_xsocket(const char *display, char *path, size_t pathlen) | |||
4401 | #endif | 4544 | #endif |
4402 | 4545 | ||
4403 | int | 4546 | int |
4404 | x11_connect_display(void) | 4547 | x11_connect_display(struct ssh *ssh) |
4405 | { | 4548 | { |
4406 | u_int display_number; | 4549 | u_int display_number; |
4407 | const char *display; | 4550 | const char *display; |
@@ -4446,9 +4589,10 @@ x11_connect_display(void) | |||
4446 | if (strncmp(display, "unix:", 5) == 0 || | 4589 | if (strncmp(display, "unix:", 5) == 0 || |
4447 | display[0] == ':') { | 4590 | display[0] == ':') { |
4448 | /* Connect to the unix domain socket. */ | 4591 | /* Connect to the unix domain socket. */ |
4449 | if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) { | 4592 | if (sscanf(strrchr(display, ':') + 1, "%u", |
4450 | error("Could not parse display number from DISPLAY: %.100s", | 4593 | &display_number) != 1) { |
4451 | display); | 4594 | error("Could not parse display number from DISPLAY: " |
4595 | "%.100s", display); | ||
4452 | return -1; | 4596 | return -1; |
4453 | } | 4597 | } |
4454 | /* Create a socket. */ | 4598 | /* Create a socket. */ |
@@ -4470,7 +4614,10 @@ x11_connect_display(void) | |||
4470 | return -1; | 4614 | return -1; |
4471 | } | 4615 | } |
4472 | *cp = 0; | 4616 | *cp = 0; |
4473 | /* buf now contains the host name. But first we parse the display number. */ | 4617 | /* |
4618 | * buf now contains the host name. But first we parse the | ||
4619 | * display number. | ||
4620 | */ | ||
4474 | if (sscanf(cp + 1, "%u", &display_number) != 1) { | 4621 | if (sscanf(cp + 1, "%u", &display_number) != 1) { |
4475 | error("Could not parse display number from DISPLAY: %.100s", | 4622 | error("Could not parse display number from DISPLAY: %.100s", |
4476 | display); | 4623 | display); |
@@ -4479,7 +4626,7 @@ x11_connect_display(void) | |||
4479 | 4626 | ||
4480 | /* Look up the host address */ | 4627 | /* Look up the host address */ |
4481 | memset(&hints, 0, sizeof(hints)); | 4628 | memset(&hints, 0, sizeof(hints)); |
4482 | hints.ai_family = IPv4or6; | 4629 | hints.ai_family = ssh->chanctxt->IPv4or6; |
4483 | hints.ai_socktype = SOCK_STREAM; | 4630 | hints.ai_socktype = SOCK_STREAM; |
4484 | snprintf(strport, sizeof strport, "%u", 6000 + display_number); | 4631 | snprintf(strport, sizeof strport, "%u", 6000 + display_number); |
4485 | if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { | 4632 | if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { |
@@ -4506,8 +4653,8 @@ x11_connect_display(void) | |||
4506 | } | 4653 | } |
4507 | freeaddrinfo(aitop); | 4654 | freeaddrinfo(aitop); |
4508 | if (!ai) { | 4655 | if (!ai) { |
4509 | error("connect %.100s port %u: %.100s", buf, 6000 + display_number, | 4656 | error("connect %.100s port %u: %.100s", buf, |
4510 | strerror(errno)); | 4657 | 6000 + display_number, strerror(errno)); |
4511 | return -1; | 4658 | return -1; |
4512 | } | 4659 | } |
4513 | set_nodelay(sock); | 4660 | set_nodelay(sock); |
@@ -4515,98 +4662,24 @@ x11_connect_display(void) | |||
4515 | } | 4662 | } |
4516 | 4663 | ||
4517 | /* | 4664 | /* |
4518 | * This is called when SSH_SMSG_X11_OPEN is received. The packet contains | ||
4519 | * the remote channel number. We should do whatever we want, and respond | ||
4520 | * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. | ||
4521 | */ | ||
4522 | |||
4523 | /* ARGSUSED */ | ||
4524 | int | ||
4525 | x11_input_open(int type, u_int32_t seq, void *ctxt) | ||
4526 | { | ||
4527 | Channel *c = NULL; | ||
4528 | int remote_id, sock = 0; | ||
4529 | char *remote_host; | ||
4530 | |||
4531 | debug("Received X11 open request."); | ||
4532 | |||
4533 | remote_id = packet_get_int(); | ||
4534 | |||
4535 | if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) { | ||
4536 | remote_host = packet_get_string(NULL); | ||
4537 | } else { | ||
4538 | remote_host = xstrdup("unknown (remote did not supply name)"); | ||
4539 | } | ||
4540 | packet_check_eom(); | ||
4541 | |||
4542 | /* Obtain a connection to the real X display. */ | ||
4543 | sock = x11_connect_display(); | ||
4544 | if (sock != -1) { | ||
4545 | /* Allocate a channel for this connection. */ | ||
4546 | c = channel_new("connected x11 socket", | ||
4547 | SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0, | ||
4548 | remote_host, 1); | ||
4549 | c->remote_id = remote_id; | ||
4550 | c->force_drain = 1; | ||
4551 | } | ||
4552 | free(remote_host); | ||
4553 | if (c == NULL) { | ||
4554 | /* Send refusal to the remote host. */ | ||
4555 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | ||
4556 | packet_put_int(remote_id); | ||
4557 | } else { | ||
4558 | /* Send a confirmation to the remote host. */ | ||
4559 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); | ||
4560 | packet_put_int(remote_id); | ||
4561 | packet_put_int(c->self); | ||
4562 | } | ||
4563 | packet_send(); | ||
4564 | return 0; | ||
4565 | } | ||
4566 | |||
4567 | /* dummy protocol handler that denies SSH-1 requests (agent/x11) */ | ||
4568 | /* ARGSUSED */ | ||
4569 | int | ||
4570 | deny_input_open(int type, u_int32_t seq, void *ctxt) | ||
4571 | { | ||
4572 | int rchan = packet_get_int(); | ||
4573 | |||
4574 | switch (type) { | ||
4575 | case SSH_SMSG_AGENT_OPEN: | ||
4576 | error("Warning: ssh server tried agent forwarding."); | ||
4577 | break; | ||
4578 | case SSH_SMSG_X11_OPEN: | ||
4579 | error("Warning: ssh server tried X11 forwarding."); | ||
4580 | break; | ||
4581 | default: | ||
4582 | error("deny_input_open: type %d", type); | ||
4583 | break; | ||
4584 | } | ||
4585 | error("Warning: this is probably a break-in attempt by a malicious server."); | ||
4586 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | ||
4587 | packet_put_int(rchan); | ||
4588 | packet_send(); | ||
4589 | return 0; | ||
4590 | } | ||
4591 | |||
4592 | /* | ||
4593 | * Requests forwarding of X11 connections, generates fake authentication | 4665 | * Requests forwarding of X11 connections, generates fake authentication |
4594 | * data, and enables authentication spoofing. | 4666 | * data, and enables authentication spoofing. |
4595 | * This should be called in the client only. | 4667 | * This should be called in the client only. |
4596 | */ | 4668 | */ |
4597 | void | 4669 | void |
4598 | x11_request_forwarding_with_spoofing(int client_session_id, const char *disp, | 4670 | x11_request_forwarding_with_spoofing(struct ssh *ssh, int client_session_id, |
4599 | const char *proto, const char *data, int want_reply) | 4671 | const char *disp, const char *proto, const char *data, int want_reply) |
4600 | { | 4672 | { |
4673 | struct ssh_channels *sc = ssh->chanctxt; | ||
4601 | u_int data_len = (u_int) strlen(data) / 2; | 4674 | u_int data_len = (u_int) strlen(data) / 2; |
4602 | u_int i, value; | 4675 | u_int i, value; |
4603 | char *new_data; | ||
4604 | int screen_number; | ||
4605 | const char *cp; | 4676 | const char *cp; |
4677 | char *new_data; | ||
4678 | int r, screen_number; | ||
4606 | 4679 | ||
4607 | if (x11_saved_display == NULL) | 4680 | if (sc->x11_saved_display == NULL) |
4608 | x11_saved_display = xstrdup(disp); | 4681 | sc->x11_saved_display = xstrdup(disp); |
4609 | else if (strcmp(disp, x11_saved_display) != 0) { | 4682 | else if (strcmp(disp, sc->x11_saved_display) != 0) { |
4610 | error("x11_request_forwarding_with_spoofing: different " | 4683 | error("x11_request_forwarding_with_spoofing: different " |
4611 | "$DISPLAY already forwarded"); | 4684 | "$DISPLAY already forwarded"); |
4612 | return; | 4685 | return; |
@@ -4620,53 +4693,37 @@ x11_request_forwarding_with_spoofing(int client_session_id, const char *disp, | |||
4620 | else | 4693 | else |
4621 | screen_number = 0; | 4694 | screen_number = 0; |
4622 | 4695 | ||
4623 | if (x11_saved_proto == NULL) { | 4696 | if (sc->x11_saved_proto == NULL) { |
4624 | /* Save protocol name. */ | 4697 | /* Save protocol name. */ |
4625 | x11_saved_proto = xstrdup(proto); | 4698 | sc->x11_saved_proto = xstrdup(proto); |
4626 | 4699 | ||
4627 | /* Extract real authentication data. */ | 4700 | /* Extract real authentication data. */ |
4628 | x11_saved_data = xmalloc(data_len); | 4701 | sc->x11_saved_data = xmalloc(data_len); |
4629 | for (i = 0; i < data_len; i++) { | 4702 | for (i = 0; i < data_len; i++) { |
4630 | if (sscanf(data + 2 * i, "%2x", &value) != 1) | 4703 | if (sscanf(data + 2 * i, "%2x", &value) != 1) |
4631 | fatal("x11_request_forwarding: bad " | 4704 | fatal("x11_request_forwarding: bad " |
4632 | "authentication data: %.100s", data); | 4705 | "authentication data: %.100s", data); |
4633 | x11_saved_data[i] = value; | 4706 | sc->x11_saved_data[i] = value; |
4634 | } | 4707 | } |
4635 | x11_saved_data_len = data_len; | 4708 | sc->x11_saved_data_len = data_len; |
4636 | 4709 | ||
4637 | /* Generate fake data of the same length. */ | 4710 | /* Generate fake data of the same length. */ |
4638 | x11_fake_data = xmalloc(data_len); | 4711 | sc->x11_fake_data = xmalloc(data_len); |
4639 | arc4random_buf(x11_fake_data, data_len); | 4712 | arc4random_buf(sc->x11_fake_data, data_len); |
4640 | x11_fake_data_len = data_len; | 4713 | sc->x11_fake_data_len = data_len; |
4641 | } | 4714 | } |
4642 | 4715 | ||
4643 | /* Convert the fake data into hex. */ | 4716 | /* Convert the fake data into hex. */ |
4644 | new_data = tohex(x11_fake_data, data_len); | 4717 | new_data = tohex(sc->x11_fake_data, data_len); |
4645 | 4718 | ||
4646 | /* Send the request packet. */ | 4719 | /* Send the request packet. */ |
4647 | if (compat20) { | 4720 | channel_request_start(ssh, client_session_id, "x11-req", want_reply); |
4648 | channel_request_start(client_session_id, "x11-req", want_reply); | 4721 | if ((r = sshpkt_put_u8(ssh, 0)) != 0 || /* bool: single connection */ |
4649 | packet_put_char(0); /* XXX bool single connection */ | 4722 | (r = sshpkt_put_cstring(ssh, proto)) != 0 || |
4650 | } else { | 4723 | (r = sshpkt_put_cstring(ssh, new_data)) != 0 || |
4651 | packet_start(SSH_CMSG_X11_REQUEST_FORWARDING); | 4724 | (r = sshpkt_put_u32(ssh, screen_number)) != 0 || |
4652 | } | 4725 | (r = sshpkt_send(ssh)) != 0 || |
4653 | packet_put_cstring(proto); | 4726 | (r = ssh_packet_write_wait(ssh)) != 0) |
4654 | packet_put_cstring(new_data); | 4727 | fatal("%s: send x11-req: %s", __func__, ssh_err(r)); |
4655 | packet_put_int(screen_number); | ||
4656 | packet_send(); | ||
4657 | packet_write_wait(); | ||
4658 | free(new_data); | 4728 | free(new_data); |
4659 | } | 4729 | } |
4660 | |||
4661 | |||
4662 | /* -- agent forwarding */ | ||
4663 | |||
4664 | /* Sends a message to the server to request authentication fd forwarding. */ | ||
4665 | |||
4666 | void | ||
4667 | auth_request_forwarding(void) | ||
4668 | { | ||
4669 | packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); | ||
4670 | packet_send(); | ||
4671 | packet_write_wait(); | ||
4672 | } | ||