[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.223 and 1.223.2.2

version 1.223, 2005/07/17 07:17:54 version 1.223.2.2, 2006/10/06 03:19:32
Line 1 
Line 1 
   /* $OpenBSD$ */
 /*  /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>   * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland   * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Line 38 
Line 39 
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */   */
   
 #include "includes.h"  #include <sys/types.h>
 RCSID("$OpenBSD$");  #include <sys/ioctl.h>
   #include <sys/un.h>
   #include <sys/socket.h>
   #include <sys/time.h>
   
   #include <netinet/in.h>
   #include <arpa/inet.h>
   
   #include <errno.h>
   #include <netdb.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <termios.h>
   #include <unistd.h>
   #include <stdarg.h>
   
   #include "xmalloc.h"
 #include "ssh.h"  #include "ssh.h"
 #include "ssh1.h"  #include "ssh1.h"
 #include "ssh2.h"  #include "ssh2.h"
 #include "packet.h"  #include "packet.h"
 #include "xmalloc.h"  
 #include "log.h"  #include "log.h"
 #include "misc.h"  #include "misc.h"
   #include "buffer.h"
 #include "channels.h"  #include "channels.h"
 #include "compat.h"  #include "compat.h"
 #include "canohost.h"  #include "canohost.h"
 #include "key.h"  #include "key.h"
 #include "authfd.h"  #include "authfd.h"
 #include "pathnames.h"  #include "pathnames.h"
 #include "bufaux.h"  
   
 /* -- channel core */  /* -- channel core */
   
 #define CHAN_RBUF       16*1024  
   
 /*  /*
  * Pointer to an array containing all allocated channels.  The array is   * Pointer to an array containing all allocated channels.  The array is
  * dynamically extended as needed.   * dynamically extended as needed.
Line 93 
Line 107 
         u_short listen_port;            /* Remote side should listen port number. */          u_short listen_port;            /* Remote side should listen port number. */
 } ForwardPermission;  } ForwardPermission;
   
 /* List of all permitted host/port pairs to connect. */  /* List of all permitted host/port pairs to connect by the user. */
 static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];  static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
   
 /* Number of permitted host/port pairs in the array. */  /* List of all permitted host/port pairs to connect by the admin. */
   static ForwardPermission permitted_adm_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
   
   /* Number of permitted host/port pairs in the array permitted by the user. */
 static int num_permitted_opens = 0;  static int num_permitted_opens = 0;
   
   /* Number of permitted host/port pair in the array permitted by the admin. */
   static int num_adm_permitted_opens = 0;
   
 /*  /*
  * If this is true, all opens are permitted.  This is the case on the server   * If this is true, all opens are permitted.  This is the case on the server
  * on which we have to trust the client anyway, and the user could do   * on which we have to trust the client anyway, and the user could do
Line 125 
Line 146 
  * Fake X11 authentication data.  This is what the server will be sending us;   * Fake X11 authentication data.  This is what the server will be sending us;
  * we should replace any occurrences of this by the real data.   * we should replace any occurrences of this by the real data.
  */   */
 static char *x11_fake_data = NULL;  static u_char *x11_fake_data = NULL;
 static u_int x11_fake_data_len;  static u_int x11_fake_data_len;
   
   
Line 142 
Line 163 
 /* -- channel core */  /* -- channel core */
   
 Channel *  Channel *
 channel_lookup(int id)  channel_by_id(int id)
 {  {
         Channel *c;          Channel *c;
   
         if (id < 0 || (u_int)id >= channels_alloc) {          if (id < 0 || (u_int)id >= channels_alloc) {
                 logit("channel_lookup: %d: bad id", id);                  logit("channel_by_id: %d: bad id", id);
                 return NULL;                  return NULL;
         }          }
         c = channels[id];          c = channels[id];
         if (c == NULL) {          if (c == NULL) {
                 logit("channel_lookup: %d: bad id: channel free", id);                  logit("channel_by_id: %d: bad id: channel free", id);
                 return NULL;                  return NULL;
         }          }
         return c;          return c;
 }  }
   
 /*  /*
    * Returns the channel if it is allowed to receive protocol messages.
    * Private channels, like listening sockets, may not receive messages.
    */
   Channel *
   channel_lookup(int id)
   {
           Channel *c;
   
           if ((c = channel_by_id(id)) == NULL)
                   return (NULL);
   
           switch (c->type) {
           case SSH_CHANNEL_X11_OPEN:
           case SSH_CHANNEL_LARVAL:
           case SSH_CHANNEL_CONNECTING:
           case SSH_CHANNEL_DYNAMIC:
           case SSH_CHANNEL_OPENING:
           case SSH_CHANNEL_OPEN:
           case SSH_CHANNEL_INPUT_DRAINING:
           case SSH_CHANNEL_OUTPUT_DRAINING:
                   return (c);
           }
           logit("Non-public channel %d, type %d.", id, c->type);
           return (NULL);
   }
   
   /*
  * Register filedescriptors for a channel, used when allocating a channel or   * Register filedescriptors for a channel, used when allocating a channel or
  * when the channel consumer/producer is ready, e.g. shell exec'd   * when the channel consumer/producer is ready, e.g. shell exec'd
  */   */
   
 static void  static void
 channel_register_fds(Channel *c, int rfd, int wfd, int efd,  channel_register_fds(Channel *c, int rfd, int wfd, int efd,
     int extusage, int nonblock)      int extusage, int nonblock)
Line 208 
Line 255 
  * Allocate a new channel object and set its type and socket. This will cause   * Allocate a new channel object and set its type and socket. This will cause
  * remote_name to be freed.   * remote_name to be freed.
  */   */
   
 Channel *  Channel *
 channel_new(char *ctype, int type, int rfd, int wfd, int efd,  channel_new(char *ctype, int type, int rfd, int wfd, int efd,
     u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock)      u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock)
