[BACK]Return to channels.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/channels.c between version 1.371 and 1.372

version 1.371, 2017/09/19 12:10:30 version 1.372, 2017/09/21 19:16:53
Line 203 
Line 203 
 /* non-blocking connect helpers */  /* non-blocking connect helpers */
 static int connect_next(struct channel_connect *);  static int connect_next(struct channel_connect *);
 static void channel_connect_ctx_free(struct channel_connect *);  static void channel_connect_ctx_free(struct channel_connect *);
   static Channel *rdynamic_connect_prepare(struct ssh *, char *, char *);
   static int rdynamic_connect_finish(struct ssh *, Channel *);
   
 /* Setup helper */  /* Setup helper */
 static void channel_handler_init(struct ssh_channels *sc);  static void channel_handler_init(struct ssh_channels *sc);
Line 276 
Line 278 
         case SSH_CHANNEL_LARVAL:          case SSH_CHANNEL_LARVAL:
         case SSH_CHANNEL_CONNECTING:          case SSH_CHANNEL_CONNECTING:
         case SSH_CHANNEL_DYNAMIC:          case SSH_CHANNEL_DYNAMIC:
           case SSH_CHANNEL_RDYNAMIC_OPEN:
           case SSH_CHANNEL_RDYNAMIC_FINISH:
         case SSH_CHANNEL_OPENING:          case SSH_CHANNEL_OPENING:
         case SSH_CHANNEL_OPEN:          case SSH_CHANNEL_OPEN:
         case SSH_CHANNEL_ABANDONED:          case SSH_CHANNEL_ABANDONED:
Line 661 
Line 665 
                 case SSH_CHANNEL_CLOSED:                  case SSH_CHANNEL_CLOSED:
                 case SSH_CHANNEL_AUTH_SOCKET:                  case SSH_CHANNEL_AUTH_SOCKET:
                 case SSH_CHANNEL_DYNAMIC:                  case SSH_CHANNEL_DYNAMIC:
                   case SSH_CHANNEL_RDYNAMIC_OPEN:
                 case SSH_CHANNEL_CONNECTING:                  case SSH_CHANNEL_CONNECTING:
                 case SSH_CHANNEL_ZOMBIE:                  case SSH_CHANNEL_ZOMBIE:
                 case SSH_CHANNEL_ABANDONED:                  case SSH_CHANNEL_ABANDONED:
Line 671 
Line 676 
                         continue;                          continue;
                 case SSH_CHANNEL_OPENING:                  case SSH_CHANNEL_OPENING:
                 case SSH_CHANNEL_OPEN:                  case SSH_CHANNEL_OPEN:
                   case SSH_CHANNEL_RDYNAMIC_FINISH:
                 case SSH_CHANNEL_X11_OPEN:                  case SSH_CHANNEL_X11_OPEN:
                 case SSH_CHANNEL_MUX_CLIENT:                  case SSH_CHANNEL_MUX_CLIENT:
                 case SSH_CHANNEL_MUX_PROXY:                  case SSH_CHANNEL_MUX_PROXY:
