[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.40 and 1.41

version 1.40, 2000/03/27 17:41:50 version 1.41, 2000/03/28 20:31:25
Line 37 
Line 37 
 /* Max len of agent socket */  /* Max len of agent socket */
 #define MAX_SOCKET_NAME 100  #define MAX_SOCKET_NAME 100
   
   /* default buffer for tcp-fwd-channel */
   #define CHAN_WINDOW_DEFAULT      (8*1024)
   #define CHAN_PACKET_DEFAULT      (CHAN_WINDOW_DEFAULT/2)
   
 /*  /*
  * Pointer to an array containing all allocated channels.  The array is   * Pointer to an array containing all allocated channels.  The array is
  * dynamically extended as needed.   * dynamically extended as needed.
Line 81 
Line 85 
  * network (which might be behind a firewall).   * network (which might be behind a firewall).
  */   */
 typedef struct {  typedef struct {
         char *host;             /* Host name. */          char *host_to_connect;          /* Connect to 'host'. */
         u_short port;           /* Port number. */          u_short port_to_connect;        /* Connect to 'port'. */
           u_short listen_port;            /* Remote side should listen port number. */
 } ForwardPermission;  } ForwardPermission;
   
 /* List of all permitted host/port pairs to connect. */  /* List of all permitted host/port pairs to connect. */
Line 119 
Line 124 
         all_opens_permitted = 1;          all_opens_permitted = 1;
 }  }
   
   /* lookup channel by id */
   
   Channel *
   channel_lookup(int id)
   {
           Channel *c;
           if (id < 0 && id > channels_alloc) {
                   log("channel_lookup: %d: bad id", id);
                   return NULL;
           }
           c = &channels[id];
           if (c->type == SSH_CHANNEL_FREE) {
                   log("channel_lookup: %d: bad id: channel free", id);
                   return NULL;
           }
           return c;
   }
   
 /*  /*
  * Allocate a new channel object and set its type and socket. This will cause   * Allocate a new channel object and set its type and socket. This will cause
  * remote_name to be freed.   * remote_name to be freed.
  */   */
   
 int  int
 channel_allocate(int type, int sock, char *remote_name)  channel_new(char *ctype, int type, int rfd, int wfd, int efd,
       int window, int maxpack, int extended_usage, char *remote_name)
 {  {
         int i, found;          int i, found;
         Channel *c;          Channel *c;
   
         /* Update the maximum file descriptor value. */          /* Update the maximum file descriptor value. */
         if (sock > channel_max_fd_value)          if (rfd > channel_max_fd_value)
                 channel_max_fd_value = sock;                  channel_max_fd_value = rfd;
           if (wfd > channel_max_fd_value)
                   channel_max_fd_value = wfd;
           if (efd > channel_max_fd_value)
                   channel_max_fd_value = efd;
         /* XXX set close-on-exec -markus */          /* XXX set close-on-exec -markus */
   
         /* Do initial allocation if this is the first call. */          /* Do initial allocation if this is the first call. */
Line 167 
Line 195 
         c = &channels[found];          c = &channels[found];
         buffer_init(&c->input);          buffer_init(&c->input);
         buffer_init(&c->output);          buffer_init(&c->output);
           buffer_init(&c->extended);
         chan_init_iostates(c);          chan_init_iostates(c);
         c->self = found;          c->self = found;
         c->type = type;          c->type = type;
         c->sock = sock;          c->ctype = ctype;
           c->local_window = window;
           c->local_window_max = window;
           c->local_consumed = 0;
           c->local_maxpacket = maxpack;
           c->remote_window = 0;
           c->remote_maxpacket = 0;
           c->rfd = rfd;
           c->wfd = wfd;
           c->sock = (rfd == wfd) ? rfd : -1;
           c->efd = efd;
           c->extended_usage = extended_usage;
         c->remote_id = -1;          c->remote_id = -1;
         c->remote_name = remote_name;          c->remote_name = remote_name;
           c->remote_window = 0;
           c->remote_maxpacket = 0;
           c->cb_fn = NULL;
           c->cb_arg = NULL;
           c->cb_event = 0;
           c->dettach_user = NULL;
         debug("channel %d: new [%s]", found, remote_name);          debug("channel %d: new [%s]", found, remote_name);
         return found;          return found;
 }  }
   int
   channel_allocate(int type, int sock, char *remote_name)
   {
           return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name);
   }
   
 /* Free the channel and close its socket. */  /* Free the channel and close its socket. */
   
 void  void
 channel_free(int channel)  channel_free(int id)
 {  {
         if (channel < 0 || channel >= channels_alloc ||          Channel *c = channel_lookup(id);
             channels[channel].type == SSH_CHANNEL_FREE)          if (c == NULL)
                 packet_disconnect("channel free: bad local channel %d", channel);                  packet_disconnect("channel free: bad local channel %d", id);
           debug("channel_free: channel %d: status: %s", id, channel_open_message());
         if (compat13)          if (compat13)
                 shutdown(channels[channel].sock, SHUT_RDWR);                  shutdown(c->sock, SHUT_RDWR);
         close(channels[channel].sock);          buffer_free(&c->input);
         buffer_free(&channels[channel].input);          buffer_free(&c->output);
         buffer_free(&channels[channel].output);          buffer_free(&c->extended);
         channels[channel].type = SSH_CHANNEL_FREE;          c->type = SSH_CHANNEL_FREE;
         if (channels[channel].remote_name) {          if (c->remote_name) {
                 xfree(channels[channel].remote_name);                  xfree(c->remote_name);
                 channels[channel].remote_name = NULL;                  c->remote_name = NULL;
         }          }
 }  }
   
 /*  /*
  * This is called just before select() to add any bits relevant to channels   * 'channel_pre*' are called just before select() to add any bits relevant to
  * in the select bitmasks.   * channels in the select bitmasks.
  */   */
   /*
    * 'channel_post*': perform any appropriate operations for channels which
    * have events pending.
    */
   typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset);
   chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
   chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
   
 void  void
 channel_prepare_select(fd_set * readset, fd_set * writeset)  channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset)
 {  {
         int i;          FD_SET(c->sock, readset);
         Channel *ch;  }
   
   void
   channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset)
   {
           if (buffer_len(&c->input) < packet_get_maxsize())
                   FD_SET(c->sock, readset);
           if (buffer_len(&c->output) > 0)
                   FD_SET(c->sock, writeset);
   }
   
   void
   channel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset)
   {
           /* test whether sockets are 'alive' for read/write */
           if (c->istate == CHAN_INPUT_OPEN)
                   if (buffer_len(&c->input) < packet_get_maxsize())
                           FD_SET(c->sock, readset);
           if (c->ostate == CHAN_OUTPUT_OPEN ||
               c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
                   if (buffer_len(&c->output) > 0) {
                           FD_SET(c->sock, writeset);
                   } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
                           chan_obuf_empty(c);
                   }
           }
   }
   
   void
   channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset)
   {
           if (buffer_len(&c->input) == 0) {
                   packet_start(SSH_MSG_CHANNEL_CLOSE);
                   packet_put_int(c->remote_id);
                   packet_send();
                   c->type = SSH_CHANNEL_CLOSED;
                   debug("Closing channel %d after input drain.", c->self);
           }
   }
   
   void
   channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset)
   {
           if (buffer_len(&c->output) == 0)
                   channel_free(c->self);
           else
                   FD_SET(c->sock, writeset);
   }
   
   /*
    * This is a special state for X11 authentication spoofing.  An opened X11
    * connection (when authentication spoofing is being done) remains in this
    * state until the first packet has been completely read.  The authentication
    * data in that packet is then substituted by the real data if it matches the
    * fake data, and the channel is put into normal mode.
    */
   int
   x11_open_helper(Channel *c)
   {
         unsigned char *ucp;          unsigned char *ucp;
         unsigned int proto_len, data_len;          unsigned int proto_len, data_len;
   
         for (i = 0; i < channels_alloc; i++) {          /* Check if the fixed size part of the packet is in buffer. */
                 ch = &channels[i];          if (buffer_len(&c->output) < 12)
 redo:                  return 0;
                 switch (ch->type) {  
                 case SSH_CHANNEL_X11_LISTENER:  
                 case SSH_CHANNEL_PORT_LISTENER:  
                 case SSH_CHANNEL_AUTH_SOCKET:  
                         FD_SET(ch->sock, readset);  
                         break;  
   
                 case SSH_CHANNEL_OPEN:          /* Parse the lengths of variable-length fields. */
                         if (compat13) {          ucp = (unsigned char *) buffer_ptr(&c->output);
                                 if (buffer_len(&ch->input) < packet_get_maxsize())          if (ucp[0] == 0x42) {   /* Byte order MSB first. */
                                         FD_SET(ch->sock, readset);                  proto_len = 256 * ucp[6] + ucp[7];
                                 if (buffer_len(&ch->output) > 0)                  data_len = 256 * ucp[8] + ucp[9];
                                         FD_SET(ch->sock, writeset);          } else if (ucp[0] == 0x6c) {    /* Byte order LSB first. */
                                 break;                  proto_len = ucp[6] + 256 * ucp[7];
                         }                  data_len = ucp[8] + 256 * ucp[9];
                         /* test whether sockets are 'alive' for read/write */          } else {
                         if (ch->istate == CHAN_INPUT_OPEN)                  debug("Initial X11 packet contains bad byte order byte: 0x%x",
                                 if (buffer_len(&ch->input) < packet_get_maxsize())                        ucp[0]);
                                         FD_SET(ch->sock, readset);                  return -1;
                         if (ch->ostate == CHAN_OUTPUT_OPEN ||          }
                             ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) {  
                                 if (buffer_len(&ch->output) > 0) {  
                                         FD_SET(ch->sock, writeset);  
                                 } else if (ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) {  
                                         chan_obuf_empty(ch);  
                                 }  
                         }  
                         break;  
   
                 case SSH_CHANNEL_INPUT_DRAINING:          /* Check if the whole packet is in buffer. */
                         if (!compat13)          if (buffer_len(&c->output) <
                                 fatal("cannot happen: IN_DRAIN");              12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
                         if (buffer_len(&ch->input) == 0) {                  return 0;
                                 packet_start(SSH_MSG_CHANNEL_CLOSE);  
                                 packet_put_int(ch->remote_id);  
                                 packet_send();  
                                 ch->type = SSH_CHANNEL_CLOSED;  
                                 debug("Closing channel %d after input drain.", ch->self);  
                                 break;  
                         }  
                         break;  
   
                 case SSH_CHANNEL_OUTPUT_DRAINING:          /* Check if authentication protocol matches. */
                         if (!compat13)          if (proto_len != strlen(x11_saved_proto) ||
                                 fatal("cannot happen: OUT_DRAIN");              memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
                         if (buffer_len(&ch->output) == 0) {                  debug("X11 connection uses different authentication protocol.");
                                 channel_free(i);                  return -1;
                                 break;          }
                         }          /* Check if authentication data matches our fake data. */
                         FD_SET(ch->sock, writeset);          if (data_len != x11_fake_data_len ||
                         break;              memcmp(ucp + 12 + ((proto_len + 3) & ~3),
                   x11_fake_data, x11_fake_data_len) != 0) {
                   debug("X11 auth data does not match fake data.");
                   return -1;
           }
           /* Check fake data length */
           if (x11_fake_data_len != x11_saved_data_len) {
                   error("X11 fake_data_len %d != saved_data_len %d",
                       x11_fake_data_len, x11_saved_data_len);
                   return -1;
           }
           /*
            * Received authentication protocol and data match
            * our fake data. Substitute the fake data with real
            * data.
            */
           memcpy(ucp + 12 + ((proto_len + 3) & ~3),
               x11_saved_data, x11_saved_data_len);
           return 1;
   }
   
                 case SSH_CHANNEL_X11_OPEN:  void
                         /*  channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset)
                          * This is a special state for X11 authentication  {
                          * spoofing.  An opened X11 connection (when          int ret = x11_open_helper(c);
                          * authentication spoofing is being done) remains in          if (ret == 1) {
                          * this state until the first packet has been                  /* Start normal processing for the channel. */
                          * completely read.  The authentication data in that                  c->type = SSH_CHANNEL_OPEN;
                          * packet is then substituted by the real data if it          } else if (ret == -1) {
                          * matches the fake data, and the channel is put into                  /*
                          * normal mode.                   * We have received an X11 connection that has bad
                          */                   * authentication information.
                         /* Check if the fixed size part of the packet is in buffer. */                   */
                         if (buffer_len(&ch->output) < 12)                  log("X11 connection rejected because of wrong authentication.\r\n");
                                 break;                  buffer_clear(&c->input);
                   buffer_clear(&c->output);
                   close(c->sock);
                   c->sock = -1;
                   c->type = SSH_CHANNEL_CLOSED;
                   packet_start(SSH_MSG_CHANNEL_CLOSE);
                   packet_put_int(c->remote_id);
                   packet_send();
           }
   }
   
                         /* Parse the lengths of variable-length fields. */  void
                         ucp = (unsigned char *) buffer_ptr(&ch->output);  channel_pre_x11_open_15(Channel *c, fd_set * readset, fd_set * writeset)
                         if (ucp[0] == 0x42) {   /* Byte order MSB first. */  {
                                 proto_len = 256 * ucp[6] + ucp[7];          int ret = x11_open_helper(c);
                                 data_len = 256 * ucp[8] + ucp[9];          if (ret == 1) {
                         } else if (ucp[0] == 0x6c) {    /* Byte order LSB first. */                  c->type = SSH_CHANNEL_OPEN;
                                 proto_len = ucp[6] + 256 * ucp[7];          } else if (ret == -1) {
                                 data_len = ucp[8] + 256 * ucp[9];                  debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
                         } else {                  chan_read_failed(c);
                                 debug("Initial X11 packet contains bad byte order byte: 0x%x",                  chan_write_failed(c);
                                       ucp[0]);                  debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
                                 ch->type = SSH_CHANNEL_OPEN;          }
                                 goto reject;  }
                         }  
   
                         /* Check if the whole packet is in buffer. */  /* This is our fake X11 server socket. */
                         if (buffer_len(&ch->output) <  void
                             12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))  channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)
                                 break;  {
           struct sockaddr addr;
           int newsock, newch;
           socklen_t addrlen;
           char buf[16384], *remote_hostname;
   
                         /* Check if authentication protocol matches. */          if (FD_ISSET(c->sock, readset)) {
                         if (proto_len != strlen(x11_saved_proto) ||                  debug("X11 connection requested.");
                             memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {                  addrlen = sizeof(addr);
                                 debug("X11 connection uses different authentication protocol.");                  newsock = accept(c->sock, &addr, &addrlen);
                                 ch->type = SSH_CHANNEL_OPEN;                  if (newsock < 0) {
                                 goto reject;                          error("accept: %.100s", strerror(errno));
                         }                          return;
                         /* Check if authentication data matches our fake data. */                  }
                         if (data_len != x11_fake_data_len ||                  remote_hostname = get_remote_hostname(newsock);
                             memcmp(ucp + 12 + ((proto_len + 3) & ~3),                  snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
                                 x11_fake_data, x11_fake_data_len) != 0) {                  remote_hostname, get_peer_port(newsock));
                                 debug("X11 auth data does not match fake data.");                  xfree(remote_hostname);
                                 ch->type = SSH_CHANNEL_OPEN;                  newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,
                                 goto reject;                                           xstrdup(buf));
                         }                  packet_start(SSH_SMSG_X11_OPEN);
                         /* Check fake data length */                  packet_put_int(newch);
                         if (x11_fake_data_len != x11_saved_data_len) {                  if (have_hostname_in_open)
                                 error("X11 fake_data_len %d != saved_data_len %d",                          packet_put_string(buf, strlen(buf));
                                   x11_fake_data_len, x11_saved_data_len);                  packet_send();
                                 ch->type = SSH_CHANNEL_OPEN;          }
                                 goto reject;  }
                         }  
                         /*  
                          * Received authentication protocol and data match  
                          * our fake data. Substitute the fake data with real  
                          * data.  
                          */  
                         memcpy(ucp + 12 + ((proto_len + 3) & ~3),  
                                x11_saved_data, x11_saved_data_len);  
   
                         /* Start normal processing for the channel. */  /*
                         ch->type = SSH_CHANNEL_OPEN;   * This socket is listening for connections to a forwarded TCP/IP port.
                         goto redo;   */
   void
   channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
   {
           struct sockaddr addr;
           int newsock, newch;
           socklen_t addrlen;
           char buf[1024], *remote_hostname;
           int remote_port;
   
         reject:          if (FD_ISSET(c->sock, readset)) {
                         /*                  debug("Connection to port %d forwarding "
                          * We have received an X11 connection that has bad                      "to %.100s port %d requested.",
                          * authentication information.                      c->listening_port, c->path, c->host_port);
                          */                  addrlen = sizeof(addr);
                         log("X11 connection rejected because of wrong authentication.\r\n");                  newsock = accept(c->sock, &addr, &addrlen);
                         buffer_clear(&ch->input);                  if (newsock < 0) {
                         buffer_clear(&ch->output);                          error("accept: %.100s", strerror(errno));
                         if (compat13) {                          return;
                                 close(ch->sock);                  }
                                 ch->sock = -1;                  remote_hostname = get_remote_hostname(newsock);
                                 ch->type = SSH_CHANNEL_CLOSED;                  remote_port = get_peer_port(newsock);
                                 packet_start(SSH_MSG_CHANNEL_CLOSE);                  snprintf(buf, sizeof buf,
                                 packet_put_int(ch->remote_id);                      "listen port %d for %.100s port %d, "
                                 packet_send();                      "connect from %.200s port %d",
                         } else {                      c->listening_port, c->path, c->host_port,
                                 debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate);                      remote_hostname, remote_port);
                                 chan_read_failed(ch);                  newch = channel_new("direct-tcpip",
                                 chan_write_failed(ch);                      SSH_CHANNEL_OPENING, newsock, newsock, -1,
                                 debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate);                      c->local_window_max, c->local_maxpacket,
                         }                      0, xstrdup(buf));
                         break;  
   
                 case SSH_CHANNEL_FREE:                  packet_start(SSH_MSG_PORT_OPEN);
                 default:                  packet_put_int(newch);
                         continue;                  packet_put_string(c->path, strlen(c->path));
                   packet_put_int(c->host_port);
                   if (have_hostname_in_open) {
                           packet_put_string(buf, strlen(buf));
                 }                  }
                   packet_send();
                   xfree(remote_hostname);
         }          }
 }  }
   
 /*  /*
  * After select, perform any appropriate operations for channels which have   * This is the authentication agent socket listening for connections from
  * events pending.   * clients.
  */   */
   void
 void  channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset)
 channel_after_select(fd_set * readset, fd_set * writeset)  
 {  {
         struct sockaddr addr;          struct sockaddr addr;
         int newsock, i, newch, len;          int newsock, newch;
         socklen_t addrlen;          socklen_t addrlen;
         Channel *ch;  
         char buf[16384], *remote_hostname;  
   
         /* Loop over all channels... */          if (FD_ISSET(c->sock, readset)) {
         for (i = 0; i < channels_alloc; i++) {                  addrlen = sizeof(addr);
                 ch = &channels[i];                  newsock = accept(c->sock, &addr, &addrlen);
                 switch (ch->type) {                  if (newsock < 0) {
                 case SSH_CHANNEL_X11_LISTENER:                          error("accept from auth socket: %.100s", strerror(errno));
                         /* This is our fake X11 server socket. */                          return;
                         if (FD_ISSET(ch->sock, readset)) {                  }
                                 debug("X11 connection requested.");                  newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,
                                 addrlen = sizeof(addr);                      xstrdup("accepted auth socket"));
                                 newsock = accept(ch->sock, &addr, &addrlen);                  packet_start(SSH_SMSG_AGENT_OPEN);
                                 if (newsock < 0) {                  packet_put_int(newch);
                                         error("accept: %.100s", strerror(errno));                  packet_send();
                                         break;          }
                                 }  }
                                 remote_hostname = get_remote_hostname(newsock);  
                                 snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",  
                                 remote_hostname, get_peer_port(newsock));  
                                 xfree(remote_hostname);  
                                 newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,  
                                                          xstrdup(buf));  
                                 packet_start(SSH_SMSG_X11_OPEN);  
                                 packet_put_int(newch);  
                                 if (have_hostname_in_open)  
                                         packet_put_string(buf, strlen(buf));  
                                 packet_send();  
                         }  
                         break;  
   
                 case SSH_CHANNEL_PORT_LISTENER:  int
                         /*  channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)
                          * This socket is listening for connections to a  {
                          * forwarded TCP/IP port.          char buf[16*1024];
                          */          int len;
                         if (FD_ISSET(ch->sock, readset)) {  
                                 debug("Connection to port %d forwarding to %.100s port %d requested.",          if (c->rfd != -1 &&
                                       ch->listening_port, ch->path, ch->host_port);              FD_ISSET(c->rfd, readset)) {
                                 addrlen = sizeof(addr);                  len = read(c->rfd, buf, sizeof(buf));
                                 newsock = accept(ch->sock, &addr, &addrlen);                  if (len <= 0) {
                                 if (newsock < 0) {                          debug("channel %d: read<0 rfd %d len %d",
                                         error("accept: %.100s", strerror(errno));                              c->self, c->rfd, len);
                                         break;                          if (compat13) {
                                 }                                  buffer_consume(&c->output, buffer_len(&c->output));
                                 remote_hostname = get_remote_hostname(newsock);                                  c->type = SSH_CHANNEL_INPUT_DRAINING;
                                 snprintf(buf, sizeof buf, "listen port %d for %.100s port %d, connect from %.200s port %d",                                  debug("Channel %d status set to input draining.", c->self);
                                          ch->listening_port, ch->path, ch->host_port,                          } else {
                                 remote_hostname, get_peer_port(newsock));                                  chan_read_failed(c);
                                 xfree(remote_hostname);  
                                 newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,  
                                                          xstrdup(buf));  
                                 packet_start(SSH_MSG_PORT_OPEN);  
                                 packet_put_int(newch);  
                                 packet_put_string(ch->path, strlen(ch->path));  
                                 packet_put_int(ch->host_port);  
                                 if (have_hostname_in_open)  
                                         packet_put_string(buf, strlen(buf));  
                                 packet_send();  
                         }                          }
                         break;                          return -1;
                   }
                   buffer_append(&c->input, buf, len);
           }
           return 1;
   }
   int
   channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
   {
           int len;
   
                 case SSH_CHANNEL_AUTH_SOCKET:          /* Send buffered output data to the socket. */
                         /*          if (c->wfd != -1 &&
                          * This is the authentication agent socket listening              FD_ISSET(c->wfd, writeset) &&
                          * for connections from clients.              buffer_len(&c->output) > 0) {
                          */                  len = write(c->wfd, buffer_ptr(&c->output),
                         if (FD_ISSET(ch->sock, readset)) {                              buffer_len(&c->output));
                                 addrlen = sizeof(addr);                  if (len <= 0) {
                                 newsock = accept(ch->sock, &addr, &addrlen);                          if (compat13) {
                                 if (newsock < 0) {                                  buffer_consume(&c->output, buffer_len(&c->output));
                                         error("accept from auth socket: %.100s", strerror(errno));                                  debug("Channel %d status set to input draining.", c->self);
                                         break;                                  c->type = SSH_CHANNEL_INPUT_DRAINING;
                                 }                          } else {
                                 newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,                                  chan_write_failed(c);
                                         xstrdup("accepted auth socket"));  
                                 packet_start(SSH_SMSG_AGENT_OPEN);  
                                 packet_put_int(newch);  
                                 packet_send();  
                         }                          }
                         break;                          return -1;
                   }
                   buffer_consume(&c->output, len);
           }
           return 1;
   }
   
                 case SSH_CHANNEL_OPEN:  void
                         /*  channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset)
                          * This is an open two-way communication channel. It  {
                          * is not of interest to us at this point what kind          channel_handle_rfd(c, readset, writeset);
                          * of data is being transmitted.          channel_handle_wfd(c, readset, writeset);
                          */  }
   
                         /*  void
                          * Read available incoming data and append it to  channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)
                          * buffer; shutdown socket, if read or write failes  {
                          */          int len;
                         if (FD_ISSET(ch->sock, readset)) {          /* Send buffered output data to the socket. */
                                 len = read(ch->sock, buf, sizeof(buf));          if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) {
                                 if (len <= 0) {                  len = write(c->sock, buffer_ptr(&c->output),
                                         if (compat13) {                              buffer_len(&c->output));
                                                 buffer_consume(&ch->output, buffer_len(&ch->output));                  if (len <= 0)
                                                 ch->type = SSH_CHANNEL_INPUT_DRAINING;                          buffer_consume(&c->output, buffer_len(&c->output));
                                                 debug("Channel %d status set to input draining.", i);                  else
                                         } else {                          buffer_consume(&c->output, len);
                                                 chan_read_failed(ch);          }
                                         }  }
                                         break;  
                                 }  
                                 buffer_append(&ch->input, buf, len);  
                         }  
                         /* Send buffered output data to the socket. */  
                         if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) {  
                                 len = write(ch->sock, buffer_ptr(&ch->output),  
                                             buffer_len(&ch->output));  
                                 if (len <= 0) {  
                                         if (compat13) {  
                                                 buffer_consume(&ch->output, buffer_len(&ch->output));  
                                                 debug("Channel %d status set to input draining.", i);  
                                                 ch->type = SSH_CHANNEL_INPUT_DRAINING;  
                                         } else {  
                                                 chan_write_failed(ch);  
                                         }  
                                         break;  
                                 }  
                                 buffer_consume(&ch->output, len);  
                         }  
                         break;  
   
                 case SSH_CHANNEL_OUTPUT_DRAINING:  void
                         if (!compat13)  channel_handler_init_13(void)
                                 fatal("cannot happen: OUT_DRAIN");  {
                         /* Send buffered output data to the socket. */          channel_pre[SSH_CHANNEL_OPEN] =                 &channel_pre_open_13;
                         if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) {          channel_pre[SSH_CHANNEL_X11_OPEN] =             &channel_pre_x11_open_13;
                                 len = write(ch->sock, buffer_ptr(&ch->output),          channel_pre[SSH_CHANNEL_X11_LISTENER] =         &channel_pre_listener;
                                             buffer_len(&ch->output));          channel_pre[SSH_CHANNEL_PORT_LISTENER] =        &channel_pre_listener;
                                 if (len <= 0)          channel_pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;
                                         buffer_consume(&ch->output, buffer_len(&ch->output));          channel_pre[SSH_CHANNEL_INPUT_DRAINING] =       &channel_pre_input_draining;
                                 else          channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] =      &channel_pre_output_draining;
                                         buffer_consume(&ch->output, len);  
                         }  
                         break;  
   
                 case SSH_CHANNEL_X11_OPEN:          channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_1;
                 case SSH_CHANNEL_FREE:          channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
                 default:          channel_post[SSH_CHANNEL_PORT_LISTENER] =       &channel_post_port_listener;
           channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
           channel_post[SSH_CHANNEL_OUTPUT_DRAINING] =     &channel_post_output_drain_13;
   }
   
   void
   channel_handler_init_15(void)
   {
           channel_pre[SSH_CHANNEL_OPEN] =                 &channel_pre_open_15;
           channel_pre[SSH_CHANNEL_X11_OPEN] =             &channel_pre_x11_open_15;
           channel_pre[SSH_CHANNEL_X11_LISTENER] =         &channel_pre_listener;
           channel_pre[SSH_CHANNEL_PORT_LISTENER] =        &channel_pre_listener;
           channel_pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;
   
           channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
           channel_post[SSH_CHANNEL_PORT_LISTENER] =       &channel_post_port_listener;
           channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
           channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_1;
   }
   
   void
   channel_handler_init(void)
   {
           int i;
           for(i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
                   channel_pre[i] = NULL;
                   channel_post[i] = NULL;
           }
           if (compat13)
                   channel_handler_init_13();
           else
                   channel_handler_init_15();
   }
   
   void
   channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset)
   {
           static int did_init = 0;
           int i;
           Channel *c;
   
           if (!did_init) {
                   channel_handler_init();
                   did_init = 1;
           }
           for (i = 0; i < channels_alloc; i++) {
                   c = &channels[i];
                   if (c->type == SSH_CHANNEL_FREE)
                         continue;                          continue;
                 }                  if (ftab[c->type] == NULL)
                           continue;
                   (*ftab[c->type])(c, readset, writeset);
                   chan_delete_if_full_closed(c);
         }          }
 }  }
   
   void
   channel_prepare_select(fd_set * readset, fd_set * writeset)
   {
           channel_handler(channel_pre, readset, writeset);
   }
   
   void
   channel_after_select(fd_set * readset, fd_set * writeset)
   {
           channel_handler(channel_post, readset, writeset);
   }
   
 /* If there is data to send to the connection, send some of it now. */  /* If there is data to send to the connection, send some of it now. */
   
 void  void
 channel_output_poll()  channel_output_poll()
 {  {
         int len, i;          int len, i;
         Channel *ch;          Channel *c;
   
         for (i = 0; i < channels_alloc; i++) {          for (i = 0; i < channels_alloc; i++) {
                 ch = &channels[i];                  c = &channels[i];
   
                 /* We are only interested in channels that can have buffered incoming data. */                  /* We are only interested in channels that can have buffered incoming data. */
                 if (compat13) {                  if (compat13) {
                         if (ch->type != SSH_CHANNEL_OPEN &&                          if (c->type != SSH_CHANNEL_OPEN &&
                             ch->type != SSH_CHANNEL_INPUT_DRAINING)                              c->type != SSH_CHANNEL_INPUT_DRAINING)
                                 continue;                                  continue;
                 } else {                  } else {
                         if (ch->type != SSH_CHANNEL_OPEN)                          if (c->type != SSH_CHANNEL_OPEN)
                                 continue;                                  continue;
                         if (ch->istate != CHAN_INPUT_OPEN &&                          if (c->istate != CHAN_INPUT_OPEN &&
                             ch->istate != CHAN_INPUT_WAIT_DRAIN)                              c->istate != CHAN_INPUT_WAIT_DRAIN)
                                 continue;                                  continue;
                 }                  }
   
                 /* Get the amount of buffered data for this channel. */                  /* Get the amount of buffered data for this channel. */
                 len = buffer_len(&ch->input);                  len = buffer_len(&c->input);
                 if (len > 0) {                  if (len > 0) {
                         /* Send some data for the other side over the secure connection. */                          /* Send some data for the other side over the secure connection. */
                         if (packet_is_interactive()) {                          if (packet_is_interactive()) {
Line 559 
Line 710 
                                 if (len > packet_get_maxsize())                                  if (len > packet_get_maxsize())
                                         len = packet_get_maxsize()/2;                                          len = packet_get_maxsize()/2;
                         }                          }
                         packet_start(SSH_MSG_CHANNEL_DATA);                          if (len > 0) {
                         packet_put_int(ch->remote_id);                                  packet_start(SSH_MSG_CHANNEL_DATA);
                         packet_put_string(buffer_ptr(&ch->input), len);                                  packet_put_int(c->remote_id);
                         packet_send();                                  packet_put_string(buffer_ptr(&c->input), len);
                         buffer_consume(&ch->input, len);                                  packet_send();
                 } else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) {                                  buffer_consume(&c->input, len);
                                   c->remote_window -= len;
   debug("channel %d: send data len %d", c->self, len);
                           }
                   } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
                         if (compat13)                          if (compat13)
                                 fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");                                  fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
                         /*                          /*
                          * input-buffer is empty and read-socket shutdown:                           * input-buffer is empty and read-socket shutdown:
                          * tell peer, that we will not send more data: send IEOF                           * tell peer, that we will not send more data: send IEOF
                          */                           */
                         chan_ibuf_empty(ch);                          chan_ibuf_empty(c);
                 }                  }
         }          }
 }  }
