[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.120 and 1.121

version 1.120, 2001/05/30 12:55:09 version 1.121, 2001/05/31 10:30:14
Line 42 
Line 42 
 #include "includes.h"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$OpenBSD$");
   
 #include <openssl/rsa.h>  
 #include <openssl/dsa.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 "xmalloc.h"
 #include "buffer.h"  
 #include "bufaux.h"  
 #include "uidswap.h"  #include "uidswap.h"
 #include "log.h"  #include "log.h"
 #include "misc.h"  #include "misc.h"
 #include "channels.h"  #include "channels.h"
 #include "nchan.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"
   
 /* Maximum number of fake X11 displays to try. */  
 #define MAX_DISPLAYS  1000  
   
 /* Max len of agent socket */  /* -- channel core */
 #define MAX_SOCKET_NAME 100  
   
 /*  /*
  * Pointer to an array containing all allocated channels.  The array is   * Pointer to an array containing all allocated channels.  The array is
Line 86 
Line 77 
  */   */
 static int channel_max_fd = 0;  static int channel_max_fd = 0;
   
 /* Name and directory of socket for authentication agent forwarding. */  
 static char *channel_forwarded_auth_socket_name = NULL;  
 static char *channel_forwarded_auth_socket_dir = NULL;  
   
 /* Saved X11 authentication protocol name. */  /* -- tcp forwarding */
 char *x11_saved_proto = NULL;  
   
 /* Saved X11 authentication data.  This is the real data. */  
 char *x11_saved_data = NULL;  
 u_int x11_saved_data_len = 0;  
   
 /*  /*
  * Fake X11 authentication data.  This is what the server will be sending us;  
  * we should replace any occurrences of this by the real data.  
  */  
 char *x11_fake_data = NULL;  
 u_int x11_fake_data_len;  
   
 /*  
  * Data structure for storing which hosts are permitted for forward requests.   * Data structure for storing which hosts are permitted for forward requests.
  * 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 local   * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
Line 118 
Line 94 
   
 /* List of all permitted host/port pairs to connect. */  /* List of all permitted host/port pairs to connect. */
 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. */  /* Number of permitted host/port pairs in the array. */
 static int num_permitted_opens = 0;  static int num_permitted_opens = 0;
 /*  /*
Line 127 
Line 104 
  */   */
 static int all_opens_permitted = 0;  static int all_opens_permitted = 0;
   
 /* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */  
 static int have_hostname_in_open = 0;  
   
 /* AF_UNSPEC or AF_INET or AF_INET6 */  /* -- X11 forwarding */
 extern int IPv4or6;  
   
 void     port_open_helper(Channel *c, char *rtype);  /* Maximum number of fake X11 displays to try. */
   #define MAX_DISPLAYS  1000
   
 /* Sets specific protocol options. */  /* Saved X11 authentication protocol name. */
   static char *x11_saved_proto = NULL;
   
 void  /* Saved X11 authentication data.  This is the real data. */
 channel_set_options(int hostname_in_open)  static char *x11_saved_data = NULL;
 {  static u_int x11_saved_data_len = 0;
         have_hostname_in_open = hostname_in_open;  
 }  
   
 /* lookup channel by id */  /*
    * Fake X11 authentication data.  This is what the server will be sending us;
    * we should replace any occurrences of this by the real data.
    */
   static char *x11_fake_data = NULL;
   static u_int x11_fake_data_len;
   
   
   /* -- agent forwarding */
   
   #define NUM_SOCKS       10
   
   /* Name and directory of socket for authentication agent forwarding. */
   static char *auth_sock_name = NULL;
   static char *auth_sock_dir = NULL;
   
   
   /* AF_UNSPEC or AF_INET or AF_INET6 */
   extern int IPv4or6;
   
   /* helper */
   void    port_open_helper(Channel *c, char *rtype);
   
   /* -- channel core */
   
 Channel *  Channel *
 channel_lookup(int id)  channel_lookup(int id)
 {  {
Line 337 
Line 334 
         xfree(c);          xfree(c);
 }  }
   
   
 /*  /*
    * Stops listening for channels, and removes any unix domain sockets that we
    * might have.
    */
   
   void
   channel_stop_listening()
   {
           int i;
           Channel *c;
   
           for (i = 0; i < channels_alloc; i++) {
                   c = channels[i];
                   if (c != NULL) {
                           switch (c->type) {
                           case SSH_CHANNEL_AUTH_SOCKET:
                                   close(c->sock);
                                   unlink(c->path);
                                   channel_free(c);
                                   break;
                           case SSH_CHANNEL_PORT_LISTENER:
                           case SSH_CHANNEL_RPORT_LISTENER:
                           case SSH_CHANNEL_X11_LISTENER:
                                   close(c->sock);
                                   channel_free(c);
                                   break;
                           default:
                                   break;
                           }
                   }
           }
   }
   
   /*
    * Closes the sockets/fds of all channels.  This is used to close extra file
    * descriptors after a fork.
    */
   
   void
   channel_close_all()
   {
           int i;
   
           for (i = 0; i < channels_alloc; i++)
                   if (channels[i] != NULL)
                           channel_close_fds(channels[i]);
   }
   
   /*
    * Returns true if no channel has too much buffered data, and false if one or
    * more channel is overfull.
    */
   
   int
   channel_not_very_much_buffered_data()
   {
           u_int i;
           Channel *c;
   
           for (i = 0; i < channels_alloc; i++) {
                   c = channels[i];
                   if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
                           if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) {
                                   debug("channel %d: big input buffer %d",
                                       c->self, buffer_len(&c->input));
                                   return 0;
                           }
                           if (buffer_len(&c->output) > packet_get_maxsize()) {
                                   debug("channel %d: big output buffer %d",
                                       c->self, buffer_len(&c->output));
                                   return 0;
                           }
                   }
           }
           return 1;
   }
   
   /* Returns true if any channel is still open. */
   
   int
   channel_still_open()
   {
           int i;
           Channel *c;
   
           for (i = 0; i < channels_alloc; i++) {
                   c = channels[i];
                   if (c == NULL)
                           continue;
                   switch (c->type) {
                   case SSH_CHANNEL_X11_LISTENER:
                   case SSH_CHANNEL_PORT_LISTENER:
                   case SSH_CHANNEL_RPORT_LISTENER:
                   case SSH_CHANNEL_CLOSED:
                   case SSH_CHANNEL_AUTH_SOCKET:
                   case SSH_CHANNEL_DYNAMIC:
                   case SSH_CHANNEL_CONNECTING:
                   case SSH_CHANNEL_ZOMBIE:
                           continue;
                   case SSH_CHANNEL_LARVAL:
                           if (!compat20)
                                   fatal("cannot happen: SSH_CHANNEL_LARVAL");
                           continue;
                   case SSH_CHANNEL_OPENING:
                   case SSH_CHANNEL_OPEN:
                   case SSH_CHANNEL_X11_OPEN:
                           return 1;
                   case SSH_CHANNEL_INPUT_DRAINING:
                   case SSH_CHANNEL_OUTPUT_DRAINING:
                           if (!compat13)
                                   fatal("cannot happen: OUT_DRAIN");
                           return 1;
                   default:
                           fatal("channel_still_open: bad channel type %d", c->type);
                           /* NOTREACHED */
                   }
           }
           return 0;
   }
   
   /* Returns the id of an open channel suitable for keepaliving */
   
   int
   channel_find_open()
   {
           int i;
           Channel *c;
   
           for (i = 0; i < channels_alloc; i++) {
                   c = channels[i];
                   if (c == NULL)
                           continue;
                   switch (c->type) {
                   case SSH_CHANNEL_CLOSED:
                   case SSH_CHANNEL_DYNAMIC:
                   case SSH_CHANNEL_X11_LISTENER:
                   case SSH_CHANNEL_PORT_LISTENER:
                   case SSH_CHANNEL_RPORT_LISTENER:
                   case SSH_CHANNEL_OPENING:
                   case SSH_CHANNEL_CONNECTING:
                   case SSH_CHANNEL_ZOMBIE:
                           continue;
                   case SSH_CHANNEL_LARVAL:
                   case SSH_CHANNEL_AUTH_SOCKET:
                   case SSH_CHANNEL_OPEN:
                   case SSH_CHANNEL_X11_OPEN:
                           return i;
                   case SSH_CHANNEL_INPUT_DRAINING:
                   case SSH_CHANNEL_OUTPUT_DRAINING:
                           if (!compat13)
                                   fatal("cannot happen: OUT_DRAIN");
                           return i;
                   default:
                           fatal("channel_find_open: bad channel type %d", c->type);
                           /* NOTREACHED */
                   }
           }
           return -1;
   }
   
   
   /*
    * Returns a message describing the currently open forwarded connections,
    * suitable for sending to the client.  The message contains crlf pairs for
    * newlines.
    */
   
   char *
   channel_open_message()
   {
           Buffer buffer;
           Channel *c;
           char buf[1024], *cp;
           int i;
   
           buffer_init(&buffer);
           snprintf(buf, sizeof buf, "The following connections are open:\r\n");
           buffer_append(&buffer, buf, strlen(buf));
           for (i = 0; i < channels_alloc; i++) {
                   c = channels[i];
                   if (c == NULL)
                           continue;
                   switch (c->type) {
                   case SSH_CHANNEL_X11_LISTENER:
                   case SSH_CHANNEL_PORT_LISTENER:
                   case SSH_CHANNEL_RPORT_LISTENER:
                   case SSH_CHANNEL_CLOSED:
                   case SSH_CHANNEL_AUTH_SOCKET:
                   case SSH_CHANNEL_ZOMBIE:
                           continue;
                   case SSH_CHANNEL_LARVAL:
                   case SSH_CHANNEL_OPENING:
                   case SSH_CHANNEL_CONNECTING:
                   case SSH_CHANNEL_DYNAMIC:
                   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/%d o%d/%d fd %d/%d)\r\n",
                               c->self, c->remote_name,
                               c->type, c->remote_id,
                               c->istate, buffer_len(&c->input),
                               c->ostate, buffer_len(&c->output),
                               c->rfd, c->wfd);
                           buffer_append(&buffer, buf, strlen(buf));
                           continue;
                   default:
                           fatal("channel_open_message: bad channel type %d", c->type);
                           /* NOTREACHED */
                   }
           }
           buffer_append(&buffer, "\0", 1);
           cp = xstrdup(buffer_ptr(&buffer));
           buffer_free(&buffer);
           return cp;
   }
   
   void
   channel_send_open(int id)
   {
           Channel *c = channel_lookup(id);
           if (c == NULL) {
                   log("channel_send_open: %d: bad id", id);
                   return;
           }
           debug("send channel open %d", id);
           packet_start(SSH2_MSG_CHANNEL_OPEN);
           packet_put_cstring(c->ctype);
           packet_put_int(c->self);
           packet_put_int(c->local_window);
           packet_put_int(c->local_maxpacket);
           packet_send();
   }
   
   void
   channel_request(int id, char *service, int wantconfirm)
   {
           channel_request_start(id, service, wantconfirm);
           packet_send();
           debug("channel request %d: %s", id, service) ;
   }
   void
   channel_request_start(int id, char *service, int wantconfirm)
   {
           Channel *c = channel_lookup(id);
           if (c == NULL) {
                   log("channel_request: %d: bad id", id);
                   return;
           }
           packet_start(SSH2_MSG_CHANNEL_REQUEST);
           packet_put_int(c->remote_id);
           packet_put_cstring(service);
           packet_put_char(wantconfirm);
   }
   void
   channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg)
   {
           Channel *c = channel_lookup(id);
           if (c == NULL) {
                   log("channel_register_callback: %d: bad id", id);
                   return;
           }
           c->cb_event = mtype;
           c->cb_fn = fn;
           c->cb_arg = arg;
   }
   void
   channel_register_cleanup(int id, channel_callback_fn *fn)
   {
           Channel *c = channel_lookup(id);
           if (c == NULL) {
                   log("channel_register_cleanup: %d: bad id", id);
                   return;
           }
           c->dettach_user = fn;
   }
   void
   channel_cancel_cleanup(int id)
   {
           Channel *c = channel_lookup(id);
           if (c == NULL) {
                   log("channel_cancel_cleanup: %d: bad id", id);
                   return;
           }
           c->dettach_user = NULL;
   }
   void
   channel_register_filter(int id, channel_filter_fn *fn)
   {
           Channel *c = channel_lookup(id);
           if (c == NULL) {
                   log("channel_register_filter: %d: bad id", id);
                   return;
           }
           c->input_filter = fn;
   }
   
   void
   channel_set_fds(int id, int rfd, int wfd, int efd,
       int extusage, int nonblock)
   {
           Channel *c = channel_lookup(id);
           if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
                   fatal("channel_activate for non-larval channel %d.", id);
           channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
           c->type = SSH_CHANNEL_OPEN;
           /* XXX window size? */
           c->local_window = c->local_window_max = c->local_maxpacket * 2;
           packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
           packet_put_int(c->remote_id);
           packet_put_int(c->local_window);
           packet_send();
   }
   
   /*
  * 'channel_pre*' are called just before select() to add any bits relevant to   * 'channel_pre*' are called just before select() to add any bits relevant to
  * channels in the select bitmasks.   * channels in the select bitmasks.
  */   */
