[BACK]Return to channels.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / crypto / external / bsd / openssh / dist

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/crypto/external/bsd/openssh/dist/channels.c between version 1.34 and 1.35

version 1.34, 2021/12/24 21:52:48 version 1.35, 2022/02/23 19:07:20
Line 1 
Line 1 
 /*      $NetBSD$        */  /*      $NetBSD$        */
 /* $OpenBSD: channels.c,v 1.408 2021/09/14 11:04:21 mbuhl Exp $ */  /* $OpenBSD: channels.c,v 1.413 2022/02/17 10:58:27 djm Exp $ */
   
 /*  /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>   * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland   * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Line 59  __RCSID("$NetBSD$");
Line 58  __RCSID("$NetBSD$");
 #include <fcntl.h>  #include <fcntl.h>
 #include <limits.h>  #include <limits.h>
 #include <netdb.h>  #include <netdb.h>
   #include <poll.h>
 #include <stdarg.h>  #include <stdarg.h>
 #include <stdint.h>  #include <stdint.h>
 #include <stdio.h>  #include <stdio.h>
Line 87  __RCSID("$NetBSD$");
Line 87  __RCSID("$NetBSD$");
 static int hpn_disabled = 0;  static int hpn_disabled = 0;
 static int hpn_buffer_size = 2 * 1024 * 1024;  static int hpn_buffer_size = 2 * 1024 * 1024;
   
   /* XXX remove once we're satisfied there's no lurking bugs */
   /* #define DEBUG_CHANNEL_POLL 1 */
   
 /* -- agent forwarding */  /* -- agent forwarding */
 #define NUM_SOCKS       10  #define NUM_SOCKS       10
   
Line 101  static int hpn_buffer_size = 2 * 1024 * 
Line 104  static int hpn_buffer_size = 2 * 1024 * 
 /* Maximum number of fake X11 displays to try. */  /* Maximum number of fake X11 displays to try. */
 #define MAX_DISPLAYS  1000  #define MAX_DISPLAYS  1000
   
 /* Per-channel callback for pre/post select() actions */  /* Per-channel callback for pre/post IO actions */
 typedef void chan_fn(struct ssh *, Channel *c,  typedef void chan_fn(struct ssh *, Channel *c);
     fd_set *readset, fd_set *writeset);  
   
 /*  /*
  * Data structure for storing which hosts are permitted for forward requests.   * Data structure for storing which hosts are permitted for forward requests.
Line 164  struct ssh_channels {
Line 166  struct ssh_channels {
         u_int channels_alloc;          u_int channels_alloc;
   
         /*          /*
          * Maximum file descriptor value used in any of the channels.  This is           * 'channel_pre*' are called just before IO to add any bits
          * updated in channel_new.           * relevant to channels in the c->io_want bitmasks.
          */  
         int channel_max_fd;  
   
         /*  
          * 'channel_pre*' are called just before select() to add any bits  
          * relevant to channels in the select bitmasks.  
          *           *
          * 'channel_post*': perform any appropriate operations for           * 'channel_post*': perform any appropriate operations for
          * channels which have events pending.           * channels which have c->io_ready events pending.
          */           */
         chan_fn **channel_pre;          chan_fn **channel_pre;
         chan_fn **channel_post;          chan_fn **channel_post;
Line 309  static void
Line 305  static void
 channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd,  channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd,
     int extusage, int nonblock, int is_tty)      int extusage, int nonblock, int is_tty)
 {  {
         struct ssh_channels *sc = ssh->chanctxt;  
   
         /* Update the maximum file descriptor value. */  
         sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, rfd);  
         sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, wfd);  
         sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, efd);  
   
         if (rfd != -1)          if (rfd != -1)
                 fcntl(rfd, F_SETFD, FD_CLOEXEC);                  fcntl(rfd, F_SETFD, FD_CLOEXEC);
         if (wfd != -1 && wfd != rfd)          if (wfd != -1 && wfd != rfd)
Line 426  channel_new(struct ssh *ssh, const char 
Line 415  channel_new(struct ssh *ssh, const char 
         return c;          return c;
 }  }
   
 static void  
 channel_find_maxfd(struct ssh_channels *sc)  
 {  
         u_int i;  
         int max = 0;  
         Channel *c;  
   
         for (i = 0; i < sc->channels_alloc; i++) {  
                 c = sc->channels[i];  
                 if (c != NULL) {  
                         max = MAXIMUM(max, c->rfd);  
                         max = MAXIMUM(max, c->wfd);  
                         max = MAXIMUM(max, c->efd);  
                 }  
         }  
         sc->channel_max_fd = max;  
 }  
   
 int  int
 channel_close_fd(struct ssh *ssh, Channel *c, int *fdp)  channel_close_fd(struct ssh *ssh, Channel *c, int *fdp)
 {  {
         struct ssh_channels *sc = ssh->chanctxt;  
         int ret, fd = *fdp;          int ret, fd = *fdp;
   
         if (fd == -1)          if (fd == -1)
Line 458  channel_close_fd(struct ssh *ssh, Channe
Line 428  channel_close_fd(struct ssh *ssh, Channe
            (*fdp == c->efd && (c->restore_block & CHANNEL_RESTORE_EFD) != 0))             (*fdp == c->efd && (c->restore_block & CHANNEL_RESTORE_EFD) != 0))
                 (void)fcntl(*fdp, F_SETFL, 0);  /* restore blocking */                  (void)fcntl(*fdp, F_SETFL, 0);  /* restore blocking */
   
           if (*fdp == c->rfd) {
                   c->io_want &= ~SSH_CHAN_IO_RFD;
                   c->io_ready &= ~SSH_CHAN_IO_RFD;
                   c->rfd = -1;
           }
           if (*fdp == c->wfd) {
                   c->io_want &= ~SSH_CHAN_IO_WFD;
                   c->io_ready &= ~SSH_CHAN_IO_WFD;
                   c->wfd = -1;
           }
           if (*fdp == c->efd) {
                   c->io_want &= ~SSH_CHAN_IO_EFD;
                   c->io_ready &= ~SSH_CHAN_IO_EFD;
                   c->efd = -1;
           }
           if (*fdp == c->sock) {
                   c->io_want &= ~SSH_CHAN_IO_SOCK;
                   c->io_ready &= ~SSH_CHAN_IO_SOCK;
                   c->sock = -1;
           }
   
         ret = close(fd);          ret = close(fd);
         *fdp = -1;          *fdp = -1; /* probably redundant */
         if (fd == sc->channel_max_fd)  
                 channel_find_maxfd(sc);  
         return ret;          return ret;
 }  }
   
