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