Line 583 
Line 738 
  */   */
   
 void  void
 channel_input_data(int payload_len)  channel_input_data(int type, int plen)
 {  {
         int id;          int id;
         char *data;          char *data;
         unsigned int data_len;          unsigned int data_len;
         Channel *ch;          Channel *c;
   
         /* Get the channel number and verify it. */          /* Get the channel number and verify it. */
         id = packet_get_int();          id = packet_get_int();
         if (id < 0 || id >= channels_alloc)          c = channel_lookup(id);
           if (c == NULL)
                 packet_disconnect("Received data for nonexistent channel %d.", id);                  packet_disconnect("Received data for nonexistent channel %d.", id);
         ch = &channels[id];  
   
         if (ch->type == SSH_CHANNEL_FREE)  
                 packet_disconnect("Received data for free channel %d.", ch->self);  
   
         /* Ignore any data for non-open channels (might happen on close) */          /* Ignore any data for non-open channels (might happen on close) */
         if (ch->type != SSH_CHANNEL_OPEN &&          if (c->type != SSH_CHANNEL_OPEN &&
             ch->type != SSH_CHANNEL_X11_OPEN)              c->type != SSH_CHANNEL_X11_OPEN)
                 return;                  return;
   
         /* same for protocol 1.5 if output end is no longer open */          /* same for protocol 1.5 if output end is no longer open */
         if (!compat13 && ch->ostate != CHAN_OUTPUT_OPEN)          if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN)
                 return;                  return;
   
         /* Get the data. */          /* Get the data. */
         data = packet_get_string(&data_len);          data = packet_get_string(&data_len);
         packet_integrity_check(payload_len, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA);  
         buffer_append(&ch->output, data, data_len);          packet_integrity_check(plen, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA);
           buffer_append(&c->output, data, data_len);
         xfree(data);          xfree(data);
 }  }
   
