Branch data Line data Source code
1 : : /* $OpenBSD: clientloop.c,v 1.258 2014/02/02 03:44:31 djm Exp $ */
2 : : /*
3 : : * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 : : * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 : : * All rights reserved
6 : : * The main loop for the interactive session (client side).
7 : : *
8 : : * As far as I am concerned, the code I have written for this software
9 : : * can be used freely for any purpose. Any derived versions of this
10 : : * software must be clearly marked as such, and if the derived work is
11 : : * incompatible with the protocol description in the RFC file, it must be
12 : : * called by a name other than "ssh" or "Secure Shell".
13 : : *
14 : : *
15 : : * Copyright (c) 1999 Theo de Raadt. All rights reserved.
16 : : *
17 : : * Redistribution and use in source and binary forms, with or without
18 : : * modification, are permitted provided that the following conditions
19 : : * are met:
20 : : * 1. Redistributions of source code must retain the above copyright
21 : : * notice, this list of conditions and the following disclaimer.
22 : : * 2. Redistributions in binary form must reproduce the above copyright
23 : : * notice, this list of conditions and the following disclaimer in the
24 : : * documentation and/or other materials provided with the distribution.
25 : : *
26 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 : : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 : : *
37 : : *
38 : : * SSH2 support added by Markus Friedl.
39 : : * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
40 : : *
41 : : * Redistribution and use in source and binary forms, with or without
42 : : * modification, are permitted provided that the following conditions
43 : : * are met:
44 : : * 1. Redistributions of source code must retain the above copyright
45 : : * notice, this list of conditions and the following disclaimer.
46 : : * 2. Redistributions in binary form must reproduce the above copyright
47 : : * notice, this list of conditions and the following disclaimer in the
48 : : * documentation and/or other materials provided with the distribution.
49 : : *
50 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
51 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53 : : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
54 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
59 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 : : */
61 : :
62 : : #include "includes.h"
63 : :
64 : : #include <sys/types.h>
65 : : #include <sys/ioctl.h>
66 : : #include <sys/param.h>
67 : : #ifdef HAVE_SYS_STAT_H
68 : : # include <sys/stat.h>
69 : : #endif
70 : : #ifdef HAVE_SYS_TIME_H
71 : : # include <sys/time.h>
72 : : #endif
73 : : #include <sys/socket.h>
74 : :
75 : : #include <ctype.h>
76 : : #include <errno.h>
77 : : #ifdef HAVE_PATHS_H
78 : : #include <paths.h>
79 : : #endif
80 : : #include <signal.h>
81 : : #include <stdarg.h>
82 : : #include <stdio.h>
83 : : #include <stdlib.h>
84 : : #include <string.h>
85 : : #include <termios.h>
86 : : #include <pwd.h>
87 : : #include <unistd.h>
88 : :
89 : : #include "openbsd-compat/sys-queue.h"
90 : : #include "xmalloc.h"
91 : : #include "ssh.h"
92 : : #include "ssh1.h"
93 : : #include "ssh2.h"
94 : : #include "packet.h"
95 : : #include "buffer.h"
96 : : #include "compat.h"
97 : : #include "channels.h"
98 : : #include "dispatch.h"
99 : : #include "key.h"
100 : : #include "cipher.h"
101 : : #include "kex.h"
102 : : #include "log.h"
103 : : #include "readconf.h"
104 : : #include "clientloop.h"
105 : : #include "sshconnect.h"
106 : : #include "authfd.h"
107 : : #include "atomicio.h"
108 : : #include "sshpty.h"
109 : : #include "misc.h"
110 : : #include "match.h"
111 : : #include "msg.h"
112 : : #include "roaming.h"
113 : :
114 : : /* import options */
115 : : extern Options options;
116 : :
117 : : /* Flag indicating that stdin should be redirected from /dev/null. */
118 : : extern int stdin_null_flag;
119 : :
120 : : /* Flag indicating that no shell has been requested */
121 : : extern int no_shell_flag;
122 : :
123 : : /* Control socket */
124 : : extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */
125 : :
126 : : /*
127 : : * Name of the host we are connecting to. This is the name given on the
128 : : * command line, or the HostName specified for the user-supplied name in a
129 : : * configuration file.
130 : : */
131 : : extern char *host;
132 : :
133 : : /*
134 : : * Flag to indicate that we have received a window change signal which has
135 : : * not yet been processed. This will cause a message indicating the new
136 : : * window size to be sent to the server a little later. This is volatile
137 : : * because this is updated in a signal handler.
138 : : */
139 : : static volatile sig_atomic_t received_window_change_signal = 0;
140 : : static volatile sig_atomic_t received_signal = 0;
141 : :
142 : : /* Flag indicating whether the user's terminal is in non-blocking mode. */
143 : : static int in_non_blocking_mode = 0;
144 : :
145 : : /* Time when backgrounded control master using ControlPersist should exit */
146 : : static time_t control_persist_exit_time = 0;
147 : :
148 : : /* Common data for the client loop code. */
149 : : volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
150 : : static int escape_char1; /* Escape character. (proto1 only) */
151 : : static int escape_pending1; /* Last character was an escape (proto1 only) */
152 : : static int last_was_cr; /* Last character was a newline. */
153 : : static int exit_status; /* Used to store the command exit status. */
154 : : static int stdin_eof; /* EOF has been encountered on stderr. */
155 : : static Buffer stdin_buffer; /* Buffer for stdin data. */
156 : : static Buffer stdout_buffer; /* Buffer for stdout data. */
157 : : static Buffer stderr_buffer; /* Buffer for stderr data. */
158 : : static u_int buffer_high; /* Soft max buffer size. */
159 : : static int connection_in; /* Connection to server (input). */
160 : : static int connection_out; /* Connection to server (output). */
161 : : static int need_rekeying; /* Set to non-zero if rekeying is requested. */
162 : : static int session_closed; /* In SSH2: login session closed. */
163 : : static int x11_refuse_time; /* If >0, refuse x11 opens after this time. */
164 : :
165 : : static void client_init_dispatch(void);
166 : : int session_ident = -1;
167 : :
168 : : int session_resumed = 0;
169 : :
170 : : /* Track escape per proto2 channel */
171 : : struct escape_filter_ctx {
172 : : int escape_pending;
173 : : int escape_char;
174 : : };
175 : :
176 : : /* Context for channel confirmation replies */
177 : : struct channel_reply_ctx {
178 : : const char *request_type;
179 : : int id;
180 : : enum confirm_action action;
181 : : };
182 : :
183 : : /* Global request success/failure callbacks */
184 : : struct global_confirm {
185 : : TAILQ_ENTRY(global_confirm) entry;
186 : : global_confirm_cb *cb;
187 : : void *ctx;
188 : : int ref_count;
189 : : };
190 : : TAILQ_HEAD(global_confirms, global_confirm);
191 : : static struct global_confirms global_confirms =
192 : : TAILQ_HEAD_INITIALIZER(global_confirms);
193 : :
194 : : /*XXX*/
195 : : extern Kex *xxx_kex;
196 : :
197 : : void ssh_process_session2_setup(int, int, int, Buffer *);
198 : :
199 : : /* Restores stdin to blocking mode. */
200 : :
201 : : static void
202 : 46 : leave_non_blocking(void)
203 : : {
204 [ + - ]: 46 : if (in_non_blocking_mode) {
205 : 46 : unset_nonblock(fileno(stdin));
206 : 46 : in_non_blocking_mode = 0;
207 : : }
208 : 46 : }
209 : :
210 : : /* Puts stdin terminal in non-blocking mode. */
211 : :
212 : : static void
213 : 46 : enter_non_blocking(void)
214 : : {
215 : 46 : in_non_blocking_mode = 1;
216 : 46 : set_nonblock(fileno(stdin));
217 : 46 : }
218 : :
219 : : /*
220 : : * Signal handler for the window change signal (SIGWINCH). This just sets a
221 : : * flag indicating that the window has changed.
222 : : */
223 : : /*ARGSUSED */
224 : : static void
225 : 0 : window_change_handler(int sig)
226 : : {
227 : 0 : received_window_change_signal = 1;
228 : 0 : signal(SIGWINCH, window_change_handler);
229 : 0 : }
230 : :
231 : : /*
232 : : * Signal handler for signals that cause the program to terminate. These
233 : : * signals must be trapped to restore terminal modes.
234 : : */
235 : : /*ARGSUSED */
236 : : static void
237 : 0 : signal_handler(int sig)
238 : : {
239 : 0 : received_signal = sig;
240 : 0 : quit_pending = 1;
241 : 0 : }
242 : :
243 : : /*
244 : : * Returns current time in seconds from Jan 1, 1970 with the maximum
245 : : * available resolution.
246 : : */
247 : :
248 : : static double
249 : 1498 : get_current_time(void)
250 : : {
251 : : struct timeval tv;
252 : 1498 : gettimeofday(&tv, NULL);
253 : 1498 : return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
254 : : }
255 : :
256 : : /*
257 : : * Sets control_persist_exit_time to the absolute time when the
258 : : * backgrounded control master should exit due to expiry of the
259 : : * ControlPersist timeout. Sets it to 0 if we are not a backgrounded
260 : : * control master process, or if there is no ControlPersist timeout.
261 : : */
262 : : static void
263 : 35690 : set_control_persist_exit_time(void)
264 : : {
265 [ + + ][ - + ]: 35690 : if (muxserver_sock == -1 || !options.control_persist
266 [ # # ]: 0 : || options.control_persist_timeout == 0) {
267 : : /* not using a ControlPersist timeout */
268 : 35690 : control_persist_exit_time = 0;
269 [ # # ]: 0 : } else if (channel_still_open()) {
270 : : /* some client connections are still open */
271 [ # # ]: 0 : if (control_persist_exit_time > 0)
272 : 0 : debug2("%s: cancel scheduled exit", __func__);
273 : 0 : control_persist_exit_time = 0;
274 [ # # ]: 0 : } else if (control_persist_exit_time <= 0) {
275 : : /* a client connection has recently closed */
276 : 0 : control_persist_exit_time = monotime() +
277 : 0 : (time_t)options.control_persist_timeout;
278 : 0 : debug2("%s: schedule exit in %d seconds", __func__,
279 : : options.control_persist_timeout);
280 : : }
281 : : /* else we are already counting down to the timeout */
282 : 35690 : }
283 : :
284 : : #define SSH_X11_VALID_DISPLAY_CHARS ":/.-_"
285 : : static int
286 : 0 : client_x11_display_valid(const char *display)
287 : : {
288 : : size_t i, dlen;
289 : :
290 : 0 : dlen = strlen(display);
291 [ # # ]: 0 : for (i = 0; i < dlen; i++) {
292 [ # # ][ # # ]: 0 : if (!isalnum((u_char)display[i]) &&
293 : 0 : strchr(SSH_X11_VALID_DISPLAY_CHARS, display[i]) == NULL) {
294 : 0 : debug("Invalid character '%c' in DISPLAY", display[i]);
295 : 0 : return 0;
296 : : }
297 : : }
298 : : return 1;
299 : : }
300 : :
301 : : #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
302 : : void
303 : 0 : client_x11_get_proto(const char *display, const char *xauth_path,
304 : : u_int trusted, u_int timeout, char **_proto, char **_data)
305 : : {
306 : : char cmd[1024];
307 : : char line[512];
308 : : char xdisplay[512];
309 : : static char proto[512], data[512];
310 : : FILE *f;
311 : 0 : int got_data = 0, generated = 0, do_unlink = 0, i;
312 : : char *xauthdir, *xauthfile;
313 : : struct stat st;
314 : : u_int now;
315 : :
316 : 0 : xauthdir = xauthfile = NULL;
317 : 0 : *_proto = proto;
318 : 0 : *_data = data;
319 : 0 : proto[0] = data[0] = '\0';
320 : :
321 [ # # # # ]: 0 : if (xauth_path == NULL ||(stat(xauth_path, &st) == -1)) {
322 : 0 : debug("No xauth program.");
323 [ # # ]: 0 : } else if (!client_x11_display_valid(display)) {
324 : 0 : logit("DISPLAY '%s' invalid, falling back to fake xauth data",
325 : : display);
326 : : } else {
327 [ # # ]: 0 : if (display == NULL) {
328 : 0 : debug("x11_get_proto: DISPLAY not set");
329 : 0 : return;
330 : : }
331 : : /*
332 : : * Handle FamilyLocal case where $DISPLAY does
333 : : * not match an authorization entry. For this we
334 : : * just try "xauth list unix:displaynum.screennum".
335 : : * XXX: "localhost" match to determine FamilyLocal
336 : : * is not perfect.
337 : : */
338 [ # # ]: 0 : if (strncmp(display, "localhost:", 10) == 0) {
339 : 0 : snprintf(xdisplay, sizeof(xdisplay), "unix:%s",
340 : : display + 10);
341 : 0 : display = xdisplay;
342 : : }
343 [ # # ]: 0 : if (trusted == 0) {
344 : 0 : xauthdir = xmalloc(MAXPATHLEN);
345 : 0 : xauthfile = xmalloc(MAXPATHLEN);
346 : 0 : mktemp_proto(xauthdir, MAXPATHLEN);
347 [ # # ]: 0 : if (mkdtemp(xauthdir) != NULL) {
348 : 0 : do_unlink = 1;
349 : : snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile",
350 : : xauthdir);
351 : : snprintf(cmd, sizeof(cmd),
352 : : "%s -f %s generate %s " SSH_X11_PROTO
353 : : " untrusted timeout %u 2>" _PATH_DEVNULL,
354 : : xauth_path, xauthfile, display, timeout);
355 : 0 : debug2("x11_get_proto: %s", cmd);
356 [ # # ]: 0 : if (system(cmd) == 0)
357 : 0 : generated = 1;
358 [ # # ]: 0 : if (x11_refuse_time == 0) {
359 : 0 : now = monotime() + 1;
360 [ # # ]: 0 : if (UINT_MAX - timeout < now)
361 : 0 : x11_refuse_time = UINT_MAX;
362 : : else
363 : 0 : x11_refuse_time = now + timeout;
364 : : }
365 : : }
366 : : }
367 : :
368 : : /*
369 : : * When in untrusted mode, we read the cookie only if it was
370 : : * successfully generated as an untrusted one in the step
371 : : * above.
372 : : */
373 [ # # ]: 0 : if (trusted || generated) {
374 [ # # ][ # # ]: 0 : snprintf(cmd, sizeof(cmd),
375 : : "%s %s%s list %s 2>" _PATH_DEVNULL,
376 : : xauth_path,
377 : : generated ? "-f " : "" ,
378 : : generated ? xauthfile : "",
379 : : display);
380 : 0 : debug2("x11_get_proto: %s", cmd);
381 : 0 : f = popen(cmd, "r");
382 [ # # # # ]: 0 : if (f && fgets(line, sizeof(line), f) &&
[ # # ]
383 : 0 : sscanf(line, "%*s %511s %511s", proto, data) == 2)
384 : 0 : got_data = 1;
385 [ # # ]: 0 : if (f)
386 : 0 : pclose(f);
387 : : } else
388 : 0 : error("Warning: untrusted X11 forwarding setup failed: "
389 : : "xauth key data not generated");
390 : : }
391 : :
392 [ # # ]: 0 : if (do_unlink) {
393 : 0 : unlink(xauthfile);
394 : 0 : rmdir(xauthdir);
395 : : }
396 : 0 : free(xauthdir);
397 : 0 : free(xauthfile);
398 : :
399 : : /*
400 : : * If we didn't get authentication data, just make up some
401 : : * data. The forwarding code will check the validity of the
402 : : * response anyway, and substitute this data. The X11
403 : : * server, however, will ignore this fake data and use
404 : : * whatever authentication mechanisms it was using otherwise
405 : : * for the local connection.
406 : : */
407 [ # # ]: 0 : if (!got_data) {
408 : 0 : u_int32_t rnd = 0;
409 : :
410 : 0 : logit("Warning: No xauth data; "
411 : : "using fake authentication data for X11 forwarding.");
412 : 0 : strlcpy(proto, SSH_X11_PROTO, sizeof proto);
413 [ # # ]: 0 : for (i = 0; i < 16; i++) {
414 [ # # ]: 0 : if (i % 4 == 0)
415 : 0 : rnd = arc4random();
416 : 0 : snprintf(data + 2 * i, sizeof data - 2 * i, "%02x",
417 : : rnd & 0xff);
418 : 0 : rnd >>= 8;
419 : : }
420 : : }
421 : : }
422 : :
423 : : /*
424 : : * This is called when the interactive is entered. This checks if there is
425 : : * an EOF coming on stdin. We must check this explicitly, as select() does
426 : : * not appear to wake up when redirecting from /dev/null.
427 : : */
428 : :
429 : : static void
430 : 61 : client_check_initial_eof_on_stdin(void)
431 : : {
432 : : int len;
433 : : char buf[1];
434 : :
435 : : /*
436 : : * If standard input is to be "redirected from /dev/null", we simply
437 : : * mark that we have seen an EOF and send an EOF message to the
438 : : * server. Otherwise, we try to read a single character; it appears
439 : : * that for some files, such /dev/null, select() never wakes up for
440 : : * read for this descriptor, which means that we never get EOF. This
441 : : * way we will get the EOF if stdin comes from /dev/null or similar.
442 : : */
443 [ + + ]: 61 : if (stdin_null_flag) {
444 : : /* Fake EOF on stdin. */
445 : 15 : debug("Sending eof.");
446 : 15 : stdin_eof = 1;
447 : 15 : packet_start(SSH_CMSG_EOF);
448 : 15 : packet_send();
449 : : } else {
450 : 46 : enter_non_blocking();
451 : :
452 : : /* Check for immediate EOF on stdin. */
453 : 46 : len = read(fileno(stdin), buf, 1);
454 [ - + ]: 46 : if (len == 0) {
455 : : /*
456 : : * EOF. Record that we have seen it and send
457 : : * EOF to server.
458 : : */
459 : 0 : debug("Sending eof.");
460 : 0 : stdin_eof = 1;
461 : 0 : packet_start(SSH_CMSG_EOF);
462 : 0 : packet_send();
463 [ + + ]: 46 : } else if (len > 0) {
464 : : /*
465 : : * Got data. We must store the data in the buffer,
466 : : * and also process it as an escape character if
467 : : * appropriate.
468 : : */
469 [ - + ]: 7 : if ((u_char) buf[0] == escape_char1)
470 : 0 : escape_pending1 = 1;
471 : : else
472 : 7 : buffer_append(&stdin_buffer, buf, 1);
473 : : }
474 : 46 : leave_non_blocking();
475 : : }
476 : 61 : }
477 : :
478 : :
479 : : /*
480 : : * Make packets from buffered stdin data, and buffer them for sending to the
481 : : * connection.
482 : : */
483 : :
484 : : static void
485 : 4620 : client_make_packets_from_stdin_data(void)
486 : : {
487 : : u_int len;
488 : :
489 : : /* Send buffered stdin data to the server. */
490 [ + + + - ]: 11270 : while (buffer_len(&stdin_buffer) > 0 &&
491 : 1015 : packet_not_very_much_data_to_write()) {
492 : 1015 : len = buffer_len(&stdin_buffer);
493 : : /* Keep the packets at reasonable size. */
494 [ - + ]: 1015 : if (len > packet_get_maxsize())
495 : 0 : len = packet_get_maxsize();
496 : 1015 : packet_start(SSH_CMSG_STDIN_DATA);
497 : 1015 : packet_put_string(buffer_ptr(&stdin_buffer), len);
498 : 1015 : packet_send();
499 : 1015 : buffer_consume(&stdin_buffer, len);
500 : : /* If we have a pending EOF, send it now. */
501 [ + - ][ # # ]: 1015 : if (stdin_eof && buffer_len(&stdin_buffer) == 0) {
502 : 0 : packet_start(SSH_CMSG_EOF);
503 : 4620 : packet_send();
504 : : }
505 : : }
506 : 4620 : }
507 : :
508 : : /*
509 : : * Checks if the client window has changed, and sends a packet about it to
510 : : * the server if so. The actual change is detected elsewhere (by a software
511 : : * interrupt on Unix); this just checks the flag and sends a message if
512 : : * appropriate.
513 : : */
514 : :
515 : : static void
516 : 33674 : client_check_window_change(void)
517 : : {
518 : : struct winsize ws;
519 : :
520 [ - + ]: 33674 : if (! received_window_change_signal)
521 : 33674 : return;
522 : : /** XXX race */
523 : 0 : received_window_change_signal = 0;
524 : :
525 : 0 : debug2("client_check_window_change: changed");
526 : :
527 [ # # ]: 0 : if (compat20) {
528 : 0 : channel_send_window_changes();
529 : : } else {
530 [ # # ]: 0 : if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
531 : : return;
532 : 0 : packet_start(SSH_CMSG_WINDOW_SIZE);
533 : 0 : packet_put_int((u_int)ws.ws_row);
534 : 0 : packet_put_int((u_int)ws.ws_col);
535 : 0 : packet_put_int((u_int)ws.ws_xpixel);
536 : 0 : packet_put_int((u_int)ws.ws_ypixel);
537 : 0 : packet_send();
538 : : }
539 : : }
540 : :
541 : : static void
542 : 20 : client_global_request_reply(int type, u_int32_t seq, void *ctxt)
543 : : {
544 : : struct global_confirm *gc;
545 : :
546 [ + - ]: 20 : if ((gc = TAILQ_FIRST(&global_confirms)) == NULL)
547 : 20 : return;
548 [ + - ]: 20 : if (gc->cb != NULL)
549 : 20 : gc->cb(type, seq, gc->ctx);
550 [ + - ]: 20 : if (--gc->ref_count <= 0) {
551 [ + + ]: 20 : TAILQ_REMOVE(&global_confirms, gc, entry);
552 : 20 : explicit_bzero(gc, sizeof(*gc));
553 : 20 : free(gc);
554 : : }
555 : :
556 : 20 : packet_set_alive_timeouts(0);
557 : : }
558 : :
559 : : static void
560 : 0 : server_alive_check(void)
561 : : {
562 [ # # ]: 0 : if (packet_inc_alive_timeouts() > options.server_alive_count_max) {
563 : 0 : logit("Timeout, server %s not responding.", host);
564 : 0 : cleanup_exit(255);
565 : : }
566 : 0 : packet_start(SSH2_MSG_GLOBAL_REQUEST);
567 : 0 : packet_put_cstring("keepalive@openssh.com");
568 : 0 : packet_put_char(1); /* boolean: want reply */
569 : 0 : packet_send();
570 : : /* Insert an empty placeholder to maintain ordering */
571 : 0 : client_register_global_confirm(NULL, NULL);
572 : 0 : }
573 : :
574 : : /*
575 : : * Waits until the client can do something (some data becomes available on
576 : : * one of the file descriptors).
577 : : */
578 : : static void
579 : 35692 : client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
580 : : int *maxfdp, u_int *nallocp, int rekeying)
581 : : {
582 : : struct timeval tv, *tvp;
583 : : int timeout_secs;
584 : 35692 : time_t minwait_secs = 0, server_alive_time = 0, now = monotime();
585 : : int ret;
586 : :
587 : : /* Add any selections by the channel mechanism. */
588 : 35692 : channel_prepare_select(readsetp, writesetp, maxfdp, nallocp,
589 : : &minwait_secs, rekeying);
590 : :
591 [ + + ]: 35692 : if (!compat20) {
592 : : /* Read from the connection, unless our buffers are full. */
593 [ + - + - ]: 9118 : if (buffer_len(&stdout_buffer) < buffer_high &&
594 [ + - ]: 9118 : buffer_len(&stderr_buffer) < buffer_high &&
595 : 4559 : channel_not_very_much_buffered_data())
596 [ - + ][ # # ]: 4559 : FD_SET(connection_in, *readsetp);
597 : : /*
598 : : * Read from stdin, unless we have seen EOF or have very much
599 : : * buffered data to send to the server.
600 : : */
601 [ + + ][ + + ]: 4559 : if (!stdin_eof && packet_not_very_much_data_to_write())
602 [ - + ][ # # ]: 1611 : FD_SET(fileno(stdin), *readsetp);
603 : :
604 : : /* Select stdout/stderr if have data in buffer. */
605 [ + + ]: 4559 : if (buffer_len(&stdout_buffer) > 0)
606 [ - + ][ # # ]: 298 : FD_SET(fileno(stdout), *writesetp);
607 [ + + ]: 4559 : if (buffer_len(&stderr_buffer) > 0)
608 [ - + ][ # # ]: 284 : FD_SET(fileno(stderr), *writesetp);
609 : : } else {
610 : : /* channel_prepare_select could have closed the last channel */
611 [ + + ]: 31820 : if (session_closed && !channel_still_open() &&
[ + + + + ]
612 : 687 : !packet_have_data_to_write()) {
613 : : /* clear mask since we did not call select() */
614 : 2 : memset(*readsetp, 0, *nallocp);
615 : 2 : memset(*writesetp, 0, *nallocp);
616 : 2 : return;
617 : : } else {
618 [ - + ][ # # ]: 31131 : FD_SET(connection_in, *readsetp);
619 : : }
620 : : }
621 : :
622 : : /* Select server connection if have data to write to the server. */
623 [ + + ]: 35690 : if (packet_have_data_to_write())
624 [ - + ][ # # ]: 19523 : FD_SET(connection_out, *writesetp);
625 : :
626 : : /*
627 : : * Wait for something to happen. This will suspend the process until
628 : : * some selected descriptor can be read, written, or has some other
629 : : * event pending, or a timeout expires.
630 : : */
631 : :
632 : 35690 : timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */
633 [ - + ][ # # ]: 35690 : if (options.server_alive_interval > 0 && compat20) {
634 : 0 : timeout_secs = options.server_alive_interval;
635 : 0 : server_alive_time = now + options.server_alive_interval;
636 : : }
637 [ + + ][ + - ]: 35690 : if (options.rekey_interval > 0 && compat20 && !rekeying)
[ + + ]
638 [ + - ]: 335 : timeout_secs = MIN(timeout_secs, packet_get_rekey_timeout());
639 : 35690 : set_control_persist_exit_time();
640 [ - + ]: 35690 : if (control_persist_exit_time > 0) {
641 : 0 : timeout_secs = MIN(timeout_secs,
642 : : control_persist_exit_time - now);
643 [ # # ]: 0 : if (timeout_secs < 0)
644 : 0 : timeout_secs = 0;
645 : : }
646 [ - + ]: 35690 : if (minwait_secs != 0)
647 : 0 : timeout_secs = MIN(timeout_secs, (int)minwait_secs);
648 [ + + ]: 35690 : if (timeout_secs == INT_MAX)
649 : : tvp = NULL;
650 : : else {
651 : 335 : tv.tv_sec = timeout_secs;
652 : 335 : tv.tv_usec = 0;
653 : 335 : tvp = &tv;
654 : : }
655 : :
656 : 35690 : ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
657 [ - + ]: 35690 : if (ret < 0) {
658 : : char buf[100];
659 : :
660 : : /*
661 : : * We have to clear the select masks, because we return.
662 : : * We have to return, because the mainloop checks for the flags
663 : : * set by the signal handlers.
664 : : */
665 : 0 : memset(*readsetp, 0, *nallocp);
666 : 0 : memset(*writesetp, 0, *nallocp);
667 : :
668 [ # # ]: 0 : if (errno == EINTR)
669 : 0 : return;
670 : : /* Note: we might still have data in the buffers. */
671 : 0 : snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
672 : 0 : buffer_append(&stderr_buffer, buf, strlen(buf));
673 : 0 : quit_pending = 1;
674 [ + + ]: 35690 : } else if (ret == 0) {
675 : : /*
676 : : * Timeout. Could have been either keepalive or rekeying.
677 : : * Keepalive we check here, rekeying is checked in clientloop.
678 : : */
679 [ - + ][ # # ]: 4 : if (server_alive_time != 0 && server_alive_time <= monotime())
680 : 35690 : server_alive_check();
681 : : }
682 : :
683 : : }
684 : :
685 : : static void
686 : 0 : client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
687 : : {
688 : : /* Flush stdout and stderr buffers. */
689 [ # # ]: 0 : if (buffer_len(bout) > 0)
690 : 0 : atomicio(vwrite, fileno(stdout), buffer_ptr(bout),
691 : 0 : buffer_len(bout));
692 [ # # ]: 0 : if (buffer_len(berr) > 0)
693 : 0 : atomicio(vwrite, fileno(stderr), buffer_ptr(berr),
694 : 0 : buffer_len(berr));
695 : :
696 : 0 : leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
697 : :
698 : : /*
699 : : * Free (and clear) the buffer to reduce the amount of data that gets
700 : : * written to swap.
701 : : */
702 : 0 : buffer_free(bin);
703 : 0 : buffer_free(bout);
704 : 0 : buffer_free(berr);
705 : :
706 : : /* Send the suspend signal to the program itself. */
707 : 0 : kill(getpid(), SIGTSTP);
708 : :
709 : : /* Reset window sizes in case they have changed */
710 : 0 : received_window_change_signal = 1;
711 : :
712 : : /* OK, we have been continued by the user. Reinitialize buffers. */
713 : 0 : buffer_init(bin);
714 : 0 : buffer_init(bout);
715 : 0 : buffer_init(berr);
716 : :
717 : 0 : enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
718 : 0 : }
719 : :
720 : : static void
721 : 35692 : client_process_net_input(fd_set *readset)
722 : : {
723 : 35692 : int len, cont = 0;
724 : : char buf[SSH_IOBUFSZ];
725 : :
726 : : /*
727 : : * Read input from the server, and add any such data to the buffer of
728 : : * the packet subsystem.
729 : : */
730 [ - + ][ # # ]: 35692 : if (FD_ISSET(connection_in, readset)) {
[ + + ]
731 : : /* Read as much as possible. */
732 : 10553 : len = roaming_read(connection_in, buf, sizeof(buf), &cont);
733 [ - + ][ # # ]: 10553 : if (len == 0 && cont == 0) {
734 : : /*
735 : : * Received EOF. The remote host has closed the
736 : : * connection.
737 : : */
738 : 0 : snprintf(buf, sizeof buf,
739 : : "Connection to %.300s closed by remote host.\r\n",
740 : : host);
741 : 0 : buffer_append(&stderr_buffer, buf, strlen(buf));
742 : 0 : quit_pending = 1;
743 : 0 : return;
744 : : }
745 : : /*
746 : : * There is a kernel bug on Solaris that causes select to
747 : : * sometimes wake up even though there is no data available.
748 : : */
749 [ - + # # ]: 10553 : if (len < 0 &&
750 [ # # ]: 0 : (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
751 : 0 : len = 0;
752 : :
753 [ - + ]: 10553 : if (len < 0) {
754 : : /*
755 : : * An error has encountered. Perhaps there is a
756 : : * network problem.
757 : : */
758 : 0 : snprintf(buf, sizeof buf,
759 : : "Read from remote host %.300s: %.100s\r\n",
760 : 0 : host, strerror(errno));
761 : 0 : buffer_append(&stderr_buffer, buf, strlen(buf));
762 : 0 : quit_pending = 1;
763 : 0 : return;
764 : : }
765 : 35692 : packet_process_incoming(buf, len);
766 : : }
767 : : }
768 : :
769 : : static void
770 : 702 : client_status_confirm(int type, Channel *c, void *ctx)
771 : : {
772 : 702 : struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx;
773 : : char errmsg[256];
774 : : int tochan;
775 : :
776 : : /*
777 : : * If a TTY was explicitly requested, then a failure to allocate
778 : : * one is fatal.
779 : : */
780 [ - + ][ # # ]: 702 : if (cr->action == CONFIRM_TTY &&
781 : 0 : (options.request_tty == REQUEST_TTY_FORCE ||
782 : : options.request_tty == REQUEST_TTY_YES))
783 : 0 : cr->action = CONFIRM_CLOSE;
784 : :
785 : : /* XXX supress on mux _client_ quietmode */
786 [ + + ]: 672 : tochan = options.log_level >= SYSLOG_LEVEL_ERROR &&
787 [ + + ][ - + ]: 1374 : c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE;
788 : :
789 [ + - ]: 702 : if (type == SSH2_MSG_CHANNEL_SUCCESS) {
790 : 702 : debug2("%s request accepted on channel %d",
791 : : cr->request_type, c->self);
792 [ # # ]: 0 : } else if (type == SSH2_MSG_CHANNEL_FAILURE) {
793 [ # # ]: 0 : if (tochan) {
794 : 0 : snprintf(errmsg, sizeof(errmsg),
795 : : "%s request failed\r\n", cr->request_type);
796 : : } else {
797 : 0 : snprintf(errmsg, sizeof(errmsg),
798 : : "%s request failed on channel %d",
799 : : cr->request_type, c->self);
800 : : }
801 : : /* If error occurred on primary session channel, then exit */
802 [ # # ][ # # ]: 0 : if (cr->action == CONFIRM_CLOSE && c->self == session_ident)
803 : 0 : fatal("%s", errmsg);
804 : : /*
805 : : * If error occurred on mux client, append to
806 : : * their stderr.
807 : : */
808 [ # # ]: 0 : if (tochan) {
809 : 0 : buffer_append(&c->extended, errmsg,
810 : 0 : strlen(errmsg));
811 : : } else
812 : 0 : error("%s", errmsg);
813 [ # # ]: 0 : if (cr->action == CONFIRM_TTY) {
814 : : /*
815 : : * If a TTY allocation error occurred, then arrange
816 : : * for the correct TTY to leave raw mode.
817 : : */
818 [ # # ]: 0 : if (c->self == session_ident)
819 : 0 : leave_raw_mode(0);
820 : : else
821 : 0 : mux_tty_alloc_failed(c);
822 [ # # ]: 0 : } else if (cr->action == CONFIRM_CLOSE) {
823 : 0 : chan_read_failed(c);
824 : 0 : chan_write_failed(c);
825 : : }
826 : : }
827 : 702 : free(cr);
828 : 702 : }
829 : :
830 : : static void
831 : 0 : client_abandon_status_confirm(Channel *c, void *ctx)
832 : : {
833 : 0 : free(ctx);
834 : 0 : }
835 : :
836 : : void
837 : 702 : client_expect_confirm(int id, const char *request,
838 : : enum confirm_action action)
839 : : {
840 : 702 : struct channel_reply_ctx *cr = xcalloc(1, sizeof(*cr));
841 : :
842 : 702 : cr->request_type = request;
843 : 702 : cr->action = action;
844 : :
845 : 702 : channel_register_status_confirm(id, client_status_confirm,
846 : : client_abandon_status_confirm, cr);
847 : 702 : }
848 : :
849 : : void
850 : 34 : client_register_global_confirm(global_confirm_cb *cb, void *ctx)
851 : : {
852 : : struct global_confirm *gc, *last_gc;
853 : :
854 : : /* Coalesce identical callbacks */
855 : 34 : last_gc = TAILQ_LAST(&global_confirms, global_confirms);
856 [ + + ][ + - ]: 34 : if (last_gc && last_gc->cb == cb && last_gc->ctx == ctx) {
[ - + ]
857 [ # # ]: 0 : if (++last_gc->ref_count >= INT_MAX)
858 : 0 : fatal("%s: last_gc->ref_count = %d",
859 : : __func__, last_gc->ref_count);
860 : 34 : return;
861 : : }
862 : :
863 : 34 : gc = xcalloc(1, sizeof(*gc));
864 : 34 : gc->cb = cb;
865 : 34 : gc->ctx = ctx;
866 : 34 : gc->ref_count = 1;
867 : 34 : TAILQ_INSERT_TAIL(&global_confirms, gc, entry);
868 : : }
869 : :
870 : : static void
871 : 0 : process_cmdline(void)
872 : : {
873 : : void (*handler)(int);
874 : : char *s, *cmd, *cancel_host;
875 : 0 : int delete = 0, local = 0, remote = 0, dynamic = 0;
876 : : int cancel_port, ok;
877 : : Forward fwd;
878 : :
879 : : memset(&fwd, 0, sizeof(fwd));
880 : : fwd.listen_host = fwd.connect_host = NULL;
881 : :
882 : 0 : leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
883 : 0 : handler = signal(SIGINT, SIG_IGN);
884 : 0 : cmd = s = read_passphrase("\r\nssh> ", RP_ECHO);
885 [ # # ]: 0 : if (s == NULL)
886 : : goto out;
887 [ # # ]: 0 : while (isspace((u_char)*s))
888 : 0 : s++;
889 [ # # ]: 0 : if (*s == '-')
890 : 0 : s++; /* Skip cmdline '-', if any */
891 [ # # ]: 0 : if (*s == '\0')
892 : : goto out;
893 : :
894 [ # # ][ # # ]: 0 : if (*s == 'h' || *s == 'H' || *s == '?') {
895 : 0 : logit("Commands:");
896 : 0 : logit(" -L[bind_address:]port:host:hostport "
897 : : "Request local forward");
898 : 0 : logit(" -R[bind_address:]port:host:hostport "
899 : : "Request remote forward");
900 : 0 : logit(" -D[bind_address:]port "
901 : : "Request dynamic forward");
902 : 0 : logit(" -KL[bind_address:]port "
903 : : "Cancel local forward");
904 : 0 : logit(" -KR[bind_address:]port "
905 : : "Cancel remote forward");
906 : 0 : logit(" -KD[bind_address:]port "
907 : : "Cancel dynamic forward");
908 [ # # ]: 0 : if (!options.permit_local_command)
909 : : goto out;
910 : 0 : logit(" !args "
911 : : "Execute local command");
912 : 0 : goto out;
913 : : }
914 : :
915 [ # # ][ # # ]: 0 : if (*s == '!' && options.permit_local_command) {
916 : 0 : s++;
917 : 0 : ssh_local_cmd(s);
918 : 0 : goto out;
919 : : }
920 : :
921 [ # # ]: 0 : if (*s == 'K') {
922 : 0 : delete = 1;
923 : 0 : s++;
924 : : }
925 [ # # ]: 0 : if (*s == 'L')
926 : : local = 1;
927 [ # # ]: 0 : else if (*s == 'R')
928 : : remote = 1;
929 [ # # ]: 0 : else if (*s == 'D')
930 : : dynamic = 1;
931 : : else {
932 : 0 : logit("Invalid command.");
933 : 0 : goto out;
934 : : }
935 : :
936 [ # # ][ # # ]: 0 : if (delete && !compat20) {
937 : 0 : logit("Not supported for SSH protocol version 1.");
938 : 0 : goto out;
939 : : }
940 : :
941 [ # # ]: 0 : while (isspace((u_char)*++s))
942 : : ;
943 : :
944 : : /* XXX update list of forwards in options */
945 [ # # ]: 0 : if (delete) {
946 : 0 : cancel_port = 0;
947 : 0 : cancel_host = hpdelim(&s); /* may be NULL */
948 [ # # ]: 0 : if (s != NULL) {
949 : 0 : cancel_port = a2port(s);
950 : 0 : cancel_host = cleanhostname(cancel_host);
951 : : } else {
952 : 0 : cancel_port = a2port(cancel_host);
953 : 0 : cancel_host = NULL;
954 : : }
955 [ # # ]: 0 : if (cancel_port <= 0) {
956 : 0 : logit("Bad forwarding close port");
957 : 0 : goto out;
958 : : }
959 [ # # ]: 0 : if (remote)
960 : 0 : ok = channel_request_rforward_cancel(cancel_host,
961 : 0 : cancel_port) == 0;
962 [ # # ]: 0 : else if (dynamic)
963 : 0 : ok = channel_cancel_lport_listener(cancel_host,
964 : 0 : cancel_port, 0, options.gateway_ports) > 0;
965 : : else
966 : 0 : ok = channel_cancel_lport_listener(cancel_host,
967 : : cancel_port, CHANNEL_CANCEL_PORT_STATIC,
968 : 0 : options.gateway_ports) > 0;
969 [ # # ]: 0 : if (!ok) {
970 : 0 : logit("Unkown port forwarding.");
971 : 0 : goto out;
972 : : }
973 : 0 : logit("Canceled forwarding.");
974 : : } else {
975 [ # # ]: 0 : if (!parse_forward(&fwd, s, dynamic, remote)) {
976 : 0 : logit("Bad forwarding specification.");
977 : 0 : goto out;
978 : : }
979 [ # # ]: 0 : if (local || dynamic) {
980 [ # # ]: 0 : if (!channel_setup_local_fwd_listener(fwd.listen_host,
981 : 0 : fwd.listen_port, fwd.connect_host,
982 : 0 : fwd.connect_port, options.gateway_ports)) {
983 : 0 : logit("Port forwarding failed.");
984 : 0 : goto out;
985 : : }
986 : : } else {
987 [ # # ]: 0 : if (channel_request_remote_forwarding(fwd.listen_host,
988 : 0 : fwd.listen_port, fwd.connect_host,
989 : 0 : fwd.connect_port) < 0) {
990 : 0 : logit("Port forwarding failed.");
991 : 0 : goto out;
992 : : }
993 : : }
994 : 0 : logit("Forwarding port.");
995 : : }
996 : :
997 : : out:
998 : 0 : signal(SIGINT, handler);
999 : 0 : enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
1000 : 0 : free(cmd);
1001 : 0 : free(fwd.listen_host);
1002 : 0 : free(fwd.connect_host);
1003 : 0 : }
1004 : :
1005 : : /* reasons to suppress output of an escape command in help output */
1006 : : #define SUPPRESS_NEVER 0 /* never suppress, always show */
1007 : : #define SUPPRESS_PROTO1 1 /* don't show in protocol 1 sessions */
1008 : : #define SUPPRESS_MUXCLIENT 2 /* don't show in mux client sessions */
1009 : : #define SUPPRESS_MUXMASTER 4 /* don't show in mux master sessions */
1010 : : #define SUPPRESS_SYSLOG 8 /* don't show when logging to syslog */
1011 : : struct escape_help_text {
1012 : : const char *cmd;
1013 : : const char *text;
1014 : : unsigned int flags;
1015 : : };
1016 : : static struct escape_help_text esc_txt[] = {
1017 : : {".", "terminate session", SUPPRESS_MUXMASTER},
1018 : : {".", "terminate connection (and any multiplexed sessions)",
1019 : : SUPPRESS_MUXCLIENT},
1020 : : {"B", "send a BREAK to the remote system", SUPPRESS_PROTO1},
1021 : : {"C", "open a command line", SUPPRESS_MUXCLIENT},
1022 : : {"R", "request rekey", SUPPRESS_PROTO1},
1023 : : {"V/v", "decrease/increase verbosity (LogLevel)", SUPPRESS_MUXCLIENT},
1024 : : {"^Z", "suspend ssh", SUPPRESS_MUXCLIENT},
1025 : : {"#", "list forwarded connections", SUPPRESS_NEVER},
1026 : : {"&", "background ssh (when waiting for connections to terminate)",
1027 : : SUPPRESS_MUXCLIENT},
1028 : : {"?", "this message", SUPPRESS_NEVER},
1029 : : };
1030 : :
1031 : : static void
1032 : 0 : print_escape_help(Buffer *b, int escape_char, int protocol2, int mux_client,
1033 : : int using_stderr)
1034 : : {
1035 : : unsigned int i, suppress_flags;
1036 : : char string[1024];
1037 : :
1038 : : snprintf(string, sizeof string, "%c?\r\n"
1039 : : "Supported escape sequences:\r\n", escape_char);
1040 : 0 : buffer_append(b, string, strlen(string));
1041 : :
1042 : 0 : suppress_flags = (protocol2 ? 0 : SUPPRESS_PROTO1) |
1043 [ # # ]: 0 : (mux_client ? SUPPRESS_MUXCLIENT : 0) |
1044 [ # # ]: 0 : (mux_client ? 0 : SUPPRESS_MUXMASTER) |
1045 [ # # ]: 0 : (using_stderr ? 0 : SUPPRESS_SYSLOG);
1046 : :
1047 [ # # ]: 0 : for (i = 0; i < sizeof(esc_txt)/sizeof(esc_txt[0]); i++) {
1048 [ # # ]: 0 : if (esc_txt[i].flags & suppress_flags)
1049 : 0 : continue;
1050 : 0 : snprintf(string, sizeof string, " %c%-3s - %s\r\n",
1051 : : escape_char, esc_txt[i].cmd, esc_txt[i].text);
1052 : 0 : buffer_append(b, string, strlen(string));
1053 : : }
1054 : :
1055 : : snprintf(string, sizeof string,
1056 : : " %c%c - send the escape character by typing it twice\r\n"
1057 : : "(Note that escapes are only recognized immediately after "
1058 : : "newline.)\r\n", escape_char, escape_char);
1059 : 0 : buffer_append(b, string, strlen(string));
1060 : 0 : }
1061 : :
1062 : : /*
1063 : : * Process the characters one by one, call with c==NULL for proto1 case.
1064 : : */
1065 : : static int
1066 : 0 : process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
1067 : : char *buf, int len)
1068 : : {
1069 : : char string[1024];
1070 : : pid_t pid;
1071 : 0 : int bytes = 0;
1072 : : u_int i;
1073 : : u_char ch;
1074 : : char *s;
1075 : : int *escape_pendingp, escape_char;
1076 : : struct escape_filter_ctx *efc;
1077 : :
1078 [ # # ]: 0 : if (c == NULL) {
1079 : 0 : escape_pendingp = &escape_pending1;
1080 : 0 : escape_char = escape_char1;
1081 : : } else {
1082 [ # # ]: 0 : if (c->filter_ctx == NULL)
1083 : : return 0;
1084 : 0 : efc = (struct escape_filter_ctx *)c->filter_ctx;
1085 : 0 : escape_pendingp = &efc->escape_pending;
1086 : 0 : escape_char = efc->escape_char;
1087 : : }
1088 : :
1089 [ # # ]: 0 : if (len <= 0)
1090 : : return (0);
1091 : :
1092 [ # # ]: 0 : for (i = 0; i < (u_int)len; i++) {
1093 : : /* Get one character at a time. */
1094 : 0 : ch = buf[i];
1095 : :
1096 [ # # ]: 0 : if (*escape_pendingp) {
1097 : : /* We have previously seen an escape character. */
1098 : : /* Clear the flag now. */
1099 : 0 : *escape_pendingp = 0;
1100 : :
1101 : : /* Process the escaped character. */
1102 [ # # # # : 0 : switch (ch) {
# # # # #
# ]
1103 : : case '.':
1104 : : /* Terminate the connection. */
1105 : : snprintf(string, sizeof string, "%c.\r\n",
1106 : : escape_char);
1107 : 0 : buffer_append(berr, string, strlen(string));
1108 : :
1109 [ # # ][ # # ]: 0 : if (c && c->ctl_chan != -1) {
1110 : 0 : chan_read_failed(c);
1111 : 0 : chan_write_failed(c);
1112 [ # # ]: 0 : if (c->detach_user)
1113 : 0 : c->detach_user(c->self, NULL);
1114 : 0 : c->type = SSH_CHANNEL_ABANDONED;
1115 : 0 : buffer_clear(&c->input);
1116 : 0 : chan_ibuf_empty(c);
1117 : 0 : return 0;
1118 : : } else
1119 : 0 : quit_pending = 1;
1120 : 0 : return -1;
1121 : :
1122 : : case 'Z' - 64:
1123 : : /* XXX support this for mux clients */
1124 [ # # ][ # # ]: 0 : if (c && c->ctl_chan != -1) {
1125 : : char b[16];
1126 : : noescape:
1127 [ # # ]: 0 : if (ch == 'Z' - 64)
1128 : : snprintf(b, sizeof b, "^Z");
1129 : : else
1130 : 0 : snprintf(b, sizeof b, "%c", ch);
1131 : : snprintf(string, sizeof string,
1132 : : "%c%s escape not available to "
1133 : : "multiplexed sessions\r\n",
1134 : : escape_char, b);
1135 : 0 : buffer_append(berr, string,
1136 : 0 : strlen(string));
1137 : 0 : continue;
1138 : : }
1139 : : /* Suspend the program. Inform the user */
1140 : : snprintf(string, sizeof string,
1141 : : "%c^Z [suspend ssh]\r\n", escape_char);
1142 : 0 : buffer_append(berr, string, strlen(string));
1143 : :
1144 : : /* Restore terminal modes and suspend. */
1145 : 0 : client_suspend_self(bin, bout, berr);
1146 : :
1147 : : /* We have been continued. */
1148 : 0 : continue;
1149 : :
1150 : : case 'B':
1151 [ # # ]: 0 : if (compat20) {
1152 : : snprintf(string, sizeof string,
1153 : : "%cB\r\n", escape_char);
1154 : 0 : buffer_append(berr, string,
1155 : 0 : strlen(string));
1156 : 0 : channel_request_start(c->self,
1157 : : "break", 0);
1158 : 0 : packet_put_int(1000);
1159 : 0 : packet_send();
1160 : : }
1161 : 0 : continue;
1162 : :
1163 : : case 'R':
1164 [ # # ]: 0 : if (compat20) {
1165 [ # # ]: 0 : if (datafellows & SSH_BUG_NOREKEY)
1166 : 0 : logit("Server does not "
1167 : : "support re-keying");
1168 : : else
1169 : 0 : need_rekeying = 1;
1170 : : }
1171 : 0 : continue;
1172 : :
1173 : : case 'V':
1174 : : /* FALLTHROUGH */
1175 : : case 'v':
1176 [ # # ][ # # ]: 0 : if (c && c->ctl_chan != -1)
1177 : : goto noescape;
1178 [ # # ]: 0 : if (!log_is_on_stderr()) {
1179 : 0 : snprintf(string, sizeof string,
1180 : : "%c%c [Logging to syslog]\r\n",
1181 : : escape_char, ch);
1182 : 0 : buffer_append(berr, string,
1183 : 0 : strlen(string));
1184 : 0 : continue;
1185 : : }
1186 [ # # ][ # # ]: 0 : if (ch == 'V' && options.log_level >
1187 : : SYSLOG_LEVEL_QUIET)
1188 : 0 : log_change_level(--options.log_level);
1189 [ # # ][ # # ]: 0 : if (ch == 'v' && options.log_level <
1190 : : SYSLOG_LEVEL_DEBUG3)
1191 : 0 : log_change_level(++options.log_level);
1192 : 0 : snprintf(string, sizeof string,
1193 : : "%c%c [LogLevel %s]\r\n", escape_char, ch,
1194 : : log_level_name(options.log_level));
1195 : 0 : buffer_append(berr, string, strlen(string));
1196 : 0 : continue;
1197 : :
1198 : : case '&':
1199 [ # # ][ # # ]: 0 : if (c && c->ctl_chan != -1)
1200 : : goto noescape;
1201 : : /*
1202 : : * Detach the program (continue to serve
1203 : : * connections, but put in background and no
1204 : : * more new connections).
1205 : : */
1206 : : /* Restore tty modes. */
1207 : 0 : leave_raw_mode(
1208 : 0 : options.request_tty == REQUEST_TTY_FORCE);
1209 : :
1210 : : /* Stop listening for new connections. */
1211 : 0 : channel_stop_listening();
1212 : :
1213 : : snprintf(string, sizeof string,
1214 : : "%c& [backgrounded]\n", escape_char);
1215 : 0 : buffer_append(berr, string, strlen(string));
1216 : :
1217 : : /* Fork into background. */
1218 : 0 : pid = fork();
1219 [ # # ]: 0 : if (pid < 0) {
1220 : 0 : error("fork: %.100s", strerror(errno));
1221 : 0 : continue;
1222 : : }
1223 [ # # ]: 0 : if (pid != 0) { /* This is the parent. */
1224 : : /* The parent just exits. */
1225 : 0 : exit(0);
1226 : : }
1227 : : /* The child continues serving connections. */
1228 [ # # ]: 0 : if (compat20) {
1229 : 0 : buffer_append(bin, "\004", 1);
1230 : : /* fake EOF on stdin */
1231 : 0 : return -1;
1232 [ # # ]: 0 : } else if (!stdin_eof) {
1233 : : /*
1234 : : * Sending SSH_CMSG_EOF alone does not
1235 : : * always appear to be enough. So we
1236 : : * try to send an EOF character first.
1237 : : */
1238 : 0 : packet_start(SSH_CMSG_STDIN_DATA);
1239 : 0 : packet_put_string("\004", 1);
1240 : 0 : packet_send();
1241 : : /* Close stdin. */
1242 : 0 : stdin_eof = 1;
1243 [ # # ]: 0 : if (buffer_len(bin) == 0) {
1244 : 0 : packet_start(SSH_CMSG_EOF);
1245 : 0 : packet_send();
1246 : : }
1247 : : }
1248 : 0 : continue;
1249 : :
1250 : : case '?':
1251 [ # # ][ # # ]: 0 : print_escape_help(berr, escape_char, compat20,
1252 : 0 : (c && c->ctl_chan != -1),
1253 : : log_is_on_stderr());
1254 : 0 : continue;
1255 : :
1256 : : case '#':
1257 : : snprintf(string, sizeof string, "%c#\r\n",
1258 : : escape_char);
1259 : 0 : buffer_append(berr, string, strlen(string));
1260 : 0 : s = channel_open_message();
1261 : 0 : buffer_append(berr, s, strlen(s));
1262 : 0 : free(s);
1263 : 0 : continue;
1264 : :
1265 : : case 'C':
1266 [ # # ][ # # ]: 0 : if (c && c->ctl_chan != -1)
1267 : : goto noescape;
1268 : 0 : process_cmdline();
1269 : 0 : continue;
1270 : :
1271 : : default:
1272 [ # # ]: 0 : if (ch != escape_char) {
1273 : 0 : buffer_put_char(bin, escape_char);
1274 : 0 : bytes++;
1275 : : }
1276 : : /* Escaped characters fall through here */
1277 : : break;
1278 : : }
1279 : : } else {
1280 : : /*
1281 : : * The previous character was not an escape char.
1282 : : * Check if this is an escape.
1283 : : */
1284 [ # # ][ # # ]: 0 : if (last_was_cr && ch == escape_char) {
1285 : : /*
1286 : : * It is. Set the flag and continue to
1287 : : * next character.
1288 : : */
1289 : 0 : *escape_pendingp = 1;
1290 : 0 : continue;
1291 : : }
1292 : : }
1293 : :
1294 : : /*
1295 : : * Normal character. Record whether it was a newline,
1296 : : * and append it to the buffer.
1297 : : */
1298 : 0 : last_was_cr = (ch == '\r' || ch == '\n');
1299 : 0 : buffer_put_char(bin, ch);
1300 : 0 : bytes++;
1301 : : }
1302 : : return bytes;
1303 : : }
1304 : :
1305 : : static void
1306 : 4559 : client_process_input(fd_set *readset)
1307 : : {
1308 : : int len;
1309 : : char buf[SSH_IOBUFSZ];
1310 : :
1311 : : /* Read input from stdin. */
1312 [ - + ][ # # ]: 4559 : if (FD_ISSET(fileno(stdin), readset)) {
[ + + ]
1313 : : /* Read as much as possible. */
1314 : 1015 : len = read(fileno(stdin), buf, sizeof(buf));
1315 [ - + # # ]: 1015 : if (len < 0 &&
1316 [ # # ]: 0 : (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
1317 : 0 : return; /* we'll try again later */
1318 [ + + ]: 1015 : if (len <= 0) {
1319 : : /*
1320 : : * Received EOF or error. They are treated
1321 : : * similarly, except that an error message is printed
1322 : : * if it was an error condition.
1323 : : */
1324 [ - + ]: 7 : if (len < 0) {
1325 : 0 : snprintf(buf, sizeof buf, "read: %.100s\r\n",
1326 : 0 : strerror(errno));
1327 : 0 : buffer_append(&stderr_buffer, buf, strlen(buf));
1328 : : }
1329 : : /* Mark that we have seen EOF. */
1330 : 7 : stdin_eof = 1;
1331 : : /*
1332 : : * Send an EOF message to the server unless there is
1333 : : * data in the buffer. If there is data in the
1334 : : * buffer, no message will be sent now. Code
1335 : : * elsewhere will send the EOF when the buffer
1336 : : * becomes empty if stdin_eof is set.
1337 : : */
1338 [ + - ]: 7 : if (buffer_len(&stdin_buffer) == 0) {
1339 : 7 : packet_start(SSH_CMSG_EOF);
1340 : 7 : packet_send();
1341 : : }
1342 [ + - ]: 1008 : } else if (escape_char1 == SSH_ESCAPECHAR_NONE) {
1343 : : /*
1344 : : * Normal successful read, and no escape character.
1345 : : * Just append the data to buffer.
1346 : : */
1347 : 1008 : buffer_append(&stdin_buffer, buf, len);
1348 : : } else {
1349 : : /*
1350 : : * Normal, successful read. But we have an escape
1351 : : * character and have to process the characters one
1352 : : * by one.
1353 : : */
1354 [ # # ]: 4559 : if (process_escapes(NULL, &stdin_buffer,
1355 : : &stdout_buffer, &stderr_buffer, buf, len) == -1)
1356 : : return;
1357 : : }
1358 : : }
1359 : : }
1360 : :
1361 : : static void
1362 : 4559 : client_process_output(fd_set *writeset)
1363 : : {
1364 : : int len;
1365 : : char buf[100];
1366 : :
1367 : : /* Write buffered output to stdout. */
1368 [ - + ][ # # ]: 4559 : if (FD_ISSET(fileno(stdout), writeset)) {
[ + + ]
1369 : : /* Write as much data as possible. */
1370 : 298 : len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
1371 : 298 : buffer_len(&stdout_buffer));
1372 [ - + ]: 298 : if (len <= 0) {
1373 [ # # ][ # # ]: 0 : if (errno == EINTR || errno == EAGAIN ||
1374 : : errno == EWOULDBLOCK)
1375 : : len = 0;
1376 : : else {
1377 : : /*
1378 : : * An error or EOF was encountered. Put an
1379 : : * error message to stderr buffer.
1380 : : */
1381 : 0 : snprintf(buf, sizeof buf,
1382 : : "write stdout: %.50s\r\n", strerror(errno));
1383 : 0 : buffer_append(&stderr_buffer, buf, strlen(buf));
1384 : 0 : quit_pending = 1;
1385 : 0 : return;
1386 : : }
1387 : : }
1388 : : /* Consume printed data from the buffer. */
1389 : 298 : buffer_consume(&stdout_buffer, len);
1390 : : }
1391 : : /* Write buffered output to stderr. */
1392 [ - + ][ # # ]: 4559 : if (FD_ISSET(fileno(stderr), writeset)) {
[ + + ]
1393 : : /* Write as much data as possible. */
1394 : 284 : len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
1395 : 284 : buffer_len(&stderr_buffer));
1396 [ - + ]: 284 : if (len <= 0) {
1397 [ # # ][ # # ]: 0 : if (errno == EINTR || errno == EAGAIN ||
1398 : : errno == EWOULDBLOCK)
1399 : : len = 0;
1400 : : else {
1401 : : /*
1402 : : * EOF or error, but can't even print
1403 : : * error message.
1404 : : */
1405 : 0 : quit_pending = 1;
1406 : 0 : return;
1407 : : }
1408 : : }
1409 : : /* Consume printed characters from the buffer. */
1410 : 4559 : buffer_consume(&stderr_buffer, len);
1411 : : }
1412 : : }
1413 : :
1414 : : /*
1415 : : * Get packets from the connection input buffer, and process them as long as
1416 : : * there are packets available.
1417 : : *
1418 : : * Any unknown packets received during the actual
1419 : : * session cause the session to terminate. This is
1420 : : * intended to make debugging easier since no
1421 : : * confirmations are sent. Any compatible protocol
1422 : : * extensions must be negotiated during the
1423 : : * preparatory phase.
1424 : : */
1425 : :
1426 : : static void
1427 : 36440 : client_process_buffered_input_packets(void)
1428 : : {
1429 [ + + ]: 36440 : dispatch_run(DISPATCH_NONBLOCK, &quit_pending,
1430 : 36440 : compat20 ? xxx_kex : NULL);
1431 : 36440 : }
1432 : :
1433 : : /* scan buf[] for '~' before sending data to the peer */
1434 : :
1435 : : /* Helper: allocate a new escape_filter_ctx and fill in its escape char */
1436 : : void *
1437 : 0 : client_new_escape_filter_ctx(int escape_char)
1438 : : {
1439 : : struct escape_filter_ctx *ret;
1440 : :
1441 : 0 : ret = xcalloc(1, sizeof(*ret));
1442 : 0 : ret->escape_pending = 0;
1443 : 0 : ret->escape_char = escape_char;
1444 : 0 : return (void *)ret;
1445 : : }
1446 : :
1447 : : /* Free the escape filter context on channel free */
1448 : : void
1449 : 0 : client_filter_cleanup(int cid, void *ctx)
1450 : : {
1451 : 0 : free(ctx);
1452 : 0 : }
1453 : :
1454 : : int
1455 : 0 : client_simple_escape_filter(Channel *c, char *buf, int len)
1456 : : {
1457 [ # # ]: 0 : if (c->extended_usage != CHAN_EXTENDED_WRITE)
1458 : : return 0;
1459 : :
1460 : 0 : return process_escapes(c, &c->input, &c->output, &c->extended,
1461 : : buf, len);
1462 : : }
1463 : :
1464 : : static void
1465 : 686 : client_channel_closed(int id, void *arg)
1466 : : {
1467 : 686 : channel_cancel_cleanup(id);
1468 : 686 : session_closed = 1;
1469 : 686 : leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
1470 : 686 : }
1471 : :
1472 : : /*
1473 : : * Implements the interactive session with the server. This is called after
1474 : : * the user has been authenticated, and a command has been started on the
1475 : : * remote host. If escape_char != SSH_ESCAPECHAR_NONE, it is the character
1476 : : * used as an escape character for terminating or suspending the session.
1477 : : */
1478 : :
1479 : : int
1480 : 749 : client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1481 : : {
1482 : 749 : fd_set *readset = NULL, *writeset = NULL;
1483 : : double start_time, total_time;
1484 : 749 : int max_fd = 0, max_fd2 = 0, len, rekeying = 0;
1485 : : u_int64_t ibytes, obytes;
1486 : 749 : u_int nalloc = 0;
1487 : : char buf[100];
1488 : :
1489 : 749 : debug("Entering interactive session.");
1490 : :
1491 : 749 : start_time = get_current_time();
1492 : :
1493 : : /* Initialize variables. */
1494 : 749 : escape_pending1 = 0;
1495 : 749 : last_was_cr = 1;
1496 : 749 : exit_status = -1;
1497 : 749 : stdin_eof = 0;
1498 : 749 : buffer_high = 64 * 1024;
1499 : 749 : connection_in = packet_get_connection_in();
1500 : 749 : connection_out = packet_get_connection_out();
1501 : 749 : max_fd = MAX(connection_in, connection_out);
1502 : :
1503 [ + + ]: 749 : if (!compat20) {
1504 : : /* enable nonblocking unless tty */
1505 [ + + ]: 61 : if (!isatty(fileno(stdin)))
1506 : 8 : set_nonblock(fileno(stdin));
1507 [ + + ]: 61 : if (!isatty(fileno(stdout)))
1508 : 19 : set_nonblock(fileno(stdout));
1509 [ + + ]: 61 : if (!isatty(fileno(stderr)))
1510 : 6 : set_nonblock(fileno(stderr));
1511 [ - + ]: 61 : max_fd = MAX(max_fd, fileno(stdin));
1512 [ - + ]: 61 : max_fd = MAX(max_fd, fileno(stdout));
1513 [ - + ]: 61 : max_fd = MAX(max_fd, fileno(stderr));
1514 : : }
1515 : 749 : quit_pending = 0;
1516 : 749 : escape_char1 = escape_char_arg;
1517 : :
1518 : : /* Initialize buffers. */
1519 : 749 : buffer_init(&stdin_buffer);
1520 : 749 : buffer_init(&stdout_buffer);
1521 : 749 : buffer_init(&stderr_buffer);
1522 : :
1523 : 749 : client_init_dispatch();
1524 : :
1525 : : /*
1526 : : * Set signal handlers, (e.g. to restore non-blocking mode)
1527 : : * but don't overwrite SIG_IGN, matches behaviour from rsh(1)
1528 : : */
1529 [ + - ]: 749 : if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1530 : 749 : signal(SIGHUP, signal_handler);
1531 [ + + ]: 749 : if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1532 : 741 : signal(SIGINT, signal_handler);
1533 [ + + ]: 749 : if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1534 : 741 : signal(SIGQUIT, signal_handler);
1535 [ + - ]: 749 : if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
1536 : 749 : signal(SIGTERM, signal_handler);
1537 : 749 : signal(SIGWINCH, window_change_handler);
1538 : :
1539 [ - + ]: 749 : if (have_pty)
1540 : 0 : enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
1541 : :
1542 [ + + ]: 749 : if (compat20) {
1543 : 688 : session_ident = ssh2_chan_id;
1544 [ + + ]: 688 : if (session_ident != -1) {
1545 [ - + ]: 686 : if (escape_char_arg != SSH_ESCAPECHAR_NONE) {
1546 : 0 : channel_register_filter(session_ident,
1547 : : client_simple_escape_filter, NULL,
1548 : : client_filter_cleanup,
1549 : : client_new_escape_filter_ctx(
1550 : : escape_char_arg));
1551 : : }
1552 : 749 : channel_register_cleanup(session_ident,
1553 : : client_channel_closed, 0);
1554 : : }
1555 : : } else {
1556 : : /* Check if we should immediately send eof on stdin. */
1557 : 61 : client_check_initial_eof_on_stdin();
1558 : : }
1559 : :
1560 : : /* Main loop of the client for the interactive session mode. */
1561 [ + - ]: 36440 : while (!quit_pending) {
1562 : :
1563 : : /* Process buffered packets sent by the server. */
1564 : 36440 : client_process_buffered_input_packets();
1565 : :
1566 [ + + ][ + + ]: 36440 : if (compat20 && session_closed && !channel_still_open())
[ + + ]
1567 : : break;
1568 : :
1569 [ + + ][ + + ]: 35753 : rekeying = (xxx_kex != NULL && !xxx_kex->done);
1570 : :
1571 [ + + ]: 35753 : if (rekeying) {
1572 : 2079 : debug("rekeying in progress");
1573 : : } else {
1574 : : /*
1575 : : * Make packets of buffered stdin data, and buffer
1576 : : * them for sending to the server.
1577 : : */
1578 [ + + ]: 33674 : if (!compat20)
1579 : 4620 : client_make_packets_from_stdin_data();
1580 : :
1581 : : /*
1582 : : * Make packets from buffered channel data, and
1583 : : * enqueue them for sending to the server.
1584 : : */
1585 [ + + ]: 33674 : if (packet_not_very_much_data_to_write())
1586 : 27551 : channel_output_poll();
1587 : :
1588 : : /*
1589 : : * Check if the window size has changed, and buffer a
1590 : : * message about it to the server if so.
1591 : : */
1592 : 33674 : client_check_window_change();
1593 : :
1594 [ + + ]: 33674 : if (quit_pending)
1595 : : break;
1596 : : }
1597 : : /*
1598 : : * Wait until we have something to do (something becomes
1599 : : * available on one of the descriptors).
1600 : : */
1601 : 35692 : max_fd2 = max_fd;
1602 : 35692 : client_wait_until_can_do_something(&readset, &writeset,
1603 : : &max_fd2, &nalloc, rekeying);
1604 : :
1605 [ + - ]: 35692 : if (quit_pending)
1606 : : break;
1607 : :
1608 : : /* Do channel operations unless rekeying in progress. */
1609 [ + + ]: 35692 : if (!rekeying) {
1610 : 33613 : channel_after_select(readset, writeset);
1611 [ + - ][ + + ]: 33613 : if (need_rekeying || packet_need_rekeying()) {
1612 : 448 : debug("need rekeying");
1613 : 448 : xxx_kex->done = 0;
1614 : 448 : kex_send_kexinit(xxx_kex);
1615 : 448 : need_rekeying = 0;
1616 : : }
1617 : : }
1618 : :
1619 : : /* Buffer input from the connection. */
1620 : 35692 : client_process_net_input(readset);
1621 : :
1622 [ + + ]: 35692 : if (quit_pending)
1623 : : break;
1624 : :
1625 [ + + ]: 35691 : if (!compat20) {
1626 : : /* Buffer data from stdin */
1627 : 4559 : client_process_input(readset);
1628 : : /*
1629 : : * Process output to stdout and stderr. Output to
1630 : : * the connection is processed elsewhere (above).
1631 : : */
1632 : 4559 : client_process_output(writeset);
1633 : : }
1634 : :
1635 [ - + ]: 35691 : if (session_resumed) {
1636 : 0 : connection_in = packet_get_connection_in();
1637 : 0 : connection_out = packet_get_connection_out();
1638 : 0 : max_fd = MAX(max_fd, connection_out);
1639 : 0 : max_fd = MAX(max_fd, connection_in);
1640 : 0 : session_resumed = 0;
1641 : : }
1642 : :
1643 : : /*
1644 : : * Send as much buffered packet data as possible to the
1645 : : * sender.
1646 : : */
1647 [ - + ][ # # ]: 35691 : if (FD_ISSET(connection_out, writeset))
[ + + ]
1648 : 12132 : packet_write_poll();
1649 : :
1650 : : /*
1651 : : * If we are a backgrounded control master, and the
1652 : : * timeout has expired without any active client
1653 : : * connections, then quit.
1654 : : */
1655 [ - + ]: 35691 : if (control_persist_exit_time > 0) {
1656 [ # # ]: 0 : if (monotime() >= control_persist_exit_time) {
1657 : 0 : debug("ControlPersist timeout expired");
1658 : 35691 : break;
1659 : : }
1660 : : }
1661 : : }
1662 : 749 : free(readset);
1663 : 749 : free(writeset);
1664 : :
1665 : : /* Terminate the session. */
1666 : :
1667 : : /* Stop watching for window change. */
1668 : 749 : signal(SIGWINCH, SIG_DFL);
1669 : :
1670 [ + + ]: 749 : if (compat20) {
1671 : 688 : packet_start(SSH2_MSG_DISCONNECT);
1672 : 688 : packet_put_int(SSH2_DISCONNECT_BY_APPLICATION);
1673 : 688 : packet_put_cstring("disconnected by user");
1674 : 688 : packet_put_cstring(""); /* language tag */
1675 : 688 : packet_send();
1676 : 688 : packet_write_wait();
1677 : : }
1678 : :
1679 : 749 : channel_free_all();
1680 : :
1681 [ - + ]: 749 : if (have_pty)
1682 : 0 : leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
1683 : :
1684 : : /* restore blocking io */
1685 [ + + ]: 749 : if (!isatty(fileno(stdin)))
1686 : 105 : unset_nonblock(fileno(stdin));
1687 [ + + ]: 749 : if (!isatty(fileno(stdout)))
1688 : 200 : unset_nonblock(fileno(stdout));
1689 [ + + ]: 749 : if (!isatty(fileno(stderr)))
1690 : 178 : unset_nonblock(fileno(stderr));
1691 : :
1692 : : /*
1693 : : * If there was no shell or command requested, there will be no remote
1694 : : * exit status to be returned. In that case, clear error code if the
1695 : : * connection was deliberately terminated at this end.
1696 : : */
1697 [ + + ][ - + ]: 749 : if (no_shell_flag && received_signal == SIGTERM) {
1698 : 0 : received_signal = 0;
1699 : 0 : exit_status = 0;
1700 : : }
1701 : :
1702 [ - + ]: 749 : if (received_signal)
1703 : 0 : fatal("Killed by signal %d.", (int) received_signal);
1704 : :
1705 : : /*
1706 : : * In interactive mode (with pseudo tty) display a message indicating
1707 : : * that the connection has been closed.
1708 : : */
1709 [ - + ][ # # ]: 749 : if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
1710 : 0 : snprintf(buf, sizeof buf,
1711 : : "Connection to %.64s closed.\r\n", host);
1712 : 0 : buffer_append(&stderr_buffer, buf, strlen(buf));
1713 : : }
1714 : :
1715 : : /* Output any buffered data for stdout. */
1716 [ + + ]: 749 : if (buffer_len(&stdout_buffer) > 0) {
1717 : 9 : len = atomicio(vwrite, fileno(stdout),
1718 : 9 : buffer_ptr(&stdout_buffer), buffer_len(&stdout_buffer));
1719 [ + - ][ - + ]: 9 : if (len < 0 || (u_int)len != buffer_len(&stdout_buffer))
1720 : 0 : error("Write failed flushing stdout buffer.");
1721 : : else
1722 : 9 : buffer_consume(&stdout_buffer, len);
1723 : : }
1724 : :
1725 : : /* Output any buffered data for stderr. */
1726 [ + + ]: 749 : if (buffer_len(&stderr_buffer) > 0) {
1727 : 5 : len = atomicio(vwrite, fileno(stderr),
1728 : 5 : buffer_ptr(&stderr_buffer), buffer_len(&stderr_buffer));
1729 [ + - ][ - + ]: 5 : if (len < 0 || (u_int)len != buffer_len(&stderr_buffer))
1730 : 0 : error("Write failed flushing stderr buffer.");
1731 : : else
1732 : 5 : buffer_consume(&stderr_buffer, len);
1733 : : }
1734 : :
1735 : : /* Clear and free any buffers. */
1736 : : memset(buf, 0, sizeof(buf));
1737 : 749 : buffer_free(&stdin_buffer);
1738 : 749 : buffer_free(&stdout_buffer);
1739 : 749 : buffer_free(&stderr_buffer);
1740 : :
1741 : : /* Report bytes transferred, and transfer rates. */
1742 : 749 : total_time = get_current_time() - start_time;
1743 : 749 : packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes);
1744 : 749 : packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
1745 : 749 : verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds",
1746 : : (unsigned long long)obytes, (unsigned long long)ibytes, total_time);
1747 [ + - ]: 749 : if (total_time > 0)
1748 : 749 : verbose("Bytes per second: sent %.1f, received %.1f",
1749 : : obytes / total_time, ibytes / total_time);
1750 : : /* Return the exit status of the program. */
1751 : 749 : debug("Exit status %d", exit_status);
1752 : 749 : return exit_status;
1753 : : }
1754 : :
1755 : : /*********/
1756 : :
1757 : : static void
1758 : 307 : client_input_stdout_data(int type, u_int32_t seq, void *ctxt)
1759 : : {
1760 : : u_int data_len;
1761 : 307 : char *data = packet_get_string(&data_len);
1762 [ - + ]: 307 : packet_check_eom();
1763 : 307 : buffer_append(&stdout_buffer, data, data_len);
1764 : 307 : explicit_bzero(data, data_len);
1765 : 307 : free(data);
1766 : 307 : }
1767 : : static void
1768 : 289 : client_input_stderr_data(int type, u_int32_t seq, void *ctxt)
1769 : : {
1770 : : u_int data_len;
1771 : 289 : char *data = packet_get_string(&data_len);
1772 [ - + ]: 289 : packet_check_eom();
1773 : 289 : buffer_append(&stderr_buffer, data, data_len);
1774 : 289 : explicit_bzero(data, data_len);
1775 : 289 : free(data);
1776 : 289 : }
1777 : : static void
1778 : 61 : client_input_exit_status(int type, u_int32_t seq, void *ctxt)
1779 : : {
1780 : 61 : exit_status = packet_get_int();
1781 [ - + ]: 61 : packet_check_eom();
1782 : : /* Acknowledge the exit. */
1783 : 61 : packet_start(SSH_CMSG_EXIT_CONFIRMATION);
1784 : 61 : packet_send();
1785 : : /*
1786 : : * Must wait for packet to be sent since we are
1787 : : * exiting the loop.
1788 : : */
1789 : 61 : packet_write_wait();
1790 : : /* Flag that we want to exit. */
1791 : 61 : quit_pending = 1;
1792 : 61 : }
1793 : : static void
1794 : 2 : client_input_agent_open(int type, u_int32_t seq, void *ctxt)
1795 : : {
1796 : 2 : Channel *c = NULL;
1797 : : int remote_id, sock;
1798 : :
1799 : : /* Read the remote channel number from the message. */
1800 : 2 : remote_id = packet_get_int();
1801 [ - + ]: 2 : packet_check_eom();
1802 : :
1803 : : /*
1804 : : * Get a connection to the local authentication agent (this may again
1805 : : * get forwarded).
1806 : : */
1807 : 2 : sock = ssh_get_authentication_socket();
1808 : :
1809 : : /*
1810 : : * If we could not connect the agent, send an error message back to
1811 : : * the server. This should never happen unless the agent dies,
1812 : : * because authentication forwarding is only enabled if we have an
1813 : : * agent.
1814 : : */
1815 [ + - ]: 2 : if (sock >= 0) {
1816 : 2 : c = channel_new("", SSH_CHANNEL_OPEN, sock, sock,
1817 : : -1, 0, 0, 0, "authentication agent connection", 1);
1818 : 2 : c->remote_id = remote_id;
1819 : 2 : c->force_drain = 1;
1820 : : }
1821 [ - + ]: 2 : if (c == NULL) {
1822 : 0 : packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
1823 : 0 : packet_put_int(remote_id);
1824 : : } else {
1825 : : /* Send a confirmation to the remote host. */
1826 : 2 : debug("Forwarding authentication connection.");
1827 : 2 : packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
1828 : 2 : packet_put_int(remote_id);
1829 : 2 : packet_put_int(c->self);
1830 : : }
1831 : 2 : packet_send();
1832 : 2 : }
1833 : :
1834 : : static Channel *
1835 : 20 : client_request_forwarded_tcpip(const char *request_type, int rchan)
1836 : : {
1837 : 10 : Channel *c = NULL;
1838 : : char *listen_address, *originator_address;
1839 : : u_short listen_port, originator_port;
1840 : :
1841 : : /* Get rest of the packet */
1842 : 10 : listen_address = packet_get_string(NULL);
1843 : 10 : listen_port = packet_get_int();
1844 : 10 : originator_address = packet_get_string(NULL);
1845 : 10 : originator_port = packet_get_int();
1846 [ - + ]: 10 : packet_check_eom();
1847 : :
1848 : 10 : debug("client_request_forwarded_tcpip: listen %s port %d, "
1849 : : "originator %s port %d", listen_address, listen_port,
1850 : : originator_address, originator_port);
1851 : :
1852 : 10 : c = channel_connect_by_listen_address(listen_port,
1853 : : "forwarded-tcpip", originator_address);
1854 : :
1855 : 10 : free(originator_address);
1856 : 10 : free(listen_address);
1857 : 10 : return c;
1858 : : }
1859 : :
1860 : : static Channel *
1861 : 0 : client_request_x11(const char *request_type, int rchan)
1862 : : {
1863 : 0 : Channel *c = NULL;
1864 : : char *originator;
1865 : : u_short originator_port;
1866 : : int sock;
1867 : :
1868 [ # # ]: 0 : if (!options.forward_x11) {
1869 : 0 : error("Warning: ssh server tried X11 forwarding.");
1870 : 0 : error("Warning: this is probably a break-in attempt by a "
1871 : : "malicious server.");
1872 : : return NULL;
1873 : : }
1874 [ # # ][ # # ]: 0 : if (x11_refuse_time != 0 && monotime() >= x11_refuse_time) {
1875 : 0 : verbose("Rejected X11 connection after ForwardX11Timeout "
1876 : : "expired");
1877 : : return NULL;
1878 : : }
1879 : 0 : originator = packet_get_string(NULL);
1880 [ # # ]: 0 : if (datafellows & SSH_BUG_X11FWD) {
1881 : 0 : debug2("buggy server: x11 request w/o originator_port");
1882 : 0 : originator_port = 0;
1883 : : } else {
1884 : 0 : originator_port = packet_get_int();
1885 : : }
1886 [ # # ]: 0 : packet_check_eom();
1887 : : /* XXX check permission */
1888 : 0 : debug("client_request_x11: request from %s %d", originator,
1889 : : originator_port);
1890 : 0 : free(originator);
1891 : 0 : sock = x11_connect_display();
1892 [ # # ]: 0 : if (sock < 0)
1893 : : return NULL;
1894 : 0 : c = channel_new("x11",
1895 : : SSH_CHANNEL_X11_OPEN, sock, sock, -1,
1896 : : CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1);
1897 : 0 : c->force_drain = 1;
1898 : : return c;
1899 : : }
1900 : :
1901 : : static Channel *
1902 : 4 : client_request_agent(const char *request_type, int rchan)
1903 : : {
1904 : 2 : Channel *c = NULL;
1905 : : int sock;
1906 : :
1907 [ - + ]: 2 : if (!options.forward_agent) {
1908 : 0 : error("Warning: ssh server tried agent forwarding.");
1909 : 0 : error("Warning: this is probably a break-in attempt by a "
1910 : : "malicious server.");
1911 : : return NULL;
1912 : : }
1913 : 2 : sock = ssh_get_authentication_socket();
1914 [ + - ]: 2 : if (sock < 0)
1915 : : return NULL;
1916 : 2 : c = channel_new("authentication agent connection",
1917 : : SSH_CHANNEL_OPEN, sock, sock, -1,
1918 : : CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
1919 : : "authentication agent connection", 1);
1920 : 2 : c->force_drain = 1;
1921 : : return c;
1922 : : }
1923 : :
1924 : : int
1925 : 0 : client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun)
1926 : : {
1927 : : Channel *c;
1928 : : int fd;
1929 : :
1930 [ # # ]: 0 : if (tun_mode == SSH_TUNMODE_NO)
1931 : : return 0;
1932 : :
1933 [ # # ]: 0 : if (!compat20) {
1934 : 0 : error("Tunnel forwarding is not supported for protocol 1");
1935 : 0 : return -1;
1936 : : }
1937 : :
1938 : 0 : debug("Requesting tun unit %d in mode %d", local_tun, tun_mode);
1939 : :
1940 : : /* Open local tunnel device */
1941 [ # # ]: 0 : if ((fd = tun_open(local_tun, tun_mode)) == -1) {
1942 : 0 : error("Tunnel device open failed.");
1943 : 0 : return -1;
1944 : : }
1945 : :
1946 : 0 : c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1,
1947 : : CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
1948 : 0 : c->datagram = 1;
1949 : :
1950 : : #if defined(SSH_TUN_FILTER)
1951 [ # # ]: 0 : if (options.tun_open == SSH_TUNMODE_POINTOPOINT)
1952 : 0 : channel_register_filter(c->self, sys_tun_infilter,
1953 : : sys_tun_outfilter, NULL, NULL);
1954 : : #endif
1955 : :
1956 : 0 : packet_start(SSH2_MSG_CHANNEL_OPEN);
1957 : 0 : packet_put_cstring("tun@openssh.com");
1958 : 0 : packet_put_int(c->self);
1959 : 0 : packet_put_int(c->local_window_max);
1960 : 0 : packet_put_int(c->local_maxpacket);
1961 : 0 : packet_put_int(tun_mode);
1962 : 0 : packet_put_int(remote_tun);
1963 : 0 : packet_send();
1964 : :
1965 : 0 : return 0;
1966 : : }
1967 : :
1968 : : /* XXXX move to generic input handler */
1969 : : static void
1970 : 12 : client_input_channel_open(int type, u_int32_t seq, void *ctxt)
1971 : : {
1972 : 12 : Channel *c = NULL;
1973 : : char *ctype;
1974 : : int rchan;
1975 : : u_int rmaxpack, rwindow, len;
1976 : :
1977 : 12 : ctype = packet_get_string(&len);
1978 : 12 : rchan = packet_get_int();
1979 : 12 : rwindow = packet_get_int();
1980 : 12 : rmaxpack = packet_get_int();
1981 : :
1982 : 12 : debug("client_input_channel_open: ctype %s rchan %d win %d max %d",
1983 : : ctype, rchan, rwindow, rmaxpack);
1984 : :
1985 [ + + ]: 12 : if (strcmp(ctype, "forwarded-tcpip") == 0) {
1986 : 10 : c = client_request_forwarded_tcpip(ctype, rchan);
1987 [ - + ][ # # ]: 2 : } else if (strcmp(ctype, "x11") == 0) {
[ # # ][ - + ]
1988 : 0 : c = client_request_x11(ctype, rchan);
1989 [ + - ]: 2 : } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
1990 : 2 : c = client_request_agent(ctype, rchan);
1991 : : }
1992 : : /* XXX duplicate : */
1993 [ + - ]: 12 : if (c != NULL) {
1994 : 12 : debug("confirm %s", ctype);
1995 : 12 : c->remote_id = rchan;
1996 : 12 : c->remote_window = rwindow;
1997 : 12 : c->remote_maxpacket = rmaxpack;
1998 [ + + ]: 12 : if (c->type != SSH_CHANNEL_CONNECTING) {
1999 : 2 : packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
2000 : 2 : packet_put_int(c->remote_id);
2001 : 2 : packet_put_int(c->self);
2002 : 2 : packet_put_int(c->local_window);
2003 : 2 : packet_put_int(c->local_maxpacket);
2004 : 2 : packet_send();
2005 : : }
2006 : : } else {
2007 : 0 : debug("failure %s", ctype);
2008 : 0 : packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
2009 : 0 : packet_put_int(rchan);
2010 : 0 : packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
2011 [ # # ]: 0 : if (!(datafellows & SSH_BUG_OPENFAILURE)) {
2012 : 0 : packet_put_cstring("open failed");
2013 : 0 : packet_put_cstring("");
2014 : : }
2015 : 0 : packet_send();
2016 : : }
2017 : 12 : free(ctype);
2018 : 12 : }
2019 : : static void
2020 : 1286 : client_input_channel_req(int type, u_int32_t seq, void *ctxt)
2021 : : {
2022 : 1286 : Channel *c = NULL;
2023 : 1286 : int exitval, id, reply, success = 0;
2024 : : char *rtype;
2025 : :
2026 : 1286 : id = packet_get_int();
2027 : 1286 : rtype = packet_get_string(NULL);
2028 : 1286 : reply = packet_get_char();
2029 : :
2030 : 1286 : debug("client_input_channel_req: channel %d rtype %s reply %d",
2031 : : id, rtype, reply);
2032 : :
2033 [ - + ]: 1286 : if (id == -1) {
2034 : 0 : error("client_input_channel_req: request for channel -1");
2035 [ - + ]: 1286 : } else if ((c = channel_lookup(id)) == NULL) {
2036 : 0 : error("client_input_channel_req: channel %d: "
2037 : : "unknown channel", id);
2038 [ + + ]: 1286 : } else if (strcmp(rtype, "eow@openssh.com") == 0) {
2039 [ - + ]: 584 : packet_check_eom();
2040 : 584 : chan_rcvd_eow(c);
2041 [ + + ]: 702 : } else if (strcmp(rtype, "exit-status") == 0) {
2042 : 695 : exitval = packet_get_int();
2043 [ + + ]: 695 : if (c->ctl_chan != -1) {
2044 : 16 : mux_exit_message(c, exitval);
2045 : 16 : success = 1;
2046 [ + - ]: 679 : } else if (id == session_ident) {
2047 : : /* Record exit value of local session */
2048 : 679 : success = 1;
2049 : 679 : exit_status = exitval;
2050 : : } else {
2051 : : /* Probably for a mux channel that has already closed */
2052 : 0 : debug("%s: no sink for exit-status on channel %d",
2053 : : __func__, id);
2054 : : }
2055 [ - + ]: 695 : packet_check_eom();
2056 : : }
2057 [ - + ]: 1286 : if (reply && c != NULL) {
2058 [ # # ]: 0 : packet_start(success ?
2059 : : SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
2060 : 0 : packet_put_int(c->remote_id);
2061 : 0 : packet_send();
2062 : : }
2063 : 1286 : free(rtype);
2064 : 1286 : }
2065 : : static void
2066 : 0 : client_input_global_request(int type, u_int32_t seq, void *ctxt)
2067 : : {
2068 : : char *rtype;
2069 : : int want_reply;
2070 : 0 : int success = 0;
2071 : :
2072 : 0 : rtype = packet_get_string(NULL);
2073 : 0 : want_reply = packet_get_char();
2074 : 0 : debug("client_input_global_request: rtype %s want_reply %d",
2075 : : rtype, want_reply);
2076 [ # # ]: 0 : if (want_reply) {
2077 : 0 : packet_start(success ?
2078 : : SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
2079 : 0 : packet_send();
2080 : 0 : packet_write_wait();
2081 : : }
2082 : 0 : free(rtype);
2083 : 0 : }
2084 : :
2085 : : void
2086 : 702 : client_session2_setup(int id, int want_tty, int want_subsystem,
2087 : : const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env)
2088 : : {
2089 : : int len;
2090 : 702 : Channel *c = NULL;
2091 : :
2092 : 702 : debug2("%s: id %d", __func__, id);
2093 : :
2094 [ - + ]: 702 : if ((c = channel_lookup(id)) == NULL)
2095 : 0 : fatal("client_session2_setup: channel %d: unknown channel", id);
2096 : :
2097 : 702 : packet_set_interactive(want_tty,
2098 : : options.ip_qos_interactive, options.ip_qos_bulk);
2099 : :
2100 [ - + ]: 702 : if (want_tty) {
2101 : : struct winsize ws;
2102 : :
2103 : : /* Store window size in the packet. */
2104 [ # # ]: 0 : if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0)
2105 : : memset(&ws, 0, sizeof(ws));
2106 : :
2107 : 0 : channel_request_start(id, "pty-req", 1);
2108 : 0 : client_expect_confirm(id, "PTY allocation", CONFIRM_TTY);
2109 [ # # ]: 0 : packet_put_cstring(term != NULL ? term : "");
2110 : 0 : packet_put_int((u_int)ws.ws_col);
2111 : 0 : packet_put_int((u_int)ws.ws_row);
2112 : 0 : packet_put_int((u_int)ws.ws_xpixel);
2113 : 0 : packet_put_int((u_int)ws.ws_ypixel);
2114 [ # # ]: 0 : if (tiop == NULL)
2115 : 0 : tiop = get_saved_tio();
2116 : 0 : tty_make_modes(-1, tiop);
2117 : 0 : packet_send();
2118 : : /* XXX wait for reply */
2119 : 0 : c->client_tty = 1;
2120 : : }
2121 : :
2122 : : /* Transfer any environment variables from client to server */
2123 [ + + ][ + + ]: 702 : if (options.num_send_env != 0 && env != NULL) {
2124 : : int i, j, matched;
2125 : : char *name, *val;
2126 : :
2127 : 4 : debug("Sending environment.");
2128 [ + + ]: 174 : for (i = 0; env[i] != NULL; i++) {
2129 : : /* Split */
2130 : 170 : name = xstrdup(env[i]);
2131 [ - + ]: 170 : if ((val = strchr(name, '=')) == NULL) {
2132 : 0 : free(name);
2133 : 0 : continue;
2134 : : }
2135 : 170 : *val++ = '\0';
2136 : :
2137 : 170 : matched = 0;
2138 [ + + ]: 280 : for (j = 0; j < options.num_send_env; j++) {
2139 [ + + ]: 170 : if (match_pattern(name, options.send_env[j])) {
2140 : : matched = 1;
2141 : : break;
2142 : : }
2143 : : }
2144 [ + + ]: 170 : if (!matched) {
2145 : 110 : debug3("Ignored env %s", name);
2146 : 110 : free(name);
2147 : 110 : continue;
2148 : : }
2149 : :
2150 : 60 : debug("Sending env %s = %s", name, val);
2151 : 60 : channel_request_start(id, "env", 0);
2152 : 60 : packet_put_cstring(name);
2153 : 60 : packet_put_cstring(val);
2154 : 60 : packet_send();
2155 : 60 : free(name);
2156 : : }
2157 : : }
2158 : :
2159 : 702 : len = buffer_len(cmd);
2160 [ + - ]: 702 : if (len > 0) {
2161 [ - + ]: 702 : if (len > 900)
2162 : 0 : len = 900;
2163 [ + + ]: 702 : if (want_subsystem) {
2164 : 1 : debug("Sending subsystem: %.*s",
2165 : 1 : len, (u_char*)buffer_ptr(cmd));
2166 : 1 : channel_request_start(id, "subsystem", 1);
2167 : 1 : client_expect_confirm(id, "subsystem", CONFIRM_CLOSE);
2168 : : } else {
2169 : 701 : debug("Sending command: %.*s",
2170 : 701 : len, (u_char*)buffer_ptr(cmd));
2171 : 701 : channel_request_start(id, "exec", 1);
2172 : 701 : client_expect_confirm(id, "exec", CONFIRM_CLOSE);
2173 : : }
2174 : 702 : packet_put_string(buffer_ptr(cmd), buffer_len(cmd));
2175 : 702 : packet_send();
2176 : : } else {
2177 : 0 : channel_request_start(id, "shell", 1);
2178 : 0 : client_expect_confirm(id, "shell", CONFIRM_CLOSE);
2179 : 0 : packet_send();
2180 : : }
2181 : 702 : }
2182 : :
2183 : : static void
2184 : 688 : client_init_dispatch_20(void)
2185 : : {
2186 : 688 : dispatch_init(&dispatch_protocol_error);
2187 : :
2188 : 688 : dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
2189 : 688 : dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
2190 : 688 : dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
2191 : 688 : dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
2192 : 688 : dispatch_set(SSH2_MSG_CHANNEL_OPEN, &client_input_channel_open);
2193 : 688 : dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
2194 : 688 : dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
2195 : 688 : dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req);
2196 : 688 : dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
2197 : 688 : dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm);
2198 : 688 : dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm);
2199 : 688 : dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request);
2200 : :
2201 : : /* rekeying */
2202 : 688 : dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
2203 : :
2204 : : /* global request reply messages */
2205 : 688 : dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply);
2206 : 688 : dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply);
2207 : 688 : }
2208 : :
2209 : : static void
2210 : 61 : client_init_dispatch_13(void)
2211 : : {
2212 : 61 : dispatch_init(NULL);
2213 : 61 : dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
2214 : 61 : dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
2215 : 61 : dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
2216 : 61 : dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
2217 : 61 : dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
2218 : 61 : dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
2219 : 61 : dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status);
2220 : 61 : dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data);
2221 : 61 : dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data);
2222 : :
2223 [ + + ]: 61 : dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ?
2224 : : &client_input_agent_open : &deny_input_open);
2225 [ + - ]: 61 : dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ?
2226 : : &x11_input_open : &deny_input_open);
2227 : 61 : }
2228 : :
2229 : : static void
2230 : 61 : client_init_dispatch_15(void)
2231 : : {
2232 : 61 : client_init_dispatch_13();
2233 : 61 : dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
2234 : 61 : dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose);
2235 : 61 : }
2236 : :
2237 : : static void
2238 : 749 : client_init_dispatch(void)
2239 : : {
2240 [ + + ]: 749 : if (compat20)
2241 : 688 : client_init_dispatch_20();
2242 [ - + ]: 61 : else if (compat13)
2243 : 0 : client_init_dispatch_13();
2244 : : else
2245 : 61 : client_init_dispatch_15();
2246 : 749 : }
2247 : :
2248 : : void
2249 : 1 : client_stop_mux(void)
2250 : : {
2251 [ + - ][ + - ]: 1 : if (options.control_path != NULL && muxserver_sock != -1)
2252 : 1 : unlink(options.control_path);
2253 : : /*
2254 : : * If we are in persist mode, or don't have a shell, signal that we
2255 : : * should close when all active channels are closed.
2256 : : */
2257 [ + - ][ + - ]: 1 : if (options.control_persist || no_shell_flag) {
2258 : 1 : session_closed = 1;
2259 : 1 : setproctitle("[stopped mux]");
2260 : : }
2261 : 1 : }
2262 : :
2263 : : /* client specific fatal cleanup */
2264 : : void
2265 : 0 : cleanup_exit(int i)
2266 : : {
2267 : 0 : leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
2268 : 0 : leave_non_blocking();
2269 [ # # ][ # # ]: 0 : if (options.control_path != NULL && muxserver_sock != -1)
2270 : 0 : unlink(options.control_path);
2271 : 0 : ssh_kill_proxy_command();
2272 : 0 : _exit(i);
2273 : : }
|