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

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