Line 220 
Line 266 
         /* 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 = xcalloc(channels_alloc, sizeof(Channel *));
                 for (i = 0; i < channels_alloc; i++)                  for (i = 0; i < channels_alloc; i++)
                         channels[i] = NULL;                          channels[i] = NULL;
         }          }
Line 237 
Line 283 
                 if (channels_alloc > 10000)                  if (channels_alloc > 10000)
                         fatal("channel_new: internal error: channels_alloc %d "                          fatal("channel_new: internal error: channels_alloc %d "
                             "too big.", channels_alloc);                              "too big.", channels_alloc);
                 channels = xrealloc(channels,                  channels = xrealloc(channels, channels_alloc + 10,
                     (channels_alloc + 10) * sizeof(Channel *));                      sizeof(Channel *));
                 channels_alloc += 10;                  channels_alloc += 10;
                 debug2("channel: expanding %d", channels_alloc);                  debug2("channel: expanding %d", channels_alloc);
                 for (i = found; i < channels_alloc; i++)                  for (i = found; i < channels_alloc; i++)
                         channels[i] = NULL;                          channels[i] = NULL;
         }          }
         /* Initialize and return new channel. */          /* Initialize and return new channel. */
         c = channels[found] = xmalloc(sizeof(Channel));          c = channels[found] = xcalloc(1, sizeof(Channel));
         memset(c, 0, sizeof(Channel));  
         buffer_init(&c->input);          buffer_init(&c->input);
         buffer_init(&c->output);          buffer_init(&c->output);
         buffer_init(&c->extended);          buffer_init(&c->extended);
Line 268 
Line 313 
         c->force_drain = 0;          c->force_drain = 0;
         c->single_connection = 0;          c->single_connection = 0;
         c->detach_user = NULL;          c->detach_user = NULL;
           c->detach_close = 0;
         c->confirm = NULL;          c->confirm = NULL;
         c->confirm_ctx = NULL;          c->confirm_ctx = NULL;
         c->input_filter = NULL;          c->input_filter = NULL;
           c->output_filter = NULL;
         debug("channel %d: new [%s]", found, remote_name);          debug("channel %d: new [%s]", found, remote_name);
         return c;          return c;
 }  }
Line 308 
Line 355 
 }  }
   
 /* Close all channel fd/socket. */  /* Close all channel fd/socket. */
   
 static void  static void
 channel_close_fds(Channel *c)  channel_close_fds(Channel *c)
 {  {
Line 323 
Line 369 
 }  }
   
 /* Free the channel and close its fd/socket. */  /* Free the channel and close its fd/socket. */
   
 void  void
 channel_free(Channel *c)  channel_free(Channel *c)
 {  {
Line 370 
Line 415 
  * Closes the sockets/fds of all channels.  This is used to close extra file   * Closes the sockets/fds of all channels.  This is used to close extra file
  * descriptors after a fork.   * descriptors after a fork.
  */   */
   
 void  void
 channel_close_all(void)  channel_close_all(void)
 {  {
Line 384 
Line 428 
 /*  /*
  * Stop listening to channels.   * Stop listening to channels.
  */   */
   
 void  void
 channel_stop_listening(void)  channel_stop_listening(void)
 {  {
Line 411 
Line 454 
  * Returns true if no channel has too much buffered data, and false if one or   * Returns true if no channel has too much buffered data, and false if one or
  * more channel is overfull.   * more channel is overfull.
  */   */
   
 int  int
 channel_not_very_much_buffered_data(void)  channel_not_very_much_buffered_data(void)
 {  {
Line 441 
Line 483 
 }  }
   
 /* Returns true if any channel is still open. */  /* Returns true if any channel is still open. */
   
 int  int
 channel_still_open(void)  channel_still_open(void)
 {  {
Line 484 
Line 525 
 }  }
   
 /* Returns the id of an open channel suitable for keepaliving */  /* Returns the id of an open channel suitable for keepaliving */
   
 int  int
 channel_find_open(void)  channel_find_open(void)
 {  {
Line 529 
Line 569 
  * suitable for sending to the client.  The message contains crlf pairs for   * suitable for sending to the client.  The message contains crlf pairs for
  * newlines.   * newlines.
  */   */
   
 char *  char *
 channel_open_message(void)  channel_open_message(void)
 {  {
Line 614 
Line 653 
         packet_put_cstring(service);          packet_put_cstring(service);
         packet_put_char(wantconfirm);          packet_put_char(wantconfirm);
 }  }
   
 void  void
 channel_register_confirm(int id, channel_callback_fn *fn, void *ctx)  channel_register_confirm(int id, channel_callback_fn *fn, void *ctx)
 {  {
Line 626 
Line 666 
         c->confirm = fn;          c->confirm = fn;
         c->confirm_ctx = ctx;          c->confirm_ctx = ctx;
 }  }
   
 void  void
 channel_register_cleanup(int id, channel_callback_fn *fn)  channel_register_cleanup(int id, channel_callback_fn *fn, int do_close)
 {  {
         Channel *c = channel_lookup(id);          Channel *c = channel_by_id(id);
   
         if (c == NULL) {          if (c == NULL) {
                 logit("channel_register_cleanup: %d: bad id", id);                  logit("channel_register_cleanup: %d: bad id", id);
                 return;                  return;
         }          }
         c->detach_user = fn;          c->detach_user = fn;
           c->detach_close = do_close;
 }  }
   
 void  void
 channel_cancel_cleanup(int id)  channel_cancel_cleanup(int id)
 {  {
         Channel *c = channel_lookup(id);          Channel *c = channel_by_id(id);
   
         if (c == NULL) {          if (c == NULL) {
                 logit("channel_cancel_cleanup: %d: bad id", id);                  logit("channel_cancel_cleanup: %d: bad id", id);
                 return;                  return;
         }          }
         c->detach_user = NULL;          c->detach_user = NULL;
           c->detach_close = 0;
 }  }
   
 void  void
 channel_register_filter(int id, channel_filter_fn *fn)  channel_register_filter(int id, channel_infilter_fn *ifn,
       channel_outfilter_fn *ofn)
 {  {
         Channel *c = channel_lookup(id);          Channel *c = channel_lookup(id);
   
Line 657 
Line 703 
                 logit("channel_register_filter: %d: bad id", id);                  logit("channel_register_filter: %d: bad id", id);
                 return;                  return;
         }          }
         c->input_filter = fn;          c->input_filter = ifn;
           c->output_filter = ofn;
 }  }
   
 void  void
Line 685 
Line 732 
  * 'channel_post*': perform any appropriate operations for channels which   * 'channel_post*': perform any appropriate operations for channels which
  * have events pending.   * have events pending.
  */   */
 typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset);  typedef void chan_fn(Channel *c, fd_set *readset, fd_set *writeset);
 chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];  chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
 chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];  chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
   
   /* ARGSUSED */
 static void  static void
 channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset)  channel_pre_listener(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         FD_SET(c->sock, readset);          FD_SET(c->sock, readset);
 }  }
   
   /* ARGSUSED */
 static void  static void
 channel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset)  channel_pre_connecting(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         debug3("channel %d: waiting for connection", c->self);          debug3("channel %d: waiting for connection", c->self);
         FD_SET(c->sock, writeset);          FD_SET(c->sock, writeset);
 }  }
   
 static void  static void
 channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset)  channel_pre_open_13(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         if (buffer_len(&c->input) < packet_get_maxsize())          if (buffer_len(&c->input) < packet_get_maxsize())
                 FD_SET(c->sock, readset);                  FD_SET(c->sock, readset);
Line 712 
Line 761 
 }  }
   
 static void  static void
 channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset)  channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         u_int limit = compat20 ? c->remote_window : packet_get_maxsize();          u_int limit = compat20 ? c->remote_window : packet_get_maxsize();
   
         /* check buffer limits */  
         limit = MIN(limit, (BUFFER_MAX_LEN - BUFFER_MAX_CHUNK - CHAN_RBUF));  
   
         if (c->istate == CHAN_INPUT_OPEN &&          if (c->istate == CHAN_INPUT_OPEN &&
             limit > 0 &&              limit > 0 &&
             buffer_len(&c->input) < limit)              buffer_len(&c->input) < limit &&
               buffer_check_alloc(&c->input, CHAN_RBUF))
                 FD_SET(c->rfd, readset);                  FD_SET(c->rfd, readset);
         if (c->ostate == CHAN_OUTPUT_OPEN ||          if (c->ostate == CHAN_OUTPUT_OPEN ||
             c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {              c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
Line 751 
Line 798 
                 FD_SET(c->ctl_fd, readset);                  FD_SET(c->ctl_fd, readset);
 }  }
   
   /* ARGSUSED */
 static void  static void
 channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset)  channel_pre_input_draining(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         if (buffer_len(&c->input) == 0) {          if (buffer_len(&c->input) == 0) {
                 packet_start(SSH_MSG_CHANNEL_CLOSE);                  packet_start(SSH_MSG_CHANNEL_CLOSE);
Line 763 
Line 811 
         }          }
 }  }
   
   /* ARGSUSED */
 static void  static void
 channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset)  channel_pre_output_draining(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         if (buffer_len(&c->output) == 0)          if (buffer_len(&c->output) == 0)
                 chan_mark_dead(c);                  chan_mark_dead(c);
Line 840 
Line 889 
 }  }
   
 static void  static void
 channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset)  channel_pre_x11_open_13(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         int ret = x11_open_helper(&c->output);          int ret = x11_open_helper(&c->output);
   
Line 866 
Line 915 
 }  }
   
 static void  static void
 channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset)  channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         int ret = x11_open_helper(&c->output);          int ret = x11_open_helper(&c->output);
   
