[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.24 and 1.25

version 1.24, 1999/11/22 21:02:38 version 1.25, 1999/11/23 22:25:53
Line 52 
Line 52 
   
 /* Name and directory of socket for authentication agent forwarding. */  /* Name and directory of socket for authentication agent forwarding. */
 static char *channel_forwarded_auth_socket_name = NULL;  static char *channel_forwarded_auth_socket_name = NULL;
 static char *channel_forwarded_auth_socket_dir  = NULL;  static char *channel_forwarded_auth_socket_dir = NULL;
   
 /* Saved X11 authentication protocol name. */  /* Saved X11 authentication protocol name. */
 char *x11_saved_proto = NULL;  char *x11_saved_proto = NULL;
Line 70 
Line 70 
    The local sides of any remote forwards are stored in this array to prevent     The local sides of any remote forwards are stored in this array to prevent
    a corrupt remote server from accessing arbitrary TCP/IP ports on our     a corrupt remote server from accessing arbitrary TCP/IP ports on our
    local network (which might be behind a firewall). */     local network (which might be behind a firewall). */
 typedef struct  typedef struct {
 {          char *host;             /* Host name. */
   char *host;           /* Host name. */          int port;               /* Port number. */
   int port;             /* Port number. */  
 } ForwardPermission;  } ForwardPermission;
   
 /* List of all permitted host/port pairs to connect. */  /* List of all permitted host/port pairs to connect. */
Line 90 
Line 89 
   
 /* Sets specific protocol options. */  /* Sets specific protocol options. */
   
 void channel_set_options(int hostname_in_open)  void
   channel_set_options(int hostname_in_open)
 {  {
   have_hostname_in_open = hostname_in_open;          have_hostname_in_open = hostname_in_open;
 }  }
   
 /* Permits opening to any host/port in SSH_MSG_PORT_OPEN.  This is usually  /* Permits opening to any host/port in SSH_MSG_PORT_OPEN.  This is usually
    called by the server, because the user could connect to any port anyway,     called by the server, because the user could connect to any port anyway,
    and the server has no way to know but to trust the client anyway. */     and the server has no way to know but to trust the client anyway. */
   
 void channel_permit_all_opens()  void
   channel_permit_all_opens()
 {  {
   all_opens_permitted = 1;          all_opens_permitted = 1;
 }  }
   
 /* Allocate a new channel object and set its type and socket.  /* Allocate a new channel object and set its type and socket.
    This will cause remote_name to be freed. */     This will cause remote_name to be freed. */
   
 int channel_allocate(int type, int sock, char *remote_name)  int
   channel_allocate(int type, int sock, 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 (sock > channel_max_fd_value)
     channel_max_fd_value = sock;                  channel_max_fd_value = sock;
   
   /* Do initial allocation if this is the first call. */          /* Do initial allocation if this is the first call. */
   if (channels_alloc == 0)          if (channels_alloc == 0) {
     {                  channels_alloc = 10;
       channels_alloc = 10;                  channels = xmalloc(channels_alloc * sizeof(Channel));
       channels = xmalloc(channels_alloc * sizeof(Channel));                  for (i = 0; i < channels_alloc; i++)
       for (i = 0; i < channels_alloc; i++)                          channels[i].type = SSH_CHANNEL_FREE;
         channels[i].type = SSH_CHANNEL_FREE;  
   
       /* Kludge: arrange a call to channel_stop_listening if we terminate                  /* Kludge: arrange a call to channel_stop_listening if we
          with fatal(). */                     terminate with fatal(). */
       fatal_add_cleanup((void (*)(void *))channel_stop_listening, NULL);                  fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL);
     }          }
           /* Try to find a free slot where to put the new channel. */
   /* Try to find a free slot where to put the new channel. */          for (found = -1, i = 0; i < channels_alloc; i++)
   for (found = -1, i = 0; i < channels_alloc; i++)                  if (channels[i].type == SSH_CHANNEL_FREE) {
     if (channels[i].type == SSH_CHANNEL_FREE)                          /* Found a free slot. */
       {                          found = i;
         /* Found a free slot. */                          break;
         found = i;                  }
         break;          if (found == -1) {
       }                  /* There are no free slots.  Take last+1 slot and expand
                      the array.  */
   if (found == -1)                  found = channels_alloc;
     {                  channels_alloc += 10;
       /* There are no free slots.  Take last+1 slot and expand the array.  */                  debug("channel: expanding %d", channels_alloc);
       found = channels_alloc;                  channels = xrealloc(channels, channels_alloc * sizeof(Channel));
       channels_alloc += 10;                  for (i = found; i < channels_alloc; i++)
       debug("channel: expanding %d", channels_alloc);                          channels[i].type = SSH_CHANNEL_FREE;
       channels = xrealloc(channels, channels_alloc * sizeof(Channel));          }
       for (i = found; i < channels_alloc; i++)          /* Initialize and return new channel number. */
         channels[i].type = SSH_CHANNEL_FREE;          c = &channels[found];
     }          buffer_init(&c->input);
           buffer_init(&c->output);
   /* Initialize and return new channel number. */          chan_init_iostates(c);
   c=&channels[found];          c->self = found;
   buffer_init(&c->input);          c->type = type;
   buffer_init(&c->output);          c->sock = sock;
   chan_init_iostates(c);          c->remote_id = -1;
   c->self = found;          c->remote_name = remote_name;
   c->type = type;          debug("channel %d: new [%s]", found, remote_name);
   c->sock = sock;          return found;
   c->remote_id = -1;  
   c->remote_name = remote_name;  
   debug("channel %d: new [%s]", found, remote_name);  
   return found;  
 }  }
   
 /* Free the channel and close its socket. */  /* Free the channel and close its socket. */
   
 void channel_free(int channel)  void
   channel_free(int channel)
 {  {
   if (channel < 0 || channel >= channels_alloc ||          if (channel < 0 || channel >= channels_alloc ||
       channels[channel].type == SSH_CHANNEL_FREE)              channels[channel].type == SSH_CHANNEL_FREE)
     packet_disconnect("channel free: bad local channel %d", channel);                  packet_disconnect("channel free: bad local channel %d", channel);
   
   if(compat13)          if (compat13)
     shutdown(channels[channel].sock, SHUT_RDWR);                  shutdown(channels[channel].sock, SHUT_RDWR);
   close(channels[channel].sock);          close(channels[channel].sock);
   buffer_free(&channels[channel].input);          buffer_free(&channels[channel].input);
   buffer_free(&channels[channel].output);          buffer_free(&channels[channel].output);
   channels[channel].type = SSH_CHANNEL_FREE;          channels[channel].type = SSH_CHANNEL_FREE;
   if (channels[channel].remote_name)          if (channels[channel].remote_name) {
     {                  xfree(channels[channel].remote_name);
       xfree(channels[channel].remote_name);                  channels[channel].remote_name = NULL;
       channels[channel].remote_name = NULL;          }
     }  
 }  }
   
 /* This is called just before select() to add any bits relevant to  /* This is called just before select() to add any bits relevant to
    channels in the select bitmasks. */     channels in the select bitmasks. */
   
 void channel_prepare_select(fd_set *readset, fd_set *writeset)  void
   channel_prepare_select(fd_set * readset, fd_set * writeset)
 {  {
   int i;          int i;
   Channel *ch;          Channel *ch;
   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++)          for (i = 0; i < channels_alloc; i++) {
     {                  ch = &channels[i];
       ch = &channels[i];  redo:
     redo:                  switch (ch->type) {
       switch (ch->type)                  case SSH_CHANNEL_X11_LISTENER:
         {                  case SSH_CHANNEL_PORT_LISTENER:
         case SSH_CHANNEL_X11_LISTENER:                  case SSH_CHANNEL_AUTH_SOCKET:
         case SSH_CHANNEL_PORT_LISTENER:                          FD_SET(ch->sock, readset);
         case SSH_CHANNEL_AUTH_SOCKET:                          break;
           FD_SET(ch->sock, readset);  
           break;  
   
         case SSH_CHANNEL_OPEN:                  case SSH_CHANNEL_OPEN:
           if(compat13){                          if (compat13) {
             if (buffer_len(&ch->input) < packet_get_maxsize())                                  if (buffer_len(&ch->input) < packet_get_maxsize())
               FD_SET(ch->sock, readset);                                          FD_SET(ch->sock, readset);
             if (buffer_len(&ch->output) > 0)                                  if (buffer_len(&ch->output) > 0)
               FD_SET(ch->sock, writeset);                                          FD_SET(ch->sock, writeset);
             break;                                  break;
           }                          }
           /* test whether sockets are 'alive' for read/write */                          /* test whether sockets are 'alive' for read/write */
           if (ch->istate == CHAN_INPUT_OPEN)                          if (ch->istate == CHAN_INPUT_OPEN)
             if (buffer_len(&ch->input) < packet_get_maxsize())                                  if (buffer_len(&ch->input) < packet_get_maxsize())
               FD_SET(ch->sock, readset);                                          FD_SET(ch->sock, readset);
           if (ch->ostate == CHAN_OUTPUT_OPEN || ch->ostate == CHAN_OUTPUT_WAIT_DRAIN){                          if (ch->ostate == CHAN_OUTPUT_OPEN ||
             if (buffer_len(&ch->output) > 0){                              ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
               FD_SET(ch->sock, writeset);                                  if (buffer_len(&ch->output) > 0) {
             }else if(ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) {                                          FD_SET(ch->sock, writeset);
               chan_obuf_empty(ch);                                  } else if (ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
             }                                          chan_obuf_empty(ch);
           }                                  }
           break;                          }
                           break;
   
         case SSH_CHANNEL_INPUT_DRAINING:                  case SSH_CHANNEL_INPUT_DRAINING:
           if (!compat13)                          if (!compat13)
             fatal("cannot happen: IN_DRAIN");                                  fatal("cannot happen: IN_DRAIN");
           if (buffer_len(&ch->input) == 0)                          if (buffer_len(&ch->input) == 0) {
             {                                  packet_start(SSH_MSG_CHANNEL_CLOSE);
               packet_start(SSH_MSG_CHANNEL_CLOSE);                                  packet_put_int(ch->remote_id);
               packet_put_int(ch->remote_id);                                  packet_send();
               packet_send();                                  ch->type = SSH_CHANNEL_CLOSED;
               ch->type = SSH_CHANNEL_CLOSED;                                  debug("Closing channel %d after input drain.", i);
               debug("Closing channel %d after input drain.", i);                                  break;
               break;                          }
             }                          break;
           break;  
   
         case SSH_CHANNEL_OUTPUT_DRAINING:                  case SSH_CHANNEL_OUTPUT_DRAINING:
           if (!compat13)                          if (!compat13)
             fatal("cannot happen: OUT_DRAIN");                                  fatal("cannot happen: OUT_DRAIN");
           if (buffer_len(&ch->output) == 0)                          if (buffer_len(&ch->output) == 0) {
             {                                  channel_free(i);
               /* debug("Freeing channel %d after output drain.", i); */                                  break;
               channel_free(i);                          }
               break;                          FD_SET(ch->sock, writeset);
             }                          break;
           FD_SET(ch->sock, writeset);  
           break;  
   
         case SSH_CHANNEL_X11_OPEN:                  case SSH_CHANNEL_X11_OPEN:
           /* This is a special state for X11 authentication spoofing.  An                          /* This is a special state for X11 authentication
              opened X11 connection (when authentication spoofing is being                             spoofing.  An opened X11 connection (when
              done) remains in this state until the first packet has been                             authentication spoofing is being done) remains
              completely read.  The authentication data in that packet is                             in this state until the first packet has been
              then substituted by the real data if it matches the fake data,                             completely read.  The authentication data in
              and the channel is put into normal mode. */                             that packet is then substituted by the real
                              data if it matches the fake data, and the
                              channel is put into normal mode. */
   
           /* Check if the fixed size part of the packet is in buffer. */                          /* Check if the fixed size part of the packet is in buffer. */
           if (buffer_len(&ch->output) < 12)                          if (buffer_len(&ch->output) < 12)
             break;                                  break;
   
           /* Parse the lengths of variable-length fields. */                          /* Parse the lengths of variable-length fields. */
           ucp = (unsigned char *)buffer_ptr(&ch->output);                          ucp = (unsigned char *) buffer_ptr(&ch->output);
           if (ucp[0] == 0x42)                          if (ucp[0] == 0x42) {   /* Byte order MSB first. */
             { /* Byte order MSB first. */                                  proto_len = 256 * ucp[6] + ucp[7];
               proto_len = 256 * ucp[6] + ucp[7];                                  data_len = 256 * ucp[8] + ucp[9];
               data_len = 256 * ucp[8] + ucp[9];                          } else if (ucp[0] == 0x6c) {    /* Byte order LSB first. */
             }                                  proto_len = ucp[6] + 256 * ucp[7];
           else                                  data_len = ucp[8] + 256 * ucp[9];
             if (ucp[0] == 0x6c)                          } else {
               { /* Byte order LSB first. */                                  debug("Initial X11 packet contains bad byte order byte: 0x%x",
                 proto_len = ucp[6] + 256 * ucp[7];                                        ucp[0]);
                 data_len = ucp[8] + 256 * ucp[9];                                  ch->type = SSH_CHANNEL_OPEN;
               }                                  goto reject;
             else                          }
               {  
                 debug("Initial X11 packet contains bad byte order byte: 0x%x",  
                       ucp[0]);  
                 ch->type = SSH_CHANNEL_OPEN;  
                 goto reject;  
               }  
   
           /* Check if the whole packet is in buffer. */                          /* Check if the whole packet is in buffer. */
           if (buffer_len(&ch->output) <                          if (buffer_len(&ch->output) <
               12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))                              12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
             break;                                  break;
   
           /* Check if authentication protocol matches. */  
           if (proto_len != strlen(x11_saved_proto) ||  
               memcmp(ucp + 12, x11_saved_proto, proto_len) != 0)  
             {  
               debug("X11 connection uses different authentication protocol.");  
               ch->type = SSH_CHANNEL_OPEN;  
               goto reject;  
             }  
   
           /* Check if authentication data matches our fake data. */                          /* Check if authentication protocol matches. */
           if (data_len != x11_fake_data_len ||                          if (proto_len != strlen(x11_saved_proto) ||
               memcmp(ucp + 12 + ((proto_len + 3) & ~3),                              memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
                      x11_fake_data, x11_fake_data_len) != 0)                                  debug("X11 connection uses different authentication protocol.");
             {                                  ch->type = SSH_CHANNEL_OPEN;
               debug("X11 auth data does not match fake data.");                                  goto reject;
               ch->type = SSH_CHANNEL_OPEN;                          }
               goto reject;                          /* Check if authentication data matches our fake data. */
             }                          if (data_len != x11_fake_data_len ||
                               memcmp(ucp + 12 + ((proto_len + 3) & ~3),
                                   x11_fake_data, x11_fake_data_len) != 0) {
                                   debug("X11 auth data does not match fake data.");
                                   ch->type = SSH_CHANNEL_OPEN;
                                   goto reject;
                           }
                           /* 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);
                                   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);
   
           /* Check fake data length */                          /* Start normal processing for the channel. */
           if (x11_fake_data_len != x11_saved_data_len)                          ch->type = SSH_CHANNEL_OPEN;
             {                          goto redo;
               error("X11 fake_data_len %d != saved_data_len %d",  
                      x11_fake_data_len, x11_saved_data_len);  
               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;  
           goto redo;  
   
         reject:          reject:
           /* We have received an X11 connection that has bad authentication                          /* We have received an X11 connection that has bad
              information. */                             authentication information. */
           log("X11 connection rejected because of wrong authentication.\r\n");                          log("X11 connection rejected because of wrong authentication.\r\n");
           buffer_clear(&ch->input);                          buffer_clear(&ch->input);
           buffer_clear(&ch->output);                          buffer_clear(&ch->output);
           if (compat13) {                          if (compat13) {
             close(ch->sock);                                  close(ch->sock);
             ch->sock = -1;                                  ch->sock = -1;
             ch->type = SSH_CHANNEL_CLOSED;                                  ch->type = SSH_CHANNEL_CLOSED;
             packet_start(SSH_MSG_CHANNEL_CLOSE);                                  packet_start(SSH_MSG_CHANNEL_CLOSE);
             packet_put_int(ch->remote_id);                                  packet_put_int(ch->remote_id);
             packet_send();                                  packet_send();
           }else{                          } else {
             debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate);                                  debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate);
             chan_read_failed(ch);                                  chan_read_failed(ch);
             chan_write_failed(ch);                                  chan_write_failed(ch);
             debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate);                                  debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate);
           }                          }
           break;                          break;
   
         case SSH_CHANNEL_FREE:                  case SSH_CHANNEL_FREE:
         default:                  default:
           continue;                          continue;
                   }
         }          }
     }  
 }  }
   
 /* After select, perform any appropriate operations for channels which  /* After select, perform any appropriate operations for channels which
    have events pending. */     have events pending. */
   
 void channel_after_select(fd_set *readset, fd_set *writeset)  void
   channel_after_select(fd_set * readset, fd_set * writeset)
 {  {
   struct sockaddr addr;          struct sockaddr addr;
   int addrlen, newsock, i, newch, len;          int addrlen, newsock, i, newch, len;
   Channel *ch;          Channel *ch;
   char buf[16384], *remote_hostname;          char buf[16384], *remote_hostname;
   
   /* Loop over all channels... */  
   for (i = 0; i < channels_alloc; i++)  
     {  
       ch = &channels[i];  
       switch (ch->type)  
         {  
         case SSH_CHANNEL_X11_LISTENER:  
           /* This is our fake X11 server socket. */  
           if (FD_ISSET(ch->sock, readset))  
             {  
               debug("X11 connection requested.");  
               addrlen = sizeof(addr);  
               newsock = accept(ch->sock, &addr, &addrlen);  
               if (newsock < 0)  
                 {  
                   error("accept: %.100s", strerror(errno));  
                   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:  
           /* This socket is listening for connections to a forwarded TCP/IP  
              port. */  
           if (FD_ISSET(ch->sock, readset))  
             {  
               debug("Connection to port %d forwarding to %.100s:%d requested.",  
                     ch->listening_port, ch->path, ch->host_port);  
               addrlen = sizeof(addr);  
               newsock = accept(ch->sock, &addr, &addrlen);  
               if (newsock < 0)  
                 {  
                   error("accept: %.100s", strerror(errno));  
                   break;  
                 }  
               remote_hostname = get_remote_hostname(newsock);  
               snprintf(buf, sizeof buf, "listen port %d:%.100s:%d, connect from %.200s:%d",  
                       ch->listening_port, ch->path, ch->host_port,  
                       remote_hostname, get_peer_port(newsock));  
               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;  
   
         case SSH_CHANNEL_AUTH_SOCKET:          /* Loop over all channels... */
           /* This is the authentication agent socket listening for connections          for (i = 0; i < channels_alloc; i++) {
              from clients. */                  ch = &channels[i];
           if (FD_ISSET(ch->sock, readset))                  switch (ch->type) {
             {                  case SSH_CHANNEL_X11_LISTENER:
               int nchan;                          /* This is our fake X11 server socket. */
               len = sizeof(addr);                          if (FD_ISSET(ch->sock, readset)) {
               newsock = accept(ch->sock, &addr, &len);                                  debug("X11 connection requested.");
               if (newsock < 0)                                  addrlen = sizeof(addr);
                 {                                  newsock = accept(ch->sock, &addr, &addrlen);
                   error("accept from auth socket: %.100s", strerror(errno));                                  if (newsock < 0) {
                   break;                                          error("accept: %.100s", strerror(errno));
                 }                                          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;
   
               nchan = channel_allocate(SSH_CHANNEL_OPENING, newsock,                  case SSH_CHANNEL_PORT_LISTENER:
                                      xstrdup("accepted auth socket"));                          /* This socket is listening for connections to a
               packet_start(SSH_SMSG_AGENT_OPEN);                             forwarded TCP/IP port. */
               packet_put_int(nchan);                          if (FD_ISSET(ch->sock, readset)) {
               packet_send();                                  debug("Connection to port %d forwarding to %.100s:%d requested.",
             }                                        ch->listening_port, ch->path, ch->host_port);
           break;                                  addrlen = sizeof(addr);
                                   newsock = accept(ch->sock, &addr, &addrlen);
                                   if (newsock < 0) {
                                           error("accept: %.100s", strerror(errno));
                                           break;
                                   }
                                   remote_hostname = get_remote_hostname(newsock);
                                   snprintf(buf, sizeof buf, "listen port %d:%.100s:%d, connect from %.200s:%d",
                                            ch->listening_port, ch->path, ch->host_port,
                                   remote_hostname, get_peer_port(newsock));
                                   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;
   
         case SSH_CHANNEL_OPEN:                  case SSH_CHANNEL_AUTH_SOCKET:
           /* This is an open two-way communication channel.  It is not of                          /* This is the authentication agent socket
              interest to us at this point what kind of data is being                             listening for connections from clients. */
              transmitted. */                          if (FD_ISSET(ch->sock, readset)) {
                                   int nchan;
                                   len = sizeof(addr);
                                   newsock = accept(ch->sock, &addr, &len);
                                   if (newsock < 0) {
                                           error("accept from auth socket: %.100s", strerror(errno));
                                           break;
                                   }
                                   nchan = channel_allocate(SSH_CHANNEL_OPENING, newsock,
                                           xstrdup("accepted auth socket"));
                                   packet_start(SSH_SMSG_AGENT_OPEN);
                                   packet_put_int(nchan);
                                   packet_send();
                           }
                           break;
   
           /* Read available incoming data and append it to buffer;                  case SSH_CHANNEL_OPEN:
              shutdown socket, if read or write failes */                          /* This is an open two-way communication channel.
           if (FD_ISSET(ch->sock, readset))                             It is not of interest to us at this point what
             {                             kind of data is being transmitted. */
               len = read(ch->sock, buf, sizeof(buf));  
               if (len <= 0)  
                 {  
                   if (compat13) {  
                     buffer_consume(&ch->output, buffer_len(&ch->output));  
                     ch->type = SSH_CHANNEL_INPUT_DRAINING;  
                     debug("Channel %d status set to input draining.", i);  
                   }else{  
                     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:                          /* Read available incoming data and append it to
           if (!compat13)                             buffer; shutdown socket, if read or write
                 fatal("cannot happen: OUT_DRAIN");                             failes */
           /* Send buffered output data to the socket. */                          if (FD_ISSET(ch->sock, readset)) {
           if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0)                                  len = read(ch->sock, buf, sizeof(buf));
             {                                  if (len <= 0) {
               len = write(ch->sock, buffer_ptr(&ch->output),                                          if (compat13) {
                           buffer_len(&ch->output));                                                  buffer_consume(&ch->output, buffer_len(&ch->output));
               if (len <= 0)                                                  ch->type = SSH_CHANNEL_INPUT_DRAINING;
                 buffer_consume(&ch->output, buffer_len(&ch->output));                                                  debug("Channel %d status set to input draining.", i);
               else                                          } else {
                 buffer_consume(&ch->output, len);                                                  chan_read_failed(ch);
             }                                          }
           break;                                          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_X11_OPEN:                  case SSH_CHANNEL_OUTPUT_DRAINING:
         case SSH_CHANNEL_FREE:                          if (!compat13)
         default:                                  fatal("cannot happen: OUT_DRAIN");
           continue;                          /* 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)
                                           buffer_consume(&ch->output, buffer_len(&ch->output));
                                   else
                                           buffer_consume(&ch->output, len);
                           }
                           break;
   
                   case SSH_CHANNEL_X11_OPEN:
                   case SSH_CHANNEL_FREE:
                   default:
                           continue;
                   }
         }          }
     }  
 }  }
   
 /* 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 channel_output_poll()  void
   channel_output_poll()
 {  {
   int len, i;          int len, i;
   Channel *ch;          Channel *ch;
   
   for (i = 0; i < channels_alloc; i++)          for (i = 0; i < channels_alloc; i++) {
     {                  ch = &channels[i];
       ch = &channels[i];                  /* We are only interested in channels that can have
       /* We are only interested in channels that can have buffered incoming                     buffered incoming data. */
          data. */                  if (ch->type != SSH_CHANNEL_OPEN &&
       if (ch->type != SSH_CHANNEL_OPEN &&                      ch->type != SSH_CHANNEL_INPUT_DRAINING)
           ch->type != SSH_CHANNEL_INPUT_DRAINING)                          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(&ch->input);
       if (len > 0)                  if (len > 0) {
         {                          /* Send some data for the other side over the
           /* Send some data for the other side over the secure connection. */                             secure connection. */
           if (packet_is_interactive())                          if (packet_is_interactive()) {
             {                                  if (len > 1024)
               if (len > 1024)                                          len = 512;
                 len = 512;                          } else {
             }                                  /* Keep the packets at reasonable size. */
           else                                  if (len > 16384)
             {                                          len = 16384;
               if (len > 16384)                          }
                 len = 16384;  /* Keep the packets at reasonable size. */                          packet_start(SSH_MSG_CHANNEL_DATA);
             }                          packet_put_int(ch->remote_id);
           packet_start(SSH_MSG_CHANNEL_DATA);                          packet_put_string(buffer_ptr(&ch->input), len);
           packet_put_int(ch->remote_id);                          packet_send();
           packet_put_string(buffer_ptr(&ch->input), len);                          buffer_consume(&ch->input, len);
           packet_send();                  } else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) {
           buffer_consume(&ch->input, len);                          if (compat13)
                                   fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
                           /* input-buffer is empty and read-socket shutdown:
                              tell peer, that we will not send more data:
                              send IEOF */
                           chan_ibuf_empty(ch);
                   }
         }          }
       else if(ch->istate == CHAN_INPUT_WAIT_DRAIN)  
         {  
           if (compat13)  
              fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");  
           /* input-buffer is empty and read-socket shutdown:  
              tell peer, that we will not send more data: send IEOF */  
           chan_ibuf_empty(ch);  
         }  
     }  
 }  }
   
 /* This is called when a packet of type CHANNEL_DATA has just been received.  /* This is called when a packet of type CHANNEL_DATA has just been received.
    The message type has already been consumed, but channel number and data     The message type has already been consumed, but channel number and data
    is still there. */     is still there. */
   
 void channel_input_data(int payload_len)  void
   channel_input_data(int payload_len)
 {  {
   int channel;          int channel;
   char *data;          char *data;
   unsigned int data_len;          unsigned int data_len;
   
   /* Get the channel number and verify it. */          /* Get the channel number and verify it. */
   channel = packet_get_int();          channel = packet_get_int();
   if (channel < 0 || channel >= channels_alloc ||          if (channel < 0 || channel >= channels_alloc ||
       channels[channel].type == SSH_CHANNEL_FREE)              channels[channel].type == SSH_CHANNEL_FREE)
     packet_disconnect("Received data for nonexistent channel %d.", channel);                  packet_disconnect("Received data for nonexistent channel %d.", channel);
   
   /* Ignore any data for non-open channels (might happen on close) */          /* Ignore any data for non-open channels (might happen on close) */
   if (channels[channel].type != SSH_CHANNEL_OPEN &&          if (channels[channel].type != SSH_CHANNEL_OPEN &&
       channels[channel].type != SSH_CHANNEL_X11_OPEN)              channels[channel].type != SSH_CHANNEL_X11_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);          packet_integrity_check(payload_len, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA);
   buffer_append(&channels[channel].output, data, data_len);          buffer_append(&channels[channel].output, data, data_len);
   xfree(data);          xfree(data);
 }  }
   
 /* Returns true if no channel has too much buffered data, and false if  /* Returns true if no channel has too much buffered data, and false if
    one or more channel is overfull. */     one or more channel is overfull. */
   
 int channel_not_very_much_buffered_data()  int
   channel_not_very_much_buffered_data()
 {  {
   unsigned int i;          unsigned int i;
   Channel *ch;          Channel *ch;
   
   for (i = 0; i < channels_alloc; i++)          for (i = 0; i < channels_alloc; i++) {
     {                  ch = &channels[i];
       ch = &channels[i];                  switch (ch->type) {
       switch (ch->type)                  case SSH_CHANNEL_X11_LISTENER:
         {                  case SSH_CHANNEL_PORT_LISTENER:
         case SSH_CHANNEL_X11_LISTENER:                  case SSH_CHANNEL_AUTH_SOCKET:
         case SSH_CHANNEL_PORT_LISTENER:                          continue;
         case SSH_CHANNEL_AUTH_SOCKET:                  case SSH_CHANNEL_OPEN:
           continue;                          if (buffer_len(&ch->input) > packet_get_maxsize())
         case SSH_CHANNEL_OPEN:                                  return 0;
           if (buffer_len(&ch->input) > packet_get_maxsize())                          if (buffer_len(&ch->output) > packet_get_maxsize())
             return 0;                                  return 0;
           if (buffer_len(&ch->output) > packet_get_maxsize())                          continue;
             return 0;                  case SSH_CHANNEL_INPUT_DRAINING:
           continue;                  case SSH_CHANNEL_OUTPUT_DRAINING:
         case SSH_CHANNEL_INPUT_DRAINING:                  case SSH_CHANNEL_X11_OPEN:
         case SSH_CHANNEL_OUTPUT_DRAINING:                  case SSH_CHANNEL_FREE:
         case SSH_CHANNEL_X11_OPEN:                  default:
         case SSH_CHANNEL_FREE:                          continue;
         default:                  }
           continue;  
         }          }
     }          return 1;
   return 1;  
 }  }
   
 /* This is called after receiving CHANNEL_CLOSE/IEOF. */  /* This is called after receiving CHANNEL_CLOSE/IEOF. */
   
 void channel_input_close()  void
   channel_input_close()
 {  {
   int channel;          int channel;
   
   /* Get the channel number and verify it. */          /* Get the channel number and verify it. */
   channel = packet_get_int();          channel = packet_get_int();
   if (channel < 0 || channel >= channels_alloc ||          if (channel < 0 || channel >= channels_alloc ||
       channels[channel].type == SSH_CHANNEL_FREE)              channels[channel].type == SSH_CHANNEL_FREE)
     packet_disconnect("Received data for nonexistent channel %d.", channel);                  packet_disconnect("Received data for nonexistent channel %d.", channel);
   
   if(!compat13){          if (!compat13) {
     /* proto version 1.5 overloads CLOSE with IEOF */                  /* proto version 1.5 overloads CLOSE with IEOF */
     chan_rcvd_ieof(&channels[channel]);                  chan_rcvd_ieof(&channels[channel]);
     return;                  return;
   }          }
           /* Send a confirmation that we have closed the channel and no more
              data is coming for it. */
           packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
           packet_put_int(channels[channel].remote_id);
           packet_send();
   
   /* Send a confirmation that we have closed the channel and no more data is          /* If the channel is in closed state, we have sent a close
      coming for it. */             request, and the other side will eventually respond with a
   packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);             confirmation.  Thus, we cannot free the channel here, because
   packet_put_int(channels[channel].remote_id);             then there would be no-one to receive the confirmation.  The
   packet_send();             channel gets freed when the confirmation arrives. */
           if (channels[channel].type != SSH_CHANNEL_CLOSED) {
   /* If the channel is in closed state, we have sent a close request, and                  /* Not a closed channel - mark it as draining, which will
      the other side will eventually respond with a confirmation.  Thus,                     cause it to be freed later. */
      we cannot free the channel here, because then there would be no-one to                  buffer_consume(&channels[channel].input,
      receive the confirmation.  The channel gets freed when the confirmation                                 buffer_len(&channels[channel].input));
      arrives. */                  channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING;
   if (channels[channel].type != SSH_CHANNEL_CLOSED)          }
     {  
       /* Not a closed channel - mark it as draining, which will cause it to  
          be freed later. */  
       buffer_consume(&channels[channel].input,  
                      buffer_len(&channels[channel].input));  
       channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING;  
       /* debug("Setting status to output draining; output len = %d",  
          buffer_len(&channels[channel].output)); */  
     }  
 }  }
   
 /* This is called after receiving CHANNEL_CLOSE_CONFIRMATION/OCLOSE. */  /* This is called after receiving CHANNEL_CLOSE_CONFIRMATION/OCLOSE. */
   
 void channel_input_close_confirmation()  void
   channel_input_close_confirmation()
 {  {
   int channel;          int channel;
   
   /* Get the channel number and verify it. */          /* Get the channel number and verify it. */
   channel = packet_get_int();          channel = packet_get_int();
   if (channel < 0 || channel >= channels_alloc)          if (channel < 0 || channel >= channels_alloc)
     packet_disconnect("Received close confirmation for out-of-range channel %d.",                  packet_disconnect("Received close confirmation for out-of-range channel %d.",
                       channel);                                    channel);
   
   if(!compat13){          if (!compat13) {
     /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */                  /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
     chan_rcvd_oclose(&channels[channel]);                  chan_rcvd_oclose(&channels[channel]);
     return;                  return;
   }          }
           if (channels[channel].type != SSH_CHANNEL_CLOSED)
                   packet_disconnect("Received close confirmation for non-closed channel %d (type %d).",
                                     channel, channels[channel].type);
   
   if (channels[channel].type != SSH_CHANNEL_CLOSED)          /* Free the channel. */
     packet_disconnect("Received close confirmation for non-closed channel %d (type %d).",          channel_free(channel);
                       channel, channels[channel].type);  
   
   /* Free the channel. */  
   channel_free(channel);  
 }  }
   
 /* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */  /* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */
   
 void channel_input_open_confirmation()  void
   channel_input_open_confirmation()
 {  {
   int channel, remote_channel;          int channel, remote_channel;
   
   /* Get the channel number and verify it. */          /* Get the channel number and verify it. */
   channel = packet_get_int();          channel = packet_get_int();
   if (channel < 0 || channel >= channels_alloc ||          if (channel < 0 || channel >= channels_alloc ||
       channels[channel].type != SSH_CHANNEL_OPENING)              channels[channel].type != SSH_CHANNEL_OPENING)
     packet_disconnect("Received open confirmation for non-opening channel %d.",                  packet_disconnect("Received open confirmation for non-opening channel %d.",
                       channel);                                    channel);
   
   /* Get remote side's id for this channel. */          /* Get remote side's id for this channel. */
   remote_channel = packet_get_int();          remote_channel = 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
   channels[channel].remote_id = remote_channel;             now open. */
   channels[channel].type = SSH_CHANNEL_OPEN;          channels[channel].remote_id = remote_channel;
           channels[channel].type = SSH_CHANNEL_OPEN;
 }  }
   
 /* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */  /* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */
   
 void channel_input_open_failure()  void
   channel_input_open_failure()
 {  {
   int channel;          int channel;
   
   /* Get the channel number and verify it. */          /* Get the channel number and verify it. */
   channel = packet_get_int();          channel = packet_get_int();
   if (channel < 0 || channel >= channels_alloc ||          if (channel < 0 || channel >= channels_alloc ||
       channels[channel].type != SSH_CHANNEL_OPENING)              channels[channel].type != SSH_CHANNEL_OPENING)
     packet_disconnect("Received open failure for non-opening channel %d.",                  packet_disconnect("Received open failure for non-opening channel %d.",
                       channel);                                    channel);
   
   /* Free the channel.  This will also close the socket. */          /* Free the channel.  This will also close the socket. */
   channel_free(channel);          channel_free(channel);
 }  }
   
 /* Stops listening for channels, and removes any unix domain sockets that  /* Stops listening for channels, and removes any unix domain sockets that
    we might have. */     we might have. */
   
 void channel_stop_listening()  void
   channel_stop_listening()
 {  {
   int i;          int i;
   for (i = 0; i < channels_alloc; i++)          for (i = 0; i < channels_alloc; i++) {
     {                  switch (channels[i].type) {
       switch (channels[i].type)                  case SSH_CHANNEL_AUTH_SOCKET:
         {                          close(channels[i].sock);
         case SSH_CHANNEL_AUTH_SOCKET:                          remove(channels[i].path);
           close(channels[i].sock);                          channel_free(i);
           remove(channels[i].path);                          break;
           channel_free(i);                  case SSH_CHANNEL_PORT_LISTENER:
           break;                  case SSH_CHANNEL_X11_LISTENER:
         case SSH_CHANNEL_PORT_LISTENER:                          close(channels[i].sock);
         case SSH_CHANNEL_X11_LISTENER:                          channel_free(i);
           close(channels[i].sock);                          break;
           channel_free(i);                  default:
           break;                          break;
         default:                  }
           break;  
         }          }
     }  
 }  }
   
 /* Closes the sockets of all channels.  This is used to close extra file  /* Closes the sockets of all channels.  This is used to close extra file
    descriptors after a fork. */     descriptors after a fork. */
   
 void channel_close_all()  void
   channel_close_all()
 {  {
   int i;          int i;
   for (i = 0; i < channels_alloc; i++)          for (i = 0; i < channels_alloc; i++) {
     {                  if (channels[i].type != SSH_CHANNEL_FREE)
       if (channels[i].type != SSH_CHANNEL_FREE)                          close(channels[i].sock);
         close(channels[i].sock);          }
     }  
 }  }
   
 /* Returns the maximum file descriptor number used by the channels. */  /* Returns the maximum file descriptor number used by the channels. */
   
 int channel_max_fd()  int
   channel_max_fd()
 {  {
   return channel_max_fd_value;          return channel_max_fd_value;
 }  }
   
 /* Returns true if any channel is still open. */  /* Returns true if any channel is still open. */
   
 int channel_still_open()  int
   channel_still_open()
 {  {
   unsigned int i;          unsigned int i;
   for (i = 0; i < channels_alloc; i++)          for (i = 0; i < channels_alloc; i++)
     switch (channels[i].type)                  switch (channels[i].type) {
       {                  case SSH_CHANNEL_FREE:
       case SSH_CHANNEL_FREE:                  case SSH_CHANNEL_X11_LISTENER:
       case SSH_CHANNEL_X11_LISTENER:                  case SSH_CHANNEL_PORT_LISTENER:
       case SSH_CHANNEL_PORT_LISTENER:                  case SSH_CHANNEL_CLOSED:
       case SSH_CHANNEL_CLOSED:                  case SSH_CHANNEL_AUTH_SOCKET:
       case SSH_CHANNEL_AUTH_SOCKET:                          continue;
         continue;                  case SSH_CHANNEL_OPENING:
       case SSH_CHANNEL_OPENING:                  case SSH_CHANNEL_OPEN:
       case SSH_CHANNEL_OPEN:                  case SSH_CHANNEL_X11_OPEN:
       case SSH_CHANNEL_X11_OPEN:                          return 1;
         return 1;                  case SSH_CHANNEL_INPUT_DRAINING:
       case SSH_CHANNEL_INPUT_DRAINING:                  case SSH_CHANNEL_OUTPUT_DRAINING:
       case SSH_CHANNEL_OUTPUT_DRAINING:                          if (!compat13)
         if (!compat13)                                  fatal("cannot happen: OUT_DRAIN");
           fatal("cannot happen: OUT_DRAIN");                          return 1;
         return 1;                  default:
       default:                          fatal("channel_still_open: bad channel type %d", channels[i].type);
         fatal("channel_still_open: bad channel type %d", channels[i].type);                          /* NOTREACHED */
         /*NOTREACHED*/                  }
       }          return 0;
   return 0;  
 }  }
   
 /* Returns a message describing the currently open forwarded  /* Returns a message describing the currently open forwarded
    connections, suitable for sending to the client.  The message     connections, suitable for sending to the client.  The message
    contains crlf pairs for newlines. */     contains crlf pairs for newlines. */
   
 char *channel_open_message()  char *
   channel_open_message()
 {  {
   Buffer buffer;          Buffer buffer;
   int i;          int i;
   char buf[512], *cp;          char buf[512], *cp;
   
   buffer_init(&buffer);          buffer_init(&buffer);
   snprintf(buf, sizeof buf, "The following connections are open:\r\n");          snprintf(buf, sizeof buf, "The following connections are open:\r\n");
   buffer_append(&buffer, buf, strlen(buf));  
   for (i = 0; i < channels_alloc; i++){  
     Channel *c=&channels[i];  
     switch (c->type)  
       {  
       case SSH_CHANNEL_FREE:  
       case SSH_CHANNEL_X11_LISTENER:  
       case SSH_CHANNEL_PORT_LISTENER:  
       case SSH_CHANNEL_CLOSED:  
       case SSH_CHANNEL_AUTH_SOCKET:  
         continue;  
       case SSH_CHANNEL_OPENING:  
       case SSH_CHANNEL_OPEN:  
       case SSH_CHANNEL_X11_OPEN:  
       case SSH_CHANNEL_INPUT_DRAINING:  
       case SSH_CHANNEL_OUTPUT_DRAINING:  
         snprintf(buf, sizeof buf, "  #%d %.300s (t%d r%d i%d o%d)\r\n",  
                  c->self,c->remote_name,  
                  c->type,c->remote_id, c->istate,c->ostate);  
         buffer_append(&buffer, buf, strlen(buf));          buffer_append(&buffer, buf, strlen(buf));
         continue;          for (i = 0; i < channels_alloc; i++) {
       default:                  Channel *c = &channels[i];
         fatal("channel_still_open: bad channel type %d", c->type);                  switch (c->type) {
         /*NOTREACHED*/                  case SSH_CHANNEL_FREE:
       }                  case SSH_CHANNEL_X11_LISTENER:
   }                  case SSH_CHANNEL_PORT_LISTENER:
   buffer_append(&buffer, "\0", 1);                  case SSH_CHANNEL_CLOSED:
   cp = xstrdup(buffer_ptr(&buffer));                  case SSH_CHANNEL_AUTH_SOCKET:
   buffer_free(&buffer);                          continue;
   return cp;                  case SSH_CHANNEL_OPENING:
                   case SSH_CHANNEL_OPEN:
                   case SSH_CHANNEL_X11_OPEN:
                   case SSH_CHANNEL_INPUT_DRAINING:
                   case SSH_CHANNEL_OUTPUT_DRAINING:
                           snprintf(buf, sizeof buf, "  #%d %.300s (t%d r%d i%d o%d)\r\n",
                                    c->self, c->remote_name,
                                    c->type, c->remote_id, c->istate, c->ostate);
                           buffer_append(&buffer, buf, strlen(buf));
                           continue;
                   default:
                           fatal("channel_still_open: bad channel type %d", c->type);
                           /* NOTREACHED */
                   }
           }
           buffer_append(&buffer, "\0", 1);
           cp = xstrdup(buffer_ptr(&buffer));
           buffer_free(&buffer);
           return cp;
 }  }
   
 /* Initiate forwarding of connections to local port "port" through the secure  /* Initiate forwarding of connections to local port "port" through the secure
    channel to host:port from remote side. */     channel to host:port from remote side. */
   
 void channel_request_local_forwarding(int port, const char *host,  void
                                       int host_port)  channel_request_local_forwarding(int port, const char *host,
                                    int host_port)
 {  {
   int ch, sock;          int ch, sock;
   struct sockaddr_in sin;          struct sockaddr_in sin;
   extern Options options;          extern Options options;
   
   if (strlen(host) > sizeof(channels[0].path) - 1)          if (strlen(host) > sizeof(channels[0].path) - 1)
     packet_disconnect("Forward host name too long.");                  packet_disconnect("Forward host name too long.");
   
   /* Create a port to listen for the host. */  
   sock = socket(AF_INET, SOCK_STREAM, 0);  
   if (sock < 0)  
     packet_disconnect("socket: %.100s", strerror(errno));  
   
   /* Initialize socket address. */          /* Create a port to listen for the host. */
   memset(&sin, 0, sizeof(sin));          sock = socket(AF_INET, SOCK_STREAM, 0);
   sin.sin_family = AF_INET;          if (sock < 0)
   if (options.gateway_ports == 1)                  packet_disconnect("socket: %.100s", strerror(errno));
     sin.sin_addr.s_addr = htonl(INADDR_ANY);  
   else  
     sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);  
   sin.sin_port = htons(port);  
   
   /* Bind the socket to the address. */  
   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)  
     packet_disconnect("bind: %.100s", strerror(errno));  
   
   /* Start listening for connections on the socket. */  
   if (listen(sock, 5) < 0)  
     packet_disconnect("listen: %.100s", strerror(errno));  
   
   /* Allocate a channel number for the socket. */  
   ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock,  
                         xstrdup("port listener"));  
   strcpy(channels[ch].path, host); /* note: host name stored here */  
   channels[ch].host_port = host_port; /* port on host to connect to */  
   channels[ch].listening_port = port; /* port being listened */  
 }  
   
           /* Initialize socket address. */
           memset(&sin, 0, sizeof(sin));
           sin.sin_family = AF_INET;
           if (options.gateway_ports == 1)
                   sin.sin_addr.s_addr = htonl(INADDR_ANY);
           else
                   sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
           sin.sin_port = htons(port);
   
           /* Bind the socket to the address. */
           if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
                   packet_disconnect("bind: %.100s", strerror(errno));
   
           /* Start listening for connections on the socket. */
           if (listen(sock, 5) < 0)
                   packet_disconnect("listen: %.100s", strerror(errno));
   
           /* Allocate a channel number for the socket. */
           ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock,
                                 xstrdup("port listener"));
           strcpy(channels[ch].path, host);
           channels[ch].host_port = host_port;
           channels[ch].listening_port = port;
   }
   
 /* Initiate forwarding of connections to port "port" on remote host through  /* Initiate forwarding of connections to port "port" on remote host through
    the secure channel to host:port from local side. */     the secure channel to host:port from local side. */
   
 void channel_request_remote_forwarding(int port, const char *host,  void
                                        int remote_port)  channel_request_remote_forwarding(int port, const char *host,
                                     int remote_port)
 {  {
   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");      /* XXX why panic? -markus */                  fatal("channel_request_remote_forwarding: too many forwards");
   permitted_opens[num_permitted_opens].host = xstrdup(host);  
   permitted_opens[num_permitted_opens].port = remote_port;  
   num_permitted_opens++;  
   
   /* Send the forward request to the remote side. */          permitted_opens[num_permitted_opens].host = xstrdup(host);
   packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);          permitted_opens[num_permitted_opens].port = remote_port;
   packet_put_int(port);          num_permitted_opens++;
   packet_put_string(host, strlen(host));  
   packet_put_int(remote_port);          /* Send the forward request to the remote side. */
   packet_send();          packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
   packet_write_wait();          packet_put_int(port);
           packet_put_string(host, strlen(host));
   /* Wait for response from the remote side.  It will send a disconnect          packet_put_int(remote_port);
      message on failure, and we will never see it here. */          packet_send();
   packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);          packet_write_wait();
   
           /* Wait for response from the remote side.  It will send a
              disconnect message on failure, and we will never see it here. */
           packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
 }  }
   
 /* This is called after receiving CHANNEL_FORWARDING_REQUEST.  This initates  /* This is called after receiving CHANNEL_FORWARDING_REQUEST.  This initates
    listening for the port, and sends back a success reply (or disconnect     listening for the port, and sends back a success reply (or disconnect
    message if there was an error).  This never returns if there was an     message if there was an error).  This never returns if there was an
    error. */     error. */
   
 void channel_input_port_forward_request(int is_root)  void
   channel_input_port_forward_request(int is_root)
 {  {
   int port, host_port;          int port, host_port;
   char *hostname;          char *hostname;
   
   /* Get arguments from the packet. */  
   port = packet_get_int();  
   hostname = packet_get_string(NULL);  
   host_port = packet_get_int();  
   
   /* Port numbers are 16 bit quantities. */  
   if ((port & 0xffff) != port)  
     packet_disconnect("Requested forwarding of nonexistent port %d.", port);  
   
   /* Check that an unprivileged user is not trying to forward a privileged          /* Get arguments from the packet. */
      port. */          port = packet_get_int();
   if (port < IPPORT_RESERVED && !is_root)          hostname = packet_get_string(NULL);
     packet_disconnect("Requested forwarding of port %d but user is not root.",          host_port = packet_get_int();
                       port);  
   
   /* Initiate forwarding. */          /* Port numbers are 16 bit quantities. */
   channel_request_local_forwarding(port, hostname, host_port);          if ((port & 0xffff) != port)
                   packet_disconnect("Requested forwarding of nonexistent port %d.", port);
   
   /* Free the argument string. */          /* Check that an unprivileged user is not trying to forward a
   xfree(hostname);             privileged port. */
           if (port < IPPORT_RESERVED && !is_root)
                   packet_disconnect("Requested forwarding of port %d but user is not root.",
                                     port);
   
           /* Initiate forwarding. */
           channel_request_local_forwarding(port, hostname, host_port);
   
           /* Free the argument string. */
           xfree(hostname);
 }  }
   
 /* This is called after receiving PORT_OPEN message.  This attempts to connect  /* This is called after receiving PORT_OPEN message.  This attempts to connect
    to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or     to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or
    CHANNEL_OPEN_FAILURE. */     CHANNEL_OPEN_FAILURE. */
   
 void channel_input_port_open(int payload_len)  void
   channel_input_port_open(int payload_len)
 {  {
   int remote_channel, sock, newch, host_port, i;          int remote_channel, sock, newch, host_port, i;
   struct sockaddr_in sin;          struct sockaddr_in sin;
   char *host, *originator_string;          char *host, *originator_string;
   struct hostent *hp;          struct hostent *hp;
   int host_len, originator_len;          int host_len, originator_len;
   
   /* Get remote channel number. */          /* Get remote channel number. */
   remote_channel = packet_get_int();          remote_channel = packet_get_int();
   
   /* Get host name to connect to. */          /* Get host name to connect to. */
   host = packet_get_string(&host_len);          host = packet_get_string(&host_len);
   
   /* Get port to connect to. */          /* Get port to connect to. */
   host_port = packet_get_int();          host_port = packet_get_int();
   
   /* Get remote originator name. */          /* Get remote originator name. */
   if (have_hostname_in_open)          if (have_hostname_in_open)
     originator_string = packet_get_string(&originator_len);                  originator_string = packet_get_string(&originator_len);
   else          else
     originator_string = xstrdup("unknown (remote did not supply name)");                  originator_string = xstrdup("unknown (remote did not supply name)");
   
   packet_integrity_check(payload_len,          packet_integrity_check(payload_len,
                          4 + 4 + host_len + 4 + 4 + originator_len,                                 4 + 4 + host_len + 4 + 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. */
   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 == host_port &&                              strcmp(permitted_opens[i].host, host) == 0)
             strcmp(permitted_opens[i].host, host) == 0)                                  break;
           break;  
   
       /* Check if we found the requested port among those permitted. */                  /* Check if we found the requested port among those permitted. */
       if (i >= num_permitted_opens)                  if (i >= num_permitted_opens) {
         {                          /* 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);                          packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
           packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);                          packet_put_int(remote_channel);
           packet_put_int(remote_channel);                          packet_send();
           packet_send();                  }
         }          }
     }          memset(&sin, 0, sizeof(sin));
           sin.sin_addr.s_addr = inet_addr(host);
   memset(&sin, 0, sizeof(sin));          if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) {
   sin.sin_addr.s_addr = inet_addr(host);                  /* It was a valid numeric host address. */
   if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff)                  sin.sin_family = AF_INET;
     {          } else {
       /* It was a valid numeric host address. */                  /* Look up the host address from the name servers. */
       sin.sin_family = AF_INET;                  hp = gethostbyname(host);
     }                  if (!hp) {
   else                          error("%.100s: unknown host.", host);
     {                          goto fail;
       /* Look up the host address from the name servers. */                  }
       hp = gethostbyname(host);                  if (!hp->h_addr_list[0]) {
       if (!hp)                          error("%.100s: host has no IP address.", host);
         {                          goto fail;
           error("%.100s: unknown host.", host);                  }
           goto fail;                  sin.sin_family = hp->h_addrtype;
                   memcpy(&sin.sin_addr, hp->h_addr_list[0],
                          sizeof(sin.sin_addr));
         }          }
       if (!hp->h_addr_list[0])          sin.sin_port = htons(host_port);
         {  
           error("%.100s: host has no IP address.", host);          /* Create the socket. */
           goto fail;          sock = socket(sin.sin_family, SOCK_STREAM, 0);
           if (sock < 0) {
                   error("socket: %.100s", strerror(errno));
                   goto fail;
         }          }
       sin.sin_family = hp->h_addrtype;          /* Connect to the host/port. */
       memcpy(&sin.sin_addr, hp->h_addr_list[0],          if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
              sizeof(sin.sin_addr));                  error("connect %.100s:%d: %.100s", host, host_port,
     }                        strerror(errno));
   sin.sin_port = htons(host_port);                  close(sock);
                   goto fail;
           }
           /* Successful connection. */
   
   /* Create the socket. */          /* Allocate a channel for this connection. */
   sock = socket(sin.sin_family, SOCK_STREAM, 0);          newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string);
   if (sock < 0)          channels[newch].remote_id = remote_channel;
     {  
       error("socket: %.100s", strerror(errno));  
       goto fail;  
     }  
   
   /* Connect to the host/port. */          /* Send a confirmation to the remote host. */
   if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)          packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
     {          packet_put_int(remote_channel);
       error("connect %.100s:%d: %.100s", host, host_port,          packet_put_int(newch);
             strerror(errno));          packet_send();
       close(sock);  
       goto fail;  
     }  
   
   /* Successful connection. */          /* Free the argument string. */
           xfree(host);
   
   /* Allocate a channel for this connection. */          return;
   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. */  fail:
   xfree(host);          /* Free the argument string. */
           xfree(host);
   return;  
   
  fail:          /* Send refusal to the remote host. */
   /* Free the argument string. */          packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
   xfree(host);          packet_put_int(remote_channel);
           packet_send();
   /* Send refusal to the remote host. */  
   packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);  
   packet_put_int(remote_channel);  
   packet_send();  
 }  }
   
 /* Creates an internet domain socket for listening for X11 connections.  /* Creates an internet domain socket for listening for X11 connections.
    Returns a suitable value for the DISPLAY variable, or NULL if an error     Returns a suitable value for the DISPLAY variable, or NULL if an error
    occurs. */     occurs. */
   
 char *x11_create_display_inet(int screen_number)  char *
   x11_create_display_inet(int screen_number)
 {  {
   extern ServerOptions options;          extern ServerOptions options;
   int display_number, port, sock;          int display_number, port, sock;
   struct sockaddr_in sin;          struct sockaddr_in sin;
   char buf[512];          char buf[512];
   char hostname[MAXHOSTNAMELEN];          char hostname[MAXHOSTNAMELEN];
   
   for (display_number = options.x11_display_offset; display_number < MAX_DISPLAYS; display_number++)          for (display_number = options.x11_display_offset;
     {               display_number < MAX_DISPLAYS;
       port = 6000 + display_number;               display_number++) {
       memset(&sin, 0, sizeof(sin));                  port = 6000 + display_number;
       sin.sin_family = AF_INET;                  memset(&sin, 0, sizeof(sin));
       sin.sin_addr.s_addr = htonl(INADDR_ANY);                  sin.sin_family = AF_INET;
       sin.sin_port = htons(port);                  sin.sin_addr.s_addr = htonl(INADDR_ANY);
                   sin.sin_port = htons(port);
       sock = socket(AF_INET, SOCK_STREAM, 0);  
       if (sock < 0)                  sock = socket(AF_INET, SOCK_STREAM, 0);
         {                  if (sock < 0) {
           error("socket: %.100s", strerror(errno));                          error("socket: %.100s", strerror(errno));
           return NULL;                          return NULL;
                   }
                   if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
                           debug("bind port %d: %.100s", port, strerror(errno));
                           shutdown(sock, SHUT_RDWR);
                           close(sock);
                           continue;
                   }
                   break;
         }          }
           if (display_number >= MAX_DISPLAYS) {
       if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)                  error("Failed to allocate internet-domain X11 display socket.");
         {                  return NULL;
           debug("bind port %d: %.100s", port, strerror(errno));  
           shutdown(sock, SHUT_RDWR);  
           close(sock);  
           continue;  
         }          }
       break;          /* Start listening for connections on the socket. */
     }          if (listen(sock, 5) < 0) {
   if (display_number >= MAX_DISPLAYS)                  error("listen: %.100s", strerror(errno));
     {                  shutdown(sock, SHUT_RDWR);
       error("Failed to allocate internet-domain X11 display socket.");                  close(sock);
       return NULL;                  return NULL;
     }          }
           /* Set up a suitable value for the DISPLAY variable. */
           if (gethostname(hostname, sizeof(hostname)) < 0)
                   fatal("gethostname: %.100s", strerror(errno));
           snprintf(buf, sizeof buf, "%.400s:%d.%d", hostname,
                    display_number, screen_number);
   
   /* Start listening for connections on the socket. */          /* Allocate a channel for the socket. */
   if (listen(sock, 5) < 0)          (void) channel_allocate(SSH_CHANNEL_X11_LISTENER, sock,
     {                                  xstrdup("X11 inet listener"));
       error("listen: %.100s", strerror(errno));  
       shutdown(sock, SHUT_RDWR);  
       close(sock);  
       return NULL;  
     }  
   
   /* Set up a suitable value for the DISPLAY variable. */          /* Return a suitable value for the DISPLAY environment variable. */
   if (gethostname(hostname, sizeof(hostname)) < 0)          return xstrdup(buf);
     fatal("gethostname: %.100s", strerror(errno));  
   snprintf(buf, sizeof buf, "%.400s:%d.%d", hostname,  
     display_number, screen_number);  
   
   /* Allocate a channel for the socket. */  
   (void)channel_allocate(SSH_CHANNEL_X11_LISTENER, sock,  
                          xstrdup("X11 inet listener"));  
   
   /* Return a suitable value for the DISPLAY environment variable. */  
   return xstrdup(buf);  
 }  }
   
 #ifndef X_UNIX_PATH  #ifndef X_UNIX_PATH