Line 442 
Line 754 
  * data in that packet is then substituted by the real data if it matches the   * data in that packet is then substituted by the real data if it matches the
  * fake data, and the channel is put into normal mode.   * fake data, and the channel is put into normal mode.
  * XXX All this happens at the client side.   * XXX All this happens at the client side.
    * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok
  */   */
 int  int
 x11_open_helper(Channel *c)  x11_open_helper(Buffer *b)
 {  {
         u_char *ucp;          u_char *ucp;
         u_int proto_len, data_len;          u_int proto_len, data_len;
   
         /* 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(&c->output) < 12)          if (buffer_len(b) < 12)
                 return 0;                  return 0;
   
         /* Parse the lengths of variable-length fields. */          /* Parse the lengths of variable-length fields. */
         ucp = (u_char *) buffer_ptr(&c->output);          ucp = (u_char *) buffer_ptr(b);
         if (ucp[0] == 0x42) {   /* Byte order MSB first. */          if (ucp[0] == 0x42) {   /* 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];
Line 468 
Line 781 
         }          }
   
         /* Check if the whole packet is in buffer. */          /* Check if the whole packet is in buffer. */
         if (buffer_len(&c->output) <          if (buffer_len(b) <
             12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))              12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
                 return 0;                  return 0;
   
Line 504 
Line 817 
 void  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);          int ret = x11_open_helper(&c->output);
         if (ret == 1) {          if (ret == 1) {
                 /* Start normal processing for the channel. */                  /* Start normal processing for the channel. */
                 c->type = SSH_CHANNEL_OPEN;                  c->type = SSH_CHANNEL_OPEN;
Line 529 
Line 842 
 void  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);          int ret = x11_open_helper(&c->output);
         if (ret == 1) {          if (ret == 1) {
                 c->type = SSH_CHANNEL_OPEN;                  c->type = SSH_CHANNEL_OPEN;
                 if (compat20)                  if (compat20)
Line 704 
Line 1017 
                 } else {                  } else {
                         packet_start(SSH_SMSG_X11_OPEN);                          packet_start(SSH_SMSG_X11_OPEN);
                         packet_put_int(nc->self);                          packet_put_int(nc->self);
                         if (have_hostname_in_open)                          if (packet_get_protocol_flags() &
                               SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
                                 packet_put_string(buf, strlen(buf));                                  packet_put_string(buf, strlen(buf));
                         packet_send();                          packet_send();
                 }                  }
Line 755 
Line 1069 
                 packet_put_int(c->self);                  packet_put_int(c->self);
                 packet_put_cstring(c->path);                  packet_put_cstring(c->path);
                 packet_put_int(c->host_port);                  packet_put_int(c->host_port);
                 if (have_hostname_in_open)                  if (packet_get_protocol_flags() &
                       SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
                         packet_put_cstring(c->remote_name);                          packet_put_cstring(c->remote_name);
                 packet_send();                  packet_send();
         }          }
Line 817 
Line 1132 
 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;
           char *name;
         int newsock;          int newsock;
         struct sockaddr addr;          struct sockaddr addr;
         socklen_t addrlen;          socklen_t addrlen;
Line 828 
Line 1144 
                         error("accept from auth socket: %.100s", strerror(errno));                          error("accept from auth socket: %.100s", strerror(errno));
                         return;                          return;
                 }                  }
                   name = xstrdup("accepted auth socket");
                 nc = channel_new("accepted auth socket",                  nc = channel_new("accepted auth socket",
                     SSH_CHANNEL_OPENING, newsock, newsock, -1,                      SSH_CHANNEL_OPENING, newsock, newsock, -1,
                     c->local_window_max, c->local_maxpacket,                      c->local_window_max, c->local_maxpacket,
                     0, xstrdup("accepted auth socket"), 1);                      0, name, 1);
                 if (nc == NULL) {                  if (nc == NULL) {
                         error("channel_post_auth_listener: channel_new failed");                          error("channel_post_auth_listener: channel_new failed");
                           xfree(name);
                         close(newsock);                          close(newsock);
                 }                  }
                 if (compat20) {                  if (compat20) {
Line 918 
Line 1236 
                         } else if (compat13) {                          } else if (compat13) {
                                 buffer_consume(&c->output, buffer_len(&c->output));                                  buffer_consume(&c->output, buffer_len(&c->output));
                                 c->type = SSH_CHANNEL_INPUT_DRAINING;                                  c->type = SSH_CHANNEL_INPUT_DRAINING;
                                 debug("channel %d: status set to input draining.", c->self);                                  debug("channel %d: input draining.", c->self);
                         } else {                          } else {
                                 chan_read_failed(c);                                  chan_read_failed(c);
                         }                          }
Line 956 
Line 1274 
                                 return -1;                                  return -1;
                         } else if (compat13) {                          } else if (compat13) {
                                 buffer_consume(&c->output, buffer_len(&c->output));                                  buffer_consume(&c->output, buffer_len(&c->output));
                                 debug("channel %d: status set to input draining.", c->self);                                  debug("channel %d: input draining.", c->self);
                                 c->type = SSH_CHANNEL_INPUT_DRAINING;                                  c->type = SSH_CHANNEL_INPUT_DRAINING;
                         } else {                          } else {
                                 chan_write_failed(c);                                  chan_write_failed(c);
Line 1196 
Line 1514 
         }          }
 }  }
   
   /*
    * Allocate/update select bitmasks and add any bits relevant to channels in
    * select bitmasks.
    */
 void  void
 channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,  channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
     int rekeying)      int rekeying)