Line 892 
Line 941 
 }  }
   
 /* try to decode a socks4 header */  /* try to decode a socks4 header */
   /* ARGSUSED */
 static int  static int
 channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)  channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         char *p, *host;          char *p, *host;
         u_int len, have, i, found;          u_int len, have, i, found;
Line 957 
Line 1007 
         s4_rsp.command = 90;                    /* cd: req granted */          s4_rsp.command = 90;                    /* cd: req granted */
         s4_rsp.dest_port = 0;                   /* ignored */          s4_rsp.dest_port = 0;                   /* ignored */
         s4_rsp.dest_addr.s_addr = INADDR_ANY;   /* ignored */          s4_rsp.dest_addr.s_addr = INADDR_ANY;   /* ignored */
         buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp));          buffer_append(&c->output, &s4_rsp, sizeof(s4_rsp));
         return 1;          return 1;
 }  }
   
Line 970 
Line 1020 
 #define SSH_SOCKS5_CONNECT      0x01  #define SSH_SOCKS5_CONNECT      0x01
 #define SSH_SOCKS5_SUCCESS      0x00  #define SSH_SOCKS5_SUCCESS      0x00
   
   /* ARGSUSED */
 static int  static int
 channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset)  channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         struct {          struct {
                 u_int8_t version;                  u_int8_t version;
Line 981 
Line 1032 
         } s5_req, s5_rsp;          } s5_req, s5_rsp;
         u_int16_t dest_port;          u_int16_t dest_port;
         u_char *p, dest_addr[255+1];          u_char *p, dest_addr[255+1];
         u_int have, i, found, nmethods, addrlen, af;          u_int have, need, i, found, nmethods, addrlen, af;
   
         debug2("channel %d: decode socks5", c->self);          debug2("channel %d: decode socks5", c->self);
         p = buffer_ptr(&c->input);          p = buffer_ptr(&c->input);
