Annotation of src/usr.bin/ssh/clientloop.c, Revision 1.11
1.1 deraadt 1: /*
2:
3: clientloop.c
4:
5: Author: Tatu Ylonen <ylo@cs.hut.fi>
6:
7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8: All rights reserved
9:
10:
11: Created: Sat Sep 23 12:23:57 1995 ylo
12:
13: The main loop for the interactive session (client side).
14:
15: */
16:
17: #include "includes.h"
1.11 ! markus 18: RCSID("$Id: clientloop.c,v 1.10 1999/11/19 19:58:18 markus Exp $");
1.1 deraadt 19:
20: #include "xmalloc.h"
21: #include "ssh.h"
22: #include "packet.h"
23: #include "buffer.h"
24: #include "authfd.h"
1.8 markus 25: #include "readconf.h"
1.1 deraadt 26:
27: /* Flag indicating that stdin should be redirected from /dev/null. */
28: extern int stdin_null_flag;
29:
30: /* Name of the host we are connecting to. This is the name given on the
31: command line, or the HostName specified for the user-supplied name
32: in a configuration file. */
33: extern char *host;
34:
35: /* Flag to indicate that we have received a window change signal which has
36: not yet been processed. This will cause a message indicating the new
37: window size to be sent to the server a little later. This is volatile
38: because this is updated in a signal handler. */
39: static volatile int received_window_change_signal = 0;
40:
41: /* Terminal modes, as saved by enter_raw_mode. */
42: static struct termios saved_tio;
43:
44: /* Flag indicating whether we are in raw mode. This is used by enter_raw_mode
45: and leave_raw_mode. */
46: static int in_raw_mode = 0;
47:
48: /* Flag indicating whether the user\'s terminal is in non-blocking mode. */
49: static int in_non_blocking_mode = 0;
50:
51: /* Common data for the client loop code. */
1.11 ! markus 52: static int escape_pending; /* Last character was the escape character */
! 53: static int last_was_cr; /* Last character was a newline. */
! 54: static int exit_status; /* Used to store the exit status of the command. */
! 55: static int stdin_eof; /* EOF has been encountered on standard error. */
! 56: static Buffer stdin_buffer; /* Buffer for stdin data. */
! 57: static Buffer stdout_buffer; /* Buffer for stdout data. */
! 58: static Buffer stderr_buffer; /* Buffer for stderr data. */
! 59: static unsigned int buffer_high;/* Soft max buffer size. */
! 60: static int max_fd; /* Maximum file descriptor number in select(). */
! 61: static int connection_in; /* Connection to server (input). */
! 62: static int connection_out; /* Connection to server (output). */
1.1 deraadt 63: static unsigned long stdin_bytes, stdout_bytes, stderr_bytes;
1.11 ! markus 64: static int quit_pending; /* Set to non-zero to quit the client loop. */
! 65: static int escape_char; /* Escape character. */
1.1 deraadt 66:
1.11 ! markus 67: /* Returns the user\'s terminal to normal mode if it had been put in raw
1.1 deraadt 68: mode. */
69:
1.11 ! markus 70: void
! 71: leave_raw_mode()
1.1 deraadt 72: {
1.11 ! markus 73: if (!in_raw_mode)
! 74: return;
! 75: in_raw_mode = 0;
! 76: if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0)
! 77: perror("tcsetattr");
1.1 deraadt 78:
1.11 ! markus 79: fatal_remove_cleanup((void (*) (void *)) leave_raw_mode, NULL);
1.1 deraadt 80: }
81:
82: /* Puts the user\'s terminal in raw mode. */
83:
1.11 ! markus 84: void
! 85: enter_raw_mode()
1.1 deraadt 86: {
1.11 ! markus 87: struct termios tio;
1.1 deraadt 88:
1.11 ! markus 89: if (tcgetattr(fileno(stdin), &tio) < 0)
! 90: perror("tcgetattr");
! 91: saved_tio = tio;
! 92: tio.c_iflag |= IGNPAR;
! 93: tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
! 94: tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
1.1 deraadt 95: #ifdef IEXTEN
1.11 ! markus 96: tio.c_lflag &= ~IEXTEN;
! 97: #endif /* IEXTEN */
! 98: tio.c_oflag &= ~OPOST;
! 99: tio.c_cc[VMIN] = 1;
! 100: tio.c_cc[VTIME] = 0;
! 101: if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0)
! 102: perror("tcsetattr");
! 103: in_raw_mode = 1;
1.1 deraadt 104:
1.11 ! markus 105: fatal_add_cleanup((void (*) (void *)) leave_raw_mode, NULL);
! 106: }
1.1 deraadt 107:
108: /* Restores stdin to blocking mode. */
109:
1.11 ! markus 110: void
! 111: leave_non_blocking()
1.1 deraadt 112: {
1.11 ! markus 113: if (in_non_blocking_mode) {
! 114: (void) fcntl(fileno(stdin), F_SETFL, 0);
! 115: in_non_blocking_mode = 0;
! 116: fatal_remove_cleanup((void (*) (void *)) leave_non_blocking, NULL);
! 117: }
1.1 deraadt 118: }
119:
1.11 ! markus 120: /* Puts stdin terminal in non-blocking mode. */
! 121:
! 122: void
! 123: enter_non_blocking()
1.1 deraadt 124: {
1.11 ! markus 125: in_non_blocking_mode = 1;
! 126: (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
! 127: fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL);
1.1 deraadt 128: }
129:
130: /* Signal handler for the window change signal (SIGWINCH). This just
131: sets a flag indicating that the window has changed. */
132:
1.11 ! markus 133: void
! 134: window_change_handler(int sig)
1.1 deraadt 135: {
1.11 ! markus 136: received_window_change_signal = 1;
! 137: signal(SIGWINCH, window_change_handler);
1.1 deraadt 138: }
139:
140: /* Signal handler for signals that cause the program to terminate. These
141: signals must be trapped to restore terminal modes. */
142:
1.11 ! markus 143: void
! 144: signal_handler(int sig)
1.1 deraadt 145: {
1.11 ! markus 146: if (in_raw_mode)
! 147: leave_raw_mode();
! 148: if (in_non_blocking_mode)
! 149: leave_non_blocking();
! 150: channel_stop_listening();
! 151: packet_close();
! 152: fatal("Killed by signal %d.", sig);
1.1 deraadt 153: }
154:
155: /* Returns current time in seconds from Jan 1, 1970 with the maximum available
156: resolution. */
157:
1.11 ! markus 158: double
! 159: get_current_time()
1.1 deraadt 160: {
1.11 ! markus 161: struct timeval tv;
! 162: gettimeofday(&tv, NULL);
! 163: return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
1.1 deraadt 164: }
165:
166: /* This is called when the interactive is entered. This checks if there
167: is an EOF coming on stdin. We must check this explicitly, as select()
168: does not appear to wake up when redirecting from /dev/null. */
169:
1.11 ! markus 170: void
! 171: client_check_initial_eof_on_stdin()
1.1 deraadt 172: {
1.11 ! markus 173: int len;
! 174: char buf[1];
1.1 deraadt 175:
1.11 ! markus 176: /* If standard input is to be "redirected from /dev/null", we
! 177: simply mark that we have seen an EOF and send an EOF message to
! 178: the server. Otherwise, we try to read a single character; it
! 179: appears that for some files, such /dev/null, select() never
! 180: wakes up for read for this descriptor, which means that we
! 181: never get EOF. This way we will get the EOF if stdin comes
! 182: from /dev/null or similar. */
! 183: if (stdin_null_flag) {
! 184: /* Fake EOF on stdin. */
! 185: debug("Sending eof.");
! 186: stdin_eof = 1;
! 187: packet_start(SSH_CMSG_EOF);
! 188: packet_send();
! 189: } else {
! 190: /* Enter non-blocking mode for stdin. */
! 191: enter_non_blocking();
! 192:
! 193: /* Check for immediate EOF on stdin. */
! 194: len = read(fileno(stdin), buf, 1);
! 195: if (len == 0) {
! 196: /* EOF. Record that we have seen it and send EOF
! 197: to server. */
! 198: debug("Sending eof.");
! 199: stdin_eof = 1;
! 200: packet_start(SSH_CMSG_EOF);
! 201: packet_send();
! 202: } else if (len > 0) {
! 203: /* Got data. We must store the data in the
! 204: buffer, and also process it as an escape
! 205: character if appropriate. */
! 206: if ((unsigned char) buf[0] == escape_char)
! 207: escape_pending = 1;
! 208: else {
! 209: buffer_append(&stdin_buffer, buf, 1);
! 210: stdin_bytes += 1;
! 211: }
! 212: }
! 213: /* Leave non-blocking mode. */
! 214: leave_non_blocking();
! 215: }
1.1 deraadt 216: }
217:
218: /* Get packets from the connection input buffer, and process them as long
219: as there are packets available. */
220:
1.11 ! markus 221: void
! 222: client_process_buffered_input_packets()
1.1 deraadt 223: {
1.11 ! markus 224: int type;
! 225: char *data;
! 226: unsigned int data_len;
! 227: int payload_len;
! 228:
! 229: /* Process any buffered packets from the server. */
! 230: while (!quit_pending &&
! 231: (type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) {
! 232: switch (type) {
! 233:
! 234: case SSH_SMSG_STDOUT_DATA:
! 235: data = packet_get_string(&data_len);
! 236: packet_integrity_check(payload_len, 4 + data_len, type);
! 237: buffer_append(&stdout_buffer, data, data_len);
! 238: stdout_bytes += data_len;
! 239: memset(data, 0, data_len);
! 240: xfree(data);
! 241: break;
! 242:
! 243: case SSH_SMSG_STDERR_DATA:
! 244: data = packet_get_string(&data_len);
! 245: packet_integrity_check(payload_len, 4 + data_len, type);
! 246: buffer_append(&stderr_buffer, data, data_len);
! 247: stdout_bytes += data_len;
! 248: memset(data, 0, data_len);
! 249: xfree(data);
! 250: break;
! 251:
! 252: case SSH_SMSG_EXITSTATUS:
! 253: packet_integrity_check(payload_len, 4, type);
! 254: exit_status = packet_get_int();
! 255: /* Acknowledge the exit. */
! 256: packet_start(SSH_CMSG_EXIT_CONFIRMATION);
! 257: packet_send();
! 258: /* Must wait for packet to be sent since we are
! 259: exiting the loop. */
! 260: packet_write_wait();
! 261: /* Flag that we want to exit. */
! 262: quit_pending = 1;
! 263: break;
! 264:
! 265: case SSH_SMSG_X11_OPEN:
! 266: x11_input_open(payload_len);
! 267: break;
! 268:
! 269: case SSH_MSG_PORT_OPEN:
! 270: channel_input_port_open(payload_len);
! 271: break;
! 272:
! 273: case SSH_SMSG_AGENT_OPEN:
! 274: packet_integrity_check(payload_len, 4, type);
! 275: auth_input_open_request();
! 276: break;
! 277:
! 278: case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
! 279: packet_integrity_check(payload_len, 4 + 4, type);
! 280: channel_input_open_confirmation();
! 281: break;
! 282:
! 283: case SSH_MSG_CHANNEL_OPEN_FAILURE:
! 284: packet_integrity_check(payload_len, 4, type);
! 285: channel_input_open_failure();
! 286: break;
! 287:
! 288: case SSH_MSG_CHANNEL_DATA:
! 289: channel_input_data(payload_len);
! 290: break;
! 291:
! 292: case SSH_MSG_CHANNEL_CLOSE:
! 293: packet_integrity_check(payload_len, 4, type);
! 294: channel_input_close();
! 295: break;
! 296:
! 297: case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
! 298: packet_integrity_check(payload_len, 4, type);
! 299: channel_input_close_confirmation();
! 300: break;
! 301:
! 302: default:
! 303: /* Any unknown packets received during the actual
! 304: session cause the session to terminate. This
! 305: is intended to make debugging easier since no
! 306: confirmations are sent. Any compatible
! 307: protocol extensions must be negotiated during
! 308: the preparatory phase. */
! 309: packet_disconnect("Protocol error during session: type %d",
! 310: type);
! 311: }
1.1 deraadt 312: }
313: }
314:
315: /* Make packets from buffered stdin data, and buffer them for sending to
316: the connection. */
317:
1.11 ! markus 318: void
! 319: client_make_packets_from_stdin_data()
1.1 deraadt 320: {
1.11 ! markus 321: unsigned int len;
1.1 deraadt 322:
1.11 ! markus 323: /* Send buffered stdin data to the server. */
! 324: while (buffer_len(&stdin_buffer) > 0 &&
! 325: packet_not_very_much_data_to_write()) {
! 326: len = buffer_len(&stdin_buffer);
! 327: /* Keep the packets at reasonable size. */
! 328: if (len > packet_get_maxsize())
! 329: len = packet_get_maxsize();
! 330: packet_start(SSH_CMSG_STDIN_DATA);
! 331: packet_put_string(buffer_ptr(&stdin_buffer), len);
! 332: packet_send();
! 333: buffer_consume(&stdin_buffer, len);
! 334: /* If we have a pending EOF, send it now. */
! 335: if (stdin_eof && buffer_len(&stdin_buffer) == 0) {
! 336: packet_start(SSH_CMSG_EOF);
! 337: packet_send();
! 338: }
1.1 deraadt 339: }
340: }
341:
342: /* Checks if the client window has changed, and sends a packet about it to
343: the server if so. The actual change is detected elsewhere (by a software
344: interrupt on Unix); this just checks the flag and sends a message if
345: appropriate. */
346:
1.11 ! markus 347: void
! 348: client_check_window_change()
1.1 deraadt 349: {
1.11 ! markus 350: /* Send possible window change message to the server. */
! 351: if (received_window_change_signal) {
! 352: struct winsize ws;
! 353:
! 354: /* Clear the window change indicator. */
! 355: received_window_change_signal = 0;
! 356:
! 357: /* Read new window size. */
! 358: if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) {
! 359: /* Successful, send the packet now. */
! 360: packet_start(SSH_CMSG_WINDOW_SIZE);
! 361: packet_put_int(ws.ws_row);
! 362: packet_put_int(ws.ws_col);
! 363: packet_put_int(ws.ws_xpixel);
! 364: packet_put_int(ws.ws_ypixel);
! 365: packet_send();
! 366: }
1.1 deraadt 367: }
368: }
369:
370: /* Waits until the client can do something (some data becomes available on
371: one of the file descriptors). */
372:
1.11 ! markus 373: void
! 374: client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
! 375: {
! 376: /* Initialize select masks. */
! 377: FD_ZERO(readset);
! 378:
! 379: /* Read from the connection, unless our buffers are full. */
! 380: if (buffer_len(&stdout_buffer) < buffer_high &&
! 381: buffer_len(&stderr_buffer) < buffer_high &&
! 382: channel_not_very_much_buffered_data())
! 383: FD_SET(connection_in, readset);
! 384:
! 385: /* Read from stdin, unless we have seen EOF or have very much
! 386: buffered data to send to the server. */
! 387: if (!stdin_eof && packet_not_very_much_data_to_write())
! 388: FD_SET(fileno(stdin), readset);
! 389:
! 390: FD_ZERO(writeset);
! 391:
! 392: /* Add any selections by the channel mechanism. */
! 393: channel_prepare_select(readset, writeset);
! 394:
! 395: /* Select server connection if have data to write to the server. */
! 396: if (packet_have_data_to_write())
! 397: FD_SET(connection_out, writeset);
! 398:
! 399: /* Select stdout if have data in buffer. */
! 400: if (buffer_len(&stdout_buffer) > 0)
! 401: FD_SET(fileno(stdout), writeset);
! 402:
! 403: /* Select stderr if have data in buffer. */
! 404: if (buffer_len(&stderr_buffer) > 0)
! 405: FD_SET(fileno(stderr), writeset);
! 406:
! 407: /* Update maximum file descriptor number, if appropriate. */
! 408: if (channel_max_fd() > max_fd)
! 409: max_fd = channel_max_fd();
! 410:
! 411: /* Wait for something to happen. This will suspend the process
! 412: until some selected descriptor can be read, written, or has
! 413: some other event pending.
! 414: Note: if you want to implement SSH_MSG_IGNORE messages to fool
! 415: traffic analysis, this might be the place to do it:
! 416: just have a random timeout for the select, and send a random
! 417: SSH_MSG_IGNORE packet when the timeout expires. */
! 418:
! 419: if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) {
! 420: char buf[100];
! 421: /* Some systems fail to clear these automatically. */
! 422: FD_ZERO(readset);
! 423: FD_ZERO(writeset);
! 424: if (errno == EINTR)
! 425: return;
! 426: /* Note: we might still have data in the buffers. */
! 427: snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
! 428: buffer_append(&stderr_buffer, buf, strlen(buf));
! 429: stderr_bytes += strlen(buf);
! 430: quit_pending = 1;
! 431: }
! 432: }
! 433:
! 434: void
! 435: client_suspend_self()
1.1 deraadt 436: {
1.11 ! markus 437: struct winsize oldws, newws;
! 438:
! 439: /* Flush stdout and stderr buffers. */
! 440: if (buffer_len(&stdout_buffer) > 0)
! 441: write(fileno(stdout),
! 442: buffer_ptr(&stdout_buffer),
! 443: buffer_len(&stdout_buffer));
! 444: if (buffer_len(&stderr_buffer) > 0)
! 445: write(fileno(stderr),
! 446: buffer_ptr(&stderr_buffer),
! 447: buffer_len(&stderr_buffer));
! 448:
! 449: /* Leave raw mode. */
! 450: leave_raw_mode();
! 451:
! 452: /* Free (and clear) the buffer to reduce the amount of data that
! 453: gets written to swap. */
! 454: buffer_free(&stdin_buffer);
! 455: buffer_free(&stdout_buffer);
! 456: buffer_free(&stderr_buffer);
! 457:
! 458: /* Save old window size. */
! 459: ioctl(fileno(stdin), TIOCGWINSZ, &oldws);
! 460:
! 461: /* Send the suspend signal to the program itself. */
! 462: kill(getpid(), SIGTSTP);
! 463:
! 464: /* Check if the window size has changed. */
! 465: if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 &&
! 466: (oldws.ws_row != newws.ws_row ||
! 467: oldws.ws_col != newws.ws_col ||
! 468: oldws.ws_xpixel != newws.ws_xpixel ||
! 469: oldws.ws_ypixel != newws.ws_ypixel))
! 470: received_window_change_signal = 1;
! 471:
! 472: /* OK, we have been continued by the user. Reinitialize buffers. */
! 473: buffer_init(&stdin_buffer);
! 474: buffer_init(&stdout_buffer);
! 475: buffer_init(&stderr_buffer);
! 476:
! 477: /* Re-enter raw mode. */
! 478: enter_raw_mode();
! 479: }
! 480:
! 481: void
! 482: client_process_input(fd_set * readset)
! 483: {
! 484: int len, pid;
! 485: char buf[8192], *s;
! 486:
! 487: /* Read input from the server, and add any such data to the buffer
! 488: of the packet subsystem. */
! 489: if (FD_ISSET(connection_in, readset)) {
! 490: /* Read as much as possible. */
! 491: len = read(connection_in, buf, sizeof(buf));
! 492: if (len == 0) {
! 493: /* Received EOF. The remote host has closed the connection. */
! 494: snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
! 495: host);
1.1 deraadt 496: buffer_append(&stderr_buffer, buf, strlen(buf));
497: stderr_bytes += strlen(buf);
498: quit_pending = 1;
499: return;
1.11 ! markus 500: }
! 501: /* There is a kernel bug on Solaris that causes select to
! 502: sometimes wake up even though there is no data
! 503: available. */
! 504: if (len < 0 && errno == EAGAIN)
! 505: len = 0;
! 506:
! 507: if (len < 0) {
! 508: /* An error has encountered. Perhaps there is a network problem. */
! 509: snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n",
! 510: host, strerror(errno));
! 511: buffer_append(&stderr_buffer, buf, strlen(buf));
! 512: stderr_bytes += strlen(buf);
! 513: quit_pending = 1;
! 514: return;
! 515: }
! 516: packet_process_incoming(buf, len);
! 517: }
! 518: /* Read input from stdin. */
! 519: if (FD_ISSET(fileno(stdin), readset)) {
! 520: /* Read as much as possible. */
! 521: len = read(fileno(stdin), buf, sizeof(buf));
! 522: if (len <= 0) {
! 523: /* Received EOF or error. They are treated
! 524: similarly, except that an error message is
! 525: printed if it was an error condition. */
! 526: if (len < 0) {
! 527: snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
! 528: buffer_append(&stderr_buffer, buf, strlen(buf));
! 529: stderr_bytes += strlen(buf);
! 530: }
! 531: /* Mark that we have seen EOF. */
! 532: stdin_eof = 1;
! 533: /* Send an EOF message to the server unless there
! 534: is data in the buffer. If there is data in the
! 535: buffer, no message will be sent now. Code
! 536: elsewhere will send the EOF when the buffer
! 537: becomes empty if stdin_eof is set. */
! 538: if (buffer_len(&stdin_buffer) == 0) {
1.1 deraadt 539: packet_start(SSH_CMSG_EOF);
540: packet_send();
1.11 ! markus 541: }
! 542: } else if (escape_char == -1) {
! 543: /* Normal successful read, and no escape
! 544: character. Just append the data to buffer. */
! 545: buffer_append(&stdin_buffer, buf, len);
! 546: stdin_bytes += len;
! 547: } else {
! 548: /* Normal, successful read. But we have an escape
! 549: character and have to process the characters
! 550: one by one. */
! 551: unsigned int i;
! 552: for (i = 0; i < len; i++) {
! 553: unsigned char ch;
! 554: /* Get one character at a time. */
! 555: ch = buf[i];
! 556:
! 557: /* Check if we have a pending escape
! 558: character. */
! 559: if (escape_pending) {
! 560: /* We have previously seen an escape character. */
! 561: /* Clear the flag now. */
! 562: escape_pending = 0;
! 563: /* Process the escaped character. */
! 564: switch (ch) {
! 565: case '.':
! 566: /* Terminate the connection. */
! 567: snprintf(buf, sizeof buf, "%c.\r\n", escape_char);
! 568: buffer_append(&stderr_buffer, buf, strlen(buf));
! 569: stderr_bytes += strlen(buf);
! 570: quit_pending = 1;
! 571: return;
! 572:
! 573: case 'Z' - 64:
! 574: /* Suspend the program. */
! 575: /* Print a message to that effect to the user. */
! 576: snprintf(buf, sizeof buf, "%c^Z\r\n", escape_char);
! 577: buffer_append(&stderr_buffer, buf, strlen(buf));
! 578: stderr_bytes += strlen(buf);
! 579:
! 580: /* Restore terminal modes and suspend. */
! 581: client_suspend_self();
! 582:
! 583: /* We have been continued. */
! 584: continue;
! 585:
! 586: case '&':
! 587: /* Detach the program (continue to serve connections,
! 588: but put in background and no more new connections). */
! 589: if (!stdin_eof) {
! 590: /* Sending SSH_CMSG_EOF alone does not always appear
! 591: to be enough. So we try to send an EOF character
! 592: first. */
! 593: packet_start(SSH_CMSG_STDIN_DATA);
! 594: packet_put_string("\004", 1);
! 595: packet_send();
! 596: /* Close stdin. */
! 597: stdin_eof = 1;
! 598: if (buffer_len(&stdin_buffer) == 0) {
! 599: packet_start(SSH_CMSG_EOF);
! 600: packet_send();
! 601: }
! 602: }
! 603: /* Restore tty modes. */
! 604: leave_raw_mode();
! 605:
! 606: /* Stop listening for new connections. */
! 607: channel_stop_listening();
! 608:
! 609: printf("%c& [backgrounded]\n", escape_char);
! 610:
! 611: /* Fork into background. */
! 612: pid = fork();
! 613: if (pid < 0) {
! 614: error("fork: %.100s", strerror(errno));
! 615: continue;
! 616: }
! 617: if (pid != 0) { /* This is the parent. */
! 618: /* The parent just exits. */
! 619: exit(0);
! 620: }
! 621: /* The child continues serving connections. */
! 622: continue;
! 623:
! 624: case '?':
! 625: snprintf(buf, sizeof buf,
! 626: "%c?\r\n\
1.1 deraadt 627: Supported escape sequences:\r\n\
628: ~. - terminate connection\r\n\
629: ~^Z - suspend ssh\r\n\
630: ~# - list forwarded connections\r\n\
631: ~& - background ssh (when waiting for connections to terminate)\r\n\
632: ~? - this message\r\n\
633: ~~ - send the escape character by typing it twice\r\n\
634: (Note that escapes are only recognized immediately after newline.)\r\n",
1.11 ! markus 635: escape_char);
! 636: buffer_append(&stderr_buffer, buf, strlen(buf));
! 637: continue;
! 638:
! 639: case '#':
! 640: snprintf(buf, sizeof buf, "%c#\r\n", escape_char);
! 641: buffer_append(&stderr_buffer, buf, strlen(buf));
! 642: s = channel_open_message();
! 643: buffer_append(&stderr_buffer, s, strlen(s));
! 644: xfree(s);
! 645: continue;
! 646:
! 647: default:
! 648: if (ch != escape_char) {
! 649: /* Escape character followed by non-special character.
! 650: Append both to the input buffer. */
! 651: buf[0] = escape_char;
! 652: buf[1] = ch;
! 653: buffer_append(&stdin_buffer, buf, 2);
! 654: stdin_bytes += 2;
! 655: continue;
! 656: }
! 657: /* Note that escape character typed twice
! 658: falls through here; the latter gets processed
! 659: as a normal character below. */
! 660: break;
! 661: }
! 662: } else {
! 663: /* The previous character was not an escape char. Check if this
! 664: is an escape. */
! 665: if (last_was_cr && ch == escape_char) {
! 666: /* It is. Set the flag and continue to next character. */
! 667: escape_pending = 1;
! 668: continue;
! 669: }
! 670: }
! 671:
! 672: /* Normal character. Record whether it was a newline, and append it to the
! 673: buffer. */
! 674: last_was_cr = (ch == '\r' || ch == '\n');
! 675: buf[0] = ch;
! 676: buffer_append(&stdin_buffer, buf, 1);
! 677: stdin_bytes += 1;
! 678: continue;
! 679: }
! 680: }
! 681: }
! 682: }
! 683:
! 684: void
! 685: client_process_output(fd_set * writeset)
! 686: {
! 687: int len;
! 688: char buf[100];
1.1 deraadt 689:
1.11 ! markus 690: /* Write buffered output to stdout. */
! 691: if (FD_ISSET(fileno(stdout), writeset)) {
! 692: /* Write as much data as possible. */
! 693: len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
! 694: buffer_len(&stdout_buffer));
! 695: if (len <= 0) {
! 696: if (errno == EAGAIN)
! 697: len = 0;
! 698: else {
! 699: /* An error or EOF was encountered. Put
! 700: an error message to stderr buffer. */
! 701: snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
! 702: buffer_append(&stderr_buffer, buf, strlen(buf));
! 703: stderr_bytes += strlen(buf);
! 704: quit_pending = 1;
! 705: return;
! 706: }
! 707: }
! 708: /* Consume printed data from the buffer. */
! 709: buffer_consume(&stdout_buffer, len);
! 710: }
! 711: /* Write buffered output to stderr. */
! 712: if (FD_ISSET(fileno(stderr), writeset)) {
! 713: /* Write as much data as possible. */
! 714: len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
! 715: buffer_len(&stderr_buffer));
! 716: if (len <= 0) {
! 717: if (errno == EAGAIN)
! 718: len = 0;
! 719: else {
! 720: /* EOF or error, but can't even print
! 721: error message. */
! 722: quit_pending = 1;
! 723: return;
! 724: }
! 725: }
! 726: /* Consume printed characters from the buffer. */
! 727: buffer_consume(&stderr_buffer, len);
! 728: }
1.1 deraadt 729: }
730:
731: /* Implements the interactive session with the server. This is called
732: after the user has been authenticated, and a command has been
733: started on the remote host. If escape_char != -1, it is the character
734: used as an escape character for terminating or suspending the
735: session. */
736:
1.11 ! markus 737: int
! 738: client_loop(int have_pty, int escape_char_arg)
1.1 deraadt 739: {
1.11 ! markus 740: extern Options options;
! 741: double start_time, total_time;
! 742: int len;
! 743: char buf[100];
! 744:
! 745: debug("Entering interactive session.");
! 746:
! 747: start_time = get_current_time();
! 748:
! 749: /* Initialize variables. */
! 750: escape_pending = 0;
! 751: last_was_cr = 1;
! 752: exit_status = -1;
! 753: stdin_eof = 0;
! 754: buffer_high = 64 * 1024;
! 755: connection_in = packet_get_connection_in();
! 756: connection_out = packet_get_connection_out();
! 757: max_fd = connection_in;
! 758: if (connection_out > max_fd)
! 759: max_fd = connection_out;
! 760: stdin_bytes = 0;
! 761: stdout_bytes = 0;
! 762: stderr_bytes = 0;
! 763: quit_pending = 0;
! 764: escape_char = escape_char_arg;
! 765:
! 766: /* Initialize buffers. */
! 767: buffer_init(&stdin_buffer);
! 768: buffer_init(&stdout_buffer);
! 769: buffer_init(&stderr_buffer);
! 770:
! 771: /* Set signal handlers to restore non-blocking mode. */
! 772: signal(SIGINT, signal_handler);
! 773: signal(SIGQUIT, signal_handler);
! 774: signal(SIGTERM, signal_handler);
! 775: signal(SIGPIPE, SIG_IGN);
! 776: if (have_pty)
! 777: signal(SIGWINCH, window_change_handler);
! 778:
! 779: /* Enter raw mode if have a pseudo terminal. */
! 780: if (have_pty)
! 781: enter_raw_mode();
! 782:
! 783: /* Check if we should immediately send of on stdin. */
! 784: client_check_initial_eof_on_stdin();
! 785:
! 786: /* Main loop of the client for the interactive session mode. */
! 787: while (!quit_pending) {
! 788: fd_set readset, writeset;
! 789:
! 790: /* Precess buffered packets sent by the server. */
! 791: client_process_buffered_input_packets();
! 792:
! 793: /* Make packets of buffered stdin data, and buffer them
! 794: for sending to the server. */
! 795: client_make_packets_from_stdin_data();
! 796:
! 797: /* Make packets from buffered channel data, and buffer
! 798: them for sending to the server. */
! 799: if (packet_not_very_much_data_to_write())
! 800: channel_output_poll();
! 801:
! 802: /* Check if the window size has changed, and buffer a
! 803: message about it to the server if so. */
! 804: client_check_window_change();
! 805:
! 806: if (quit_pending)
! 807: break;
! 808:
! 809: /* Wait until we have something to do (something becomes
! 810: available on one of the descriptors). */
! 811: client_wait_until_can_do_something(&readset, &writeset);
! 812:
! 813: if (quit_pending)
! 814: break;
! 815:
! 816: /* Do channel operations. */
! 817: channel_after_select(&readset, &writeset);
! 818:
! 819: /* Process input from the connection and from stdin.
! 820: Buffer any data that is available. */
! 821: client_process_input(&readset);
! 822:
! 823: /* Process output to stdout and stderr. Output to the
! 824: connection is processed elsewhere (above). */
! 825: client_process_output(&writeset);
! 826:
! 827: /* Send as much buffered packet data as possible to the
! 828: sender. */
! 829: if (FD_ISSET(connection_out, &writeset))
! 830: packet_write_poll();
! 831: }
! 832:
! 833: /* Terminate the session. */
! 834:
! 835: /* Stop watching for window change. */
! 836: if (have_pty)
! 837: signal(SIGWINCH, SIG_DFL);
! 838:
! 839: /* Stop listening for connections. */
! 840: channel_stop_listening();
! 841:
! 842: /* In interactive mode (with pseudo tty) display a message
! 843: indicating that the connection has been closed. */
! 844: if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
! 845: snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
! 846: buffer_append(&stderr_buffer, buf, strlen(buf));
! 847: stderr_bytes += strlen(buf);
! 848: }
! 849: /* Output any buffered data for stdout. */
! 850: while (buffer_len(&stdout_buffer) > 0) {
! 851: len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
! 852: buffer_len(&stdout_buffer));
! 853: if (len <= 0) {
! 854: error("Write failed flushing stdout buffer.");
! 855: break;
! 856: }
! 857: buffer_consume(&stdout_buffer, len);
! 858: }
! 859:
! 860: /* Output any buffered data for stderr. */
! 861: while (buffer_len(&stderr_buffer) > 0) {
! 862: len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
! 863: buffer_len(&stderr_buffer));
! 864: if (len <= 0) {
! 865: error("Write failed flushing stderr buffer.");
! 866: break;
! 867: }
! 868: buffer_consume(&stderr_buffer, len);
! 869: }
! 870:
! 871: /* Leave raw mode. */
! 872: if (have_pty)
! 873: leave_raw_mode();
! 874:
! 875: /* Clear and free any buffers. */
! 876: memset(buf, 0, sizeof(buf));
! 877: buffer_free(&stdin_buffer);
! 878: buffer_free(&stdout_buffer);
! 879: buffer_free(&stderr_buffer);
! 880:
! 881: /* Report bytes transferred, and transfer rates. */
! 882: total_time = get_current_time() - start_time;
! 883: debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds",
! 884: stdin_bytes, stdout_bytes, stderr_bytes, total_time);
! 885: if (total_time > 0)
! 886: debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f",
! 887: stdin_bytes / total_time, stdout_bytes / total_time,
! 888: stderr_bytes / total_time);
! 889:
! 890: /* Return the exit status of the program. */
! 891: debug("Exit status %d", exit_status);
! 892: return exit_status;
1.1 deraadt 893: }