Line 1222 
Line 1544 
                 channel_handler(channel_pre, *readsetp, *writesetp);                  channel_handler(channel_pre, *readsetp, *writesetp);
 }  }
   
   /*
    * After select, perform any appropriate operations for channels which have
    * 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
Line 1237 
Line 1564 
         Channel *c;          Channel *c;
   
         for (i = 0; i < channels_alloc; i++) {          for (i = 0; i < channels_alloc; i++) {
   
                 c = channels[i];                  c = channels[i];
                 if (c == NULL)                  if (c == NULL)
                         continue;                          continue;
   
                 /* We are only interested in channels that can have buffered incoming data. */                  /*
                    * We are only interested in channels that can have buffered
                    * incoming data.
                    */
                 if (compat13) {                  if (compat13) {
                         if (c->type != SSH_CHANNEL_OPEN &&                          if (c->type != SSH_CHANNEL_OPEN &&
                             c->type != SSH_CHANNEL_INPUT_DRAINING)                              c->type != SSH_CHANNEL_INPUT_DRAINING)
Line 1262 
Line 1591 
                 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) {
                         /* Send some data for the other side over the secure connection. */                          /*
                            * Send some data for the other side over the secure
                            * connection.
                            */
                         if (compat20) {                          if (compat20) {
                                 if (len > c->remote_window)                                  if (len > c->remote_window)
                                         len = c->remote_window;                                          len = c->remote_window;
Line 1320 
Line 1652 
         }          }
 }  }
   
 /*  
  * 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 is  
  * still there.  
  */  
   
   /* -- protocol input */
   
 void  void
 channel_input_data(int type, int plen, void *ctxt)  channel_input_data(int type, int plen, void *ctxt)
 {  {
Line 1371 
Line 1700 
         buffer_append(&c->output, data, data_len);          buffer_append(&c->output, data, data_len);
         xfree(data);          xfree(data);
 }  }
   
 void  void
 channel_input_extended_data(int type, int plen, void *ctxt)  channel_input_extended_data(int type, int plen, void *ctxt)
 {  {
Line 1411 
Line 1741 
         xfree(data);          xfree(data);
 }  }
   
   
 /*  
  * Returns true if no channel has too much buffered data, and false if one or  
  * more channel is overfull.  
  */  
   
 int  
 channel_not_very_much_buffered_data()  
 {  
         u_int i;  
         Channel *c;  
   
         for (i = 0; i < channels_alloc; i++) {  
                 c = channels[i];  
                 if (c != NULL && c->type == SSH_CHANNEL_OPEN) {  
                         if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) {  
                                 debug("channel %d: big input buffer %d",  
                                     c->self, buffer_len(&c->input));  
                                 return 0;  
                         }  
                         if (buffer_len(&c->output) > packet_get_maxsize()) {  
                                 debug("channel %d: big output buffer %d",  
                                     c->self, buffer_len(&c->output));  
                                 return 0;  
                         }  
                 }  
         }  
         return 1;  
 }  
   
 void  void
 channel_input_ieof(int type, int plen, void *ctxt)  channel_input_ieof(int type, int plen, void *ctxt)
 {  {
Line 1655 
Line 1955 
         c->remote_window += adjust;          c->remote_window += adjust;
 }  }
   
 /*  
  * Stops listening for channels, and removes any unix domain sockets that we  
  * might have.  
  */  
   
 void  void
 channel_stop_listening()  channel_input_port_open(int type, int plen, void *ctxt)
 {  {
         int i;          Channel *c = NULL;
         Channel *c;          u_short host_port;
           char *host, *originator_string;
           int remote_id, sock = -1;
   
         for (i = 0; i < channels_alloc; i++) {          remote_id = packet_get_int();
                 c = channels[i];          host = packet_get_string(NULL);
                 if (c != NULL) {          host_port = packet_get_int();
                         switch (c->type) {  
                         case SSH_CHANNEL_AUTH_SOCKET:  
                                 close(c->sock);  
                                 unlink(c->path);  
                                 channel_free(c);  
                                 break;  
                         case SSH_CHANNEL_PORT_LISTENER:  
                         case SSH_CHANNEL_RPORT_LISTENER:  
                         case SSH_CHANNEL_X11_LISTENER:  
                                 close(c->sock);  
                                 channel_free(c);  
                                 break;  
                         default:  
                                 break;  
                         }  
                 }  
         }  
 }  
   
 /*          if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
  * Closes the sockets/fds of all channels.  This is used to close extra file                  originator_string = packet_get_string(NULL);
  * descriptors after a fork.          } else {
  */                  originator_string = xstrdup("unknown (remote did not supply name)");
   
 void  
 channel_close_all()  
 {  
         int i;  
   
         for (i = 0; i < channels_alloc; i++)  
                 if (channels[i] != NULL)  
                         channel_close_fds(channels[i]);  
 }  
   
 /* Returns true if any channel is still open. */  
   
 int  
 channel_still_open()  
 {  
         int i;  
         Channel *c;  
   
         for (i = 0; i < channels_alloc; i++) {  
                 c = channels[i];  
                 if (c == NULL)  
                         continue;  
                 switch (c->type) {  
                 case SSH_CHANNEL_X11_LISTENER:  
                 case SSH_CHANNEL_PORT_LISTENER:  
                 case SSH_CHANNEL_RPORT_LISTENER:  
                 case SSH_CHANNEL_CLOSED:  
                 case SSH_CHANNEL_AUTH_SOCKET:  
                 case SSH_CHANNEL_DYNAMIC:  
                 case SSH_CHANNEL_CONNECTING:  
                 case SSH_CHANNEL_ZOMBIE:  
                         continue;  
                 case SSH_CHANNEL_LARVAL:  
                         if (!compat20)  
                                 fatal("cannot happen: SSH_CHANNEL_LARVAL");  
                         continue;  
                 case SSH_CHANNEL_OPENING:  
                 case SSH_CHANNEL_OPEN:  
                 case SSH_CHANNEL_X11_OPEN:  
                         return 1;  
                 case SSH_CHANNEL_INPUT_DRAINING:  
                 case SSH_CHANNEL_OUTPUT_DRAINING:  
                         if (!compat13)  
                                 fatal("cannot happen: OUT_DRAIN");  
                         return 1;  
                 default:  
                         fatal("channel_still_open: bad channel type %d", c->type);  
                         /* NOTREACHED */  
                 }  
         }          }
         return 0;          packet_done();
 }          sock = channel_connect_to(host, host_port);
           if (sock != -1) {
 /* Returns the id of an open channel suitable for keepaliving */                  c = channel_new("connected socket",
                       SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0,
 int                      originator_string, 1);
 channel_find_open()                  if (c == NULL) {
 {                          error("channel_input_port_open: channel_new failed");
         int i;                          close(sock);
         Channel *c;                  } else {
                           c->remote_id = remote_id;
         for (i = 0; i < channels_alloc; i++) {  
                 c = channels[i];  
                 if (c == NULL)  
                         continue;  
                 switch (c->type) {  
                 case SSH_CHANNEL_CLOSED:  
                 case SSH_CHANNEL_DYNAMIC:  
                 case SSH_CHANNEL_X11_LISTENER:  
                 case SSH_CHANNEL_PORT_LISTENER:  
                 case SSH_CHANNEL_RPORT_LISTENER:  
                 case SSH_CHANNEL_OPENING:  
                 case SSH_CHANNEL_CONNECTING:  
                 case SSH_CHANNEL_ZOMBIE:  
                         continue;  
                 case SSH_CHANNEL_LARVAL:  
                 case SSH_CHANNEL_AUTH_SOCKET:  
                 case SSH_CHANNEL_OPEN:  
                 case SSH_CHANNEL_X11_OPEN:  
                         return i;  
                 case SSH_CHANNEL_INPUT_DRAINING:  
                 case SSH_CHANNEL_OUTPUT_DRAINING:  
                         if (!compat13)  
                                 fatal("cannot happen: OUT_DRAIN");  
                         return i;  
                 default:  
                         fatal("channel_find_open: bad channel type %d", c->type);  
                         /* NOTREACHED */  
                 }                  }
         }          }
         return -1;          if (c == NULL) {
                   packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
                   packet_put_int(remote_id);
                   packet_send();
           }
           xfree(host);
 }  }
   
   
 /*  /* -- tcp forwarding */
  * Returns a message describing the currently open forwarded connections,  
  * suitable for sending to the client.  The message contains crlf pairs for  
  * newlines.  
  */  
   
 char *  
 channel_open_message()  
 {  
         Buffer buffer;  
         Channel *c;  
         char buf[1024], *cp;  
         int i;  
   
         buffer_init(&buffer);  
         snprintf(buf, sizeof buf, "The following connections are open:\r\n");  
         buffer_append(&buffer, buf, strlen(buf));  
         for (i = 0; i < channels_alloc; i++) {  
                 c = channels[i];  
                 if (c == NULL)  
                         continue;  
                 switch (c->type) {  
                 case SSH_CHANNEL_X11_LISTENER:  
                 case SSH_CHANNEL_PORT_LISTENER:  
                 case SSH_CHANNEL_RPORT_LISTENER:  
                 case SSH_CHANNEL_CLOSED:  
                 case SSH_CHANNEL_AUTH_SOCKET:  
                 case SSH_CHANNEL_ZOMBIE:  
                         continue;  
                 case SSH_CHANNEL_LARVAL:  
                 case SSH_CHANNEL_OPENING:  
                 case SSH_CHANNEL_CONNECTING:  
                 case SSH_CHANNEL_DYNAMIC:  
                 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/%d o%d/%d fd %d/%d)\r\n",  
                             c->self, c->remote_name,  
                             c->type, c->remote_id,  
                             c->istate, buffer_len(&c->input),  
                             c->ostate, buffer_len(&c->output),  
                             c->rfd, c->wfd);  
                         buffer_append(&buffer, buf, strlen(buf));  
                         continue;  
                 default:  
                         fatal("channel_open_message: 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.
Line 1868 
Line 2021 
     int gateway_ports, int remote_fwd)      int gateway_ports, int remote_fwd)
 {  {
         Channel *c;          Channel *c;
         int success, sock, on = 1, ctype;          int success, sock, on = 1, type;
         struct addrinfo hints, *ai, *aitop;          struct addrinfo hints, *ai, *aitop;
         char ntop[NI_MAXHOST], strport[NI_MAXSERV];          char ntop[NI_MAXHOST], strport[NI_MAXSERV];
         const char *host;          const char *host;
Line 1878 
Line 2031 
   
         if (remote_fwd) {          if (remote_fwd) {
                 host = listen_address;                  host = listen_address;
                 ctype = SSH_CHANNEL_RPORT_LISTENER;                  type = SSH_CHANNEL_RPORT_LISTENER;
         } else {          } else {
                 host = host_to_connect;                  host = host_to_connect;
                 ctype  =SSH_CHANNEL_PORT_LISTENER;                  type = SSH_CHANNEL_PORT_LISTENER;
         }          }
   
         if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) {          if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) {
Line 1941 
Line 2094 
                         continue;                          continue;
                 }                  }
                 /* Allocate a channel number for the socket. */                  /* Allocate a channel number for the socket. */
                 c = channel_new("port listener", ctype, sock, sock, -1,                  c = channel_new("port listener", type, sock, sock, -1,
                     CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,                      CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
                     0, xstrdup("port listener"), 1);                      0, xstrdup("port listener"), 1);
                 if (c == NULL) {                  if (c == NULL) {
Line 2177 
Line 2330 
         return connect_to(host, port);          return connect_to(host, port);
 }  }
   
 /*  /* -- X11 forwarding */
  * This is called after receiving PORT_OPEN message.  This attempts to  
  * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION  
  * or CHANNEL_OPEN_FAILURE.  
  */  
   
 void  
 channel_input_port_open(int type, int plen, void *ctxt)  
 {  
         Channel *c = NULL;  
         u_short host_port;  
         char *host, *originator_string;  
         int remote_id, sock = -1;  
   
         remote_id = packet_get_int();  
         host = packet_get_string(NULL);  
         host_port = packet_get_int();  
   
         if (have_hostname_in_open) {  
                 originator_string = packet_get_string(NULL);  
         } else {  
                 originator_string = xstrdup("unknown (remote did not supply name)");  
         }  
         packet_done();  
         sock = channel_connect_to(host, host_port);  
         if (sock != -1) {  
                 c = channel_new("connected socket",  
                     SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0,  
                     originator_string, 1);  
                 if (c == NULL) {  
                         error("channel_input_port_open: channel_new failed");  
                         close(sock);  
                 } else {  
                         c->remote_id = remote_id;  
                 }  
         }  
         if (c == NULL) {  
                 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);  
                 packet_put_int(remote_id);  
                 packet_send();  
         }  
         xfree(host);  
 }  
   
 /*  /*
  * 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.
  */   */
   
 #define NUM_SOCKS       10  
   
 char *  char *
 x11_create_display_inet(int screen_number, int x11_display_offset)  x11_create_display_inet(int screen_number, int x11_display_offset)
 {  {
Line 2458 
Line 2566 
         debug("Received X11 open request.");          debug("Received X11 open request.");
   
         remote_id = packet_get_int();          remote_id = packet_get_int();
         if (have_hostname_in_open) {  
           if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
                 remote_host = packet_get_string(NULL);                  remote_host = packet_get_string(NULL);
         } else {          } else {
                 remote_host = xstrdup("unknown (remote did not supply name)");                  remote_host = xstrdup("unknown (remote did not supply name)");
Line 2517 
Line 2626 
 /*  /*
  * 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.
    * This should be called in the client only.
  */   */
   
 void  void
 x11_request_forwarding_with_spoofing(int client_session_id,  x11_request_forwarding_with_spoofing(int client_session_id,
     const char *proto, const char *data)      const char *proto, const char *data)
Line 2583 
Line 2692 
         xfree(new_data);          xfree(new_data);
 }  }
   
   
   /* -- agent forwarding */
   
 /* Sends a message to the server to request authentication fd forwarding. */  /* Sends a message to the server to request authentication fd forwarding. */
   
 void  void
Line 2602 
Line 2714 
 char *  char *
 auth_get_socket_name()  auth_get_socket_name()
 {  {
         return channel_forwarded_auth_socket_name;          return auth_sock_name;
 }  }
   
 /* removes the agent forwarding socket */  /* removes the agent forwarding socket */
Line 2610 
Line 2722 
 void  void
 cleanup_socket(void)  cleanup_socket(void)
 {  {
         unlink(channel_forwarded_auth_socket_name);          unlink(auth_sock_name);
         rmdir(channel_forwarded_auth_socket_dir);          rmdir(auth_sock_dir);
 }  }
   
 /*  /*
Line 2626 
Line 2738 
         int sock;          int sock;
         struct sockaddr_un sunaddr;          struct sockaddr_un sunaddr;
   
         if (auth_get_socket_name() != NULL)          if (auth_get_socket_name() != NULL) {
                 fatal("Protocol error: authentication forwarding requested twice.");                  error("authentication forwarding requested twice.");
                   return 0;
           }
   
         /* Temporarily drop privileged uid for mkdir/bind. */          /* Temporarily drop privileged uid for mkdir/bind. */
         temporarily_use_uid(pw);          temporarily_use_uid(pw);
   
         /* Allocate a buffer for the socket name, and format the name. */          /* Allocate a buffer for the socket name, and format the name. */
         channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME);          auth_sock_name = xmalloc(MAXPATHLEN);
         channel_forwarded_auth_socket_dir = xmalloc(MAX_SOCKET_NAME);          auth_sock_dir = xmalloc(MAXPATHLEN);
         strlcpy(channel_forwarded_auth_socket_dir, "/tmp/ssh-XXXXXXXX", MAX_SOCKET_NAME);          strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
   
         /* Create private directory for socket */          /* Create private directory for socket */
         if (mkdtemp(channel_forwarded_auth_socket_dir) == NULL) {          if (mkdtemp(auth_sock_dir) == NULL) {
                 packet_send_debug("Agent forwarding disabled: mkdtemp() failed: %.100s",                  packet_send_debug("Agent forwarding disabled: "
                     strerror(errno));                      "mkdtemp() failed: %.100s", strerror(errno));
                 restore_uid();                  restore_uid();
                 xfree(channel_forwarded_auth_socket_name);                  xfree(auth_sock_name);
                 xfree(channel_forwarded_auth_socket_dir);                  xfree(auth_sock_dir);
                 channel_forwarded_auth_socket_name = NULL;                  auth_sock_name = NULL;
                 channel_forwarded_auth_socket_dir = NULL;                  auth_sock_dir = NULL;
                 return 0;                  return 0;
         }          }
         snprintf(channel_forwarded_auth_socket_name, MAX_SOCKET_NAME, "%s/agent.%d",          snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%d",
                  channel_forwarded_auth_socket_dir, (int) getpid());                   auth_sock_dir, (int) getpid());
   
         if (atexit(cleanup_socket) < 0) {          if (atexit(cleanup_socket) < 0) {
                 int saved = errno;                  int saved = errno;
Line 2664 
Line 2778 
         /* 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, auth_sock_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)
Line 2687 
Line 2801 
                 close(sock);                  close(sock);
                 return 0;                  return 0;
         }          }
         strlcpy(nc->path, channel_forwarded_auth_socket_name, sizeof(nc->path));          strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
         return 1;          return 1;
 }  }
   
Line 2698 
Line 2812 
 {  {
         Channel *c = NULL;          Channel *c = NULL;
         int remote_id, sock;          int remote_id, sock;
         char *dummyname;          char *name;
   
         packet_integrity_check(plen, 4, type);          packet_integrity_check(plen, 4, type);
   
Line 2718 
Line 2832 
          * agent.           * agent.
          */           */
         if (sock >= 0) {          if (sock >= 0) {
                 dummyname = xstrdup("authentication agent connection");                  name = xstrdup("authentication agent connection");
                 c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, -1, 0, 0, 0, dummyname, 1);                  c = channel_new("", SSH_CHANNEL_OPEN, sock, sock,
                       -1, 0, 0, 0, name, 1);
                 if (c == NULL) {                  if (c == NULL) {
                         error("auth_input_open_request: channel_new failed");                          error("auth_input_open_request: channel_new failed");
                           xfree(name);
                         close(sock);                          close(sock);
                 } else {                  } else {
                         c->remote_id = remote_id;                          c->remote_id = remote_id;
Line 2737 
Line 2853 
                 packet_put_int(remote_id);                  packet_put_int(remote_id);
                 packet_put_int(c->self);                  packet_put_int(c->self);
         }          }
         packet_send();  
 }  
   
 void  
 channel_start_open(int id)  
 {  
         Channel *c = channel_lookup(id);  
         if (c == NULL) {  
                 log("channel_open: %d: bad id", id);  
                 return;  
         }  
         debug("send channel open %d", id);  
         packet_start(SSH2_MSG_CHANNEL_OPEN);  
         packet_put_cstring(c->ctype);  
         packet_put_int(c->self);  
         packet_put_int(c->local_window);  
         packet_put_int(c->local_maxpacket);  
 }  
 void  
 channel_open(int id)  
 {  
         /* XXX REMOVE ME */  
         channel_start_open(id);  
         packet_send();  
 }  
 void  
 channel_request(int id, char *service, int wantconfirm)  
 {  
         channel_request_start(id, service, wantconfirm);  
         packet_send();  
         debug("channel request %d: %s", id, service) ;  
 }  
 void  
 channel_request_start(int id, char *service, int wantconfirm)  
 {  
         Channel *c = channel_lookup(id);  
         if (c == NULL) {  
                 log("channel_request: %d: bad id", id);  
                 return;  
         }  
         packet_start(SSH2_MSG_CHANNEL_REQUEST);  
         packet_put_int(c->remote_id);  
         packet_put_cstring(service);  
         packet_put_char(wantconfirm);  
 }  
 void  
 channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg)  
 {  
         Channel *c = channel_lookup(id);  
         if (c == NULL) {  
                 log("channel_register_callback: %d: bad id", id);  
                 return;  
         }  
         c->cb_event = mtype;  
         c->cb_fn = fn;  
         c->cb_arg = arg;  
 }  
 void  
 channel_register_cleanup(int id, channel_callback_fn *fn)  
 {  
         Channel *c = channel_lookup(id);  
         if (c == NULL) {  
                 log("channel_register_cleanup: %d: bad id", id);  
                 return;  
         }  
         c->dettach_user = fn;  
 }  
 void  
 channel_cancel_cleanup(int id)  
 {  
         Channel *c = channel_lookup(id);  
         if (c == NULL) {  
                 log("channel_cancel_cleanup: %d: bad id", id);  
                 return;  
         }  
         c->dettach_user = NULL;  
 }  
 void  
 channel_register_filter(int id, channel_filter_fn *fn)  
 {  
         Channel *c = channel_lookup(id);  
         if (c == NULL) {  
                 log("channel_register_filter: %d: bad id", id);  
                 return;  
         }  
         c->input_filter = fn;  
 }  
   
 void  
 channel_set_fds(int id, int rfd, int wfd, int efd,  
     int extusage, int nonblock)  
 {  
         Channel *c = channel_lookup(id);  
         if (c == NULL || c->type != SSH_CHANNEL_LARVAL)  
                 fatal("channel_activate for non-larval channel %d.", id);  
         channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);  
         c->type = SSH_CHANNEL_OPEN;  
         /* XXX window size? */  
         c->local_window = c->local_window_max = c->local_maxpacket * 2;  
         packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);  
         packet_put_int(c->remote_id);  
         packet_put_int(c->local_window);  
         packet_send();          packet_send();
 }  }

Legend:
Removed from v.1.120  
changed lines
  Added in v.1.121