Line 997 
Line 1048 
                         return 0;                          return 0;
                 /* look for method: "NO AUTHENTICATION REQUIRED" */                  /* look for method: "NO AUTHENTICATION REQUIRED" */
                 for (found = 0, i = 2 ; i < nmethods + 2; i++) {                  for (found = 0, i = 2 ; i < nmethods + 2; i++) {
                         if (p[i] == SSH_SOCKS5_NOAUTH ) {                          if (p[i] == SSH_SOCKS5_NOAUTH) {
                                 found = 1;                                  found = 1;
                                 break;                                  break;
                         }                          }
Line 1018 
Line 1069 
         debug2("channel %d: socks5 post auth", c->self);          debug2("channel %d: socks5 post auth", c->self);
         if (have < sizeof(s5_req)+1)          if (have < sizeof(s5_req)+1)
                 return 0;                       /* need more */                  return 0;                       /* need more */
         memcpy((char *)&s5_req, p, sizeof(s5_req));          memcpy(&s5_req, p, sizeof(s5_req));
         if (s5_req.version != 0x05 ||          if (s5_req.version != 0x05 ||
             s5_req.command != SSH_SOCKS5_CONNECT ||              s5_req.command != SSH_SOCKS5_CONNECT ||
             s5_req.reserved != 0x00) {              s5_req.reserved != 0x00) {
Line 1042 
Line 1093 
                 debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);                  debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);
                 return -1;                  return -1;
         }          }
         if (have < 4 + addrlen + 2)          need = sizeof(s5_req) + addrlen + 2;
           if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
                   need++;
           if (have < need)
                 return 0;                  return 0;
         buffer_consume(&c->input, sizeof(s5_req));          buffer_consume(&c->input, sizeof(s5_req));
         if (s5_req.atyp == SSH_SOCKS5_DOMAIN)          if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
Line 1066 
Line 1120 
         ((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY;          ((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY;
         dest_port = 0;                          /* ignored */          dest_port = 0;                          /* ignored */
   
         buffer_append(&c->output, (char *)&s5_rsp, sizeof(s5_rsp));          buffer_append(&c->output, &s5_rsp, sizeof(s5_rsp));
         buffer_append(&c->output, (char *)&dest_addr, sizeof(struct in_addr));          buffer_append(&c->output, &dest_addr, sizeof(struct in_addr));
         buffer_append(&c->output, (char *)&dest_port, sizeof(dest_port));          buffer_append(&c->output, &dest_port, sizeof(dest_port));
         return 1;          return 1;
 }  }
   
 /* dynamic port forwarding */  /* dynamic port forwarding */
 static void  static void
 channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)  channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         u_char *p;          u_char *p;
         u_int have;          u_int have;
Line 1117 
Line 1171 
 }  }
   
 /* This is our fake X11 server socket. */  /* This is our fake X11 server socket. */
   /* ARGSUSED */
 static void  static void
 channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)  channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         Channel *nc;          Channel *nc;
         struct sockaddr addr;          struct sockaddr addr;
Line 1226 
Line 1281 
         xfree(remote_ipaddr);          xfree(remote_ipaddr);
 }  }
   
   static void
   channel_set_reuseaddr(int fd)
   {
           int on = 1;
   
           /*
            * Set socket options.
            * Allow local port reuse in TIME_WAIT.
            */
           if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
                   error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
   }
   
 /*  /*
  * This socket is listening for connections to a forwarded TCP/IP port.   * This socket is listening for connections to a forwarded TCP/IP port.
  */   */
   /* ARGSUSED */
 static void  static void
 channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)  channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         Channel *nc;          Channel *nc;
         struct sockaddr addr;          struct sockaddr addr;
Line 1286 
Line 1355 
  * This is the authentication agent socket listening for connections from   * This is the authentication agent socket listening for connections from
  * clients.   * clients.
  */   */
   /* ARGSUSED */
 static void  static void
 channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset)  channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         Channel *nc;          Channel *nc;
         int newsock;          int newsock;
Line 1319 
Line 1389 
         }          }
 }  }
   
   /* ARGSUSED */
 static void  static void
 channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset)  channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         int err = 0;          int err = 0;
         socklen_t sz = sizeof(err);          socklen_t sz = sizeof(err);
Line 1365 
Line 1436 
         }          }
 }  }
   
   /* ARGSUSED */
 static int  static int
 channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)  channel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         char buf[CHAN_RBUF];          char buf[CHAN_RBUF];
         int len;          int len;
Line 1397 
Line 1469 
                                 debug2("channel %d: filter stops", c->self);                                  debug2("channel %d: filter stops", c->self);
                                 chan_read_failed(c);                                  chan_read_failed(c);
                         }                          }
                   } else if (c->datagram) {
                           buffer_put_string(&c->input, buf, len);
                 } else {                  } else {
                         buffer_append(&c->input, buf, len);                          buffer_append(&c->input, buf, len);
                 }                  }
         }          }
         return 1;          return 1;
 }  }
   
   /* ARGSUSED */
 static int  static int
 channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)  channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         struct termios tio;          struct termios tio;
         u_char *data;          u_char *data = NULL, *buf;
         u_int dlen;          u_int dlen;
         int len;          int len;
   