Line 624 
Line 777 
 channel_not_very_much_buffered_data()  channel_not_very_much_buffered_data()
 {  {
         unsigned int i;          unsigned int i;
         Channel *ch;          Channel *c;
   
         for (i = 0; i < channels_alloc; i++) {          for (i = 0; i < channels_alloc; i++) {
                 ch = &channels[i];                  c = &channels[i];
                 if (ch->type == SSH_CHANNEL_OPEN) {                  if (c->type == SSH_CHANNEL_OPEN) {
                         if (buffer_len(&ch->input) > packet_get_maxsize())                          if (buffer_len(&c->input) > packet_get_maxsize()) {
                                   debug("channel %d: big input buffer %d",
                                       c->self, buffer_len(&c->input));
                                 return 0;                                  return 0;
                         if (buffer_len(&ch->output) > packet_get_maxsize())                          }
                           if (buffer_len(&c->output) > packet_get_maxsize()) {
                                   debug("channel %d: big output buffer %d",
                                       c->self, buffer_len(&c->output));
                                 return 0;                                  return 0;
                           }
                 }                  }
         }          }
         return 1;          return 1;
 }  }
   
 /* This is called after receiving CHANNEL_CLOSE/IEOF. */  void
   channel_input_ieof(int type, int plen)
   {
           int id;
           Channel *c;
   
           packet_integrity_check(plen, 4, type);
   
           id = packet_get_int();
           c = channel_lookup(id);
           if (c == NULL)
                   packet_disconnect("Received ieof for nonexistent channel %d.", id);
           chan_rcvd_ieof(c);
   }
   
 void  void
 channel_input_close()  channel_input_close(int type, int plen)
 {  {
         int channel;          int id;
           Channel *c;
   
         /* Get the channel number and verify it. */          packet_integrity_check(plen, 4, type);
         channel = packet_get_int();  
         if (channel < 0 || channel >= channels_alloc ||  
             channels[channel].type == SSH_CHANNEL_FREE)  
                 packet_disconnect("Received data for nonexistent channel %d.", channel);  
   
         if (!compat13) {          id = packet_get_int();
                 /* proto version 1.5 overloads CLOSE with IEOF */          c = channel_lookup(id);
                 chan_rcvd_ieof(&channels[channel]);          if (c == NULL)
                 return;                  packet_disconnect("Received close for nonexistent channel %d.", id);
         }  
   
         /*          /*
          * 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.
          */           */
         packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);          packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
         packet_put_int(channels[channel].remote_id);          packet_put_int(c->remote_id);
         packet_send();          packet_send();
   
         /*          /*
Line 672 
Line 840 
          * no-one to receive the confirmation.  The channel gets freed when           * no-one to receive the confirmation.  The channel gets freed when
          * the confirmation arrives.           * the confirmation arrives.
          */           */
         if (channels[channel].type != SSH_CHANNEL_CLOSED) {          if (c->type != SSH_CHANNEL_CLOSED) {
                 /*                  /*
                  * Not a closed channel - mark it as draining, which will                   * Not a closed channel - mark it as draining, which will
                  * cause it to be freed later.                   * cause it to be freed later.
                  */                   */
                 buffer_consume(&channels[channel].input,                  buffer_consume(&c->input, buffer_len(&c->input));
                                buffer_len(&channels[channel].input));                  c->type = SSH_CHANNEL_OUTPUT_DRAINING;
                 channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING;  
         }          }
 }  }
   
 /* This is called after receiving CHANNEL_CLOSE_CONFIRMATION/OCLOSE. */  /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
   void
   channel_input_oclose(int type, int plen)
   {
           int id = packet_get_int();
           Channel *c = channel_lookup(id);
           packet_integrity_check(plen, 4, type);
           if (c == NULL)
                   packet_disconnect("Received oclose for nonexistent channel %d.", id);
           chan_rcvd_oclose(c);
   }
   
 void  void
 channel_input_close_confirmation()  channel_input_close_confirmation(int type, int plen)
 {  {
         int channel;          int id = packet_get_int();
           Channel *c = channel_lookup(id);
   
         /* Get the channel number and verify it. */          if (c == NULL)
         channel = packet_get_int();                  packet_disconnect("Received close confirmation for "
         if (channel < 0 || channel >= channels_alloc)                      "out-of-range channel %d.", id);
                 packet_disconnect("Received close confirmation for out-of-range channel %d.",          if (c->type != SSH_CHANNEL_CLOSED)
                                   channel);                  packet_disconnect("Received close confirmation for "
                       "non-closed channel %d (type %d).", id, c->type);
         if (!compat13) {          channel_free(c->self);
                 /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */  
                 chan_rcvd_oclose(&channels[channel]);  
                 return;  
         }  
         if (channels[channel].type != SSH_CHANNEL_CLOSED)  
                 packet_disconnect("Received close confirmation for non-closed channel %d (type %d).",  
                                   channel, channels[channel].type);  
   
         /* Free the channel. */  
         channel_free(channel);  
 }  }
   
 /* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */  
   
 void  void
 channel_input_open_confirmation()  channel_input_open_confirmation(int type, int plen)
 {  {
         int channel, remote_channel;          int id, remote_id;
           Channel *c;
   
         /* Get the channel number and verify it. */          packet_integrity_check(plen, 4 + 4, type);
         channel = packet_get_int();  
         if (channel < 0 || channel >= channels_alloc ||  
             channels[channel].type != SSH_CHANNEL_OPENING)  
                 packet_disconnect("Received open confirmation for non-opening channel %d.",  
                                   channel);  
   
         /* Get remote side's id for this channel. */          id = packet_get_int();
         remote_channel = packet_get_int();          c = channel_lookup(id);
   
           if (c==NULL || c->type != SSH_CHANNEL_OPENING)
                   packet_disconnect("Received open confirmation for "
                       "non-opening channel %d.", id);
           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. */
         channels[channel].remote_id = remote_channel;          c->remote_id = remote_id;
         channels[channel].type = SSH_CHANNEL_OPEN;          c->type = SSH_CHANNEL_OPEN;
 }  }
   
 /* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */  
   
 void  void
 channel_input_open_failure()  channel_input_open_failure(int type, int plen)
 {  {
         int channel;          int id;
           Channel *c;
   
         /* Get the channel number and verify it. */          packet_integrity_check(plen, 4, type);
         channel = packet_get_int();  
         if (channel < 0 || channel >= channels_alloc ||  
             channels[channel].type != SSH_CHANNEL_OPENING)  
                 packet_disconnect("Received open failure for non-opening channel %d.",  
                                   channel);  
   
           id = packet_get_int();
           c = channel_lookup(id);
   
           if (c==NULL || c->type != SSH_CHANNEL_OPENING)
                   packet_disconnect("Received open failure for "
                       "non-opening channel %d.", id);
   
         /* Free the channel.  This will also close the socket. */          /* Free the channel.  This will also close the socket. */
         channel_free(channel);          channel_free(id);
 }  }
   
 /*  /*
Line 859 
Line 1026 
                 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:
                         snprintf(buf, sizeof buf, "  #%d %.300s (t%d r%d i%d/%d o%d/%d)\r\n",                          snprintf(buf, sizeof buf, "  #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n",
                             c->self, c->remote_name,                              c->self, c->remote_name,
                             c->type, c->remote_id,                              c->type, c->remote_id,
                             c->istate, buffer_len(&c->input),                              c->istate, buffer_len(&c->input),
                             c->ostate, buffer_len(&c->output));                              c->ostate, buffer_len(&c->output),
                               c->rfd, c->wfd);
                         buffer_append(&buffer, buf, strlen(buf));                          buffer_append(&buffer, buf, strlen(buf));
                         continue;                          continue;
                 default:                  default:
                         fatal("channel_still_open: bad channel type %d", c->type);                          fatal("channel_open_message: bad channel type %d", c->type);
                         /* NOTREACHED */                          /* NOTREACHED */
                 }                  }
         }          }
