[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.353 and 1.354

version 1.353, 2016/09/19 07:52:42 version 1.354, 2016/09/30 09:19:13
Line 65 
Line 65 
 #include "ssh.h"  #include "ssh.h"
 #include "ssh1.h"  #include "ssh1.h"
 #include "ssh2.h"  #include "ssh2.h"
   #include "ssherr.h"
 #include "packet.h"  #include "packet.h"
 #include "log.h"  #include "log.h"
 #include "misc.h"  #include "misc.h"
Line 114 
Line 115 
         char *listen_host;              /* Remote side should listen address. */          char *listen_host;              /* Remote side should listen address. */
         char *listen_path;              /* Remote side should listen path. */          char *listen_path;              /* Remote side should listen path. */
         int listen_port;                /* Remote side should listen port. */          int listen_port;                /* Remote side should listen port. */
           Channel *downstream;            /* Downstream mux*/
 } ForwardPermission;  } ForwardPermission;
   
 /* List of all permitted host/port pairs to connect by the user. */  /* List of all permitted host/port pairs to connect by the user. */
Line 177 
Line 179 
   
 /* helper */  /* helper */
 static void port_open_helper(Channel *c, char *rtype);  static void port_open_helper(Channel *c, char *rtype);
   static const char *channel_rfwd_bind_host(const char *listen_host);
   
 /* non-blocking connect helpers */  /* non-blocking connect helpers */
 static int connect_next(struct channel_connect *);  static int connect_next(struct channel_connect *);
Line 201 
Line 204 
         return c;          return c;
 }  }
   
   Channel *
   channel_by_remote_id(int remote_id)
   {
           Channel *c;
           u_int i;
   
           for (i = 0; i < channels_alloc; i++) {
                   c = channels[i];
                   if (c != NULL && c->remote_id == remote_id)
                           return c;
           }
           return NULL;
   }
   
 /*  /*
  * Returns the channel if it is allowed to receive protocol messages.   * Returns the channel if it is allowed to receive protocol messages.
  * Private channels, like listening sockets, may not receive messages.   * Private channels, like listening sockets, may not receive messages.
Line 223 
Line 240 
         case SSH_CHANNEL_INPUT_DRAINING:          case SSH_CHANNEL_INPUT_DRAINING:
         case SSH_CHANNEL_OUTPUT_DRAINING:          case SSH_CHANNEL_OUTPUT_DRAINING:
         case SSH_CHANNEL_ABANDONED:          case SSH_CHANNEL_ABANDONED:
           case SSH_CHANNEL_MUX_PROXY:
                 return (c);                  return (c);
         }          }
         logit("Non-public channel %d, type %d.", id, c->type);          logit("Non-public channel %d, type %d.", id, c->type);
Line 400 
Line 418 
 {  {
         char *s;          char *s;
         u_int i, n;          u_int i, n;
           Channel *other;
         struct channel_confirm *cc;          struct channel_confirm *cc;
   
         for (n = 0, i = 0; i < channels_alloc; i++)          for (n = 0, i = 0; i < channels_alloc; i++) {
                 if (channels[i])                  if ((other = channels[i]) != NULL) {
                         n++;                          n++;
   
                           /* detach from mux client and prepare for closing */
                           if (c->type == SSH_CHANNEL_MUX_CLIENT &&
                               other->type == SSH_CHANNEL_MUX_PROXY &&
                               other->mux_ctx == c) {
                                   other->mux_ctx = NULL;
                                   other->type = SSH_CHANNEL_OPEN;
                                   other->istate = CHAN_INPUT_CLOSED;
                                   other->ostate = CHAN_OUTPUT_CLOSED;
                           }
                   }
           }
         debug("channel %d: free: %s, nchannels %u", c->self,          debug("channel %d: free: %s, nchannels %u", c->self,
             c->remote_name ? c->remote_name : "???", n);              c->remote_name ? c->remote_name : "???", n);
   
           /* XXX more MUX cleanup: remove remote forwardings */
           if (c->type == SSH_CHANNEL_MUX_CLIENT) {
                   for (i = 0; i < (u_int)num_permitted_opens; i++) {
                           if (permitted_opens[i].downstream != c)
                                   continue;
                           /* cancel on the server, since mux client is gone */
                           debug("channel %d: cleanup remote forward for %s:%u",
                               c->self,
                               permitted_opens[i].listen_host,
                               permitted_opens[i].listen_port);
                           packet_start(SSH2_MSG_GLOBAL_REQUEST);
                           packet_put_cstring("cancel-tcpip-forward");
                           packet_put_char(0);
                           packet_put_cstring(channel_rfwd_bind_host(
                               permitted_opens[i].listen_host));
                           packet_put_int(permitted_opens[i].listen_port);
                           packet_send();
                           /* unregister */
                           permitted_opens[i].listen_port = 0;
                           permitted_opens[i].port_to_connect = 0;
                           free(permitted_opens[i].host_to_connect);
                           permitted_opens[i].host_to_connect = NULL;
                           free(permitted_opens[i].listen_host);
                           permitted_opens[i].listen_host = NULL;
                           permitted_opens[i].listen_path = NULL;
                           permitted_opens[i].downstream = NULL;
                   }
           }
   
         s = channel_open_message();          s = channel_open_message();
         debug3("channel %d: status: %s", c->self, s);          debug3("channel %d: status: %s", c->self, s);
         free(s);          free(s);