Line 1415 
Line 1491 
         if (c->wfd != -1 &&          if (c->wfd != -1 &&
             FD_ISSET(c->wfd, writeset) &&              FD_ISSET(c->wfd, writeset) &&
             buffer_len(&c->output) > 0) {              buffer_len(&c->output) > 0) {
                 data = buffer_ptr(&c->output);                  if (c->output_filter != NULL) {
                 dlen = buffer_len(&c->output);                          if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
                 len = write(c->wfd, data, dlen);                                  debug2("channel %d: filter stops", c->self);
                                   if (c->type != SSH_CHANNEL_OPEN)
                                           chan_mark_dead(c);
                                   else
                                           chan_write_failed(c);
                                   return -1;
                           }
                   } else if (c->datagram) {
                           buf = data = buffer_get_string(&c->output, &dlen);
                   } else {
                           buf = data = buffer_ptr(&c->output);
                           dlen = buffer_len(&c->output);
                   }
   
                   if (c->datagram) {
                           /* ignore truncated writes, datagrams might get lost */
                           c->local_consumed += dlen + 4;
                           len = write(c->wfd, buf, dlen);
                           xfree(data);
                           if (len < 0 && (errno == EINTR || errno == EAGAIN))
                                   return 1;
                           if (len <= 0) {
                                   if (c->type != SSH_CHANNEL_OPEN)
                                           chan_mark_dead(c);
                                   else
                                           chan_write_failed(c);
                                   return -1;
                           }
                           return 1;
                   }
   
                   len = write(c->wfd, buf, dlen);
                 if (len < 0 && (errno == EINTR || errno == EAGAIN))                  if (len < 0 && (errno == EINTR || errno == EAGAIN))
                         return 1;                          return 1;
                 if (len <= 0) {                  if (len <= 0) {
Line 1434 
Line 1541 
                         }                          }
                         return -1;                          return -1;
                 }                  }
                 if (compat20 && c->isatty && dlen >= 1 && data[0] != '\r') {                  if (compat20 && c->isatty && dlen >= 1 && buf[0] != '\r') {
                         if (tcgetattr(c->wfd, &tio) == 0 &&                          if (tcgetattr(c->wfd, &tio) == 0 &&
                             !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {                              !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
                                 /*                                  /*
                                  * Simulate echo to reduce the impact of                                   * Simulate echo to reduce the impact of
                                  * traffic analysis. We need to match the                                   * traffic analysis. We need to match the
                                  * size of a SSH2_MSG_CHANNEL_DATA message                                   * size of a SSH2_MSG_CHANNEL_DATA message
                                  * (4 byte channel id + data)                                   * (4 byte channel id + buf)
                                  */                                   */
                                 packet_send_ignore(4 + len);                                  packet_send_ignore(4 + len);
                                 packet_send();                                  packet_send();
Line 1454 
Line 1561 
         }          }
         return 1;          return 1;
 }  }
   
 static int  static int
 channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)  channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         char buf[CHAN_RBUF];          char buf[CHAN_RBUF];
         int len;          int len;
