source: trunk/third/ssh/serverloop.c @ 12648

Revision 12648, 23.8 KB checked in by danw, 26 years ago (diff)
merge changes
Line 
1/*
2
3serverloop.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8                   All rights reserved
9
10Created: Sun Sep 10 00:30:37 1995 ylo
11
12Server main loop for handling the interactive session.
13
14*/
15
16/*
17 * $Id: serverloop.c,v 1.3 1999-03-08 18:20:08 danw Exp $
18 * $Log: not supported by cvs2svn $
19 * Revision 1.2  1999/01/21 23:10:47  ghudson
20 * From amu: if possible, wait specifically for child_pid.  And don't block.
21 *
22 * Revision 1.1.1.2  1998/05/13 19:11:16  danw
23 * Import of ssh 1.2.23
24 *
25 * Revision 1.1.1.3  1999/03/08 17:43:09  danw
26 * Import of ssh 1.2.26
27 *
28 * Revision 1.17  1998/05/23  20:37:21  kivinen
29 *      Changed () -> (void).
30 *
31 * Revision 1.16  1998/05/04  13:36:28  kivinen
32 *      Fixed no_port_forwarding_flag so that it will also disable
33 *      local port forwardings from the server side. Moved
34 *      packet_get_all after reading the the remote_channel number
35 *      from the packet.
36 *
37 * Revision 1.15  1998/03/27 17:01:02  kivinen
38 *      Fixed idle_time code.
39 *
40 * Revision 1.14  1997/04/21 01:04:46  kivinen
41 *      Changed server_loop to call pty_cleanup_proc instead of
42 *      pty_release, so we can be sure it is never called twice.
43 *
44 * Revision 1.13  1997/04/17 04:19:28  kivinen
45 *      Added ttyame argument to wait_until_can_do_something and
46 *      server_loop functions.
47 *      Release pty before closing it.
48 *
49 * Revision 1.12  1997/04/05 21:52:54  kivinen
50 *      Fixed closing of pty, and changed it to use shutdown first and
51 *      close the pty only after pty have been released.
52 *
53 * Revision 1.11  1997/03/26 07:16:11  kivinen
54 *      Fixed idle_time code.
55 *
56 * Revision 1.10  1997/03/26 05:28:18  kivinen
57 *      Added idle timeout support.
58 *
59 * Revision 1.9  1997/03/25 05:48:49  kivinen
60 *      Moved closing of sockets/pipes out from server_loop.
61 *
62 * Revision 1.8  1997/03/19 19:25:17  kivinen
63 *      Added input buffer clearing for error conditions, so packet.c
64 *      can check that buffer must be empty before new packet is read
65 *      in.
66 *
67 * Revision 1.7  1997/03/19 17:56:31  kivinen
68 *      Fixed sigchld race condition.
69 *
70 * Revision 1.6  1996/11/24 08:25:14  kivinen
71 *      Added SSHD_NO_PORT_FORWARDING support.
72 *      Changed all code that checked EAGAIN to check EWOULDBLOCK too.
73 *
74 * Revision 1.5  1996/09/29 13:42:55  ylo
75 *      Increased the time to wait for more data from 10 ms to 17 ms
76 *      and bytes to 512 (I'm worried it might not always be
77 *      working due to the delay being shorter than the systems
78 *      fundamental clock tick).
79 *
80 * Revision 1.4  1996/09/14 08:42:26  ylo
81 *      Added cvs logs.
82 *
83 * $EndLog$
84 */
85
86#include "includes.h"
87#include "xmalloc.h"
88#include "ssh.h"
89#include "packet.h"
90#include "buffer.h"
91#include "servconf.h"
92#include "pty.h"
93
94/* Flags that may be set in authorized_keys options. */
95extern int no_port_forwarding_flag;
96
97extern time_t idle_timeout;
98static time_t idle_time_last = 0;
99
100static Buffer stdin_buffer;     /* Buffer for stdin data. */
101static Buffer stdout_buffer;    /* Buffer for stdout data. */
102static Buffer stderr_buffer;    /* Buffer for stderr data. */
103static int fdin;                /* Descriptor for stdin (for writing) */
104static int fdout;               /* Descriptor for stdout (for reading);
105                                   May be same number as fdin. */
106static int fderr;               /* Descriptor for stderr.  May be -1. */
107static long stdin_bytes = 0;    /* Number of bytes written to stdin. */
108static long stdout_bytes = 0;   /* Number of stdout bytes sent to client. */
109static long stderr_bytes = 0;   /* Number of stderr bytes sent to client. */
110static long fdout_bytes = 0;    /* Number of stdout bytes read from program. */
111static int stdin_eof = 0;       /* EOF message received from client. */
112static int fdout_eof = 0;       /* EOF encountered reading from fdout. */
113static int fderr_eof = 0;       /* EOF encountered readung from fderr. */
114static int connection_in;       /* Connection to client (input). */
115static int connection_out;      /* Connection to client (output). */
116static unsigned int buffer_high;/* "Soft" max buffer size. */
117static int max_fd;              /* Max file descriptor number for select(). */
118
119/* This SIGCHLD kludge is used to detect when the child exits.  The server
120   will exit after that, as soon as forwarded connections have terminated. */
121
122static int child_pid;                   /* Pid of the child. */
123static volatile int child_terminated;   /* The child has terminated. */
124static volatile int child_wait_status;  /* Status from wait(). */
125static int child_just_terminated;       /* No select() done after termin. */
126
127RETSIGTYPE sigchld_handler(int sig)
128{
129  int wait_pid;
130  debug("Received SIGCHLD.");
131#ifdef HAVE_WAITPID
132  wait_pid = waitpid(child_pid, (int *)&child_wait_status, WNOHANG);
133#else
134  wait_pid = wait((int *)&child_wait_status);
135#endif
136  if (wait_pid > 0)
137    {
138      if (wait_pid != child_pid)
139        error("Strange, got SIGCHLD and wait returned pid %d but child is %d",
140              wait_pid, child_pid);
141      if (WIFEXITED(child_wait_status) ||
142          WIFSIGNALED(child_wait_status))
143        {
144          child_terminated = 1;
145          child_just_terminated = 1;
146        }
147    }
148  signal(SIGCHLD, sigchld_handler);
149}
150
151/* Process any buffered packets that have been received from the client. */
152
153void process_buffered_input_packets(void)
154{
155  int type;
156  char *data;
157  unsigned int data_len;
158  int row, col, xpixel, ypixel;
159
160  /* Process buffered packets from the client. */
161  while ((type = packet_read_poll()) != SSH_MSG_NONE)
162    {
163      switch (type)
164        {
165        case SSH_CMSG_STDIN_DATA:
166          /* Stdin data from the client.  Append it to the buffer. */
167          if (fdin == -1)
168            {
169              packet_get_all();
170              break; /* Ignore any data if the client has closed stdin. */
171            }
172          data = packet_get_string(&data_len);
173          buffer_append(&stdin_buffer, data, data_len);
174          memset(data, 0, data_len);
175          xfree(data);
176          break;
177         
178        case SSH_CMSG_EOF:
179          /* Eof from the client.  The stdin descriptor to the program
180             will be closed when all buffered data has drained. */
181          debug("EOF received for stdin.");
182          stdin_eof = 1;
183          break;
184
185        case SSH_CMSG_WINDOW_SIZE:
186          debug("Window change received.");
187          row = packet_get_int();
188          col = packet_get_int();
189          xpixel = packet_get_int();
190          ypixel = packet_get_int();
191          if (fdin != -1)
192            pty_change_window_size(fdin, row, col, xpixel, ypixel);
193          break;
194         
195        case SSH_MSG_PORT_OPEN:
196#ifndef SSHD_NO_PORT_FORWARDING
197          if (no_port_forwarding_flag)
198#endif /* SSHD_NO_PORT_FORWARDING */
199            {
200              int remote_channel;
201             
202              /* Get remote channel number. */
203              remote_channel = packet_get_int();
204             
205              packet_get_all();
206             
207              debug("Denied port open request.");
208              packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
209              packet_put_int(remote_channel);
210              packet_send();
211            }
212#ifndef SSHD_NO_PORT_FORWARDING
213          else
214            {
215              debug("Received port open request.");
216              channel_input_port_open();
217            }
218#endif /* SSHD_NO_PORT_FORWARDING */
219          break;
220         
221        case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
222          debug("Received channel open confirmation.");
223          channel_input_open_confirmation();
224          break;
225
226        case SSH_MSG_CHANNEL_OPEN_FAILURE:
227          debug("Received channel open failure.");
228          channel_input_open_failure();
229          break;
230         
231        case SSH_MSG_CHANNEL_DATA:
232          channel_input_data();
233          break;
234         
235#ifdef SUPPORT_OLD_CHANNELS
236        case SSH_MSG_CHANNEL_CLOSE:
237          debug("Received channel close.");
238          channel_input_close();
239          break;
240
241        case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
242          debug("Received channel close confirmation.");
243          channel_input_close_confirmation();
244          break;
245#else
246        case SSH_MSG_CHANNEL_INPUT_EOF:
247          debug("Received channel input eof.");
248          channel_ieof();         
249          break;
250
251        case SSH_MSG_CHANNEL_OUTPUT_CLOSED:
252          debug("Received channel output closed.");
253          channel_oclosed();
254          break;
255
256#endif
257
258        default:
259          /* In this phase, any unexpected messages cause a protocol
260             error.  This is to ease debugging; also, since no
261             confirmations are sent messages, unprocessed unknown
262             messages could cause strange problems.  Any compatible
263             protocol extensions must be negotiated before entering the
264             interactive session. */
265          packet_disconnect("Protocol error during session: type %d",
266                            type);
267        }
268    }
269}
270
271/* Make packets from buffered stderr data, and buffer it for sending
272   to the client. */
273
274void make_packets_from_stderr_data(void)
275{
276  int len;
277
278  /* Send buffered stderr data to the client. */
279  while (buffer_len(&stderr_buffer) > 0 &&
280         packet_not_very_much_data_to_write())
281    {
282      len = buffer_len(&stderr_buffer);
283      if (packet_is_interactive())
284        {
285          if (len > 512)
286            len = 512;
287        }
288      else
289        {
290          if (len > 32768)
291            len = 32768;  /* Keep the packets at reasonable size. */
292          if (len > packet_max_size() / 2)
293            len = packet_max_size() / 2;
294        }
295      packet_start(SSH_SMSG_STDERR_DATA);
296      packet_put_string(buffer_ptr(&stderr_buffer), len);
297      packet_send();
298      buffer_consume(&stderr_buffer, len);
299      stderr_bytes += len;
300    }
301}
302
303/* Make packets from buffered stdout data, and buffer it for sending to the
304   client. */
305
306void make_packets_from_stdout_data(void)
307{
308  int len;
309
310  /* Send buffered stdout data to the client. */
311  while (buffer_len(&stdout_buffer) > 0 &&
312         packet_not_very_much_data_to_write())
313    {
314      len = buffer_len(&stdout_buffer);
315      if (packet_is_interactive())
316        {
317          if (len > 512)
318            len = 512;
319        }
320      else
321        {
322          if (len > 32768)
323            len = 32768;  /* Keep the packets at reasonable size. */
324          if (len > packet_max_size() / 2)
325            len = packet_max_size() / 2;
326        }
327      packet_start(SSH_SMSG_STDOUT_DATA);
328      packet_put_string(buffer_ptr(&stdout_buffer), len);
329      packet_send();
330      buffer_consume(&stdout_buffer, len);
331      stdout_bytes += len;
332    }
333}
334
335/* Sleep in select() until we can do something.  This will initialize the
336   select masks.  Upon return, the masks will indicate which descriptors
337   have data or can accept data.  Optionally, a maximum time can be specified
338   for the duration of the wait (0 = infinite). */
339
340void wait_until_can_do_something(fd_set *readset, fd_set *writeset,
341                                 unsigned int max_time_milliseconds,
342                                 void *cleanup_context)
343{
344  struct timeval tv, *tvp;
345  int ret;
346
347  /* Mark that we have slept since the child died. */
348  child_just_terminated = 0;
349
350  /* Initialize select() masks. */
351  FD_ZERO(readset);
352 
353  /* Read packets from the client unless we have too much buffered stdin
354     or channel data. */
355  if (buffer_len(&stdin_buffer) < 4096 &&
356      channel_not_very_much_buffered_data())
357    FD_SET(connection_in, readset);
358 
359  /* If there is not too much data already buffered going to the client,
360     try to get some more data from the program. */
361  if (packet_not_very_much_data_to_write())
362    {
363      if (!fdout_eof)
364        FD_SET(fdout, readset);
365      if (!fderr_eof)
366        FD_SET(fderr, readset);
367    }
368 
369  FD_ZERO(writeset);
370 
371  /* Set masks for channel descriptors. */
372  channel_prepare_select(readset, writeset);
373 
374  /* If we have buffered packet data going to the client, mark that
375     descriptor. */
376  if (packet_have_data_to_write())
377    FD_SET(connection_out, writeset);
378 
379  /* If we have buffered data, try to write some of that data to the
380     program. */
381  if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
382    FD_SET(fdin, writeset);
383 
384  /* Update the maximum descriptor number if appropriate. */
385  if (channel_max_fd() > max_fd)
386    max_fd = channel_max_fd();
387 
388  /* If child has terminated, read as much as is available and then exit. */
389  if (child_terminated)
390    if (max_time_milliseconds == 0)
391      max_time_milliseconds = 100;
392
393  if (idle_timeout != 0 &&
394      (max_time_milliseconds == 0 ||
395       max_time_milliseconds / 1000 > idle_timeout))
396    {
397      time_t diff;
398
399      diff = time(NULL) - idle_time_last;
400     
401      if (idle_timeout > diff)
402        tv.tv_sec = idle_timeout - diff;
403      else
404        tv.tv_sec = 1;
405      tv.tv_usec = 0;
406      tvp = &tv;
407    }
408  else
409    {
410      if (max_time_milliseconds == 0)
411        tvp = NULL;
412      else
413        {
414          tv.tv_sec = max_time_milliseconds / 1000;
415          tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
416          tvp = &tv;
417        }
418    }
419
420  /* Wait for something to happen, or the timeout to expire. */
421  ret = select(max_fd + 1, readset, writeset, NULL, tvp);
422 
423  if (ret < 0)
424    {
425      if (errno != EINTR)
426        error("select: %.100s", strerror(errno));
427      /* At least HPSUX fails to zero these, contrary to its documentation. */
428      FD_ZERO(readset);
429      FD_ZERO(writeset);
430    }
431 
432  /* If the child has terminated and there was no data, shutdown all
433     descriptors to it. */
434  if (ret <= 0 && child_terminated && !child_just_terminated)
435    {
436      /* Released the pseudo-tty. */
437      if (cleanup_context)
438        pty_cleanup_proc(cleanup_context);
439     
440      if (fdout != -1)
441        close(fdout);
442      fdout = -1;
443      fdout_eof = 1;
444      if (fderr != -1)
445        close(fderr);
446      fderr = -1;
447      fderr_eof = 1;
448      if (fdin != -1)
449        close(fdin);
450      fdin = -1;
451    }
452  else
453    {
454      if (ret == 0)             /* Nothing read, timeout expired */
455        {
456          /* Check if idle_timeout expired ? */
457          if (idle_timeout != 0 && !child_terminated &&
458              time(NULL) - idle_time_last > idle_timeout)
459            {
460              /* Yes, kill the child */
461              kill(child_pid, SIGHUP);
462              sleep(5);
463              if (!child_terminated) /* Not exited, be rude */
464                kill(child_pid, SIGKILL);
465            }
466        }
467      else
468        {
469          /* Got something, reset idle timer */
470          idle_time_last = time(NULL);
471        }
472    }
473}
474
475/* Processes input from the client and the program.  Input data is stored
476   in buffers and processed later. */
477
478void process_input(fd_set *readset)
479{
480  int len;
481  char buf[16384];
482
483  /* Read and buffer any input data from the client. */
484  if (FD_ISSET(connection_in, readset))
485    {
486      len = read(connection_in, buf, sizeof(buf));
487      if (len == 0)
488        fatal_severity(SYSLOG_SEVERITY_INFO,
489                       "Connection closed by remote host.");
490
491      /* There is a kernel bug on Solaris that causes select to sometimes
492         wake up even though there is no data available. */
493      if (len < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
494        len = 0;
495
496      if (len < 0)
497        fatal_severity(SYSLOG_SEVERITY_INFO,
498                       "Read error from remote host: %.100s", strerror(errno));
499
500      /* Buffer any received data. */
501      packet_process_incoming(buf, len);
502    }
503 
504  /* Read and buffer any available stdout data from the program. */
505  if (!fdout_eof && FD_ISSET(fdout, readset))
506    {
507      len = read(fdout, buf, sizeof(buf));
508      if (len <= 0)
509        fdout_eof = 1;
510      else
511        {
512          buffer_append(&stdout_buffer, buf, len);
513          fdout_bytes += len;
514        }
515    }
516 
517  /* Read and buffer any available stderr data from the program. */
518  if (!fderr_eof && FD_ISSET(fderr, readset))
519    {
520      len = read(fderr, buf, sizeof(buf));
521      if (len <= 0)
522        fderr_eof = 1;
523      else
524        buffer_append(&stderr_buffer, buf, len);
525    }
526}
527
528/* Sends data from internal buffers to client program stdin. */
529
530void process_output(fd_set *writeset)
531{
532  int len;
533
534  /* Write buffered data to program stdin. */
535  if (fdin != -1 && FD_ISSET(fdin, writeset))
536    {
537      len = write(fdin, buffer_ptr(&stdin_buffer),
538                  buffer_len(&stdin_buffer));
539      if (len <= 0)
540        {
541          if (errno != EWOULDBLOCK && errno != EAGAIN)
542            {
543              debug("Process_output: write to fdin failed, len = %d : %.50s",
544                    len, strerror(errno));
545              if (fdin == fdout)
546                shutdown(fdin, 1); /* We will no longer send. */
547              else
548                close(fdin);
549              fdin = -1;
550            }
551        }
552      else
553        {
554          /* Successful write.  Consume the data from the buffer. */
555          buffer_consume(&stdin_buffer, len);
556          /* Update the count of bytes written to the program. */
557          stdin_bytes += len;
558        }
559    }
560 
561  /* Send any buffered packet data to the client. */
562  if (FD_ISSET(connection_out, writeset))
563    packet_write_poll();
564}
565
566/* Wait until all buffered output has been sent to the client.
567   This is used when the program terminates. */
568
569void drain_output(void)
570{
571  /* Send any buffered stdout data to the client. */
572  if (buffer_len(&stdout_buffer) > 0)
573    {
574      packet_start(SSH_SMSG_STDOUT_DATA);
575      packet_put_string(buffer_ptr(&stdout_buffer),
576                        buffer_len(&stdout_buffer));
577      packet_send();
578      /* Update the count of sent bytes. */
579      stdout_bytes += buffer_len(&stdout_buffer);
580    }
581 
582  /* Send any buffered stderr data to the client. */
583  if (buffer_len(&stderr_buffer) > 0)
584    {
585      packet_start(SSH_SMSG_STDERR_DATA);
586      packet_put_string(buffer_ptr(&stderr_buffer),
587                        buffer_len(&stderr_buffer));
588      packet_send();
589      /* Update the count of sent bytes. */
590      stderr_bytes += buffer_len(&stderr_buffer);
591    }
592 
593  /* Wait until all buffered data has been written to the client. */
594  packet_write_wait();
595}
596
597/* Performs the interactive session.  This handles data transmission between
598   the client and the program.  Note that the notion of stdin, stdout, and
599   stderr in this function is sort of reversed: this function writes to
600   stdin (of the child program), and reads from stdout and stderr (of the
601   child program).
602   This will close fdin, fdout and fderr after releasing pty (if ttyname is non
603   NULL) */
604
605void server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg,
606                 void *cleanup_context)
607{
608  int wait_status, wait_pid;    /* Status and pid returned by wait(). */
609  int waiting_termination = 0;  /* Have displayed waiting close message. */
610  unsigned int max_time_milliseconds;
611  unsigned int previous_stdout_buffer_bytes;
612  unsigned int stdout_buffer_bytes;
613  int type;
614
615  debug("Entering interactive session.");
616
617  /* Initialize the SIGCHLD kludge. */
618  child_pid = pid;
619  child_terminated = 0;
620  signal(SIGCHLD, sigchld_handler);
621
622  /* Initialize our global variables. */
623  idle_time_last = time(NULL);
624  fdin = fdin_arg;
625  fdout = fdout_arg;
626  fderr = fderr_arg;
627  connection_in = packet_get_connection_in();
628  connection_out = packet_get_connection_out();
629 
630  previous_stdout_buffer_bytes = 0;
631
632  /* Set approximate I/O buffer size. */
633  if (packet_is_interactive())
634    buffer_high = 4096;
635  else
636    buffer_high = 64 * 1024;
637
638  /* Initialize max_fd to the maximum of the known file descriptors. */
639  max_fd = fdin;
640  if (fdout > max_fd)
641    max_fd = fdout;
642  if (fderr != -1 && fderr > max_fd)
643    max_fd = fderr;
644  if (connection_in > max_fd)
645    max_fd = connection_in;
646  if (connection_out > max_fd)
647    max_fd = connection_out;
648
649  /* Initialize Initialize buffers. */
650  buffer_init(&stdin_buffer);
651  buffer_init(&stdout_buffer);
652  buffer_init(&stderr_buffer);
653
654  /* If we have no separate fderr (which is the case when we have a pty - there
655     we cannot make difference between data sent to stdout and stderr),
656     indicate that we have seen an EOF from stderr.  This way we don\'t
657     need to check the descriptor everywhere. */
658  if (fderr == -1)
659    fderr_eof = 1;
660
661  /*
662   * Set ttyfd to non-blocking i/o to avoid deadlock in process_output()
663   * when doing large paste from xterm into slow program such as vi.  - corey
664   */
665#if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN)
666  (void)fcntl(fdin, F_SETFL, O_NONBLOCK);
667#else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
668  (void)fcntl(fdin, F_SETFL, O_NDELAY);
669#endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
670
671  /* Main loop of the server for the interactive session mode. */
672  for (;;)
673    {
674      fd_set readset, writeset;
675
676      /* Process buffered packets from the client. */
677      process_buffered_input_packets();
678
679      /* If we have received eof, and there is no more pending input data,
680         cause a real eof by closing fdin. */
681      if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0)
682        {
683          if (fdin == fdout)
684            shutdown(fdin, 1); /* We will no longer send. */
685          else
686            close(fdin);
687          fdin = -1;
688        }
689
690      /* Make packets from buffered stderr data to send to the client. */
691      make_packets_from_stderr_data();
692
693      /* Make packets from buffered stdout data to send to the client.
694         If there is very little to send, this arranges to not send them
695         now, but to wait a short while to see if we are getting more data.
696         This is necessary, as some systems wake up readers from a pty after
697         each separate character. */
698      max_time_milliseconds = 0;
699      stdout_buffer_bytes = buffer_len(&stdout_buffer);
700      if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 512 &&
701          stdout_buffer_bytes != previous_stdout_buffer_bytes)
702        max_time_milliseconds = 17; /* try again after a while (1/60sec)*/
703      else
704        make_packets_from_stdout_data(); /* Send it now. */
705      previous_stdout_buffer_bytes = buffer_len(&stdout_buffer);
706
707      /* Send channel data to the client. */
708      if (packet_not_very_much_data_to_write())
709        channel_output_poll();
710
711      /* Bail out of the loop if the program has closed its output descriptors,
712         and we have no more data to send to the client, and there is no
713         pending buffered data. */
714      if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
715          buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0)
716        {
717          if (!channel_still_open())
718            goto quit;
719          if (!waiting_termination && !child_just_terminated)
720            {
721              const char *s =
722                "Waiting for forwarded connections to terminate...\r\n";
723              char *cp;
724              waiting_termination = 1;
725              buffer_append(&stderr_buffer, s, strlen(s));
726
727              /* Display list of open channels. */
728              cp = channel_open_message();
729              buffer_append(&stderr_buffer, cp, strlen(cp));
730              xfree(cp);
731            }
732        }
733
734      /* Sleep in select() until we can do something. */
735      wait_until_can_do_something(&readset, &writeset,
736                                  max_time_milliseconds, cleanup_context);
737
738      /* Process any channel events. */
739      channel_after_select(&readset, &writeset);
740
741      /* Process input from the client and from program stdout/stderr. */
742      process_input(&readset);
743
744      /* Process output to the client and to program stdin. */
745      process_output(&writeset);
746    }
747
748 quit:
749  /* Cleanup and termination code. */
750
751  /* Wait until all output has been sent to the client. */
752  drain_output();
753
754  debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",
755        stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
756
757  /* Free and clear the buffers. */
758  buffer_free(&stdin_buffer);
759  buffer_free(&stdout_buffer);
760  buffer_free(&stderr_buffer);
761
762  /* Released the pseudo-tty. */
763  if (cleanup_context)
764    pty_cleanup_proc(cleanup_context);
765 
766  /* Close the file descriptors. */
767  if (fdout != -1)
768    close(fdout);
769  if (fdin != -1 && fdin != fdout)
770    close(fdin);
771  if (fderr != -1)
772    close(fderr);
773 
774  /* Stop listening for channels; this removes unix domain sockets. */
775  channel_stop_listening();
776 
777  /* We no longer want our SIGCHLD handler to be called. */
778  signal(SIGCHLD, SIG_DFL);
779
780  if (child_terminated)
781    wait_status = child_wait_status;
782  else
783    {
784      /* Wait for the child to exit.  Get its exit status. */
785      wait_pid = wait(&wait_status);
786      if (wait_pid < 0)
787        {
788          packet_disconnect("wait: %.100s", strerror(errno));
789        }
790      else
791        {
792          /* Check if it matches the process we forked. */
793          if (wait_pid != pid)
794            error("Strange, wait returned pid %d, expected %d", wait_pid, pid);
795        }
796    }
797
798  /* Check if it exited normally. */
799  if (WIFEXITED(wait_status))
800    {
801      /* Yes, normal exit.  Get exit status and send it to the client. */
802      debug("Command exited with status %d.", WEXITSTATUS(wait_status));
803      packet_start(SSH_SMSG_EXITSTATUS);
804      packet_put_int(WEXITSTATUS(wait_status));
805      packet_send();
806      packet_write_wait();
807
808      /* Wait for exit confirmation.  Note that there might be other
809         packets coming before it; however, the program has already died
810         so we just ignore them.  The client is supposed to respond with
811         the confirmation when it receives the exit status. */
812      do
813        {
814          type = packet_read();
815          if (type != SSH_CMSG_EXIT_CONFIRMATION)
816            {
817              packet_get_all();
818              debug("Received packet of type %d after exit.\n", type);
819            }
820        }
821      while (type != SSH_CMSG_EXIT_CONFIRMATION);
822
823      debug("Received exit confirmation.");
824      return;
825    }
826
827  /* Check if the program terminated due to a signal. */
828  if (WIFSIGNALED(wait_status))
829    packet_disconnect("Command terminated on signal %d.",
830                      WTERMSIG(wait_status));
831
832  /* Some weird exit cause.  Just exit. */
833  packet_disconnect("wait returned status %04x.", wait_status);
834  /*NOTREACHED*/
835}
836
Note: See TracBrowser for help on using the repository browser.