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