Line 1150 
Line 1108 
 int  int
 connect_local_xsocket(unsigned dnr)  connect_local_xsocket(unsigned dnr)
 {  {
   static const char *const x_sockets[] = {          static const char *const x_sockets[] = {
     X_UNIX_PATH "%u",                  X_UNIX_PATH "%u",
     "/var/X/.X11-unix/X" "%u",                  "/var/X/.X11-unix/X" "%u",
     "/usr/spool/sockets/X11/" "%u",                  "/usr/spool/sockets/X11/" "%u",
     NULL                  NULL
   };          };
   int sock;          int sock;
   struct sockaddr_un addr;          struct sockaddr_un addr;
   const char *const *path;          const char *const * path;
   
   for (path = x_sockets; *path; ++path)          for (path = x_sockets; *path; ++path) {
     {                  sock = socket(AF_UNIX, SOCK_STREAM, 0);
       sock = socket(AF_UNIX, SOCK_STREAM, 0);                  if (sock < 0)
       if (sock < 0)                          error("socket: %.100s", strerror(errno));
         error("socket: %.100s", strerror(errno));                  memset(&addr, 0, sizeof(addr));
       memset(&addr, 0, sizeof(addr));                  addr.sun_family = AF_UNIX;
       addr.sun_family = AF_UNIX;                  snprintf(addr.sun_path, sizeof addr.sun_path, *path, dnr);
       snprintf(addr.sun_path, sizeof addr.sun_path, *path, dnr);                  if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0)
       if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0)                          return sock;
         return sock;                  close(sock);
       close(sock);          }
     }          error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
   error("connect %.100s: %.100s", addr.sun_path, strerror(errno));          return -1;
   return -1;  
 }  }
   
   