Line 553 
Line 613 
                 case SSH_CHANNEL_OPEN:                  case SSH_CHANNEL_OPEN:
                 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:
                         return 1;                          return 1;
                 case SSH_CHANNEL_INPUT_DRAINING:                  case SSH_CHANNEL_INPUT_DRAINING:
                 case SSH_CHANNEL_OUTPUT_DRAINING:                  case SSH_CHANNEL_OUTPUT_DRAINING:
Line 586 
Line 647 
                 case SSH_CHANNEL_RPORT_LISTENER:                  case SSH_CHANNEL_RPORT_LISTENER:
                 case SSH_CHANNEL_MUX_LISTENER:                  case SSH_CHANNEL_MUX_LISTENER:
                 case SSH_CHANNEL_MUX_CLIENT:                  case SSH_CHANNEL_MUX_CLIENT:
                   case SSH_CHANNEL_MUX_PROXY:
                 case SSH_CHANNEL_OPENING:                  case SSH_CHANNEL_OPENING:
                 case SSH_CHANNEL_CONNECTING:                  case SSH_CHANNEL_CONNECTING:
                 case SSH_CHANNEL_ZOMBIE:                  case SSH_CHANNEL_ZOMBIE:
Line 611 
Line 673 
         return -1;          return -1;
 }  }
   
   
 /*  /*
  * Returns a message describing the currently open forwarded connections,   * Returns a message describing the currently open forwarded connections,
  * suitable for sending to the client.  The message contains crlf pairs for   * suitable for sending to the client.  The message contains crlf pairs for
Line 640 
Line 701 
                 case SSH_CHANNEL_AUTH_SOCKET:                  case SSH_CHANNEL_AUTH_SOCKET:
                 case SSH_CHANNEL_ZOMBIE:                  case SSH_CHANNEL_ZOMBIE:
                 case SSH_CHANNEL_ABANDONED:                  case SSH_CHANNEL_ABANDONED:
                 case SSH_CHANNEL_MUX_CLIENT:  
                 case SSH_CHANNEL_MUX_LISTENER:                  case SSH_CHANNEL_MUX_LISTENER:
                 case SSH_CHANNEL_UNIX_LISTENER:                  case SSH_CHANNEL_UNIX_LISTENER:
                 case SSH_CHANNEL_RUNIX_LISTENER:                  case SSH_CHANNEL_RUNIX_LISTENER:
Line 653 
Line 713 
                 case SSH_CHANNEL_X11_OPEN:                  case SSH_CHANNEL_X11_OPEN:
                 case SSH_CHANNEL_INPUT_DRAINING:                  case SSH_CHANNEL_INPUT_DRAINING:
                 case SSH_CHANNEL_OUTPUT_DRAINING:                  case SSH_CHANNEL_OUTPUT_DRAINING:
                   case SSH_CHANNEL_MUX_PROXY:
                   case SSH_CHANNEL_MUX_CLIENT:
                         snprintf(buf, sizeof buf,                          snprintf(buf, sizeof buf,
                             "  #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n",                              "  #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n",
                             c->self, c->remote_name,                              c->self, c->remote_name,
Line 2333 
Line 2395 
         }          }
 }  }
   
   /* -- mux proxy support  */
   
   /*
    * When multiplexing channel messages for mux clients we have to deal
    * with downstream messages from the mux client and upstream messages
    * from the ssh server:
    * 1) Handling downstream messages is straightforward and happens
    *    in channel_proxy_downstream():
    *    - We forward all messages (mostly) unmodified to the server.
    *    - However, in order to route messages from upstream to the correct
    *      downstream client, we have to replace the channel IDs used by the
    *      mux clients with a unique channel ID because the mux clients might
    *      use conflicting channel IDs.
    *    - so we inspect and change both SSH2_MSG_CHANNEL_OPEN and
    *      SSH2_MSG_CHANNEL_OPEN_CONFIRMATION messages, create a local
    *      SSH_CHANNEL_MUX_PROXY channel and replace the mux clients ID
    *      with the newly allocated channel ID.
    * 2) Upstream messages are received by matching SSH_CHANNEL_MUX_PROXY
    *    channels and procesed by channel_proxy_upstream(). The local channel ID
    *    is then translated back to the original mux client ID.
    * 3) In both cases we need to keep track of matching SSH2_MSG_CHANNEL_CLOSE
    *    messages so we can clean up SSH_CHANNEL_MUX_PROXY channels.
    * 4) The SSH_CHANNEL_MUX_PROXY channels also need to closed when the
    *    downstream mux client are removed.
    * 5) Handling SSH2_MSG_CHANNEL_OPEN messages from the upstream server
    *    requires more work, because they are not addressed to a specific
    *    channel. E.g. client_request_forwarded_tcpip() needs to figure
    *    out whether the request is addressed to the local client or a
    *    specific downstream client based on the listen-address/port.
    * 6) Agent and X11-Forwarding have a similar problem and are currenly
    *    not supported as the matching session/channel cannot be identified
    *    easily.
    */
   
   /*
    * receive packets from downstream mux clients:
    * channel callback fired on read from mux client, creates
    * SSH_CHANNEL_MUX_PROXY channels and translates channel IDs
    * on channel creation.
    */
   int
   channel_proxy_downstream(Channel *downstream)
   {
           Channel *c = NULL;
           struct ssh *ssh = active_state;
           struct sshbuf *original = NULL, *modified = NULL;
           const u_char *cp;
           char *ctype = NULL, *listen_host = NULL;
           u_char type;
           size_t have;
           int ret = -1, r, id, remote_id, listen_port, idx;
   
           /* sshbuf_dump(&downstream->input, stderr); */
           if ((r = sshbuf_get_string_direct(&downstream->input, &cp, &have))
               != 0) {
                   error("%s: malformed message: %s", __func__, ssh_err(r));
                   return -1;
           }
           if (have < 2) {
                   error("%s: short message", __func__);
                   return -1;
           }
           type = cp[1];
           /* skip padlen + type */
           cp += 2;
           have -= 2;
           if (ssh_packet_log_type(type))
                   debug3("%s: channel %u: down->up: type %u", __func__,
                       downstream->self, type);
   
           switch (type) {
           case SSH2_MSG_CHANNEL_OPEN:
                   if ((original = sshbuf_from(cp, have)) == NULL ||
                       (modified = sshbuf_new()) == NULL) {
                           error("%s: alloc", __func__);
                           goto out;
                   }
                   if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0 ||
                       (r = sshbuf_get_u32(original, &id)) != 0) {
                           error("%s: parse error %s", __func__, ssh_err(r));
                           goto out;
                   }
                   c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY,
                      -1, -1, -1, 0, 0, 0, ctype, 1);
                   c->mux_ctx = downstream;        /* point to mux client */
                   c->mux_downstream_id = id;      /* original downstream id */
                   if ((r = sshbuf_put_cstring(modified, ctype)) != 0 ||
                       (r = sshbuf_put_u32(modified, c->self)) != 0 ||
                       (r = sshbuf_putb(modified, original)) != 0) {
                           error("%s: compose error %s", __func__, ssh_err(r));
                           channel_free(c);
                           goto out;
                   }
                   break;
           case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
                   /*
                    * Almost the same as SSH2_MSG_CHANNEL_OPEN, except then we
                    * need to parse 'remote_id' instead of 'ctype'.
                    */
                   if ((original = sshbuf_from(cp, have)) == NULL ||
                       (modified = sshbuf_new()) == NULL) {
                           error("%s: alloc", __func__);
                           goto out;
                   }
                   if ((r = sshbuf_get_u32(original, &remote_id)) != 0 ||
                       (r = sshbuf_get_u32(original, &id)) != 0) {
                           error("%s: parse error %s", __func__, ssh_err(r));
                           goto out;
                   }
                   c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY,
                      -1, -1, -1, 0, 0, 0, "mux-down-connect", 1);
                   c->mux_ctx = downstream;        /* point to mux client */
                   c->mux_downstream_id = id;
                   c->remote_id = remote_id;
                   if ((r = sshbuf_put_u32(modified, remote_id)) != 0 ||
                       (r = sshbuf_put_u32(modified, c->self)) != 0 ||
                       (r = sshbuf_putb(modified, original)) != 0) {
                           error("%s: compose error %s", __func__, ssh_err(r));
                           channel_free(c);
                           goto out;
                   }
                   break;
           case SSH2_MSG_GLOBAL_REQUEST:
                   if ((original = sshbuf_from(cp, have)) == NULL) {
                           error("%s: alloc", __func__);
                           goto out;
                   }
                   if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0) {
                           error("%s: parse error %s", __func__, ssh_err(r));
                           goto out;
                   }
                   if (strcmp(ctype, "tcpip-forward") != 0) {
                           error("%s: unsupported request %s", __func__, ctype);
                           goto out;
                   }
                   if ((r = sshbuf_get_u8(original, NULL)) != 0 ||
                       (r = sshbuf_get_cstring(original, &listen_host, NULL)) != 0 ||
                       (r = sshbuf_get_u32(original, &listen_port)) != 0) {
                           error("%s: parse error %s", __func__, ssh_err(r));
                           goto out;
                   }
                   /* Record that connection to this host/port is permitted. */
                   permitted_opens = xreallocarray(permitted_opens,
                       num_permitted_opens + 1, sizeof(*permitted_opens));
                   idx = num_permitted_opens++;
                   permitted_opens[idx].host_to_connect = xstrdup("<mux>");
                   permitted_opens[idx].port_to_connect = -1;
                   permitted_opens[idx].listen_host = listen_host;
                   permitted_opens[idx].listen_port = listen_port;
                   permitted_opens[idx].downstream = downstream;
                   listen_host = NULL;
                   break;
           case SSH2_MSG_CHANNEL_CLOSE:
                   if (have < 4)
                           break;
                   remote_id = PEEK_U32(cp);
                   if ((c = channel_by_remote_id(remote_id)) != NULL) {
                           if (c->flags & CHAN_CLOSE_RCVD)
                                   channel_free(c);
                           else
                                   c->flags |= CHAN_CLOSE_SENT;
                   }
                   break;
           }
           if (modified) {
                   if ((r = sshpkt_start(ssh, type)) != 0 ||
                       (r = sshpkt_putb(ssh, modified)) != 0 ||
                       (r = sshpkt_send(ssh)) != 0) {
                           error("%s: send %s", __func__, ssh_err(r));
                           goto out;
                   }
           } else {
                   if ((r = sshpkt_start(ssh, type)) != 0 ||
                       (r = sshpkt_put(ssh, cp, have)) != 0 ||
                       (r = sshpkt_send(ssh)) != 0) {
                           error("%s: send %s", __func__, ssh_err(r));
                           goto out;
                   }
           }
           ret = 0;
    out:
           free(ctype);
           free(listen_host);
           sshbuf_free(original);
           sshbuf_free(modified);
           return ret;
   }
   
   /*
    * receive packets from upstream server and de-multiplex packets
    * to correct downstream:
    * implemented as a helper for channel input handlers,
    * replaces local (proxy) channel ID with downstream channel ID.
    */
   int
   channel_proxy_upstream(Channel *c, int type, u_int32_t seq, void *ctxt)
   {
           struct ssh *ssh = active_state;
           struct sshbuf *b = NULL;
           Channel *downstream;
           const u_char *cp = NULL;
           size_t len;
           int r;
   
           /*
            * When receiving packets from the peer we need to check whether we
            * need to forward the packets to the mux client. In this case we
            * restore the orignal channel id and keep track of CLOSE messages,
            * so we can cleanup the channel.
            */
           if (c == NULL || c->type != SSH_CHANNEL_MUX_PROXY)
                   return 0;
           if ((downstream = c->mux_ctx) == NULL)
                   return 0;
           switch (type) {
           case SSH2_MSG_CHANNEL_CLOSE:
           case SSH2_MSG_CHANNEL_DATA:
           case SSH2_MSG_CHANNEL_EOF:
           case SSH2_MSG_CHANNEL_EXTENDED_DATA:
           case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
           case SSH2_MSG_CHANNEL_OPEN_FAILURE:
           case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
           case SSH2_MSG_CHANNEL_SUCCESS:
           case SSH2_MSG_CHANNEL_FAILURE:
           case SSH2_MSG_CHANNEL_REQUEST:
                   break;
           default:
                   debug2("%s: channel %u: unsupported type %u", __func__,
                       c->self, type);
                   return 0;
           }
           if ((b = sshbuf_new()) == NULL) {
                   error("%s: alloc reply", __func__);
                   goto out;
           }
           /* get remaining payload (after id) */
           cp = sshpkt_ptr(ssh, &len);
           if (cp == NULL) {
                   error("%s: no packet", __func__);
                   goto out;
           }
           /* translate id and send to muxclient */
           if ((r = sshbuf_put_u8(b, 0)) != 0 ||   /* padlen */
               (r = sshbuf_put_u8(b, type)) != 0 ||
               (r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 ||
               (r = sshbuf_put(b, cp, len)) != 0 ||
               (r = sshbuf_put_stringb(&downstream->output, b)) != 0) {
                   error("%s: compose for muxclient %s", __func__, ssh_err(r));
                   goto out;
           }
           /* sshbuf_dump(b, stderr); */
           if (ssh_packet_log_type(type))
                   debug3("%s: channel %u: up->down: type %u", __func__, c->self,
                       type);
    out:
           /* update state */
           switch (type) {
           case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
                   /* record remote_id for SSH2_MSG_CHANNEL_CLOSE */
                   if (cp && len > 4)
                           c->remote_id = PEEK_U32(cp);
                   break;
           case SSH2_MSG_CHANNEL_CLOSE:
                   if (c->flags & CHAN_CLOSE_SENT)
                           channel_free(c);
                   else
                           c->flags |= CHAN_CLOSE_RCVD;
                   break;
           }
           sshbuf_free(b);
           return 1;
   }
   
 /* -- protocol input */  /* -- protocol input */
   
 /* ARGSUSED */  /* ARGSUSED */
Line 2350 
Line 2684 
         c = channel_lookup(id);          c = channel_lookup(id);
         if (c == NULL)          if (c == NULL)
                 packet_disconnect("Received data for nonexistent channel %d.", id);                  packet_disconnect("Received data for nonexistent channel %d.", id);
           if (channel_proxy_upstream(c, type, seq, ctxt))
                   return 0;
   
         /* 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 &&
Line 2412 
Line 2748 
   
         if (c == NULL)          if (c == NULL)
                 packet_disconnect("Received extended_data for bad channel %d.", id);                  packet_disconnect("Received extended_data for bad channel %d.", id);
           if (channel_proxy_upstream(c, type, seq, ctxt))
                   return 0;
         if (c->type != SSH_CHANNEL_OPEN) {          if (c->type != SSH_CHANNEL_OPEN) {
                 logit("channel %d: ext data for non open", id);                  logit("channel %d: ext data for non open", id);
                 return 0;                  return 0;
Line 2457 
Line 2795 
         c = channel_lookup(id);          c = channel_lookup(id);
         if (c == NULL)          if (c == NULL)
                 packet_disconnect("Received ieof for nonexistent channel %d.", id);                  packet_disconnect("Received ieof for nonexistent channel %d.", id);
           if (channel_proxy_upstream(c, type, seq, ctxt))
                   return 0;
         chan_rcvd_ieof(c);          chan_rcvd_ieof(c);
   
         /* XXX force input close */          /* XXX force input close */
Line 2481 
Line 2821 
         c = channel_lookup(id);          c = channel_lookup(id);
         if (c == NULL)          if (c == NULL)
                 packet_disconnect("Received close for nonexistent channel %d.", id);                  packet_disconnect("Received close for nonexistent channel %d.", id);
           if (channel_proxy_upstream(c, type, seq, ctxt))
                   return 0;
         /*          /*
          * Send a confirmation that we have closed the channel and no more           * Send a confirmation that we have closed the channel and no more
          * data is coming for it.           * data is coming for it.
Line 2516 
Line 2857 
         int id = packet_get_int();          int id = packet_get_int();
         Channel *c = channel_lookup(id);          Channel *c = channel_lookup(id);
   
         packet_check_eom();  
         if (c == NULL)          if (c == NULL)
                 packet_disconnect("Received oclose for nonexistent channel %d.", id);                  packet_disconnect("Received oclose for nonexistent channel %d.", id);
           if (channel_proxy_upstream(c, type, seq, ctxt))
                   return 0;
           packet_check_eom();
         chan_rcvd_oclose(c);          chan_rcvd_oclose(c);
         return 0;          return 0;
 }  }
Line 2530 
Line 2873 
         int id = packet_get_int();          int id = packet_get_int();
         Channel *c = channel_lookup(id);          Channel *c = channel_lookup(id);
   
         packet_check_eom();  
         if (c == NULL)          if (c == NULL)
                 packet_disconnect("Received close confirmation for "                  packet_disconnect("Received close confirmation for "
                     "out-of-range channel %d.", id);                      "out-of-range channel %d.", id);
           if (channel_proxy_upstream(c, type, seq, ctxt))
                   return 0;
           packet_check_eom();
         if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED)          if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED)
                 packet_disconnect("Received close confirmation for "                  packet_disconnect("Received close confirmation for "
                     "non-closed channel %d (type %d).", id, c->type);                      "non-closed channel %d (type %d).", id, c->type);
Line 2551 
Line 2896 
         id = packet_get_int();          id = packet_get_int();
         c = channel_lookup(id);          c = channel_lookup(id);
   
         if (c==NULL || c->type != SSH_CHANNEL_OPENING)          if (c==NULL)
                 packet_disconnect("Received open confirmation for "                  packet_disconnect("Received open confirmation for "
                       "unknown channel %d.", id);
           if (channel_proxy_upstream(c, type, seq, ctxt))
                   return 0;
           if (c->type != SSH_CHANNEL_OPENING)
                   packet_disconnect("Received open confirmation for "
                     "non-opening channel %d.", id);                      "non-opening channel %d.", id);
         remote_id = packet_get_int();          remote_id = packet_get_int();
         /* Record the remote channel number and mark that the channel is now open. */          /* Record the remote channel number and mark that the channel is now open. */
Line 2601 
Line 2951 
         id = packet_get_int();          id = packet_get_int();
         c = channel_lookup(id);          c = channel_lookup(id);
   
         if (c==NULL || c->type != SSH_CHANNEL_OPENING)          if (c==NULL)
                 packet_disconnect("Received open failure for "                  packet_disconnect("Received open failure for "
                       "unknown channel %d.", id);
           if (channel_proxy_upstream(c, type, seq, ctxt))
                   return 0;
           if (c->type != SSH_CHANNEL_OPENING)
                   packet_disconnect("Received open failure for "
                     "non-opening channel %d.", id);                      "non-opening channel %d.", id);
         if (compat20) {          if (compat20) {
                 reason = packet_get_int();                  reason = packet_get_int();
Line 2645 
Line 3000 
                 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, ctxt))
                   return 0;
         adjust = packet_get_int();          adjust = packet_get_int();
         packet_check_eom();          packet_check_eom();
         debug2("channel %d: rcvd adjust %u", id, adjust);          debug2("channel %d: rcvd adjust %u", id, adjust);
Line 2699 
Line 3056 
         packet_set_alive_timeouts(0);          packet_set_alive_timeouts(0);
   
         id = packet_get_int();          id = packet_get_int();
         packet_check_eom();  
   
         debug2("channel_input_status_confirm: type %d id %d", type, id);          debug2("channel_input_status_confirm: type %d id %d", type, id);
   
         if ((c = channel_lookup(id)) == NULL) {          if ((c = channel_lookup(id)) == NULL) {
                 logit("channel_input_status_confirm: %d: unknown", id);                  logit("channel_input_status_confirm: %d: unknown", id);
                 return 0;                  return 0;
         }          }
           if (channel_proxy_upstream(c, type, seq, ctxt))
                   return 0;
           packet_check_eom();
         if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)          if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
                 return 0;                  return 0;
         cc->cb(type, c, cc->ctx);          cc->cb(type, c, cc->ctx);