Line 546  permission_set_get_array(struct ssh *ssh
Line 535  permission_set_get_array(struct ssh *ssh
         }          }
 }  }
   
 /* Adds an entry to the spcified forwarding list */  /* Adds an entry to the specified forwarding list */
 static int  static int
 permission_set_add(struct ssh *ssh, int who, int where,  permission_set_add(struct ssh *ssh, int who, int where,
     const char *host_to_connect, int port_to_connect,      const char *host_to_connect, int port_to_connect,
Line 683  channel_free_all(struct ssh *ssh)
Line 672  channel_free_all(struct ssh *ssh)
         free(sc->channels);          free(sc->channels);
         sc->channels = NULL;          sc->channels = NULL;
         sc->channels_alloc = 0;          sc->channels_alloc = 0;
         sc->channel_max_fd = 0;  
   
         free(sc->x11_saved_display);          free(sc->x11_saved_display);
         sc->x11_saved_display = NULL;          sc->x11_saved_display = NULL;
Line 875  channel_format_status(const Channel *c)
Line 863  channel_format_status(const Channel *c)
         char *ret = NULL;          char *ret = NULL;
   
         xasprintf(&ret, "t%d %s%u i%u/%zu o%u/%zu e[%s]/%zu "          xasprintf(&ret, "t%d %s%u i%u/%zu o%u/%zu e[%s]/%zu "
             "fd %d/%d/%d sock %d cc %d",              "fd %d/%d/%d sock %d cc %d io 0x%02x/0x%02x",
             c->type,              c->type,
             c->have_remote_id ? "r" : "nr", c->remote_id,              c->have_remote_id ? "r" : "nr", c->remote_id,
             c->istate, sshbuf_len(c->input),              c->istate, sshbuf_len(c->input),
             c->ostate, sshbuf_len(c->output),              c->ostate, sshbuf_len(c->output),
             channel_format_extended_usage(c), sshbuf_len(c->extended),              channel_format_extended_usage(c), sshbuf_len(c->extended),
             c->rfd, c->wfd, c->efd, c->sock, c->ctl_chan);              c->rfd, c->wfd, c->efd, c->sock, c->ctl_chan,
               c->io_want, c->io_ready);
         return ret;          return ret;
 }  }
   
Line 1100  channel_set_fds(struct ssh *ssh, int id,
Line 1089  channel_set_fds(struct ssh *ssh, int id,
 }  }
   
 static void  static void
 channel_pre_listener(struct ssh *ssh, Channel *c,  channel_pre_listener(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         FD_SET(c->sock, readset);          c->io_want = SSH_CHAN_IO_SOCK_R;
 }  }
   
 static void  static void
 channel_pre_connecting(struct ssh *ssh, Channel *c,  channel_pre_connecting(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         debug3("channel %d: waiting for connection", c->self);          debug3("channel %d: waiting for connection", c->self);
         FD_SET(c->sock, writeset);          c->io_want = SSH_CHAN_IO_SOCK_W;
 }  }
   
 static int  static int