Line 946 
Line 1114 
                         continue;                          continue;
                 }                  }
                 /* Allocate a channel number for the socket. */                  /* Allocate a channel number for the socket. */
                 ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock,                  ch = channel_new(
                     xstrdup("port listener"));                      "port listener", SSH_CHANNEL_PORT_LISTENER,
                       sock, sock, -1,
                       CHAN_WINDOW_DEFAULT, CHAN_PACKET_DEFAULT,
                       0, xstrdup("port listener"));
                 strlcpy(channels[ch].path, host, sizeof(channels[ch].path));                  strlcpy(channels[ch].path, host, sizeof(channels[ch].path));
                 channels[ch].host_port = host_port;                  channels[ch].host_port = host_port;
                 channels[ch].listening_port = port;                  channels[ch].listening_port = port;
Line 964 
Line 1135 
  */   */
   
 void  void
 channel_request_remote_forwarding(u_short port, const char *host,  channel_request_remote_forwarding(u_short listen_port, const char *host_to_connect,
                                   u_short remote_port)                                    u_short port_to_connect)
 {  {
         int payload_len;          int payload_len;
         /* Record locally that connection to this host/port is permitted. */          /* Record locally that connection to this host/port is permitted. */
         if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)          if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
                 fatal("channel_request_remote_forwarding: too many forwards");                  fatal("channel_request_remote_forwarding: too many forwards");
   
         permitted_opens[num_permitted_opens].host = xstrdup(host);          permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect);
         permitted_opens[num_permitted_opens].port = remote_port;          permitted_opens[num_permitted_opens].port_to_connect = port_to_connect;
           permitted_opens[num_permitted_opens].listen_port = listen_port;
         num_permitted_opens++;          num_permitted_opens++;
   
         /* Send the forward request to the remote side. */          /* Send the forward request to the remote side. */
         packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);          packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
         packet_put_int(port);          packet_put_int(port_to_connect);
         packet_put_string(host, strlen(host));          packet_put_string(host_to_connect, strlen(host_to_connect));
         packet_put_int(remote_port);          packet_put_int(listen_port);
         packet_send();          packet_send();
         packet_write_wait();          packet_write_wait();
   
         /*          /*
          * Wait for response from the remote side.  It will send a disconnect           * Wait for response from the remote side.  It will send a disconnect
          * message on failure, and we will never see it here.           * message on failure, and we will never see it here.
Line 1025 
Line 1196 
         xfree(hostname);          xfree(hostname);
 }  }
   
   /* XXX move to aux.c */
   int
   channel_connect_to(const char *host, u_short host_port)
   {
           struct addrinfo hints, *ai, *aitop;
           char ntop[NI_MAXHOST], strport[NI_MAXSERV];
           int gaierr;
           int sock = -1;
   
           memset(&hints, 0, sizeof(hints));
           hints.ai_family = IPv4or6;
           hints.ai_socktype = SOCK_STREAM;
           snprintf(strport, sizeof strport, "%d", host_port);
           if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
                   error("%.100s: unknown host (%s)", host, gai_strerror(gaierr));
                   return -1;
           }
           for (ai = aitop; ai; ai = ai->ai_next) {
                   if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
                           continue;
                   if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
                       strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
                           error("channel_connect_to: getnameinfo failed");
                           continue;
                   }
                   /* Create the socket. */
                   sock = socket(ai->ai_family, SOCK_STREAM, 0);
                   if (sock < 0) {
                           error("socket: %.100s", strerror(errno));
                           continue;
                   }
                   /* Connect to the host/port. */
                   if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
                           error("connect %.100s port %s: %.100s", ntop, strport,
                               strerror(errno));
                           close(sock);
                           continue;       /* fail -- try next */
                   }
                   break; /* success */
   
           }
           freeaddrinfo(aitop);
           if (!ai) {
                   error("connect %.100s port %d: failed.", host, host_port);
                   return -1;
           }
           /* success */
           return sock;
   }
 /*  /*
  * This is called after receiving PORT_OPEN message.  This attempts to   * This is called after receiving PORT_OPEN message.  This attempts to
  * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION   * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
Line 1032 
Line 1252 
  */   */
   
 void  void
 channel_input_port_open(int payload_len)  channel_input_port_open(int type, int plen)
 {  {
         int remote_channel, sock = 0, newch, i;  
         u_short host_port;          u_short host_port;
         char *host, *originator_string;          char *host, *originator_string;
           int remote_channel, sock = -1, newch, i, denied;
         unsigned int host_len, originator_len;          unsigned int host_len, originator_len;
         struct addrinfo hints, *ai, *aitop;  
         char ntop[NI_MAXHOST], strport[NI_MAXSERV];  
         int gaierr;  
   
         /* Get remote channel number. */          /* Get remote channel number. */
         remote_channel = packet_get_int();          remote_channel = packet_get_int();
Line 1060 
Line 1277 
                 originator_len = 0;     /* no originator supplied */                  originator_len = 0;     /* no originator supplied */
         }          }
   
         packet_integrity_check(payload_len,          packet_integrity_check(plen,
                                4 + 4 + host_len + 4 + originator_len,              4 + 4 + host_len + 4 + originator_len, SSH_MSG_PORT_OPEN);
                                SSH_MSG_PORT_OPEN);  
   
         /* Check if opening that port is permitted. */          /* Check if opening that port is permitted. */
           denied = 0;
         if (!all_opens_permitted) {          if (!all_opens_permitted) {
                 /* Go trough all permitted ports. */                  /* Go trough all permitted ports. */
                 for (i = 0; i < num_permitted_opens; i++)                  for (i = 0; i < num_permitted_opens; i++)
                         if (permitted_opens[i].port == host_port &&                          if (permitted_opens[i].port_to_connect == host_port &&
                             strcmp(permitted_opens[i].host, host) == 0)                              strcmp(permitted_opens[i].host_to_connect, host) == 0)
                                 break;                                  break;
   
                 /* Check if we found the requested port among those permitted. */                  /* Check if we found the requested port among those permitted. */
Line 1077 
Line 1294 
                         /* The port is not permitted. */                          /* The port is not permitted. */
                         log("Received request to connect to %.100s:%d, but the request was denied.",                          log("Received request to connect to %.100s:%d, but the request was denied.",
                             host, host_port);                              host, host_port);
                         goto fail;                          denied = 1;
                 }                  }
         }          }
           sock = denied ? -1 : channel_connect_to(host, host_port);
           if (sock > 0) {
                   /* Allocate a channel for this connection. */
                   newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string);
                   channels[newch].remote_id = remote_channel;
   
         memset(&hints, 0, sizeof(hints));                  packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
         hints.ai_family = IPv4or6;                  packet_put_int(remote_channel);
         hints.ai_socktype = SOCK_STREAM;                  packet_put_int(newch);
         snprintf(strport, sizeof strport, "%d", host_port);                  packet_send();
         if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {          } else {
                 error("%.100s: unknown host (%s)", host, gai_strerror(gaierr));                  packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
                 goto fail;                  packet_put_int(remote_channel);
                   packet_send();
         }          }
   
         for (ai = aitop; ai; ai = ai->ai_next) {  
                 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)  
                         continue;  
                 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),  
                     strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {  
                         error("channel_input_port_open: getnameinfo failed");  
                         continue;  
                 }  
                 /* Create the socket. */  
                 sock = socket(ai->ai_family, SOCK_STREAM, 0);  
                 if (sock < 0) {  
                         error("socket: %.100s", strerror(errno));  
                         continue;  
                 }  
                 /* Connect to the host/port. */  
                 if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {  
                         error("connect %.100s port %s: %.100s", ntop, strport,  
                             strerror(errno));  
                         close(sock);  
                         continue;       /* fail -- try next */  
                 }  
                 break; /* success */  
   
         }  
         freeaddrinfo(aitop);  
   
         if (!ai) {  
                 error("connect %.100s port %d: failed.", host, host_port);  
                 goto fail;  
         }  
   
         /* Successful connection. */  
   
         /* Allocate a channel for this connection. */  
         newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string);  
         channels[newch].remote_id = remote_channel;  
   
         /* Send a confirmation to the remote host. */  
         packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);  
         packet_put_int(remote_channel);  
         packet_put_int(newch);  
         packet_send();  
   
         /* Free the argument string. */  
         xfree(host);          xfree(host);
   
         return;  
   
 fail:  
         /* Free the argument string. */  
         xfree(host);  
   
         /* Send refusal to the remote host. */  
         packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);  
         packet_put_int(remote_channel);  
         packet_send();  
 }  }
   
 /*  /*
Line 1279 
Line 1446 
  */   */
   
 void  void
 x11_input_open(int payload_len)  x11_input_open(int type, int plen)
 {  {
         int remote_channel, display_number, sock = 0, newch;          int remote_channel, display_number, sock = 0, newch;
         const char *display;          const char *display;
Line 1302 
Line 1469 
         }          }
   
         debug("Received X11 open request.");          debug("Received X11 open request.");
         packet_integrity_check(payload_len, 4 + remote_len, SSH_SMSG_X11_OPEN);          packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN);
   
         /* Try to open a socket for the local X server. */          /* Try to open a socket for the local X server. */
         display = getenv("DISPLAY");          display = getenv("DISPLAY");