Line 1181 
Line 1138 
    the remote channel number.  We should do whatever we want, and respond     the remote channel number.  We should do whatever we want, and respond
    with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */     with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */
   
 void x11_input_open(int payload_len)  void
   x11_input_open(int payload_len)
 {  {
   int remote_channel, display_number, sock, newch;          int remote_channel, display_number, sock, newch;
   const char *display;          const char *display;
   struct sockaddr_in sin;          struct sockaddr_in sin;
   char buf[1024], *cp, *remote_host;          char buf[1024], *cp, *remote_host;
   struct hostent *hp;          struct hostent *hp;
   int remote_len;          int remote_len;
   
   /* Get remote channel number. */          /* Get remote channel number. */
   remote_channel = packet_get_int();          remote_channel = packet_get_int();
   
   /* Get remote originator name. */          /* Get remote originator name. */
   if (have_hostname_in_open)          if (have_hostname_in_open)
     remote_host = packet_get_string(&remote_len);                  remote_host = packet_get_string(&remote_len);
   else          else
     remote_host = xstrdup("unknown (remote did not supply name)");                  remote_host = xstrdup("unknown (remote did not supply name)");
   
   debug("Received X11 open request.");          debug("Received X11 open request.");
   packet_integrity_check(payload_len, 4 + 4+remote_len, SSH_SMSG_X11_OPEN);          packet_integrity_check(payload_len, 4 + 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");
   if (!display)          if (!display) {
     {                  error("DISPLAY not set.");
       error("DISPLAY not set.");                  goto fail;
       goto fail;          }
     }          /* Now we decode the value of the DISPLAY variable and make a
              connection to the real X server. */
   /* Now we decode the value of the DISPLAY variable and make a connection  
      to the real X server. */  
   
   /* Check if it is a unix domain socket.  Unix domain displays are in one          /* Check if it is a unix domain socket.  Unix domain displays are
      of the following formats: unix:d[.s], :d[.s], ::d[.s] */             in one of the following formats: unix:d[.s], :d[.s], ::d[.s] */
   if (strncmp(display, "unix:", 5) == 0 ||          if (strncmp(display, "unix:", 5) == 0 ||
       display[0] == ':')              display[0] == ':') {
     {                  /* Connect to the unix domain socket. */
       /* Connect to the unix domain socket. */                  if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) {
       if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1)                          error("Could not parse display number from DISPLAY: %.100s",
         {                                display);
           error("Could not parse display number from DISPLAY: %.100s",                          goto fail;
                 display);                  }
           goto fail;                  /* Create a socket. */
                   sock = connect_local_xsocket(display_number);
                   if (sock < 0)
                           goto fail;
   
                   /* OK, we now have a connection to the display. */
                   goto success;
         }          }
       /* Create a socket. */          /* Connect to an inet socket.  The DISPLAY value is supposedly
       sock = connect_local_xsocket(display_number);             hostname:d[.s], where hostname may also be numeric IP address. */
       if (sock < 0)          strncpy(buf, display, sizeof(buf));
         goto fail;          buf[sizeof(buf) - 1] = 0;
           cp = strchr(buf, ':');
           if (!cp) {
                   error("Could not find ':' in DISPLAY: %.100s", display);
                   goto fail;
           }
           *cp = 0;
           /* buf now contains the host name.  But first we parse the display
              number. */
           if (sscanf(cp + 1, "%d", &display_number) != 1) {
                   error("Could not parse display number from DISPLAY: %.100s",
                         display);
                   goto fail;
           }
           /* Try to parse the host name as a numeric IP address. */
           memset(&sin, 0, sizeof(sin));
           sin.sin_addr.s_addr = inet_addr(buf);
           if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) {
                   /* It was a valid numeric host address. */
                   sin.sin_family = AF_INET;
           } else {
                   /* Not a numeric IP address. */
                   /* Look up the host address from the name servers. */
                   hp = gethostbyname(buf);
                   if (!hp) {
                           error("%.100s: unknown host.", buf);
                           goto fail;
                   }
                   if (!hp->h_addr_list[0]) {
                           error("%.100s: host has no IP address.", buf);
                           goto fail;
                   }
                   sin.sin_family = hp->h_addrtype;
                   memcpy(&sin.sin_addr, hp->h_addr_list[0],
                          sizeof(sin.sin_addr));
           }
           /* Set port number. */
           sin.sin_port = htons(6000 + display_number);
   
       /* OK, we now have a connection to the display. */          /* Create a socket. */
       goto success;          sock = socket(sin.sin_family, SOCK_STREAM, 0);
     }          if (sock < 0) {
                   error("socket: %.100s", strerror(errno));
   /* Connect to an inet socket.  The DISPLAY value is supposedly                  goto fail;
       hostname:d[.s], where hostname may also be numeric IP address. */  
   strncpy(buf, display, sizeof(buf));  
   buf[sizeof(buf) - 1] = 0;  
   cp = strchr(buf, ':');  
   if (!cp)  
     {  
       error("Could not find ':' in DISPLAY: %.100s", display);  
       goto fail;  
     }  
   *cp = 0;  
   /* buf now contains the host name.  But first we parse the display number. */  
   if (sscanf(cp + 1, "%d", &display_number) != 1)  
     {  
        error("Could not parse display number from DISPLAY: %.100s",  
              display);  
       goto fail;  
     }  
   
   /* Try to parse the host name as a numeric IP address. */  
   memset(&sin, 0, sizeof(sin));  
   sin.sin_addr.s_addr = inet_addr(buf);  
   if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff)  
     {  
       /* It was a valid numeric host address. */  
       sin.sin_family = AF_INET;  
     }  
   else  
     {  
       /* Not a numeric IP address. */  
       /* Look up the host address from the name servers. */  
       hp = gethostbyname(buf);  
       if (!hp)  
         {  
           error("%.100s: unknown host.", buf);  
           goto fail;  
         }          }
       if (!hp->h_addr_list[0])          /* Connect it to the display. */
         {          if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
           error("%.100s: host has no IP address.", buf);                  error("connect %.100s:%d: %.100s", buf, 6000 + display_number,
           goto fail;                        strerror(errno));
                   close(sock);
                   goto fail;
         }          }
       sin.sin_family = hp->h_addrtype;  success:
       memcpy(&sin.sin_addr, hp->h_addr_list[0],          /* We have successfully obtained a connection to the real X display. */
              sizeof(sin.sin_addr));  
     }  
   /* Set port number. */  
   sin.sin_port = htons(6000 + display_number);  
   
   /* Create a socket. */          /* Allocate a channel for this connection. */
   sock = socket(sin.sin_family, SOCK_STREAM, 0);          if (x11_saved_proto == NULL)
   if (sock < 0)                  newch = channel_allocate(SSH_CHANNEL_OPEN, sock, remote_host);
     {          else
       error("socket: %.100s", strerror(errno));                  newch = channel_allocate(SSH_CHANNEL_X11_OPEN, sock, remote_host);
       goto fail;          channels[newch].remote_id = remote_channel;
     }  
   /* Connect it to the display. */  
   if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)  
     {  
       error("connect %.100s:%d: %.100s", buf, 6000 + display_number,  
             strerror(errno));  
       close(sock);  
       goto fail;  
     }  
   
  success:          /* Send a confirmation to the remote host. */
   /* We have successfully obtained a connection to the real X display. */          packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
           packet_put_int(remote_channel);
   /* Allocate a channel for this connection. */          packet_put_int(newch);
   if (x11_saved_proto == NULL)          packet_send();
     newch = channel_allocate(SSH_CHANNEL_OPEN, sock, remote_host);  
   else  
     newch = channel_allocate(SSH_CHANNEL_X11_OPEN, sock, remote_host);  
   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();  
   
   return;  
   
  fail:          return;
   /* Send refusal to the remote host. */  
   packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);  fail:
   packet_put_int(remote_channel);          /* Send refusal to the remote host. */
   packet_send();          packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
           packet_put_int(remote_channel);
           packet_send();
 }  }
   
 /* Requests forwarding of X11 connections, generates fake authentication  /* Requests forwarding of X11 connections, generates fake authentication
    data, and enables authentication spoofing. */     data, and enables authentication spoofing. */
   
 void x11_request_forwarding_with_spoofing(const char *proto, const char *data)  void
   x11_request_forwarding_with_spoofing(const char *proto, const char *data)
 {  {
   unsigned int data_len = (unsigned int)strlen(data) / 2;          unsigned int data_len = (unsigned int) strlen(data) / 2;
   unsigned int i, value;          unsigned int i, value;
   char *new_data;          char *new_data;
   int screen_number;          int screen_number;
   const char *cp;          const char *cp;
   u_int32_t rand = 0;          u_int32_t rand = 0;
   
   cp = getenv("DISPLAY");          cp = getenv("DISPLAY");
   if (cp)          if (cp)
     cp = strchr(cp, ':');                  cp = strchr(cp, ':');
   if (cp)          if (cp)
     cp = strchr(cp, '.');                  cp = strchr(cp, '.');
   if (cp)          if (cp)
     screen_number = atoi(cp + 1);                  screen_number = atoi(cp + 1);
   else          else
     screen_number = 0;                  screen_number = 0;
   
   /* Save protocol name. */          /* Save protocol name. */
   x11_saved_proto = xstrdup(proto);          x11_saved_proto = xstrdup(proto);
   
   /* Extract real authentication data and generate fake data of the same          /* Extract real authentication data and generate fake data of the
      length. */             same length. */
   x11_saved_data = xmalloc(data_len);          x11_saved_data = xmalloc(data_len);
   x11_fake_data = xmalloc(data_len);          x11_fake_data = xmalloc(data_len);
   for (i = 0; i < data_len; i++)          for (i = 0; i < data_len; i++) {
     {                  if (sscanf(data + 2 * i, "%2x", &value) != 1)
       if (sscanf(data + 2 * i, "%2x", &value) != 1)                          fatal("x11_request_forwarding: bad authentication data: %.100s", data);
         fatal("x11_request_forwarding: bad authentication data: %.100s", data);                  if (i % 4 == 0)
       if (i % 4 == 0)                          rand = arc4random();
         rand = arc4random();                  x11_saved_data[i] = value;
       x11_saved_data[i] = value;                  x11_fake_data[i] = rand & 0xff;
       x11_fake_data[i] = rand & 0xff;                  rand >>= 8;
       rand >>= 8;          }
     }          x11_saved_data_len = data_len;
   x11_saved_data_len = data_len;          x11_fake_data_len = data_len;
   x11_fake_data_len = data_len;  
   
   /* Convert the fake data into hex. */          /* Convert the fake data into hex. */
   new_data = xmalloc(2 * data_len + 1);          new_data = xmalloc(2 * data_len + 1);
   for (i = 0; i < data_len; i++)          for (i = 0; i < data_len; i++)
     sprintf(new_data + 2 * i, "%02x", (unsigned char)x11_fake_data[i]);                  sprintf(new_data + 2 * i, "%02x", (unsigned char) x11_fake_data[i]);
   
   /* Send the request packet. */          /* Send the request packet. */
   packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);          packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);
   packet_put_string(proto, strlen(proto));          packet_put_string(proto, strlen(proto));
   packet_put_string(new_data, strlen(new_data));          packet_put_string(new_data, strlen(new_data));
   packet_put_int(screen_number);          packet_put_int(screen_number);
   packet_send();          packet_send();
   packet_write_wait();          packet_write_wait();
   xfree(new_data);          xfree(new_data);
 }  }
   
 /* Sends a message to the server to request authentication fd forwarding. */  /* Sends a message to the server to request authentication fd forwarding. */
   
 void auth_request_forwarding()  void
   auth_request_forwarding()
 {  {
   packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);          packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);
   packet_send();          packet_send();
   packet_write_wait();          packet_write_wait();
 }  }
   
 /* Returns the name of the forwarded authentication socket.  Returns NULL  /* Returns the name of the forwarded authentication socket.  Returns NULL
    if there is no forwarded authentication socket.  The returned value     if there is no forwarded authentication socket.  The returned value
    points to a static buffer. */     points to a static buffer. */
   
 char *auth_get_socket_name()  char *
   auth_get_socket_name()
 {  {
   return channel_forwarded_auth_socket_name;          return channel_forwarded_auth_socket_name;
 }  }
   
 /* removes the agent forwarding socket */  /* removes the agent forwarding socket */
   
 void cleanup_socket(void) {  void
   remove(channel_forwarded_auth_socket_name);  cleanup_socket(void)
   rmdir(channel_forwarded_auth_socket_dir);  {
           remove(channel_forwarded_auth_socket_name);
           rmdir(channel_forwarded_auth_socket_dir);
 }  }
   
 /* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.  /* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
    This starts forwarding authentication requests. */     This starts forwarding authentication requests. */
   
 void auth_input_request_forwarding(struct passwd *pw)  void
   auth_input_request_forwarding(struct passwd * pw)
 {  {
   int sock, newch;          int sock, newch;
   struct sockaddr_un sunaddr;          struct sockaddr_un sunaddr;
   
   if (auth_get_socket_name() != NULL)  
     fatal("Protocol error: authentication forwarding requested twice.");  
   
   /* Temporarily drop privileged uid for mkdir/bind. */          if (auth_get_socket_name() != NULL)
   temporarily_use_uid(pw->pw_uid);                  fatal("Protocol error: authentication forwarding requested twice.");
   
   /* Allocate a buffer for the socket name, and format the name. */          /* Temporarily drop privileged uid for mkdir/bind. */
   channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME);          temporarily_use_uid(pw->pw_uid);
   channel_forwarded_auth_socket_dir  = xmalloc(MAX_SOCKET_NAME);  
   strlcpy(channel_forwarded_auth_socket_dir, "/tmp/ssh-XXXXXXXX", MAX_SOCKET_NAME);  
   
   /* Create private directory for socket */          /* Allocate a buffer for the socket name, and format the name. */
   if (mkdtemp(channel_forwarded_auth_socket_dir) == NULL)          channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME);
     packet_disconnect("mkdtemp: %.100s", strerror(errno));          channel_forwarded_auth_socket_dir = xmalloc(MAX_SOCKET_NAME);
   snprintf(channel_forwarded_auth_socket_name, MAX_SOCKET_NAME,          strlcpy(channel_forwarded_auth_socket_dir, "/tmp/ssh-XXXXXXXX", MAX_SOCKET_NAME);
            "%s/agent.%d", channel_forwarded_auth_socket_dir, (int)getpid());  
   
   if (atexit(cleanup_socket) < 0) {          /* Create private directory for socket */
     int saved=errno;          if (mkdtemp(channel_forwarded_auth_socket_dir) == NULL)
     cleanup_socket();                  packet_disconnect("mkdtemp: %.100s", strerror(errno));
     packet_disconnect("socket: %.100s", strerror(saved));          snprintf(channel_forwarded_auth_socket_name, MAX_SOCKET_NAME, "%s/agent.%d",
   }                   channel_forwarded_auth_socket_dir, (int) getpid());
   
   /* Create the socket. */          if (atexit(cleanup_socket) < 0) {
   sock = socket(AF_UNIX, SOCK_STREAM, 0);                  int saved = errno;
   if (sock < 0)                  cleanup_socket();
     packet_disconnect("socket: %.100s", strerror(errno));                  packet_disconnect("socket: %.100s", strerror(saved));
           }
           /* Create the socket. */
           sock = socket(AF_UNIX, SOCK_STREAM, 0);
           if (sock < 0)
                   packet_disconnect("socket: %.100s", strerror(errno));
   
   /* Bind it to the name. */          /* Bind it to the name. */
   memset(&sunaddr, 0, sizeof(sunaddr));          memset(&sunaddr, 0, sizeof(sunaddr));
   sunaddr.sun_family = AF_UNIX;          sunaddr.sun_family = AF_UNIX;
   strncpy(sunaddr.sun_path, channel_forwarded_auth_socket_name,          strncpy(sunaddr.sun_path, channel_forwarded_auth_socket_name,
           sizeof(sunaddr.sun_path));                  sizeof(sunaddr.sun_path));
   
   if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)          if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0)
     packet_disconnect("bind: %.100s", strerror(errno));                  packet_disconnect("bind: %.100s", strerror(errno));
   
   /* Restore the privileged uid. */          /* Restore the privileged uid. */
   restore_uid();          restore_uid();
   
   /* Start listening on the socket. */          /* Start listening on the socket. */
   if (listen(sock, 5) < 0)          if (listen(sock, 5) < 0)
     packet_disconnect("listen: %.100s", strerror(errno));                  packet_disconnect("listen: %.100s", strerror(errno));
   
   /* Allocate a channel for the authentication agent socket. */          /* Allocate a channel for the authentication agent socket. */
   newch = channel_allocate(SSH_CHANNEL_AUTH_SOCKET, sock,          newch = channel_allocate(SSH_CHANNEL_AUTH_SOCKET, sock,
                        xstrdup("auth socket"));                                   xstrdup("auth socket"));
   strcpy(channels[newch].path, channel_forwarded_auth_socket_name);          strcpy(channels[newch].path, channel_forwarded_auth_socket_name);
 }  }
   
 /* This is called to process an SSH_SMSG_AGENT_OPEN message. */  /* This is called to process an SSH_SMSG_AGENT_OPEN message. */
   
 void auth_input_open_request()  void
   auth_input_open_request()
 {  {
   int remch, sock, newch;          int remch, sock, newch;
   char *dummyname;          char *dummyname;
   
   /* Read the remote channel number from the message. */          /* Read the remote channel number from the message. */
   remch = packet_get_int();          remch = packet_get_int();
   
   /* Get a connection to the local authentication agent (this may again get  
      forwarded). */  
   sock = ssh_get_authentication_socket();  
   
   /* If we could not connect the agent, send an error message back to          /* Get a connection to the local authentication agent (this may
      the server. This should never happen unless the agent             again get forwarded). */
      dies, because authentication forwarding is only enabled if we have an          sock = ssh_get_authentication_socket();
      agent. */  
   if (sock < 0){  
     packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);  
     packet_put_int(remch);  
     packet_send();  
     return;  
   }  
   
   debug("Forwarding authentication connection.");          /* If we could not connect the agent, send an error message back
              to the server. This should never happen unless the agent dies,
              because authentication forwarding is only enabled if we have an
              agent. */
           if (sock < 0) {
                   packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
                   packet_put_int(remch);
                   packet_send();
                   return;
           }
           debug("Forwarding authentication connection.");
   
   /* Dummy host name.  This will be freed when the channel is freed; it will          /* Dummy host name.  This will be freed when the channel is freed;
      still be valid in the packet_put_string below since the channel cannot             it will still be valid in the packet_put_string below since the
      yet be freed at that point. */             channel cannot yet be freed at that point. */
   dummyname = xstrdup("authentication agent connection");          dummyname = xstrdup("authentication agent connection");
   
   newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname);          newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname);
   channels[newch].remote_id = remch;          channels[newch].remote_id = remch;
   
   /* Send a confirmation to the remote host. */          /* Send a confirmation to the remote host. */
   packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);          packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
   packet_put_int(remch);          packet_put_int(remch);
   packet_put_int(newch);          packet_put_int(newch);
   packet_send();          packet_send();
 }  }

Legend:
Removed from v.1.24  
changed lines
  Added in v.1.25