Line 1497 
Line 1605 
         }          }
         return 1;          return 1;
 }  }
   
   /* ARGSUSED */
 static int  static int
 channel_handle_ctl(Channel *c, fd_set * readset, fd_set * writeset)  channel_handle_ctl(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         char buf[16];          char buf[16];
         int len;          int len;
Line 1524 
Line 1634 
         }          }
         return 1;          return 1;
 }  }
   
 static int  static int
 channel_check_window(Channel *c)  channel_check_window(Channel *c)
 {  {
Line 1545 
Line 1656 
 }  }
   
 static void  static void
 channel_post_open(Channel *c, fd_set * readset, fd_set * writeset)  channel_post_open(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         if (c->delayed)          if (c->delayed)
                 return;                  return;
Line 1558 
Line 1669 
         channel_check_window(c);          channel_check_window(c);
 }  }
   
   /* ARGSUSED */
 static void  static void
 channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)  channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset)
 {  {
         int len;          int len;
   
Line 1660 
Line 1772 
         if (c == NULL)          if (c == NULL)
                 return;                  return;
         if (c->detach_user != NULL) {          if (c->detach_user != NULL) {
                 if (!chan_is_dead(c, 0))                  if (!chan_is_dead(c, c->detach_close))
                         return;                          return;
                 debug2("channel %d: gc: notify user", c->self);                  debug2("channel %d: gc: notify user", c->self);
                 c->detach_user(c->self, NULL);                  c->detach_user(c->self, NULL);
Line 1676 
Line 1788 
 }  }
   
 static void  static void
 channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset)  channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
 {  {
         static int did_init = 0;          static int did_init = 0;
         u_int i;          u_int i;
Line 1704 
Line 1816 
 channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,  channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
     u_int *nallocp, int rekeying)      u_int *nallocp, int rekeying)
 {  {
         u_int n, sz;          u_int n, sz, nfdset;
   
         n = MAX(*maxfdp, channel_max_fd);          n = MAX(*maxfdp, channel_max_fd);
   
         sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);          nfdset = howmany(n+1, NFDBITS);
           /* Explicitly test here, because xrealloc isn't always called */
           if (nfdset && SIZE_T_MAX / nfdset < sizeof(fd_mask))
                   fatal("channel_prepare_select: max_fd (%d) is too large", n);
           sz = nfdset * sizeof(fd_mask);
   
         /* perhaps check sz < nalloc/2 and shrink? */          /* perhaps check sz < nalloc/2 and shrink? */
         if (*readsetp == NULL || sz > *nallocp) {          if (*readsetp == NULL || sz > *nallocp) {
                 *readsetp = xrealloc(*readsetp, sz);                  *readsetp = xrealloc(*readsetp, nfdset, sizeof(fd_mask));
                 *writesetp = xrealloc(*writesetp, sz);                  *writesetp = xrealloc(*writesetp, nfdset, sizeof(fd_mask));
                 *nallocp = sz;                  *nallocp = sz;
         }          }
         *maxfdp = n;          *maxfdp = n;
Line 1728 
Line 1845 
  * events pending.   * events pending.
  */   */
 void  void
 channel_after_select(fd_set * readset, fd_set * writeset)  channel_after_select(fd_set *readset, fd_set *writeset)
 {  {
         channel_handler(channel_post, readset, writeset);          channel_handler(channel_post, readset, writeset);
 }  }
   
   
 /* If there is data to send to the connection, enqueue some of it now. */  /* If there is data to send to the connection, enqueue some of it now. */
   
 void  void
 channel_output_poll(void)  channel_output_poll(void)
 {  {
Line 1770 
Line 1886 
                 if ((c->istate == CHAN_INPUT_OPEN ||                  if ((c->istate == CHAN_INPUT_OPEN ||
                     c->istate == CHAN_INPUT_WAIT_DRAIN) &&                      c->istate == CHAN_INPUT_WAIT_DRAIN) &&
                     (len = buffer_len(&c->input)) > 0) {                      (len = buffer_len(&c->input)) > 0) {
                           if (c->datagram) {
                                   if (len > 0) {
                                           u_char *data;
                                           u_int dlen;
   
                                           data = buffer_get_string(&c->input,
                                               &dlen);
                                           packet_start(SSH2_MSG_CHANNEL_DATA);
                                           packet_put_int(c->remote_id);
                                           packet_put_string(data, dlen);
                                           packet_send();
                                           c->remote_window -= dlen + 4;
                                           xfree(data);
                                   }
                                   continue;
                           }
                         /*                          /*
                          * Send some data for the other side over the secure                           * Send some data for the other side over the secure
                          * connection.                           * connection.
Line 1840 
Line 1972 
   
 /* -- protocol input */  /* -- protocol input */
   
   /* ARGSUSED */
 void  void
 channel_input_data(int type, u_int32_t seq, void *ctxt)  channel_input_data(int type, u_int32_t seq, void *ctxt)
 {  {
Line 1892 
Line 2025 
                 c->local_window -= data_len;                  c->local_window -= data_len;
         }          }
         packet_check_eom();          packet_check_eom();
         buffer_append(&c->output, data, data_len);          if (c->datagram)
                   buffer_put_string(&c->output, data, data_len);
           else
                   buffer_append(&c->output, data, data_len);
         xfree(data);          xfree(data);
 }  }
   
   /* ARGSUSED */
 void  void
 channel_input_extended_data(int type, u_int32_t seq, void *ctxt)  channel_input_extended_data(int type, u_int32_t seq, void *ctxt)
 {  {
Line 1942 
Line 2079 
         xfree(data);          xfree(data);
 }  }
   
   /* ARGSUSED */
 void  void
 channel_input_ieof(int type, u_int32_t seq, void *ctxt)  channel_input_ieof(int type, u_int32_t seq, void *ctxt)
 {  {
Line 1965 
Line 2103 
   
 }  }
   
   /* ARGSUSED */
 void  void
 channel_input_close(int type, u_int32_t seq, void *ctxt)  channel_input_close(int type, u_int32_t seq, void *ctxt)
 {  {
Line 2003 
Line 2142 
 }  }
   
 /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */  /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
   /* ARGSUSED */
 void  void
 channel_input_oclose(int type, u_int32_t seq, void *ctxt)  channel_input_oclose(int type, u_int32_t seq, void *ctxt)
 {  {
Line 2015 
Line 2155 
         chan_rcvd_oclose(c);          chan_rcvd_oclose(c);
 }  }
   
   /* ARGSUSED */
 void  void
 channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)  channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)
 {  {
Line 2031 
Line 2172 
         channel_free(c);          channel_free(c);
 }  }
   
   /* ARGSUSED */
 void  void
 channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)  channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
 {  {
Line 2078 
Line 2220 
         return "unknown reason";          return "unknown reason";
 }  }
   
   /* ARGSUSED */
 void  void
 channel_input_open_failure(int type, u_int32_t seq, void *ctxt)  channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
 {  {
Line 2109 
Line 2252 
         channel_free(c);          channel_free(c);
 }  }
   
   /* ARGSUSED */
 void  void
 channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)  channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
 {  {
Line 2123 
Line 2267 
         id = packet_get_int();          id = packet_get_int();
         c = channel_lookup(id);          c = channel_lookup(id);
   
         if (c == NULL || c->type != SSH_CHANNEL_OPEN) {          if (c == NULL) {
                 logit("Received window adjust for "                  logit("Received window adjust for non-open channel %d.", id);
                     "non-open channel %d.", id);  
                 return;                  return;
         }          }
         adjust = packet_get_int();          adjust = packet_get_int();
Line 2134 
Line 2277 
         c->remote_window += adjust;          c->remote_window += adjust;
 }  }
   
   /* ARGSUSED */
 void  void
 channel_input_port_open(int type, u_int32_t seq, void *ctxt)  channel_input_port_open(int type, u_int32_t seq, void *ctxt)
 {  {
Line 2182 
Line 2326 
     const char *host_to_connect, u_short port_to_connect, int gateway_ports)      const char *host_to_connect, u_short port_to_connect, int gateway_ports)
 {  {
         Channel *c;          Channel *c;
         int sock, r, success = 0, on = 1, wildcard = 0, is_client;          int sock, r, success = 0, wildcard = 0, is_client;
         struct addrinfo hints, *ai, *aitop;          struct addrinfo hints, *ai, *aitop;
         const char *host, *addr;          const char *host, *addr;
         char ntop[NI_MAXHOST], strport[NI_MAXSERV];          char ntop[NI_MAXHOST], strport[NI_MAXSERV];
Line 2269 
Line 2413 
                         verbose("socket: %.100s", strerror(errno));                          verbose("socket: %.100s", strerror(errno));
                         continue;                          continue;
                 }                  }
                 /*  
                  * Set socket options.  
                  * Allow local port reuse in TIME_WAIT.  
                  */  
                 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on,  
                     sizeof(on)) == -1)  
                         error("setsockopt SO_REUSEADDR: %s", strerror(errno));  
   
                   channel_set_reuseaddr(sock);
   
                 debug("Local forwarding listening on %s port %s.", ntop, strport);                  debug("Local forwarding listening on %s port %s.", ntop, strport);
   
                 /* Bind the socket to the address. */                  /* Bind the socket to the address. */