Line 1135  channel_tcpwinsz(struct ssh *ssh)
Line 1122  channel_tcpwinsz(struct ssh *ssh)
 }  }
   
 static void  static void
 channel_pre_open(struct ssh *ssh, Channel *c,  channel_pre_open(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         /* check buffer limits */          /* check buffer limits */
         if ((!c->tcpwinsz) || (c->dynamic_window > 0))          if ((!c->tcpwinsz) || (c->dynamic_window > 0))
             c->tcpwinsz = channel_tcpwinsz(ssh);              c->tcpwinsz = channel_tcpwinsz(ssh);
   
           c->io_want = 0;
         if (c->istate == CHAN_INPUT_OPEN &&          if (c->istate == CHAN_INPUT_OPEN &&
             c->remote_window > 0 &&              c->remote_window > 0 &&
             sshbuf_len(c->input) < c->remote_window &&              sshbuf_len(c->input) < c->remote_window &&
             sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)              sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)
                 FD_SET(c->rfd, readset);                  c->io_want |= SSH_CHAN_IO_RFD;
         if (c->ostate == CHAN_OUTPUT_OPEN ||          if (c->ostate == CHAN_OUTPUT_OPEN ||
             c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {              c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
                 if (sshbuf_len(c->output) > 0) {                  if (sshbuf_len(c->output) > 0) {
                         FD_SET(c->wfd, writeset);                          c->io_want |= SSH_CHAN_IO_WFD;
                 } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {                  } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
                         if (CHANNEL_EFD_OUTPUT_ACTIVE(c))                          if (CHANNEL_EFD_OUTPUT_ACTIVE(c))
                                 debug2("channel %d: "                                  debug2("channel %d: "
Line 1165  channel_pre_open(struct ssh *ssh, Channe
Line 1152  channel_pre_open(struct ssh *ssh, Channe
             c->ostate == CHAN_OUTPUT_CLOSED)) {              c->ostate == CHAN_OUTPUT_CLOSED)) {
                 if (c->extended_usage == CHAN_EXTENDED_WRITE &&                  if (c->extended_usage == CHAN_EXTENDED_WRITE &&
                     sshbuf_len(c->extended) > 0)                      sshbuf_len(c->extended) > 0)
                         FD_SET(c->efd, writeset);                          c->io_want |= SSH_CHAN_IO_EFD_W;
                 else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&                  else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&
                     (c->extended_usage == CHAN_EXTENDED_READ ||                      (c->extended_usage == CHAN_EXTENDED_READ ||
                     c->extended_usage == CHAN_EXTENDED_IGNORE) &&                      c->extended_usage == CHAN_EXTENDED_IGNORE) &&
                     sshbuf_len(c->extended) < c->remote_window)                      sshbuf_len(c->extended) < c->remote_window)
                         FD_SET(c->efd, readset);                          c->io_want |= SSH_CHAN_IO_EFD_R;
         }          }
         /* XXX: What about efd? races? */          /* XXX: What about efd? races? */
 }  }
Line 1252  x11_open_helper(struct ssh *ssh, struct 
Line 1239  x11_open_helper(struct ssh *ssh, struct 
 }  }
   
 static void  static void
 channel_pre_x11_open(struct ssh *ssh, Channel *c,  channel_pre_x11_open(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         int ret = x11_open_helper(ssh, c->output);          int ret = x11_open_helper(ssh, c->output);
   
Line 1261  channel_pre_x11_open(struct ssh *ssh, Ch
Line 1247  channel_pre_x11_open(struct ssh *ssh, Ch
   
         if (ret == 1) {          if (ret == 1) {
                 c->type = SSH_CHANNEL_OPEN;                  c->type = SSH_CHANNEL_OPEN;
                 channel_pre_open(ssh, c, readset, writeset);                  channel_pre_open(ssh, c);
         } else if (ret == -1) {          } else if (ret == -1) {
                 logit("X11 connection rejected because of wrong authentication.");                  logit("X11 connection rejected because of wrong authentication.");
                 debug2("X11 rejected %d i%d/o%d",                  debug2("X11 rejected %d i%d/o%d",
Line 1276  channel_pre_x11_open(struct ssh *ssh, Ch
Line 1262  channel_pre_x11_open(struct ssh *ssh, Ch
 }  }
   
 static void  static void
 channel_pre_mux_client(struct ssh *ssh,  channel_pre_mux_client(struct ssh *ssh, Channel *c)
     Channel *c, fd_set *readset, fd_set *writeset)  
 {  {
           c->io_want = 0;
         if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&          if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&
             sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)              sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)
                 FD_SET(c->rfd, readset);                  c->io_want |= SSH_CHAN_IO_RFD;
         if (c->istate == CHAN_INPUT_WAIT_DRAIN) {          if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
                 /* clear buffer immediately (discard any partial packet) */                  /* clear buffer immediately (discard any partial packet) */
                 sshbuf_reset(c->input);                  sshbuf_reset(c->input);
Line 1292  channel_pre_mux_client(struct ssh *ssh,
Line 1278  channel_pre_mux_client(struct ssh *ssh,
         if (c->ostate == CHAN_OUTPUT_OPEN ||          if (c->ostate == CHAN_OUTPUT_OPEN ||
             c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {              c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
                 if (sshbuf_len(c->output) > 0)                  if (sshbuf_len(c->output) > 0)
                         FD_SET(c->wfd, writeset);                          c->io_want |= SSH_CHAN_IO_WFD;
                 else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN)                  else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN)
                         chan_obuf_empty(ssh, c);                          chan_obuf_empty(ssh, c);
         }          }
Line 1571  channel_connect_stdio_fwd(struct ssh *ss
Line 1557  channel_connect_stdio_fwd(struct ssh *ss
   
 /* dynamic port forwarding */  /* dynamic port forwarding */
 static void  static void
 channel_pre_dynamic(struct ssh *ssh, Channel *c,  channel_pre_dynamic(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         const u_char *p;          const u_char *p;
         u_int have;          u_int have;
         int ret;          int ret;
   
           c->io_want = 0;
         have = sshbuf_len(c->input);          have = sshbuf_len(c->input);
         debug2("channel %d: pre_dynamic: have %d", c->self, have);          debug2("channel %d: pre_dynamic: have %d", c->self, have);
         /* sshbuf_dump(c->input, stderr); */          /* sshbuf_dump(c->input, stderr); */
         /* check if the fixed size part of the packet is in buffer. */          /* check if the fixed size part of the packet is in buffer. */
         if (have < 3) {          if (have < 3) {
                 /* need more */                  /* need more */
                 FD_SET(c->sock, readset);                  c->io_want |= SSH_CHAN_IO_RFD;
                 return;                  return;
         }          }
         /* try to guess the protocol */          /* try to guess the protocol */
Line 1606  channel_pre_dynamic(struct ssh *ssh, Cha
Line 1592  channel_pre_dynamic(struct ssh *ssh, Cha
         } else if (ret == 0) {          } else if (ret == 0) {
                 debug2("channel %d: pre_dynamic: need more", c->self);                  debug2("channel %d: pre_dynamic: need more", c->self);
                 /* need more */                  /* need more */
                 FD_SET(c->sock, readset);                  c->io_want |= SSH_CHAN_IO_RFD;
                 if (sshbuf_len(c->output))                  if (sshbuf_len(c->output))
                         FD_SET(c->sock, writeset);                          c->io_want |= SSH_CHAN_IO_WFD;
         } else {          } else {
                 /* switch to the next state */                  /* switch to the next state */
                 c->type = SSH_CHANNEL_OPENING;                  c->type = SSH_CHANNEL_OPENING;
Line 1630  rdynamic_close(struct ssh *ssh, Channel 
Line 1616  rdynamic_close(struct ssh *ssh, Channel 
   
 /* reverse dynamic port forwarding */  /* reverse dynamic port forwarding */
 static void  static void
 channel_before_prepare_select_rdynamic(struct ssh *ssh, Channel *c)  channel_before_prepare_io_rdynamic(struct ssh *ssh, Channel *c)
 {  {
         const u_char *p;          const u_char *p;
         u_int have, len;          u_int have, len;
Line 1688  channel_before_prepare_select_rdynamic(s
Line 1674  channel_before_prepare_select_rdynamic(s
   
 /* This is our fake X11 server socket. */  /* This is our fake X11 server socket. */
 static void  static void
 channel_post_x11_listener(struct ssh *ssh, Channel *c,  channel_post_x11_listener(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         Channel *nc;          Channel *nc;
         struct sockaddr_storage addr;          struct sockaddr_storage addr;
Line 1697  channel_post_x11_listener(struct ssh *ss
Line 1682  channel_post_x11_listener(struct ssh *ss
         socklen_t addrlen;          socklen_t addrlen;
         char buf[16384], *remote_ipaddr;          char buf[16384], *remote_ipaddr;
   
         if (!FD_ISSET(c->sock, readset))          if ((c->io_ready & SSH_CHAN_IO_SOCK_R) == 0)
                 return;                  return;
   
         debug("X11 connection requested.");          debug("X11 connection requested.");
Line 1806  channel_set_x11_refuse_time(struct ssh *
Line 1791  channel_set_x11_refuse_time(struct ssh *
  * This socket is listening for connections to a forwarded TCP/IP port.   * This socket is listening for connections to a forwarded TCP/IP port.
  */   */
 static void  static void
 channel_post_port_listener(struct ssh *ssh, Channel *c,  channel_post_port_listener(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         Channel *nc;          Channel *nc;
         struct sockaddr_storage addr;          struct sockaddr_storage addr;
Line 1815  channel_post_port_listener(struct ssh *s
Line 1799  channel_post_port_listener(struct ssh *s
         socklen_t addrlen;          socklen_t addrlen;
         const char *rtype;          const char *rtype;
   
         if (!FD_ISSET(c->sock, readset))          if ((c->io_ready & SSH_CHAN_IO_SOCK_R) == 0)
                 return;                  return;
   
         debug("Connection to port %d forwarding to %.100s port %d requested.",          debug("Connection to port %d forwarding to %.100s port %d requested.",
Line 1866  channel_post_port_listener(struct ssh *s
Line 1850  channel_post_port_listener(struct ssh *s
  * clients.   * clients.
  */   */
 static void  static void
 channel_post_auth_listener(struct ssh *ssh, Channel *c,  channel_post_auth_listener(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         Channel *nc;          Channel *nc;
         int r, newsock;          int r, newsock;
         struct sockaddr_storage addr;          struct sockaddr_storage addr;
         socklen_t addrlen;          socklen_t addrlen;
   
         if (!FD_ISSET(c->sock, readset))          if ((c->io_ready & SSH_CHAN_IO_SOCK_R) == 0)
                 return;                  return;
   
         addrlen = sizeof(addr);          addrlen = sizeof(addr);
Line 1895  channel_post_auth_listener(struct ssh *s
Line 1878  channel_post_auth_listener(struct ssh *s
 }  }
   
 static void  static void
 channel_post_connecting(struct ssh *ssh, Channel *c,  channel_post_connecting(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         int err = 0, sock, isopen, r;          int err = 0, sock, isopen, r;
         socklen_t sz = sizeof(err);          socklen_t sz = sizeof(err);
   
         if (!FD_ISSET(c->sock, writeset))          if ((c->io_ready & SSH_CHAN_IO_SOCK_W) == 0)
                 return;                  return;
         if (!c->have_remote_id)          if (!c->have_remote_id)
                 fatal_f("channel %d: no remote id", c->self);                  fatal_f("channel %d: no remote id", c->self);
Line 1935  channel_post_connecting(struct ssh *ssh,
Line 1917  channel_post_connecting(struct ssh *ssh,
                 if ((sock = connect_next(&c->connect_ctx)) > 0) {                  if ((sock = connect_next(&c->connect_ctx)) > 0) {
                         close(c->sock);                          close(c->sock);
                         c->sock = c->rfd = c->wfd = sock;                          c->sock = c->rfd = c->wfd = sock;
                         channel_find_maxfd(ssh->chanctxt);  
                         return;                          return;
                 }                  }
                 /* Exhausted all addresses */                  /* Exhausted all addresses */
Line 1960  channel_post_connecting(struct ssh *ssh,
Line 1941  channel_post_connecting(struct ssh *ssh,
 }  }
   
 static int  static int
 channel_handle_rfd(struct ssh *ssh, Channel *c,  channel_handle_rfd(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         char buf[CHAN_RBUF];          char buf[CHAN_RBUF];
         ssize_t len;          ssize_t len;
         int r;          int r;
           size_t have, avail, maxlen = CHANNEL_MAX_READ;
   
           if ((c->io_ready & SSH_CHAN_IO_RFD) == 0)
                   return 1; /* Shouldn't happen */
           if ((avail = sshbuf_avail(c->input)) == 0)
                   return 1; /* Shouldn't happen */
   
         if (c->rfd == -1 || !FD_ISSET(c->rfd, readset))          /*
            * For "simple" channels (i.e. not datagram or filtered), we can
            * read directly to the channel buffer.
            */
           if (c->input_filter == NULL && !c->datagram) {
                   /* Only OPEN channels have valid rwin */
                   if (c->type == SSH_CHANNEL_OPEN) {
                           if ((have = sshbuf_len(c->input)) >= c->remote_window)
                                   return 1; /* shouldn't happen */
                           if (maxlen > c->remote_window - have)
                                   maxlen = c->remote_window - have;
                   }
                   if (maxlen > avail)
                           maxlen = avail;
                   if ((r = sshbuf_read(c->rfd, c->input, maxlen, NULL)) != 0) {
                           if (errno == EINTR || errno == EAGAIN)
                                   return 1;
                           debug2("channel %d: read failed rfd %d maxlen %zu: %s",
                               c->self, c->rfd, maxlen, ssh_err(r));
                           goto rfail;
                   }
                 return 1;                  return 1;
           }
   
         len = read(c->rfd, buf, sizeof(buf));          len = read(c->rfd, buf, sizeof(buf));
         if (len == -1 && (errno == EINTR || errno == EAGAIN))          if (len == -1 && (errno == EINTR || errno == EAGAIN))
                 return 1;                  return 1;
         if (len <= 0) {          if (len <= 0) {
                 debug2("channel %d: read<=0 rfd %d len %zd",                  debug2("channel %d: read<=0 rfd %d len %zd: %s",
                     c->self, c->rfd, len);                      c->self, c->rfd, len,
                       len == 0 ? "closed" : strerror(errno));
    rfail:
                 if (c->type != SSH_CHANNEL_OPEN) {                  if (c->type != SSH_CHANNEL_OPEN) {
                         debug2("channel %d: not open", c->self);                          debug2("channel %d: not open", c->self);
                         chan_mark_dead(ssh, c);                          chan_mark_dead(ssh, c);
Line 1993  channel_handle_rfd(struct ssh *ssh, Chan
Line 2002  channel_handle_rfd(struct ssh *ssh, Chan
         } else if (c->datagram) {          } else if (c->datagram) {
                 if ((r = sshbuf_put_string(c->input, buf, len)) != 0)                  if ((r = sshbuf_put_string(c->input, buf, len)) != 0)
                         fatal_fr(r, "channel %i: put datagram", c->self);                          fatal_fr(r, "channel %i: put datagram", c->self);
         } else if ((r = sshbuf_put(c->input, buf, len)) != 0)          }
                 fatal_fr(r, "channel %i: put data", c->self);  
         return 1;          return 1;
 }  }
   
 static int  static int
 channel_handle_wfd(struct ssh *ssh, Channel *c,  channel_handle_wfd(struct ssh *ssh, Channel *c)
    fd_set *readset, fd_set *writeset)  
 {  {
         struct termios tio;          struct termios tio;
         u_char *data = NULL, *buf; /* XXX const; need filter API change */          u_char *data = NULL, *buf; /* XXX const; need filter API change */
         size_t dlen, olen = 0;          size_t dlen, olen = 0;
         int r, len;          int r, len;
   
         if (c->wfd == -1 || !FD_ISSET(c->wfd, writeset) ||          if ((c->io_ready & SSH_CHAN_IO_WFD) == 0)
             sshbuf_len(c->output) == 0)                  return 1;
           if (sshbuf_len(c->output) == 0)
                 return 1;                  return 1;
   
         /* Send buffered output data to the socket. */          /* Send buffered output data to the socket. */
Line 2079  channel_handle_wfd(struct ssh *ssh, Chan
Line 2087  channel_handle_wfd(struct ssh *ssh, Chan
 }  }
   
 static int  static int
 channel_handle_efd_write(struct ssh *ssh, Channel *c,  channel_handle_efd_write(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         int r;          int r;
         ssize_t len;          ssize_t len;
   
         if (!FD_ISSET(c->efd, writeset) || sshbuf_len(c->extended) == 0)          if ((c->io_ready & SSH_CHAN_IO_EFD_W) == 0)
                   return 1;
           if (sshbuf_len(c->extended) == 0)
                 return 1;                  return 1;
   
         len = write(c->efd, sshbuf_ptr(c->extended),          len = write(c->efd, sshbuf_ptr(c->extended),
Line 2105  channel_handle_efd_write(struct ssh *ssh
Line 2114  channel_handle_efd_write(struct ssh *ssh
 }  }
   
 static int  static int
 channel_handle_efd_read(struct ssh *ssh, Channel *c,  channel_handle_efd_read(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         char buf[CHAN_RBUF];          char buf[CHAN_RBUF];
         int r;          int r;
         ssize_t len;          ssize_t len;
   
         if (!FD_ISSET(c->efd, readset))          if ((c->io_ready & SSH_CHAN_IO_EFD_R) == 0)
                 return 1;                  return 1;
   
         len = read(c->efd, buf, sizeof(buf));          len = read(c->efd, buf, sizeof(buf));
Line 2130  channel_handle_efd_read(struct ssh *ssh,
Line 2138  channel_handle_efd_read(struct ssh *ssh,
 }  }
   
 static int  static int
 channel_handle_efd(struct ssh *ssh, Channel *c,  channel_handle_efd(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         if (c->efd == -1)          if (c->efd == -1)
                 return 1;                  return 1;
Line 2139  channel_handle_efd(struct ssh *ssh, Chan
Line 2146  channel_handle_efd(struct ssh *ssh, Chan
         /** XXX handle drain efd, too */          /** XXX handle drain efd, too */
   
         if (c->extended_usage == CHAN_EXTENDED_WRITE)          if (c->extended_usage == CHAN_EXTENDED_WRITE)
                 return channel_handle_efd_write(ssh, c, readset, writeset);                  return channel_handle_efd_write(ssh, c);
         else if (c->extended_usage == CHAN_EXTENDED_READ ||          else if (c->extended_usage == CHAN_EXTENDED_READ ||
             c->extended_usage == CHAN_EXTENDED_IGNORE)              c->extended_usage == CHAN_EXTENDED_IGNORE)
                 return channel_handle_efd_read(ssh, c, readset, writeset);                  return channel_handle_efd_read(ssh, c);
   
         return 1;          return 1;
 }  }
Line 2186  channel_check_window(struct ssh *ssh, Ch
Line 2193  channel_check_window(struct ssh *ssh, Ch
 }  }
   
 static void  static void
 channel_post_open(struct ssh *ssh, Channel *c,  channel_post_open(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         channel_handle_rfd(ssh, c, readset, writeset);          channel_handle_rfd(ssh, c);
         channel_handle_wfd(ssh, c, readset, writeset);          channel_handle_wfd(ssh, c);
         channel_handle_efd(ssh, c, readset, writeset);          channel_handle_efd(ssh, c);
         channel_check_window(ssh, c);          channel_check_window(ssh, c);
 }  }
   
Line 2220  read_mux(struct ssh *ssh, Channel *c, u_
Line 2226  read_mux(struct ssh *ssh, Channel *c, u_
 }  }
   
 static void  static void
 channel_post_mux_client_read(struct ssh *ssh, Channel *c,  channel_post_mux_client_read(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         u_int need;          u_int need;
   
         if (c->rfd == -1 || !FD_ISSET(c->rfd, readset))          if ((c->io_ready & SSH_CHAN_IO_RFD) == 0)
                 return;                  return;
         if (c->istate != CHAN_INPUT_OPEN && c->istate != CHAN_INPUT_WAIT_DRAIN)          if (c->istate != CHAN_INPUT_OPEN && c->istate != CHAN_INPUT_WAIT_DRAIN)
                 return;                  return;
Line 2257  channel_post_mux_client_read(struct ssh 
Line 2262  channel_post_mux_client_read(struct ssh 
 }  }
   
 static void  static void
 channel_post_mux_client_write(struct ssh *ssh, Channel *c,  channel_post_mux_client_write(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         ssize_t len;          ssize_t len;
         int r;          int r;
   
         if (c->wfd == -1 || !FD_ISSET(c->wfd, writeset) ||          if ((c->io_ready & SSH_CHAN_IO_WFD) == 0)
             sshbuf_len(c->output) == 0)                  return;
           if (sshbuf_len(c->output) == 0)
                 return;                  return;
   
         len = write(c->wfd, sshbuf_ptr(c->output), sshbuf_len(c->output));          len = write(c->wfd, sshbuf_ptr(c->output), sshbuf_len(c->output));
Line 2279  channel_post_mux_client_write(struct ssh
Line 2284  channel_post_mux_client_write(struct ssh
 }  }
   
 static void  static void
 channel_post_mux_client(struct ssh *ssh, Channel *c,  channel_post_mux_client(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         channel_post_mux_client_read(ssh, c, readset, writeset);          channel_post_mux_client_read(ssh, c);
         channel_post_mux_client_write(ssh, c, readset, writeset);          channel_post_mux_client_write(ssh, c);
 }  }
   
 static void  static void
 channel_post_mux_listener(struct ssh *ssh, Channel *c,  channel_post_mux_listener(struct ssh *ssh, Channel *c)
     fd_set *readset, fd_set *writeset)  
 {  {
         Channel *nc;          Channel *nc;
         struct sockaddr_storage addr;          struct sockaddr_storage addr;
Line 2297  channel_post_mux_listener(struct ssh *ss
Line 2300  channel_post_mux_listener(struct ssh *ss
         uid_t euid;          uid_t euid;
         gid_t egid;          gid_t egid;
   
         if (!FD_ISSET(c->sock, readset))          if ((c->io_ready & SSH_CHAN_IO_SOCK_R) == 0)
                 return;                  return;
   
         debug("multiplexing control connection");          debug("multiplexing control connection");
Line 2403  channel_garbage_collect(struct ssh *ssh,
Line 2406  channel_garbage_collect(struct ssh *ssh,
 enum channel_table { CHAN_PRE, CHAN_POST };  enum channel_table { CHAN_PRE, CHAN_POST };
   
 static void  static void
 channel_handler(struct ssh *ssh, int table,  channel_handler(struct ssh *ssh, int table, time_t *unpause_secs)
     fd_set *readset, fd_set *writeset, time_t *unpause_secs)  
 {  {
         struct ssh_channels *sc = ssh->chanctxt;          struct ssh_channels *sc = ssh->chanctxt;
         chan_fn **ftab = table == CHAN_PRE ? sc->channel_pre : sc->channel_post;          chan_fn **ftab = table == CHAN_PRE ? sc->channel_pre : sc->channel_post;
Line 2430  channel_handler(struct ssh *ssh, int tab
Line 2432  channel_handler(struct ssh *ssh, int tab
                          * Run handlers that are not paused.                           * Run handlers that are not paused.
                          */                           */
                         if (c->notbefore <= now)                          if (c->notbefore <= now)
                                 (*ftab[c->type])(ssh, c, readset, writeset);                                  (*ftab[c->type])(ssh, c);
                         else if (unpause_secs != NULL) {                          else if (unpause_secs != NULL) {
                                 /*                                  /*
                                  * Collect the time that the earliest                                   * Collect the time that the earliest
Line 2452  channel_handler(struct ssh *ssh, int tab
Line 2454  channel_handler(struct ssh *ssh, int tab
 }  }
   
 /*  /*
  * Create sockets before allocating the select bitmasks.   * Create sockets before preparing IO.
  * This is necessary for things that need to happen after reading   * This is necessary for things that need to happen after reading
  * the network-input but before channel_prepare_select().   * the network-input but need to be completed before IO event setup, e.g.
    * because they may create new channels.
  */   */
 static void  static void
 channel_before_prepare_select(struct ssh *ssh)  channel_before_prepare_io(struct ssh *ssh)
 {  {
         struct ssh_channels *sc = ssh->chanctxt;          struct ssh_channels *sc = ssh->chanctxt;
         Channel *c;          Channel *c;
Line 2468  channel_before_prepare_select(struct ssh
Line 2471  channel_before_prepare_select(struct ssh
                 if (c == NULL)                  if (c == NULL)
                         continue;                          continue;
                 if (c->type == SSH_CHANNEL_RDYNAMIC_OPEN)                  if (c->type == SSH_CHANNEL_RDYNAMIC_OPEN)
                         channel_before_prepare_select_rdynamic(ssh, c);                          channel_before_prepare_io_rdynamic(ssh, c);
         }          }
 }  }
   
 /*  static void
  * Allocate/update select bitmasks and add any bits relevant to channels in  dump_channel_poll(const char *func, const char *what, Channel *c,
  * select bitmasks.      u_int pollfd_offset, struct pollfd *pfd)
  */  
 void  
 channel_prepare_select(struct ssh *ssh, fd_set **readsetp, fd_set **writesetp,  
     int *maxfdp, u_int *nallocp, time_t *minwait_secs)  
 {  {
         u_int n, sz, nfdset;  #ifdef DEBUG_CHANNEL_POLL
           debug3_f("channel %d: rfd r%d w%d e%d s%d "
               "pfd[%u].fd=%d want 0x%02x ev 0x%02x ready 0x%02x rev 0x%02x",
               c->self, c->rfd, c->wfd, c->efd, c->sock, pollfd_offset, pfd->fd,
               c->io_want, pfd->events, c->io_ready, pfd->revents);
   #endif
   }
   
         channel_before_prepare_select(ssh); /* might update channel_max_fd */  /* Prepare pollfd entries for a single channel */
   static void
   channel_prepare_pollfd(Channel *c, u_int *next_pollfd,
       struct pollfd *pfd, u_int npfd)
   {
           u_int p = *next_pollfd;
   
           if (c == NULL)
                   return;
           if (p + 4 > npfd) {
                   /* Shouldn't happen */
                   fatal_f("channel %d: bad pfd offset %u (max %u)",
                       c->self, p, npfd);
           }
           c->pollfd_offset = -1;
           /*
            * prepare c->rfd
            *
            * This is a special case, since c->rfd might be the same as
            * c->wfd, c->efd and/or c->sock. Handle those here if they want
            * IO too.
            */
           if (c->rfd != -1) {
                   if (c->pollfd_offset == -1)
                           c->pollfd_offset = p;
                   pfd[p].fd = c->rfd;
                   pfd[p].events = 0;
                   if ((c->io_want & SSH_CHAN_IO_RFD) != 0)
                           pfd[p].events |= POLLIN;
                   /* rfd == wfd */
                   if (c->wfd == c->rfd &&
                       (c->io_want & SSH_CHAN_IO_WFD) != 0)
                           pfd[p].events |= POLLOUT;
                   /* rfd == efd */
                   if (c->efd == c->rfd &&
                       (c->io_want & SSH_CHAN_IO_EFD_R) != 0)
                           pfd[p].events |= POLLIN;
                   if (c->efd == c->rfd &&
                       (c->io_want & SSH_CHAN_IO_EFD_W) != 0)
                           pfd[p].events |= POLLOUT;
                   /* rfd == sock */
                   if (c->sock == c->rfd &&
                       (c->io_want & SSH_CHAN_IO_SOCK_R) != 0)
                           pfd[p].events |= POLLIN;
                   if (c->sock == c->rfd &&
                       (c->io_want & SSH_CHAN_IO_SOCK_W) != 0)
                           pfd[p].events |= POLLOUT;
                   dump_channel_poll(__func__, "rfd", c, p, &pfd[p]);
                   p++;
           }
           /* prepare c->wfd (if not already handled above) */
           if (c->wfd != -1 && c->rfd != c->wfd) {
                   if (c->pollfd_offset == -1)
                           c->pollfd_offset = p;
                   pfd[p].fd = c->wfd;
                   pfd[p].events = 0;
                   if ((c->io_want & SSH_CHAN_IO_WFD) != 0)
                           pfd[p].events = POLLOUT;
                   dump_channel_poll(__func__, "wfd", c, p, &pfd[p]);
                   p++;
           }
           /* prepare c->efd (if not already handled above) */
           if (c->efd != -1 && c->rfd != c->efd) {
                   if (c->pollfd_offset == -1)
                           c->pollfd_offset = p;
                   pfd[p].fd = c->efd;
                   pfd[p].events = 0;
                   if ((c->io_want & SSH_CHAN_IO_EFD_R) != 0)
                           pfd[p].events |= POLLIN;
                   if ((c->io_want & SSH_CHAN_IO_EFD_W) != 0)
                           pfd[p].events |= POLLOUT;
                   dump_channel_poll(__func__, "efd", c, p, &pfd[p]);
                   p++;
           }
           /* prepare c->sock (if not already handled above) */
           if (c->sock != -1 && c->rfd != c->sock) {
                   if (c->pollfd_offset == -1)
                           c->pollfd_offset = p;
                   pfd[p].fd = c->sock;
                   pfd[p].events = 0;
                   if ((c->io_want & SSH_CHAN_IO_SOCK_R) != 0)
                           pfd[p].events |= POLLIN;
                   if ((c->io_want & SSH_CHAN_IO_SOCK_W) != 0)
                           pfd[p].events |= POLLOUT;
                   dump_channel_poll(__func__, "sock", c, p, &pfd[p]);
                   p++;
           }
           *next_pollfd = p;
   }
   
         n = MAXIMUM(*maxfdp, ssh->chanctxt->channel_max_fd);  /* * Allocate/prepare poll structure */
   void
   channel_prepare_poll(struct ssh *ssh, struct pollfd **pfdp, u_int *npfd_allocp,
       u_int *npfd_activep, u_int npfd_reserved, time_t *minwait_secs)
   {
           struct ssh_channels *sc = ssh->chanctxt;
           u_int i, oalloc, p, npfd = npfd_reserved;
   
         nfdset = howmany(n+1, NFDBITS);          channel_before_prepare_io(ssh); /* might create a new channel */
         /* Explicitly test here, because xrealloc isn't always called */  
         if (nfdset && SIZE_MAX / nfdset < sizeof(fd_mask))  
                 fatal("channel_prepare_select: max_fd (%d) is too large", n);  
         sz = nfdset * sizeof(fd_mask);  
   
         /* perhaps check sz < nalloc/2 and shrink? */  
         if (*readsetp == NULL || sz > *nallocp) {  
                 *readsetp = xreallocarray(*readsetp, nfdset, sizeof(fd_mask));  
                 *writesetp = xreallocarray(*writesetp, nfdset, sizeof(fd_mask));  
                 *nallocp = sz;  
         }  
         *maxfdp = n;  
         memset(*readsetp, 0, sz);  
         memset(*writesetp, 0, sz);  
   
           /* Allocate 4x pollfd for each channel (rfd, wfd, efd, sock) */
           if (sc->channels_alloc >= (INT_MAX / 4) - npfd_reserved)
                   fatal_f("too many channels"); /* shouldn't happen */
         if (!ssh_packet_is_rekeying(ssh))          if (!ssh_packet_is_rekeying(ssh))
                 channel_handler(ssh, CHAN_PRE, *readsetp, *writesetp,                  npfd += sc->channels_alloc * 4;
                     minwait_secs);          if (npfd > *npfd_allocp) {
                   *pfdp = xrecallocarray(*pfdp, *npfd_allocp,
                       npfd, sizeof(**pfdp));
                   *npfd_allocp = npfd;
           }
           *npfd_activep = npfd_reserved;
           if (ssh_packet_is_rekeying(ssh))
                   return;
   
           oalloc = sc->channels_alloc;
   
           channel_handler(ssh, CHAN_PRE, minwait_secs);
   
           if (oalloc != sc->channels_alloc) {
                   /* shouldn't happen */
                   fatal_f("channels_alloc changed during CHAN_PRE "
                       "(was %u, now %u)", oalloc, sc->channels_alloc);
           }
   
           /* Prepare pollfd */
           p = npfd_reserved;
           for (i = 0; i < sc->channels_alloc; i++)
                   channel_prepare_pollfd(sc->channels[i], &p, *pfdp, npfd);
           *npfd_activep = p;
   }
   
   static void
   fd_ready(Channel *c, u_int p, struct pollfd *pfds, int fd,
       const char *what, u_int revents_mask, u_int ready)
   {
           struct pollfd *pfd = &pfds[p];
   
           if (fd == -1)
                   return;
           dump_channel_poll(__func__, what, c, p, pfd);
           if (pfd->fd != fd) {
                   fatal("channel %d: inconsistent %s fd=%d pollfd[%u].fd %d "
                       "r%d w%d e%d s%d", c->self, what, fd, p, pfd->fd,
                       c->rfd, c->wfd, c->efd, c->sock);
           }
           if ((pfd->revents & POLLNVAL) != 0) {
                   fatal("channel %d: invalid %s pollfd[%u].fd %d r%d w%d e%d s%d",
                       c->self, what, p, pfd->fd, c->rfd, c->wfd, c->efd, c->sock);
           }
           if ((pfd->revents & (revents_mask|POLLHUP|POLLERR)) != 0)
                   c->io_ready |= ready & c->io_want;
 }  }
   
 /*  /*
  * After select, perform any appropriate operations for channels which have   * After poll, perform any appropriate operations for channels which have
  * events pending.   * events pending.
  */   */
 void  void
 channel_after_select(struct ssh *ssh, fd_set *readset, fd_set *writeset)  channel_after_poll(struct ssh *ssh, struct pollfd *pfd, u_int npfd)
 {  {
         channel_handler(ssh, CHAN_POST, readset, writeset, NULL);          struct ssh_channels *sc = ssh->chanctxt;
           u_int i, p;
           Channel *c;
   
   #ifdef DEBUG_CHANNEL_POLL
           for (p = 0; p < npfd; p++) {
                   if (pfd[p].revents == 0)
                           continue;
                   debug_f("pfd[%u].fd %d rev 0x%04x",
                       p, pfd[p].fd, pfd[p].revents);
           }
   #endif
   
           /* Convert pollfd into c->io_ready */
           for (i = 0; i < sc->channels_alloc; i++) {
                   c = sc->channels[i];
                   if (c == NULL || c->pollfd_offset < 0)
                           continue;
                   if ((u_int)c->pollfd_offset >= npfd) {
                           /* shouldn't happen */
                           fatal_f("channel %d: (before) bad pfd %u (max %u)",
                               c->self, c->pollfd_offset, npfd);
                   }
                   /* if rfd is shared with efd/sock then wfd should be too */
                   if (c->rfd != -1 && c->wfd != -1 && c->rfd != c->wfd &&
                       (c->rfd == c->efd || c->rfd == c->sock)) {
                           /* Shouldn't happen */
                           fatal_f("channel %d: unexpected fds r%d w%d e%d s%d",
                               c->self, c->rfd, c->wfd, c->efd, c->sock);
                   }
                   c->io_ready = 0;
                   p = c->pollfd_offset;
                   /* rfd, potentially shared with wfd, efd and sock */
                   if (c->rfd != -1) {
                           fd_ready(c, p, pfd, c->rfd, "rfd", POLLIN,
                               SSH_CHAN_IO_RFD);
                           if (c->rfd == c->wfd) {
                                   fd_ready(c, p, pfd, c->wfd, "wfd/r", POLLOUT,
                                       SSH_CHAN_IO_WFD);
                           }
                           if (c->rfd == c->efd) {
                                   fd_ready(c, p, pfd, c->efd, "efdr/r", POLLIN,
                                       SSH_CHAN_IO_EFD_R);
                                   fd_ready(c, p, pfd, c->efd, "efdw/r", POLLOUT,
                                       SSH_CHAN_IO_EFD_W);
                           }
                           if (c->rfd == c->sock) {
                                   fd_ready(c, p, pfd, c->sock, "sockr/r", POLLIN,
                                       SSH_CHAN_IO_SOCK_R);
                                   fd_ready(c, p, pfd, c->sock, "sockw/r", POLLOUT,
                                       SSH_CHAN_IO_SOCK_W);
                           }
                           p++;
                   }
                   /* wfd */
                   if (c->wfd != -1 && c->wfd != c->rfd) {
                           fd_ready(c, p, pfd, c->wfd, "wfd", POLLOUT,
                               SSH_CHAN_IO_WFD);
                           p++;
                   }
                   /* efd */
                   if (c->efd != -1 && c->efd != c->rfd) {
                           fd_ready(c, p, pfd, c->efd, "efdr", POLLIN,
                               SSH_CHAN_IO_EFD_R);
                           fd_ready(c, p, pfd, c->efd, "efdw", POLLOUT,
                               SSH_CHAN_IO_EFD_W);
                           p++;
                   }
                   /* sock */
                   if (c->sock != -1 && c->sock != c->rfd) {
                           fd_ready(c, p, pfd, c->sock, "sockr", POLLIN,
                               SSH_CHAN_IO_SOCK_R);
                           fd_ready(c, p, pfd, c->sock, "sockw", POLLOUT,
                               SSH_CHAN_IO_SOCK_W);
                           p++;
                   }
   
                   if (p > npfd) {
                           /* shouldn't happen */
                           fatal_f("channel %d: (after) bad pfd %u (max %u)",
                               c->self, c->pollfd_offset, npfd);
                   }
           }
           channel_handler(ssh, CHAN_POST, NULL);
 }  }
   
 /*  /*

Legend:
Removed from v.1.34  
changed lines
  Added in v.1.35

CVSweb <webmaster@jp.NetBSD.org>