Line 1368 
Line 1535 
                 sock = socket(ai->ai_family, SOCK_STREAM, 0);                  sock = socket(ai->ai_family, SOCK_STREAM, 0);
                 if (sock < 0) {                  if (sock < 0) {
                         debug("socket: %.100s", strerror(errno));                          debug("socket: %.100s", strerror(errno));
                 continue;                          continue;
                   }
                   /* Connect it to the display. */
                   if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
                           debug("connect %.100s port %d: %.100s", buf,
                               6000 + display_number, strerror(errno));
                           close(sock);
                           continue;
                   }
                   /* Success */
                   break;
         }          }
         /* Connect it to the display. */  
         if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {  
                 debug("connect %.100s port %d: %.100s", buf, 6000 + display_number,  
                     strerror(errno));  
                 close(sock);  
                 continue;  
         }  
         /* Success */  
         break;  
   
         } /* (ai = aitop, ai; ai = ai->ai_next) */  
         freeaddrinfo(aitop);          freeaddrinfo(aitop);
         if (!ai) {          if (!ai) {
                 error("connect %.100s port %d: %.100s", buf, 6000 + display_number,                  error("connect %.100s port %d: %.100s", buf, 6000 + display_number,
Line 1568 
Line 1734 
 /* This is called to process an SSH_SMSG_AGENT_OPEN message. */  /* This is called to process an SSH_SMSG_AGENT_OPEN message. */
   
 void  void
 auth_input_open_request()  auth_input_open_request(int type, int plen)
 {  {
         int remch, sock, newch;          int remch, sock, newch;
         char *dummyname;          char *dummyname;
   
           packet_integrity_check(plen, 4, type);
   
         /* Read the remote channel number from the message. */          /* Read the remote channel number from the message. */
         remch = packet_get_int();          remch = packet_get_int();

Legend:
Removed from v.1.40  
changed lines
  Added in v.1.41