Line 2353 
Line 2492 
  * the secure channel to host:port from local side.   * the secure channel to host:port from local side.
  */   */
   
 void  int
 channel_request_remote_forwarding(const char *listen_host, u_short listen_port,  channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
     const char *host_to_connect, u_short port_to_connect)      const char *host_to_connect, u_short port_to_connect)
 {  {
Line 2397 
Line 2536 
                         success = 1;                          success = 1;
                         break;                          break;
                 case SSH_SMSG_FAILURE:                  case SSH_SMSG_FAILURE:
                         logit("Warning: Server denied remote port forwarding.");  
                         break;                          break;
                 default:                  default:
                         /* Unknown packet */                          /* Unknown packet */
Line 2411 
Line 2549 
                 permitted_opens[num_permitted_opens].listen_port = listen_port;                  permitted_opens[num_permitted_opens].listen_port = listen_port;
                 num_permitted_opens++;                  num_permitted_opens++;
         }          }
           return (success ? 0 : -1);
 }  }
   
 /*  /*
Line 2443 
Line 2582 
   
         permitted_opens[i].listen_port = 0;          permitted_opens[i].listen_port = 0;
         permitted_opens[i].port_to_connect = 0;          permitted_opens[i].port_to_connect = 0;
         free(permitted_opens[i].host_to_connect);          xfree(permitted_opens[i].host_to_connect);
         permitted_opens[i].host_to_connect = NULL;          permitted_opens[i].host_to_connect = NULL;
 }  }
   
 /*  /*
  * 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 error.   * message if there was an error).
  */   */
   int
 void  
 channel_input_port_forward_request(int is_root, int gateway_ports)  channel_input_port_forward_request(int is_root, int gateway_ports)
 {  {
         u_short port, host_port;          u_short port, host_port;
           int success = 0;
         char *hostname;          char *hostname;
   
         /* Get arguments from the packet. */          /* Get arguments from the packet. */
Line 2476 
Line 2615 
                 packet_disconnect("Dynamic forwarding denied.");                  packet_disconnect("Dynamic forwarding denied.");
   
         /* Initiate forwarding */          /* Initiate forwarding */
         channel_setup_local_fwd_listener(NULL, port, hostname,          success = channel_setup_local_fwd_listener(NULL, port, hostname,
             host_port, gateway_ports);              host_port, gateway_ports);
   
         /* Free the argument string. */          /* Free the argument string. */
         xfree(hostname);          xfree(hostname);
   
           return (success ? 0 : -1);
 }  }
   
 /*  /*
Line 2499 
Line 2640 
 channel_add_permitted_opens(char *host, int port)  channel_add_permitted_opens(char *host, int port)
 {  {
         if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)          if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
                 fatal("channel_request_remote_forwarding: too many forwards");                  fatal("channel_add_permitted_opens: too many forwards");
         debug("allow port forwarding to host %s port %d", host, port);          debug("allow port forwarding to host %s port %d", host, port);
   
         permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);          permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
Line 2509 
Line 2650 
         all_opens_permitted = 0;          all_opens_permitted = 0;
 }  }
   
   int
   channel_add_adm_permitted_opens(char *host, int port)
   {
           if (num_adm_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
                   fatal("channel_add_adm_permitted_opens: too many forwards");
           debug("config allows port forwarding to host %s port %d", host, port);
   
           permitted_adm_opens[num_adm_permitted_opens].host_to_connect
                = xstrdup(host);
           permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
           return ++num_adm_permitted_opens;
   }
   
 void  void
 channel_clear_permitted_opens(void)  channel_clear_permitted_opens(void)
 {  {
Line 2518 
Line 2672 
                 if (permitted_opens[i].host_to_connect != NULL)                  if (permitted_opens[i].host_to_connect != NULL)
                         xfree(permitted_opens[i].host_to_connect);                          xfree(permitted_opens[i].host_to_connect);
         num_permitted_opens = 0;          num_permitted_opens = 0;
   
 }  }
   
   void
   channel_clear_adm_permitted_opens(void)
   {
           int i;
   
           for (i = 0; i < num_adm_permitted_opens; i++)
                   if (permitted_adm_opens[i].host_to_connect != NULL)
                           xfree(permitted_adm_opens[i].host_to_connect);
           num_adm_permitted_opens = 0;
   }
   
 /* return socket to remote host, port */  /* return socket to remote host, port */
 static int  static int
 connect_to(const char *host, u_short port)  connect_to(const char *host, u_short port)
Line 2598 
Line 2761 
 int  int
 channel_connect_to(const char *host, u_short port)  channel_connect_to(const char *host, u_short port)
 {  {
         int i, permit;          int i, permit, permit_adm = 1;
   
         permit = all_opens_permitted;          permit = all_opens_permitted;
         if (!permit) {          if (!permit) {
Line 2607 
Line 2770 
                             permitted_opens[i].port_to_connect == port &&                              permitted_opens[i].port_to_connect == port &&
                             strcmp(permitted_opens[i].host_to_connect, host) == 0)                              strcmp(permitted_opens[i].host_to_connect, host) == 0)
                                 permit = 1;                                  permit = 1;
           }
   
           if (num_adm_permitted_opens > 0) {
                   permit_adm = 0;
                   for (i = 0; i < num_adm_permitted_opens; i++)
                           if (permitted_adm_opens[i].host_to_connect != NULL &&
                               permitted_adm_opens[i].port_to_connect == port &&
                               strcmp(permitted_adm_opens[i].host_to_connect, host)
                               == 0)
                                   permit_adm = 1;
         }          }
         if (!permit) {  
           if (!permit || !permit_adm) {
                 logit("Received request to connect to host %.100s port %d, "                  logit("Received request to connect to host %.100s port %d, "
                     "but the request was denied.", host, port);                      "but the request was denied.", host, port);
                 return -1;                  return -1;
Line 2630 
Line 2803 
                 if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0)                  if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0)
                         continue;                          continue;
                 channel_request_start(i, "window-change", 0);                  channel_request_start(i, "window-change", 0);
                 packet_put_int(ws.ws_col);                  packet_put_int((u_int)ws.ws_col);
                 packet_put_int(ws.ws_row);                  packet_put_int((u_int)ws.ws_row);
                 packet_put_int(ws.ws_xpixel);                  packet_put_int((u_int)ws.ws_xpixel);
                 packet_put_int(ws.ws_ypixel);                  packet_put_int((u_int)ws.ws_ypixel);
                 packet_send();                  packet_send();
         }          }
 }  }