Line 697 
Line 703 
                 switch (c->type) {                  switch (c->type) {
                 case SSH_CHANNEL_CLOSED:                  case SSH_CHANNEL_CLOSED:
                 case SSH_CHANNEL_DYNAMIC:                  case SSH_CHANNEL_DYNAMIC:
                   case SSH_CHANNEL_RDYNAMIC_OPEN:
                   case SSH_CHANNEL_RDYNAMIC_FINISH:
                 case SSH_CHANNEL_X11_LISTENER:                  case SSH_CHANNEL_X11_LISTENER:
                 case SSH_CHANNEL_PORT_LISTENER:                  case SSH_CHANNEL_PORT_LISTENER:
                 case SSH_CHANNEL_RPORT_LISTENER:                  case SSH_CHANNEL_RPORT_LISTENER:
Line 762 
Line 770 
                 case SSH_CHANNEL_OPENING:                  case SSH_CHANNEL_OPENING:
                 case SSH_CHANNEL_CONNECTING:                  case SSH_CHANNEL_CONNECTING:
                 case SSH_CHANNEL_DYNAMIC:                  case SSH_CHANNEL_DYNAMIC:
                   case SSH_CHANNEL_RDYNAMIC_OPEN:
                   case SSH_CHANNEL_RDYNAMIC_FINISH:
                 case SSH_CHANNEL_OPEN:                  case SSH_CHANNEL_OPEN:
                 case SSH_CHANNEL_X11_OPEN:                  case SSH_CHANNEL_X11_OPEN:
                 case SSH_CHANNEL_MUX_PROXY:                  case SSH_CHANNEL_MUX_PROXY:
Line 1114 
Line 1124 
   
 /* try to decode a socks4 header */  /* try to decode a socks4 header */
 static int  static int
 channel_decode_socks4(struct ssh *ssh, Channel *c,  channel_decode_socks4(Channel *c, struct sshbuf *input, struct sshbuf *output)
     fd_set *readset, fd_set *writeset)  
 {  {
         const u_char *p;          const u_char *p;
         char *host;          char *host;
Line 1131 
Line 1140 
   
         debug2("channel %d: decode socks4", c->self);          debug2("channel %d: decode socks4", c->self);
   
         have = sshbuf_len(c->input);          have = sshbuf_len(input);
         len = sizeof(s4_req);          len = sizeof(s4_req);
         if (have < len)          if (have < len)
                 return 0;                  return 0;
         p = sshbuf_ptr(c->input);          p = sshbuf_ptr(input);
   
         need = 1;          need = 1;
         /* SOCKS4A uses an invalid IP address 0.0.0.x */          /* SOCKS4A uses an invalid IP address 0.0.0.x */
Line 1160 
Line 1169 
         }          }
         if (found < need)          if (found < need)
                 return 0;                  return 0;
         if ((r = sshbuf_get(c->input, &s4_req.version, 1)) != 0 ||          if ((r = sshbuf_get(input, &s4_req.version, 1)) != 0 ||
             (r = sshbuf_get(c->input, &s4_req.command, 1)) != 0 ||              (r = sshbuf_get(input, &s4_req.command, 1)) != 0 ||
             (r = sshbuf_get(c->input, &s4_req.dest_port, 2)) != 0 ||              (r = sshbuf_get(input, &s4_req.dest_port, 2)) != 0 ||
             (r = sshbuf_get(c->input, &s4_req.dest_addr, 4)) != 0) {              (r = sshbuf_get(input, &s4_req.dest_addr, 4)) != 0) {
                 debug("channels %d: decode socks4: %s", c->self, ssh_err(r));                  debug("channels %d: decode socks4: %s", c->self, ssh_err(r));
                 return -1;                  return -1;
         }          }
         have = sshbuf_len(c->input);          have = sshbuf_len(input);
         p = sshbuf_ptr(c->input);          p = sshbuf_ptr(input);
         if (memchr(p, '\0', have) == NULL) {          if (memchr(p, '\0', have) == NULL) {
                 error("channel %d: decode socks4: user not nul terminated",                  error("channel %d: decode socks4: user not nul terminated",
                     c->self);                      c->self);
Line 1178 
Line 1187 
         debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);          debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
         len++; /* trailing '\0' */          len++; /* trailing '\0' */
         strlcpy(username, p, sizeof(username));          strlcpy(username, p, sizeof(username));
         if ((r = sshbuf_consume(c->input, len)) != 0) {          if ((r = sshbuf_consume(input, len)) != 0) {
                 fatal("%s: channel %d: consume: %s", __func__,                  fatal("%s: channel %d: consume: %s", __func__,
                     c->self, ssh_err(r));                      c->self, ssh_err(r));
         }          }
Line 1188 
Line 1197 
                 host = inet_ntoa(s4_req.dest_addr);                  host = inet_ntoa(s4_req.dest_addr);
                 c->path = xstrdup(host);                  c->path = xstrdup(host);
         } else {                                /* SOCKS4A: two strings */          } else {                                /* SOCKS4A: two strings */
                 have = sshbuf_len(c->input);                  have = sshbuf_len(input);
                 p = sshbuf_ptr(c->input);                  p = sshbuf_ptr(input);
                 if (memchr(p, '\0', have) == NULL) {                  if (memchr(p, '\0', have) == NULL) {
                         error("channel %d: decode socks4a: host not nul "                          error("channel %d: decode socks4a: host not nul "
                             "terminated", c->self);                              "terminated", c->self);
Line 1205 
Line 1214 
                         return -1;                          return -1;
                 }                  }
                 c->path = xstrdup(p);                  c->path = xstrdup(p);
                 if ((r = sshbuf_consume(c->input, len)) != 0) {                  if ((r = sshbuf_consume(input, len)) != 0) {
                         fatal("%s: channel %d: consume: %s", __func__,                          fatal("%s: channel %d: consume: %s", __func__,
                             c->self, ssh_err(r));                              c->self, ssh_err(r));
                 }                  }
Line 1224 
Line 1233 
         s4_rsp.command = 90;                    /* cd: req granted */          s4_rsp.command = 90;                    /* cd: req granted */
         s4_rsp.dest_port = 0;                   /* ignored */          s4_rsp.dest_port = 0;                   /* ignored */
         s4_rsp.dest_addr.s_addr = INADDR_ANY;   /* ignored */          s4_rsp.dest_addr.s_addr = INADDR_ANY;   /* ignored */
         if ((r = sshbuf_put(c->output, &s4_rsp, sizeof(s4_rsp))) != 0) {          if ((r = sshbuf_put(output, &s4_rsp, sizeof(s4_rsp))) != 0) {
                 fatal("%s: channel %d: append reply: %s", __func__,                  fatal("%s: channel %d: append reply: %s", __func__,
                     c->self, ssh_err(r));                      c->self, ssh_err(r));
         }          }
Line 1241 
Line 1250 
 #define SSH_SOCKS5_SUCCESS      0x00  #define SSH_SOCKS5_SUCCESS      0x00
   
 static int  static int
 channel_decode_socks5(struct ssh *ssh, Channel *c,  channel_decode_socks5(Channel *c, struct sshbuf *input, struct sshbuf *output)
     fd_set *readset, fd_set *writeset)  
 {  {
         /* XXX use get/put_u8 instead of trusting struct padding */          /* XXX use get/put_u8 instead of trusting struct padding */
         struct {          struct {
Line 1258 
Line 1266 
         int r;          int r;
   
         debug2("channel %d: decode socks5", c->self);          debug2("channel %d: decode socks5", c->self);
         p = sshbuf_ptr(c->input);          p = sshbuf_ptr(input);
         if (p[0] != 0x05)          if (p[0] != 0x05)
                 return -1;                  return -1;
         have = sshbuf_len(c->input);          have = sshbuf_len(input);
         if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {          if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {
                 /* format: ver | nmethods | methods */                  /* format: ver | nmethods | methods */
                 if (have < 2)                  if (have < 2)
Line 1281 
Line 1289 
                             c->self);                              c->self);
                         return -1;                          return -1;
                 }                  }
                 if ((r = sshbuf_consume(c->input, nmethods + 2)) != 0) {                  if ((r = sshbuf_consume(input, nmethods + 2)) != 0) {
                         fatal("%s: channel %d: consume: %s", __func__,                          fatal("%s: channel %d: consume: %s", __func__,
                             c->self, ssh_err(r));                              c->self, ssh_err(r));
                 }                  }
                 /* version, method */                  /* version, method */
                 if ((r = sshbuf_put_u8(c->output, 0x05)) != 0 ||                  if ((r = sshbuf_put_u8(output, 0x05)) != 0 ||
                     (r = sshbuf_put_u8(c->output, SSH_SOCKS5_NOAUTH)) != 0) {                      (r = sshbuf_put_u8(output, SSH_SOCKS5_NOAUTH)) != 0) {
                         fatal("%s: channel %d: append reply: %s", __func__,                          fatal("%s: channel %d: append reply: %s", __func__,
                             c->self, ssh_err(r));                              c->self, ssh_err(r));
                 }                  }
                 FD_SET(c->sock, writeset);  
                 c->flags |= SSH_SOCKS5_AUTHDONE;                  c->flags |= SSH_SOCKS5_AUTHDONE;
                 debug2("channel %d: socks5 auth done", c->self);                  debug2("channel %d: socks5 auth done", c->self);
                 return 0;                               /* need more */                  return 0;                               /* need more */
Line 1328 
Line 1335 
                 need++;                  need++;
         if (have < need)          if (have < need)
                 return 0;                  return 0;
         if ((r = sshbuf_consume(c->input, sizeof(s5_req))) != 0) {          if ((r = sshbuf_consume(input, sizeof(s5_req))) != 0) {
                 fatal("%s: channel %d: consume: %s", __func__,                  fatal("%s: channel %d: consume: %s", __func__,
                     c->self, ssh_err(r));                      c->self, ssh_err(r));
         }          }
         if (s5_req.atyp == SSH_SOCKS5_DOMAIN) {          if (s5_req.atyp == SSH_SOCKS5_DOMAIN) {
                 /* host string length */                  /* host string length */
                 if ((r = sshbuf_consume(c->input, 1)) != 0) {                  if ((r = sshbuf_consume(input, 1)) != 0) {
                         fatal("%s: channel %d: consume: %s", __func__,                          fatal("%s: channel %d: consume: %s", __func__,
                             c->self, ssh_err(r));                              c->self, ssh_err(r));
                 }                  }
         }          }
         if ((r = sshbuf_get(c->input, &dest_addr, addrlen)) != 0 ||          if ((r = sshbuf_get(input, &dest_addr, addrlen)) != 0 ||
             (r = sshbuf_get(c->input, &dest_port, 2)) != 0) {              (r = sshbuf_get(input, &dest_port, 2)) != 0) {
                 debug("channel %d: parse addr/port: %s", c->self, ssh_err(r));                  debug("channel %d: parse addr/port: %s", c->self, ssh_err(r));
                 return -1;                  return -1;
         }          }
Line 1370 
Line 1377 
         s5_rsp.atyp = SSH_SOCKS5_IPV4;          s5_rsp.atyp = SSH_SOCKS5_IPV4;
         dest_port = 0;                          /* ignored */          dest_port = 0;                          /* ignored */
   
         if ((r = sshbuf_put(c->output, &s5_rsp, sizeof(s5_rsp))) != 0 ||          if ((r = sshbuf_put(output, &s5_rsp, sizeof(s5_rsp))) != 0 ||
             (r = sshbuf_put_u32(c->output, ntohl(INADDR_ANY))) != 0 ||              (r = sshbuf_put_u32(output, ntohl(INADDR_ANY))) != 0 ||
             (r = sshbuf_put(c->output, &dest_port, sizeof(dest_port))) != 0)              (r = sshbuf_put(output, &dest_port, sizeof(dest_port))) != 0)
                 fatal("%s: channel %d: append reply: %s", __func__,                  fatal("%s: channel %d: append reply: %s", __func__,
                     c->self, ssh_err(r));                      c->self, ssh_err(r));
         return 1;          return 1;
Line 1424 
Line 1431 
         /* XXX sshbuf_peek_u8? */          /* XXX sshbuf_peek_u8? */
         switch (p[0]) {          switch (p[0]) {
         case 0x04:          case 0x04:
                 ret = channel_decode_socks4(ssh, c, readset, writeset);                  ret = channel_decode_socks4(c, c->input, c->output);
                 break;                  break;
         case 0x05:          case 0x05:
                 ret = channel_decode_socks5(ssh, c, readset, writeset);                  ret = channel_decode_socks5(c, c->input, c->output);
                 break;                  break;
         default:          default:
                 ret = -1;                  ret = -1;
Line 1439 
Line 1446 
                 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);                  FD_SET(c->sock, readset);
                   if (sshbuf_len(c->output))
                           FD_SET(c->sock, writeset);
         } else {          } else {
                 /* switch to the next state */                  /* switch to the next state */
                 c->type = SSH_CHANNEL_OPENING;                  c->type = SSH_CHANNEL_OPENING;
Line 1446 
Line 1455 
         }          }
 }  }
   
   /* simulate read-error */
   static void
   rdynamic_close(struct ssh *ssh, Channel *c)
   {
           c->type = SSH_CHANNEL_OPEN;
           chan_read_failed(ssh, c);
           sshbuf_reset(c->input);
           chan_ibuf_empty(ssh, c);
           sshbuf_reset(c->output);
           chan_write_failed(ssh, c);
   }
   
   /* reverse dynamic port forwarding */
   static void
   channel_before_prepare_select_rdynamic(struct ssh *ssh, Channel *c)
   {
           const u_char *p;
           u_int have, len;
           int r, ret;
   
           have = sshbuf_len(c->output);
           debug2("channel %d: pre_rdynamic: have %d", c->self, have);
           /* sshbuf_dump(c->output, stderr); */
           /* EOF received */
           if (c->flags & CHAN_EOF_RCVD) {
                   if ((r = sshbuf_consume(c->output, have)) != 0) {
                           fatal("%s: channel %d: consume: %s",
                               __func__, c->self, ssh_err(r));
                   }
                   rdynamic_close(ssh, c);
                   return;
           }
           /* check if the fixed size part of the packet is in buffer. */
           if (have < 3)
                   return;
           /* try to guess the protocol */
           p = sshbuf_ptr(c->output);
           switch (p[0]) {
           case 0x04:
                   /* switch input/output for reverse forwarding */
                   ret = channel_decode_socks4(c, c->output, c->input);
                   break;
           case 0x05:
                   ret = channel_decode_socks5(c, c->output, c->input);
                   break;
           default:
                   ret = -1;
                   break;
           }
           if (ret < 0) {
                   rdynamic_close(ssh, c);
           } else if (ret == 0) {
                   debug2("channel %d: pre_rdynamic: need more", c->self);
                   /* send socks request to peer */
                   len = sshbuf_len(c->input);
                   if (len > 0 && len < c->remote_window) {
                           if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 ||
                               (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
                               (r = sshpkt_put_stringb(ssh, c->input)) != 0 ||
                               (r = sshpkt_send(ssh)) != 0) {
                                   fatal("%s: channel %i: rdynamic: %s", __func__,
                                       c->self, ssh_err(r));
                           }
                           if ((r = sshbuf_consume(c->input, len)) != 0) {
                                   fatal("%s: channel %d: consume: %s",
                                       __func__, c->self, ssh_err(r));
                           }
                           c->remote_window -= len;
                   }
           } else if (rdynamic_connect_finish(ssh, c) < 0) {
                   /* the connect failed */
                   rdynamic_close(ssh, c);
           }
   }
   
 /* 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,
Line 1689 
Line 1773 
 channel_post_connecting(struct ssh *ssh, Channel *c,  channel_post_connecting(struct ssh *ssh, Channel *c,
     fd_set *readset, fd_set *writeset)      fd_set *readset, fd_set *writeset)
 {  {
         int err = 0, sock, r;          int err = 0, sock, isopen, r;
         socklen_t sz = sizeof(err);          socklen_t sz = sizeof(err);
   
         if (!FD_ISSET(c->sock, writeset))          if (!FD_ISSET(c->sock, writeset))
                 return;                  return;
         if (!c->have_remote_id)          if (!c->have_remote_id)
                 fatal(":%s: channel %d: no remote id", __func__, c->self);                  fatal(":%s: channel %d: no remote id", __func__, c->self);
           /* for rdynamic the OPEN_CONFIRMATION has been sent already */
           isopen = (c->type == SSH_CHANNEL_RDYNAMIC_FINISH);
         if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) {          if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) {
                 err = errno;                  err = errno;
                 error("getsockopt SO_ERROR failed");                  error("getsockopt SO_ERROR failed");
Line 1706 
Line 1791 
                     c->self, c->connect_ctx.host, c->connect_ctx.port);                      c->self, c->connect_ctx.host, c->connect_ctx.port);
                 channel_connect_ctx_free(&c->connect_ctx);                  channel_connect_ctx_free(&c->connect_ctx);
                 c->type = SSH_CHANNEL_OPEN;                  c->type = SSH_CHANNEL_OPEN;
                 if ((r = sshpkt_start(ssh,                  if (isopen) {
                     SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 ||                          /* no message necessary */
                     (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||                  } else {
                     (r = sshpkt_put_u32(ssh, c->self)) != 0 ||                          if ((r = sshpkt_start(ssh,
                     (r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||                              SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 ||
                     (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) {                              (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
                         fatal("%s: channel %i: confirm: %s", __func__,                              (r = sshpkt_put_u32(ssh, c->self)) != 0 ||
                             c->self, ssh_err(r));                              (r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
                               (r = sshpkt_put_u32(ssh, c->local_maxpacket))
                               != 0)
                                   fatal("%s: channel %i: confirm: %s", __func__,
                                       c->self, ssh_err(r));
                           if ((r = sshpkt_send(ssh)) != 0)
                                   fatal("%s: channel %i: %s", __func__, c->self,
                                       ssh_err(r));
                 }                  }
         } else {          } else {
                 debug("channel %d: connection failed: %s",                  debug("channel %d: connection failed: %s",
Line 1729 
Line 1821 
                 error("connect_to %.100s port %d: failed.",                  error("connect_to %.100s port %d: failed.",
                     c->connect_ctx.host, c->connect_ctx.port);                      c->connect_ctx.host, c->connect_ctx.port);
                 channel_connect_ctx_free(&c->connect_ctx);                  channel_connect_ctx_free(&c->connect_ctx);
                 if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 ||                  if (isopen) {
                     (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||                          rdynamic_close(ssh, c);
                     (r = sshpkt_put_u32(ssh, SSH2_OPEN_CONNECT_FAILED)) != 0) {                  } else {
                         fatal("%s: channel %i: failure: %s", __func__,                          if ((r = sshpkt_start(ssh,
                             c->self, ssh_err(r));                              SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 ||
                               (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
                               (r = sshpkt_put_u32(ssh, SSH2_OPEN_CONNECT_FAILED))
                               != 0)
                                   fatal("%s: channel %i: failure: %s", __func__,
                                       c->self, ssh_err(r));
                           if ((datafellows & SSH_BUG_OPENFAILURE) == 0 &&
                               ((r = sshpkt_put_cstring(ssh, strerror(err))) != 0 ||
                               (r = sshpkt_put_cstring(ssh, "")) != 0))
                                   fatal("%s: channel %i: failure: %s", __func__,
                                       c->self, ssh_err(r));
                           if ((r = sshpkt_send(ssh)) != 0)
                                   fatal("%s: channel %i: %s", __func__, c->self,
                                       ssh_err(r));
                           chan_mark_dead(ssh, c);
                 }                  }
                 if ((datafellows & SSH_BUG_OPENFAILURE) == 0 &&  
                     ((r = sshpkt_put_cstring(ssh, strerror(err))) != 0 ||  
                     (r = sshpkt_put_cstring(ssh, "")) != 0)) {  
                         fatal("%s: channel %i: failure: %s", __func__,  
                             c->self, ssh_err(r));  
                 }  
                 chan_mark_dead(ssh, c);  
         }          }
         if ((r = sshpkt_send(ssh)) != 0)  
                 fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r));  
 }  }
   
 static int  static int
Line 2156 
Line 2253 
         pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;          pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;
         pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;          pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;
         pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;          pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;
           pre[SSH_CHANNEL_RDYNAMIC_FINISH] =      &channel_pre_connecting;
         pre[SSH_CHANNEL_MUX_LISTENER] =         &channel_pre_listener;          pre[SSH_CHANNEL_MUX_LISTENER] =         &channel_pre_listener;
         pre[SSH_CHANNEL_MUX_CLIENT] =           &channel_pre_mux_client;          pre[SSH_CHANNEL_MUX_CLIENT] =           &channel_pre_mux_client;
   
Line 2168 
Line 2266 
         post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;          post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
         post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;          post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
         post[SSH_CHANNEL_DYNAMIC] =             &channel_post_open;          post[SSH_CHANNEL_DYNAMIC] =             &channel_post_open;
           post[SSH_CHANNEL_RDYNAMIC_FINISH] =     &channel_post_connecting;
         post[SSH_CHANNEL_MUX_LISTENER] =        &channel_post_mux_listener;          post[SSH_CHANNEL_MUX_LISTENER] =        &channel_post_mux_listener;
         post[SSH_CHANNEL_MUX_CLIENT] =          &channel_post_mux_client;          post[SSH_CHANNEL_MUX_CLIENT] =          &channel_post_mux_client;
   
Line 2249 
Line 2348 
 }  }
   
 /*  /*
    * Create sockets before allocating the select bitmasks.
    * This is necessary for things that need to happen after reading
    * the network-input but before channel_prepare_select().
    */
   static void
   channel_before_prepare_select(struct ssh *ssh)
   {
           struct ssh_channels *sc = ssh->chanctxt;
           Channel *c;
           u_int i, oalloc;
   
           for (i = 0, oalloc = sc->channels_alloc; i < oalloc; i++) {
                   c = sc->channels[i];
                   if (c == NULL)
                           continue;
                   if (c->type == SSH_CHANNEL_RDYNAMIC_OPEN)
                           channel_before_prepare_select_rdynamic(ssh, c);
           }
   }
   
   /*
  * Allocate/update select bitmasks and add any bits relevant to channels in   * Allocate/update select bitmasks and add any bits relevant to channels in
  * select bitmasks.   * select bitmasks.
  */   */
Line 2258 
Line 2378 
 {  {
         u_int n, sz, nfdset;          u_int n, sz, nfdset;
   
           channel_before_prepare_select(ssh); /* might update channel_max_fd */
   
         n = MAXIMUM(*maxfdp, ssh->chanctxt->channel_max_fd);          n = MAXIMUM(*maxfdp, ssh->chanctxt->channel_max_fd);
   
         nfdset = howmany(n+1, NFDBITS);          nfdset = howmany(n+1, NFDBITS);
Line 2763 
Line 2885 
   
         /* Ignore any data for non-open channels (might happen on close) */          /* Ignore any data for non-open channels (might happen on close) */
         if (c->type != SSH_CHANNEL_OPEN &&          if (c->type != SSH_CHANNEL_OPEN &&
               c->type != SSH_CHANNEL_RDYNAMIC_OPEN &&
               c->type != SSH_CHANNEL_RDYNAMIC_FINISH &&
             c->type != SSH_CHANNEL_X11_OPEN)              c->type != SSH_CHANNEL_X11_OPEN)
                 return 0;                  return 0;
   
Line 3001 
Line 3125 
         if ((c = channel_lookup(ssh, id)) == NULL) {          if ((c = channel_lookup(ssh, id)) == NULL) {
                 logit("Received window adjust for non-open channel %d.", id);                  logit("Received window adjust for non-open channel %d.", id);
                 return 0;                  return 0;
         }          }
   
         if (channel_proxy_upstream(c, type, seq, ssh))          if (channel_proxy_upstream(c, type, seq, ssh))
                 return 0;                  return 0;
Line 3902 
Line 4026 
 }  }
   
 /*  /*
  * Return CONNECTING channel to remote host:port or local socket path,   * Return connecting socket to remote host:port or local socket path,
  * passing back the failure reason if appropriate.   * passing back the failure reason if appropriate.
  */   */
 static Channel *  static int
 connect_to_reason(struct ssh *ssh, const char *name, int port,  connect_to_helper(struct ssh *ssh, const char *name, int port, int socktype,
     char *ctype, char *rname, int *reason, const char **errmsg)      char *ctype, char *rname, struct channel_connect *cctx,
       int *reason, const char **errmsg)
 {  {
         struct addrinfo hints;          struct addrinfo hints;
         int gaierr;          int gaierr;
         int sock = -1;          int sock = -1;
         char strport[NI_MAXSERV];          char strport[NI_MAXSERV];
         struct channel_connect cctx;  
         Channel *c;  
   
         memset(&cctx, 0, sizeof(cctx));  
   
         if (port == PORT_STREAMLOCAL) {          if (port == PORT_STREAMLOCAL) {
                 struct sockaddr_un *sunaddr;                  struct sockaddr_un *sunaddr;
                 struct addrinfo *ai;                  struct addrinfo *ai;
   
                 if (strlen(name) > sizeof(sunaddr->sun_path)) {                  if (strlen(name) > sizeof(sunaddr->sun_path)) {
                         error("%.100s: %.100s", name, strerror(ENAMETOOLONG));                          error("%.100s: %.100s", name, strerror(ENAMETOOLONG));
                         return (NULL);                          return -1;
                 }                  }
   
                 /*                  /*
Line 3937 
Line 4058 
                 ai->ai_addr = (struct sockaddr *)(ai + 1);                  ai->ai_addr = (struct sockaddr *)(ai + 1);
                 ai->ai_addrlen = sizeof(*sunaddr);                  ai->ai_addrlen = sizeof(*sunaddr);
                 ai->ai_family = AF_UNIX;                  ai->ai_family = AF_UNIX;
                 ai->ai_socktype = SOCK_STREAM;                  ai->ai_socktype = socktype;
                 ai->ai_protocol = PF_UNSPEC;                  ai->ai_protocol = PF_UNSPEC;
                 sunaddr = (struct sockaddr_un *)ai->ai_addr;                  sunaddr = (struct sockaddr_un *)ai->ai_addr;
                 sunaddr->sun_family = AF_UNIX;                  sunaddr->sun_family = AF_UNIX;
                 strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path));                  strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path));
                 cctx.aitop = ai;                  cctx->aitop = ai;
         } else {          } else {
                 memset(&hints, 0, sizeof(hints));                  memset(&hints, 0, sizeof(hints));
                 hints.ai_family = ssh->chanctxt->IPv4or6;                  hints.ai_family = ssh->chanctxt->IPv4or6;
                 hints.ai_socktype = SOCK_STREAM;                  hints.ai_socktype = socktype;
                 snprintf(strport, sizeof strport, "%d", port);                  snprintf(strport, sizeof strport, "%d", port);
                 if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop))                  if ((gaierr = getaddrinfo(name, strport, &hints, &cctx->aitop))
                     != 0) {                      != 0) {
                         if (errmsg != NULL)                          if (errmsg != NULL)
                                 *errmsg = ssh_gai_strerror(gaierr);                                  *errmsg = ssh_gai_strerror(gaierr);
Line 3956 
Line 4077 
                                 *reason = SSH2_OPEN_CONNECT_FAILED;                                  *reason = SSH2_OPEN_CONNECT_FAILED;
                         error("connect_to %.100s: unknown host (%s)", name,                          error("connect_to %.100s: unknown host (%s)", name,
                             ssh_gai_strerror(gaierr));                              ssh_gai_strerror(gaierr));
                         return NULL;                          return -1;
                 }                  }
         }          }
   
         cctx.host = xstrdup(name);          cctx->host = xstrdup(name);
         cctx.port = port;          cctx->port = port;
         cctx.ai = cctx.aitop;          cctx->ai = cctx->aitop;
   
         if ((sock = connect_next(&cctx)) == -1) {          if ((sock = connect_next(cctx)) == -1) {
                 error("connect to %.100s port %d failed: %s",                  error("connect to %.100s port %d failed: %s",
                     name, port, strerror(errno));                      name, port, strerror(errno));
                   return -1;
           }
   
           return sock;
   }
   
   /* Return CONNECTING channel to remote host:port or local socket path */
   static Channel *
   connect_to(struct ssh *ssh, const char *host, int port,
       char *ctype, char *rname)
   {
           struct channel_connect cctx;
           Channel *c;
           int sock;
   
           memset(&cctx, 0, sizeof(cctx));
           sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname,
               &cctx, NULL, NULL);
           if (sock == -1) {
                 channel_connect_ctx_free(&cctx);                  channel_connect_ctx_free(&cctx);
                 return NULL;                  return NULL;
         }          }
         c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,          c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
             CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);              CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
           c->host_port = port;
           c->path = xstrdup(host);
         c->connect_ctx = cctx;          c->connect_ctx = cctx;
   
         return c;          return c;
 }  }
   
 /* Return CONNECTING channel to remote host:port or local socket path */  
 static Channel *  
 connect_to(struct ssh *ssh, const char *name, int port,  
     char *ctype, char *rname)  
 {  
         return connect_to_reason(ssh, name, port, ctype, rname, NULL, NULL);  
 }  
   
 /*  /*
  * returns either the newly connected channel or the downstream channel   * returns either the newly connected channel or the downstream channel
  * that needs to deal with this connection.   * that needs to deal with this connection.
Line 4001 
Line 4136 
                 if (open_listen_match_tcpip(fp, listen_host, listen_port, 1)) {                  if (open_listen_match_tcpip(fp, listen_host, listen_port, 1)) {
                         if (fp->downstream)                          if (fp->downstream)
                                 return fp->downstream;                                  return fp->downstream;
                           if (fp->port_to_connect == 0)
                                   return rdynamic_connect_prepare(ssh,
                                       ctype, rname);
                         return connect_to(ssh,                          return connect_to(ssh,
                             fp->host_to_connect, fp->port_to_connect,                              fp->host_to_connect, fp->port_to_connect,
                             ctype, rname);                              ctype, rname);
Line 4038 
Line 4176 
     char *ctype, char *rname, int *reason, const char **errmsg)      char *ctype, char *rname, int *reason, const char **errmsg)
 {  {
         struct ssh_channels *sc = ssh->chanctxt;          struct ssh_channels *sc = ssh->chanctxt;
           struct channel_connect cctx;
           Channel *c;
         u_int i, permit, permit_adm = 1;          u_int i, permit, permit_adm = 1;
           int sock;
         ForwardPermission *fp;          ForwardPermission *fp;
   
         permit = sc->all_opens_permitted;          permit = sc->all_opens_permitted;
Line 4070 
Line 4211 
                         *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;                          *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;
                 return NULL;                  return NULL;
         }          }
         return connect_to_reason(ssh, host, port, ctype, rname, reason, errmsg);  
           memset(&cctx, 0, sizeof(cctx));
           sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname,
               &cctx, reason, errmsg);
           if (sock == -1) {
                   channel_connect_ctx_free(&cctx);
                   return NULL;
           }
   
           c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
               CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
           c->host_port = port;
           c->path = xstrdup(host);
           c->connect_ctx = cctx;
   
           return c;
 }  }
   
 /* Check if connecting to that path is permitted and connect. */  /* Check if connecting to that path is permitted and connect. */
Line 4135 
Line 4291 
                         fatal("%s: channel %u: send window-change: %s",                          fatal("%s: channel %u: send window-change: %s",
                             __func__, i, ssh_err(r));                              __func__, i, ssh_err(r));
         }          }
   }
   
   /* Return RDYNAMIC_OPEN channel: channel allows SOCKS, but is not connected */
   static Channel *
   rdynamic_connect_prepare(struct ssh *ssh, char *ctype, char *rname)
   {
           Channel *c;
           int r;
   
           c = channel_new(ssh, ctype, SSH_CHANNEL_RDYNAMIC_OPEN, -1, -1, -1,
               CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
           c->host_port = 0;
           c->path = NULL;
   
           /*
            * We need to open the channel before we have a FD,
            * so that we can get SOCKS header from peer.
            */
           if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 ||
               (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
               (r = sshpkt_put_u32(ssh, c->self)) != 0 ||
               (r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
               (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) {
                   fatal("%s: channel %i: confirm: %s", __func__,
                       c->self, ssh_err(r));
           }
           return c;
   }
   
   /* Return CONNECTING socket to remote host:port or local socket path */
   static int
   rdynamic_connect_finish(struct ssh *ssh, Channel *c)
   {
           struct channel_connect cctx;
           int sock;
   
           memset(&cctx, 0, sizeof(cctx));
           sock = connect_to_helper(ssh, c->path, c->host_port, SOCK_STREAM, NULL,
               NULL, &cctx, NULL, NULL);
           if (sock == -1)
                   channel_connect_ctx_free(&cctx);
           else {
                   /* similar to SSH_CHANNEL_CONNECTING but we've already sent the open */
                   c->type = SSH_CHANNEL_RDYNAMIC_FINISH;
                   c->connect_ctx = cctx;
                   channel_register_fds(ssh, c, sock, sock, -1, 0, 1, 0);
           }
           return sock;
 }  }
   
 /* -- X11 forwarding */  /* -- X11 forwarding */

Legend:
Removed from v.1.371  
changed lines
  Added in v.1.372