Line 3254 
Line 3612 
                         permitted_opens[idx].listen_path = NULL;                          permitted_opens[idx].listen_path = NULL;
                         permitted_opens[idx].listen_port = fwd->listen_port;                          permitted_opens[idx].listen_port = fwd->listen_port;
                 }                  }
                   permitted_opens[idx].downstream = NULL;
         }          }
         return (idx);          return (idx);
 }  }
Line 3349 
Line 3708 
         free(permitted_opens[i].listen_host);          free(permitted_opens[i].listen_host);
         permitted_opens[i].listen_host = NULL;          permitted_opens[i].listen_host = NULL;
         permitted_opens[i].listen_path = NULL;          permitted_opens[i].listen_path = NULL;
           permitted_opens[i].downstream = NULL;
   
         return 0;          return 0;
 }  }
Line 3386 
Line 3746 
         permitted_opens[i].listen_host = NULL;          permitted_opens[i].listen_host = NULL;
         free(permitted_opens[i].listen_path);          free(permitted_opens[i].listen_path);
         permitted_opens[i].listen_path = NULL;          permitted_opens[i].listen_path = NULL;
           permitted_opens[i].downstream = NULL;
   
         return 0;          return 0;
 }  }
Line 3466 
Line 3827 
         permitted_opens[num_permitted_opens].listen_host = NULL;          permitted_opens[num_permitted_opens].listen_host = NULL;
         permitted_opens[num_permitted_opens].listen_path = NULL;          permitted_opens[num_permitted_opens].listen_path = NULL;
         permitted_opens[num_permitted_opens].listen_port = 0;          permitted_opens[num_permitted_opens].listen_port = 0;
           permitted_opens[num_permitted_opens].downstream = NULL;
         num_permitted_opens++;          num_permitted_opens++;
   
         all_opens_permitted = 0;          all_opens_permitted = 0;
Line 3728 
Line 4090 
         return c;          return c;
 }  }
   
   /*
    * returns either the newly connected channel or the downstream channel
    * that needs to deal with this connection.
    */
 Channel *  Channel *
 channel_connect_by_listen_address(const char *listen_host,  channel_connect_by_listen_address(const char *listen_host,
     u_short listen_port, char *ctype, char *rname)      u_short listen_port, char *ctype, char *rname)
Line 3737 
Line 4103 
         for (i = 0; i < num_permitted_opens; i++) {          for (i = 0; i < num_permitted_opens; i++) {
                 if (open_listen_match_tcpip(&permitted_opens[i], listen_host,                  if (open_listen_match_tcpip(&permitted_opens[i], listen_host,
                     listen_port, 1)) {                      listen_port, 1)) {
                           if (permitted_opens[i].downstream)
                                   return permitted_opens[i].downstream;
                         return connect_to(                          return connect_to(
                             permitted_opens[i].host_to_connect,                              permitted_opens[i].host_to_connect,
                             permitted_opens[i].port_to_connect, ctype, rname);                              permitted_opens[i].port_to_connect, ctype, rname);

Legend:
Removed from v.1.353  
changed lines
  Added in v.1.354