Line 2656 
Line 2829 
         char strport[NI_MAXSERV];          char strport[NI_MAXSERV];
         int gaierr, n, num_socks = 0, socks[NUM_SOCKS];          int gaierr, n, num_socks = 0, socks[NUM_SOCKS];
   
           if (chanids == NULL)
                   return -1;
   
         for (display_number = x11_display_offset;          for (display_number = x11_display_offset;
             display_number < MAX_DISPLAYS;              display_number < MAX_DISPLAYS;
             display_number++) {              display_number++) {
Line 2679 
Line 2855 
                                 freeaddrinfo(aitop);                                  freeaddrinfo(aitop);
                                 return -1;                                  return -1;
                         }                          }
                           channel_set_reuseaddr(sock);
                         if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {                          if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
                                 debug2("bind port %d: %.100s", port, strerror(errno));                                  debug2("bind port %d: %.100s", port, strerror(errno));
                                 close(sock);                                  close(sock);
Line 2715 
Line 2892 
         }          }
   
         /* Allocate a channel for each socket. */          /* Allocate a channel for each socket. */
         if (chanids != NULL)          *chanids = xcalloc(num_socks + 1, sizeof(**chanids));
                 *chanids = xmalloc(sizeof(**chanids) * (num_socks + 1));  
         for (n = 0; n < num_socks; n++) {          for (n = 0; n < num_socks; n++) {
                 sock = socks[n];                  sock = socks[n];
                 nc = channel_new("x11 listener",                  nc = channel_new("x11 listener",
Line 2724 
Line 2900 
                     CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,                      CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
                     0, "X11 inet listener", 1);                      0, "X11 inet listener", 1);
                 nc->single_connection = single_connection;                  nc->single_connection = single_connection;
                 if (*chanids != NULL)                  (*chanids)[n] = nc->self;
                         (*chanids)[n] = nc->self;  
         }          }
         if (*chanids != NULL)          (*chanids)[n] = -1;
                 (*chanids)[n] = -1;  
   
         /* Return the display number for the DISPLAY environment variable. */          /* Return the display number for the DISPLAY environment variable. */
         *display_numberp = display_number;          *display_numberp = display_number;
Line 2747 
Line 2921 
         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_UNIX_X, dnr);          snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, 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));
Line 2757 
Line 2931 
 int  int
 x11_connect_display(void)  x11_connect_display(void)
 {  {
         int display_number, sock = 0;          u_int display_number;
         const char *display;          const char *display;
         char buf[1024], *cp;          char buf[1024], *cp;
         struct addrinfo hints, *ai, *aitop;          struct addrinfo hints, *ai, *aitop;
         char strport[NI_MAXSERV];          char strport[NI_MAXSERV];
         int gaierr;          int gaierr, sock = 0;
   
         /* Try to open a socket for the local X server. */          /* Try to open a socket for the local X server. */
         display = getenv("DISPLAY");          display = getenv("DISPLAY");
Line 2782 
Line 2956 
         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, "%u", &display_number) != 1) {
                         error("Could not parse display number from DISPLAY: %.100s",                          error("Could not parse display number from DISPLAY: %.100s",
                             display);                              display);
                         return -1;                          return -1;
Line 2807 
Line 2981 
         }          }
         *cp = 0;          *cp = 0;
         /* buf now contains the host name.  But first we parse the display number. */          /* buf now contains the host name.  But first we parse the display number. */
         if (sscanf(cp + 1, "%d", &display_number) != 1) {          if (sscanf(cp + 1, "%u", &display_number) != 1) {
                 error("Could not parse display number from DISPLAY: %.100s",                  error("Could not parse display number from DISPLAY: %.100s",
                     display);                      display);
                 return -1;                  return -1;
Line 2817 
Line 2991 
         memset(&hints, 0, sizeof(hints));          memset(&hints, 0, sizeof(hints));
         hints.ai_family = IPv4or6;          hints.ai_family = IPv4or6;
         hints.ai_socktype = SOCK_STREAM;          hints.ai_socktype = SOCK_STREAM;
         snprintf(strport, sizeof strport, "%d", 6000 + display_number);          snprintf(strport, sizeof strport, "%u", 6000 + display_number);
         if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {          if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
                 error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr));                  error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr));
                 return -1;                  return -1;
Line 2831 
Line 3005 
                 }                  }
                 /* Connect it to the display. */                  /* Connect it to the display. */
                 if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {                  if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
                         debug2("connect %.100s port %d: %.100s", buf,                          debug2("connect %.100s port %u: %.100s", buf,
                             6000 + display_number, strerror(errno));                              6000 + display_number, strerror(errno));
                         close(sock);                          close(sock);
                         continue;                          continue;
Line 2841 
Line 3015 
         }          }
         freeaddrinfo(aitop);          freeaddrinfo(aitop);
         if (!ai) {          if (!ai) {
                 error("connect %.100s port %d: %.100s", buf, 6000 + display_number,                  error("connect %.100s port %u: %.100s", buf, 6000 + display_number,
                     strerror(errno));                      strerror(errno));
                 return -1;                  return -1;
         }          }
Line 2855 
Line 3029 
  * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.   * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
  */   */
   
   /* ARGSUSED */
 void  void
 x11_input_open(int type, u_int32_t seq, void *ctxt)  x11_input_open(int type, u_int32_t seq, void *ctxt)
 {  {
Line 2898 
Line 3073 
 }  }
   
 /* dummy protocol handler that denies SSH-1 requests (agent/x11) */  /* dummy protocol handler that denies SSH-1 requests (agent/x11) */
   /* ARGSUSED */
 void  void
 deny_input_open(int type, u_int32_t seq, void *ctxt)  deny_input_open(int type, u_int32_t seq, void *ctxt)
 {  {
Line 2914 
Line 3090 
                 error("deny_input_open: type %d", type);                  error("deny_input_open: type %d", type);
                 break;                  break;
         }          }
         error("Warning: this is probably a break in attempt by a malicious server.");          error("Warning: this is probably a break-in attempt by a malicious server.");
         packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);          packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
         packet_put_int(rchan);          packet_put_int(rchan);
         packet_send();          packet_send();
Line 2944 
Line 3120 
                 return;                  return;
         }          }
   
         cp = disp;          cp = strchr(disp, ':');
         if (disp)  
                 cp = strchr(disp, ':');  
         if (cp)          if (cp)
                 cp = strchr(cp, '.');                  cp = strchr(cp, '.');
         if (cp)          if (cp)
                 screen_number = atoi(cp + 1);                  screen_number = (u_int)strtonum(cp + 1, 0, 400, NULL);
         else          else
                 screen_number = 0;                  screen_number = 0;
   

Legend:
Removed from v.1.223  
changed lines
  Added in v.1.223.2.2