[BACK]Return to clientloop.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/clientloop.c between version 1.117 and 1.117.2.2

version 1.117, 2003/12/16 15:49:51 version 1.117.2.2, 2005/03/10 17:15:04
Line 79 
Line 79 
 #include "clientloop.h"  #include "clientloop.h"
 #include "authfd.h"  #include "authfd.h"
 #include "atomicio.h"  #include "atomicio.h"
 #include "sshtty.h"  #include "sshpty.h"
 #include "misc.h"  #include "misc.h"
 #include "readpass.h"  #include "monitor_fdpass.h"
   #include "match.h"
   #include "msg.h"
   
 /* import options */  /* import options */
 extern Options options;  extern Options options;
Line 92 
Line 94 
 /* Flag indicating that no shell has been requested */  /* Flag indicating that no shell has been requested */
 extern int no_shell_flag;  extern int no_shell_flag;
   
   /* Control socket */
   extern int control_fd;
   
 /*  /*
  * Name of the host we are connecting to.  This is the name given on the   * Name of the host we are connecting to.  This is the name given on the
  * command line, or the HostName specified for the user-supplied name in a   * command line, or the HostName specified for the user-supplied name in a
Line 132 
Line 137 
 static void client_init_dispatch(void);  static void client_init_dispatch(void);
 int     session_ident = -1;  int     session_ident = -1;
   
   struct confirm_ctx {
           int want_tty;
           int want_subsys;
           Buffer cmd;
           char *term;
           struct termios tio;
           char **env;
   };
   
 /*XXX*/  /*XXX*/
 extern Kex *xxx_kex;  extern Kex *xxx_kex;
   
   void ssh_process_session2_setup(int, int, int, Buffer *);
   
 /* Restores stdin to blocking mode. */  /* Restores stdin to blocking mode. */
   
 static void  static void
 leave_non_blocking(void)  leave_non_blocking(void)
 {  {
         if (in_non_blocking_mode) {          if (in_non_blocking_mode) {
                 (void) fcntl(fileno(stdin), F_SETFL, 0);                  unset_nonblock(fileno(stdin));
                 in_non_blocking_mode = 0;                  in_non_blocking_mode = 0;
         }          }
 }  }
Line 152 
Line 168 
 enter_non_blocking(void)  enter_non_blocking(void)
 {  {
         in_non_blocking_mode = 1;          in_non_blocking_mode = 1;
         (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);          set_nonblock(fileno(stdin));
 }  }
   
 /*  /*
Line 292 
Line 308 
         /** XXX race */          /** XXX race */
         received_window_change_signal = 0;          received_window_change_signal = 0;
   
         if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)  
                 return;  
   
         debug2("client_check_window_change: changed");          debug2("client_check_window_change: changed");
   
         if (compat20) {          if (compat20) {
                 channel_request_start(session_ident, "window-change", 0);                  channel_send_window_changes();
                 packet_put_int(ws.ws_col);  
                 packet_put_int(ws.ws_row);  
                 packet_put_int(ws.ws_xpixel);  
                 packet_put_int(ws.ws_ypixel);  
                 packet_send();  
         } else {          } else {
                   if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
                           return;
                 packet_start(SSH_CMSG_WINDOW_SIZE);                  packet_start(SSH_CMSG_WINDOW_SIZE);
                 packet_put_int(ws.ws_row);                  packet_put_int(ws.ws_row);
                 packet_put_int(ws.ws_col);                  packet_put_int(ws.ws_col);
Line 336 
Line 346 
  * Waits until the client can do something (some data becomes available on   * Waits until the client can do something (some data becomes available on
  * one of the file descriptors).   * one of the file descriptors).
  */   */
   
 static void  static void
 client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,  client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
     int *maxfdp, int *nallocp, int rekeying)      int *maxfdp, u_int *nallocp, int rekeying)
 {  {
         struct timeval tv, *tvp;          struct timeval tv, *tvp;
         int ret;          int ret;
Line 382 
Line 391 
         if (packet_have_data_to_write())          if (packet_have_data_to_write())
                 FD_SET(connection_out, *writesetp);                  FD_SET(connection_out, *writesetp);
   
           if (control_fd != -1)
                   FD_SET(control_fd, *readsetp);
   
         /*          /*
          * Wait for something to happen.  This will suspend the process until           * Wait for something to happen.  This will suspend the process until
          * some selected descriptor can be read, written, or has some other           * some selected descriptor can be read, written, or has some other
Line 390 
Line 402 
   
         if (options.server_alive_interval == 0 || !compat20)          if (options.server_alive_interval == 0 || !compat20)
                 tvp = NULL;                  tvp = NULL;
         else {          else {
                 tv.tv_sec = options.server_alive_interval;                  tv.tv_sec = options.server_alive_interval;
                 tv.tv_usec = 0;                  tv.tv_usec = 0;
                 tvp = &tv;                  tvp = &tv;
Line 420 
Line 432 
 static void  static void
 client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)  client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
 {  {
         struct winsize oldws, newws;  
   
         /* Flush stdout and stderr buffers. */          /* Flush stdout and stderr buffers. */
         if (buffer_len(bout) > 0)          if (buffer_len(bout) > 0)
                 atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout));                  atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout));
Line 438 
Line 448 
         buffer_free(bout);          buffer_free(bout);
         buffer_free(berr);          buffer_free(berr);
   
         /* Save old window size. */  
         ioctl(fileno(stdin), TIOCGWINSZ, &oldws);  
   
         /* Send the suspend signal to the program itself. */          /* Send the suspend signal to the program itself. */
         kill(getpid(), SIGTSTP);          kill(getpid(), SIGTSTP);
   
         /* Check if the window size has changed. */          /* Reset window sizes in case they have changed */
         if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 &&          received_window_change_signal = 1;
             (oldws.ws_row != newws.ws_row ||  
             oldws.ws_col != newws.ws_col ||  
             oldws.ws_xpixel != newws.ws_xpixel ||  
             oldws.ws_ypixel != newws.ws_ypixel))  
                 received_window_change_signal = 1;  
   
         /* OK, we have been continued by the user. Reinitialize buffers. */          /* OK, we have been continued by the user. Reinitialize buffers. */
         buffer_init(bin);          buffer_init(bin);
Line 501 
Line 503 
 }  }
   
 static void  static void
   client_subsystem_reply(int type, u_int32_t seq, void *ctxt)
   {
           int id;
           Channel *c;
   
           id = packet_get_int();
           packet_check_eom();
   
           if ((c = channel_lookup(id)) == NULL) {
                   error("%s: no channel for id %d", __func__, id);
                   return;
           }
   
           if (type == SSH2_MSG_CHANNEL_SUCCESS)
                   debug2("Request suceeded on channel %d", id);
           else if (type == SSH2_MSG_CHANNEL_FAILURE) {
                   error("Request failed on channel %d", id);
                   channel_free(c);
           }
   }
   
   static void
   client_extra_session2_setup(int id, void *arg)
   {
           struct confirm_ctx *cctx = arg;
           Channel *c;
           int i;
   
           if (cctx == NULL)
                   fatal("%s: cctx == NULL", __func__);
           if ((c = channel_lookup(id)) == NULL)
                   fatal("%s: no channel for id %d", __func__, id);
   
           client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
               cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env,
               client_subsystem_reply);
   
           c->confirm_ctx = NULL;
           buffer_free(&cctx->cmd);
           xfree(cctx->term);
           if (cctx->env != NULL) {
                   for (i = 0; cctx->env[i] != NULL; i++)
                           xfree(cctx->env[i]);
                   xfree(cctx->env);
           }
           xfree(cctx);
   }
   
   static void
   client_process_control(fd_set * readset)
   {
           Buffer m;
           Channel *c;
           int client_fd, new_fd[3], ver, i, allowed;
           socklen_t addrlen;
           struct sockaddr_storage addr;
           struct confirm_ctx *cctx;
           char *cmd;
           u_int len, env_len, command, flags;
           uid_t euid;
           gid_t egid;
   
           /*
            * Accept connection on control socket
            */
           if (control_fd == -1 || !FD_ISSET(control_fd, readset))
                   return;
   
           memset(&addr, 0, sizeof(addr));
           addrlen = sizeof(addr);
           if ((client_fd = accept(control_fd,
               (struct sockaddr*)&addr, &addrlen)) == -1) {
                   error("%s accept: %s", __func__, strerror(errno));
                   return;
           }
   
           if (getpeereid(client_fd, &euid, &egid) < 0) {
                   error("%s getpeereid failed: %s", __func__, strerror(errno));
                   close(client_fd);
                   return;
           }
           if ((euid != 0) && (getuid() != euid)) {
                   error("control mode uid mismatch: peer euid %u != uid %u",
                       (u_int) euid, (u_int) getuid());
                   close(client_fd);
                   return;
           }
   
           unset_nonblock(client_fd);
   
           /* Read command */
           buffer_init(&m);
           if (ssh_msg_recv(client_fd, &m) == -1) {
                   error("%s: client msg_recv failed", __func__);
                   close(client_fd);
                   buffer_free(&m);
                   return;
           }
           if ((ver = buffer_get_char(&m)) != 1) {
                   error("%s: wrong client version %d", __func__, ver);
                   buffer_free(&m);
                   close(client_fd);
                   return;
           }
   
           allowed = 1;
           command = buffer_get_int(&m);
           flags = buffer_get_int(&m);
   
           buffer_clear(&m);
   
           switch (command) {
           case SSHMUX_COMMAND_OPEN:
                   if (options.control_master == 2)
                           allowed = ask_permission("Allow shared connection "
                               "to %s? ", host);
                   /* continue below */
                   break;
           case SSHMUX_COMMAND_TERMINATE:
                   if (options.control_master == 2)
                           allowed = ask_permission("Terminate shared connection "
                               "to %s? ", host);
                   if (allowed)
                           quit_pending = 1;
                   /* FALLTHROUGH */
           case SSHMUX_COMMAND_ALIVE_CHECK:
                   /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */
                   buffer_clear(&m);
                   buffer_put_int(&m, allowed);
                   buffer_put_int(&m, getpid());
                   if (ssh_msg_send(client_fd, /* version */1, &m) == -1) {
                           error("%s: client msg_send failed", __func__);
                           close(client_fd);
                           buffer_free(&m);
                           return;
                   }
                   buffer_free(&m);
                   close(client_fd);
                   return;
           default:
                   error("Unsupported command %d", command);
                   buffer_free(&m);
                   close(client_fd);
                   return;
           }
   
           /* Reply for SSHMUX_COMMAND_OPEN */
           buffer_clear(&m);
           buffer_put_int(&m, allowed);
           buffer_put_int(&m, getpid());
           if (ssh_msg_send(client_fd, /* version */1, &m) == -1) {
                   error("%s: client msg_send failed", __func__);
                   close(client_fd);
                   buffer_free(&m);
                   return;
           }
   
           if (!allowed) {
                   error("Refused control connection");
                   close(client_fd);
                   buffer_free(&m);
                   return;
           }
   
           buffer_clear(&m);
           if (ssh_msg_recv(client_fd, &m) == -1) {
                   error("%s: client msg_recv failed", __func__);
                   close(client_fd);
                   buffer_free(&m);
                   return;
           }
           if ((ver = buffer_get_char(&m)) != 1) {
                   error("%s: wrong client version %d", __func__, ver);
                   buffer_free(&m);
                   close(client_fd);
                   return;
           }
   
           cctx = xmalloc(sizeof(*cctx));
           memset(cctx, 0, sizeof(*cctx));
           cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0;
           cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0;
           cctx->term = buffer_get_string(&m, &len);
   
           cmd = buffer_get_string(&m, &len);
           buffer_init(&cctx->cmd);
           buffer_append(&cctx->cmd, cmd, strlen(cmd));
   
           env_len = buffer_get_int(&m);
           env_len = MIN(env_len, 4096);
           debug3("%s: receiving %d env vars", __func__, env_len);
           if (env_len != 0) {
                   cctx->env = xmalloc(sizeof(*cctx->env) * (env_len + 1));
                   for (i = 0; i < env_len; i++)
                           cctx->env[i] = buffer_get_string(&m, &len);
                   cctx->env[i] = NULL;
           }
   
           debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__,
               cctx->want_tty, cctx->want_subsys, cmd);
   
           /* Gather fds from client */
           new_fd[0] = mm_receive_fd(client_fd);
           new_fd[1] = mm_receive_fd(client_fd);
           new_fd[2] = mm_receive_fd(client_fd);
   
           debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
               new_fd[0], new_fd[1], new_fd[2]);
   
           /* Try to pick up ttymodes from client before it goes raw */
           if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
                   error("%s: tcgetattr: %s", __func__, strerror(errno));
   
           /* This roundtrip is just for synchronisation of ttymodes */
           buffer_clear(&m);
           if (ssh_msg_send(client_fd, /* version */1, &m) == -1) {
                   error("%s: client msg_send failed", __func__);
                   close(client_fd);
                   close(new_fd[0]);
                   close(new_fd[1]);
                   close(new_fd[2]);
                   buffer_free(&m);
                   xfree(cctx->term);
                   if (env_len != 0) {
                           for (i = 0; i < env_len; i++)
                                   xfree(cctx->env[i]);
                           xfree(cctx->env);
                   }
                   return;
           }
           buffer_free(&m);
   
           /* enable nonblocking unless tty */
           if (!isatty(new_fd[0]))
                   set_nonblock(new_fd[0]);
           if (!isatty(new_fd[1]))
                   set_nonblock(new_fd[1]);
           if (!isatty(new_fd[2]))
                   set_nonblock(new_fd[2]);
   
           set_nonblock(client_fd);
   
           c = channel_new("session", SSH_CHANNEL_OPENING,
               new_fd[0], new_fd[1], new_fd[2],
               CHAN_SES_WINDOW_DEFAULT, CHAN_SES_PACKET_DEFAULT,
               CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
   
           /* XXX */
           c->ctl_fd = client_fd;
   
           debug3("%s: channel_new: %d", __func__, c->self);
   
           channel_send_open(c->self);
           channel_register_confirm(c->self, client_extra_session2_setup, cctx);
   }
   
   static void
 process_cmdline(void)  process_cmdline(void)
 {  {
         void (*handler)(int);          void (*handler)(int);
         char *s, *cmd;          char *s, *cmd, *cancel_host;
         u_short fwd_port, fwd_host_port;          int delete = 0;
         char buf[1024], sfwd_port[6], sfwd_host_port[6];  
         int local = 0;          int local = 0;
           u_short cancel_port;
           Forward fwd;
   
         leave_raw_mode();          leave_raw_mode();
         handler = signal(SIGINT, SIG_IGN);          handler = signal(SIGINT, SIG_IGN);
Line 516 
Line 776 
                 goto out;                  goto out;
         while (*s && isspace(*s))          while (*s && isspace(*s))
                 s++;                  s++;
         if (*s == 0)          if (*s == '-')
                   s++;    /* Skip cmdline '-', if any */
           if (*s == '\0')
                 goto out;                  goto out;
         if (strlen(s) < 2 || s[0] != '-' || !(s[1] == 'L' || s[1] == 'R')) {  
           if (*s == 'h' || *s == 'H' || *s == '?') {
                   logit("Commands:");
                   logit("      -Lport:host:hostport    Request local forward");
                   logit("      -Rport:host:hostport    Request remote forward");
                   logit("      -KRhostport             Cancel remote forward");
                   goto out;
           }
   
           if (*s == 'K') {
                   delete = 1;
                   s++;
           }
           if (*s != 'L' && *s != 'R') {
                 logit("Invalid command.");                  logit("Invalid command.");
                 goto out;                  goto out;
         }          }
         if (s[1] == 'L')          if (*s == 'L')
                 local = 1;                  local = 1;
         if (!local && !compat20) {          if (local && delete) {
                   logit("Not supported.");
                   goto out;
           }
           if ((!local || delete) && !compat20) {
                 logit("Not supported for SSH protocol version 1.");                  logit("Not supported for SSH protocol version 1.");
                 goto out;                  goto out;
         }          }
         s += 2;  
           s++;
         while (*s && isspace(*s))          while (*s && isspace(*s))
                 s++;                  s++;
   
         if (sscanf(s, "%5[0-9]:%255[^:]:%5[0-9]",          if (delete) {
             sfwd_port, buf, sfwd_host_port) != 3 &&                  cancel_port = 0;
             sscanf(s, "%5[0-9]/%255[^/]/%5[0-9]",                  cancel_host = hpdelim(&s);      /* may be NULL */
             sfwd_port, buf, sfwd_host_port) != 3) {                  if (s != NULL) {
                 logit("Bad forwarding specification.");                          cancel_port = a2port(s);
                 goto out;                          cancel_host = cleanhostname(cancel_host);
         }                  } else {
         if ((fwd_port = a2port(sfwd_port)) == 0 ||                          cancel_port = a2port(cancel_host);
             (fwd_host_port = a2port(sfwd_host_port)) == 0) {                          cancel_host = NULL;
                 logit("Bad forwarding port(s).");                  }
                 goto out;                  if (cancel_port == 0) {
         }                          logit("Bad forwarding close port");
         if (local) {  
                 if (channel_setup_local_fwd_listener(fwd_port, buf,  
                     fwd_host_port, options.gateway_ports) < 0) {  
                         logit("Port forwarding failed.");  
                         goto out;                          goto out;
                 }                  }
         } else                  channel_request_rforward_cancel(cancel_host, cancel_port);
                 channel_request_remote_forwarding(fwd_port, buf,          } else {
                     fwd_host_port);                  if (!parse_forward(&fwd, s)) {
         logit("Forwarding port.");                          logit("Bad forwarding specification.");
                           goto out;
                   }
                   if (local) {
                           if (channel_setup_local_fwd_listener(fwd.listen_host,
                               fwd.listen_port, fwd.connect_host,
                               fwd.connect_port, options.gateway_ports) < 0) {
                                   logit("Port forwarding failed.");
                                   goto out;
                           }
                   } else {
                           channel_request_remote_forwarding(fwd.listen_host,
                               fwd.listen_port, fwd.connect_host,
                               fwd.connect_port);
                   }
   
                   logit("Forwarding port.");
           }
   
 out:  out:
         signal(SIGINT, handler);          signal(SIGINT, handler);
         enter_raw_mode();          enter_raw_mode();
Line 868 
Line 1162 
 static void  static void
 client_channel_closed(int id, void *arg)  client_channel_closed(int id, void *arg)
 {  {
         if (id != session_ident)  
                 error("client_channel_closed: id %d != session_ident %d",  
                     id, session_ident);  
         channel_cancel_cleanup(id);          channel_cancel_cleanup(id);
         session_closed = 1;          session_closed = 1;
         leave_raw_mode();          leave_raw_mode();
Line 888 
Line 1179 
 {  {
         fd_set *readset = NULL, *writeset = NULL;          fd_set *readset = NULL, *writeset = NULL;
         double start_time, total_time;          double start_time, total_time;
         int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0;          int max_fd = 0, max_fd2 = 0, len, rekeying = 0;
           u_int nalloc = 0;
         char buf[100];          char buf[100];
   
         debug("Entering interactive session.");          debug("Entering interactive session.");
Line 904 
Line 1196 
         connection_in = packet_get_connection_in();          connection_in = packet_get_connection_in();
         connection_out = packet_get_connection_out();          connection_out = packet_get_connection_out();
         max_fd = MAX(connection_in, connection_out);          max_fd = MAX(connection_in, connection_out);
           if (control_fd != -1)
                   max_fd = MAX(max_fd, control_fd);
   
         if (!compat20) {          if (!compat20) {
                 /* enable nonblocking unless tty */                  /* enable nonblocking unless tty */
Line 934 
Line 1228 
          * Set signal handlers, (e.g. to restore non-blocking mode)           * Set signal handlers, (e.g. to restore non-blocking mode)
          * but don't overwrite SIG_IGN, matches behaviour from rsh(1)           * but don't overwrite SIG_IGN, matches behaviour from rsh(1)
          */           */
           if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
                   signal(SIGHUP, signal_handler);
         if (signal(SIGINT, SIG_IGN) != SIG_IGN)          if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                 signal(SIGINT, signal_handler);                  signal(SIGINT, signal_handler);
         if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)          if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
                 signal(SIGQUIT, signal_handler);                  signal(SIGQUIT, signal_handler);
         if (signal(SIGTERM, SIG_IGN) != SIG_IGN)          if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
                 signal(SIGTERM, signal_handler);                  signal(SIGTERM, signal_handler);
         if (have_pty)          signal(SIGWINCH, window_change_handler);
                 signal(SIGWINCH, window_change_handler);  
   
         if (have_pty)          if (have_pty)
                 enter_raw_mode();                  enter_raw_mode();
Line 1021 
Line 1316 
                 /* Buffer input from the connection.  */                  /* Buffer input from the connection.  */
                 client_process_net_input(readset);                  client_process_net_input(readset);
   
                   /* Accept control connections.  */
                   client_process_control(readset);
   
                 if (quit_pending)                  if (quit_pending)
                         break;                          break;
   
Line 1046 
Line 1344 
         /* Terminate the session. */          /* Terminate the session. */
   
         /* Stop watching for window change. */          /* Stop watching for window change. */
         if (have_pty)          signal(SIGWINCH, SIG_DFL);
                 signal(SIGWINCH, SIG_DFL);  
   
         channel_free_all();          channel_free_all();
   
Line 1352 
Line 1649 
 client_input_channel_req(int type, u_int32_t seq, void *ctxt)  client_input_channel_req(int type, u_int32_t seq, void *ctxt)
 {  {
         Channel *c = NULL;          Channel *c = NULL;
         int id, reply, success = 0;          int exitval, id, reply, success = 0;
         char *rtype;          char *rtype;
   
         id = packet_get_int();          id = packet_get_int();
Line 1362 
Line 1659 
         debug("client_input_channel_req: channel %d rtype %s reply %d",          debug("client_input_channel_req: channel %d rtype %s reply %d",
             id, rtype, reply);              id, rtype, reply);
   
         if (session_ident == -1) {          if (id == -1) {
                 error("client_input_channel_req: no channel %d", session_ident);                  error("client_input_channel_req: request for channel -1");
         } else if (id != session_ident) {          } else if ((c = channel_lookup(id)) == NULL) {
                 error("client_input_channel_req: channel %d: wrong channel: %d",  
                     session_ident, id);  
         }  
         c = channel_lookup(id);  
         if (c == NULL) {  
                 error("client_input_channel_req: channel %d: unknown channel", id);                  error("client_input_channel_req: channel %d: unknown channel", id);
         } else if (strcmp(rtype, "exit-status") == 0) {          } else if (strcmp(rtype, "exit-status") == 0) {
                 success = 1;                  exitval = packet_get_int();
                 exit_status = packet_get_int();                  if (id == session_ident) {
                           success = 1;
                           exit_status = exitval;
                   } else if (c->ctl_fd == -1) {
                           error("client_input_channel_req: unexpected channel %d",
                               session_ident);
                   } else {
                           atomicio(vwrite, c->ctl_fd, &exitval, sizeof(exitval));
                           success = 1;
                   }
                 packet_check_eom();                  packet_check_eom();
         }          }
         if (reply) {          if (reply) {
                 packet_start(success ?                  packet_start(success ?
                     SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);                      SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
                 packet_put_int(c->remote_id);                  packet_put_int(id);
                 packet_send();                  packet_send();
         }          }
         xfree(rtype);          xfree(rtype);
Line 1404 
Line 1705 
         xfree(rtype);          xfree(rtype);
 }  }
   
   void
   client_session2_setup(int id, int want_tty, int want_subsystem,
       const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env,
       dispatch_fn *subsys_repl)
   {
           int len;
           Channel *c = NULL;
   
           debug2("%s: id %d", __func__, id);
   
           if ((c = channel_lookup(id)) == NULL)
                   fatal("client_session2_setup: channel %d: unknown channel", id);
   
           if (want_tty) {
                   struct winsize ws;
                   struct termios tio;
   
                   /* Store window size in the packet. */
                   if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0)
                           memset(&ws, 0, sizeof(ws));
   
                   channel_request_start(id, "pty-req", 0);
                   packet_put_cstring(term != NULL ? term : "");
                   packet_put_int(ws.ws_col);
                   packet_put_int(ws.ws_row);
                   packet_put_int(ws.ws_xpixel);
                   packet_put_int(ws.ws_ypixel);
                   tio = get_saved_tio();
                   tty_make_modes(-1, tiop != NULL ? tiop : &tio);
                   packet_send();
                   /* XXX wait for reply */
                   c->client_tty = 1;
           }
   
           /* Transfer any environment variables from client to server */
           if (options.num_send_env != 0 && env != NULL) {
                   int i, j, matched;
                   char *name, *val;
   
                   debug("Sending environment.");
                   for (i = 0; env[i] != NULL; i++) {
                           /* Split */
                           name = xstrdup(env[i]);
                           if ((val = strchr(name, '=')) == NULL) {
                                   free(name);
                                   continue;
                           }
                           *val++ = '\0';
   
                           matched = 0;
                           for (j = 0; j < options.num_send_env; j++) {
                                   if (match_pattern(name, options.send_env[j])) {
                                           matched = 1;
                                           break;
                                   }
                           }
                           if (!matched) {
                                   debug3("Ignored env %s", name);
                                   free(name);
                                   continue;
                           }
   
                           debug("Sending env %s = %s", name, val);
                           channel_request_start(id, "env", 0);
                           packet_put_cstring(name);
                           packet_put_cstring(val);
                           packet_send();
                           free(name);
                   }
           }
   
           len = buffer_len(cmd);
           if (len > 0) {
                   if (len > 900)
                           len = 900;
                   if (want_subsystem) {
                           debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd));
                           channel_request_start(id, "subsystem", subsys_repl != NULL);
                           if (subsys_repl != NULL) {
                                   /* register callback for reply */
                                   /* XXX we assume that client_loop has already been called */
                                   dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl);
                                   dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl);
                           }
                   } else {
                           debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd));
                           channel_request_start(id, "exec", 0);
                   }
                   packet_put_string(buffer_ptr(cmd), buffer_len(cmd));
                   packet_send();
           } else {
                   channel_request_start(id, "shell", 0);
                   packet_send();
           }
   }
   
 static void  static void
 client_init_dispatch_20(void)  client_init_dispatch_20(void)
 {  {
Line 1470 
Line 1867 
 {  {
         leave_raw_mode();          leave_raw_mode();
         leave_non_blocking();          leave_non_blocking();
           if (options.control_path != NULL && control_fd != -1)
                   unlink(options.control_path);
         _exit(i);          _exit(i);
 }  }

Legend:
Removed from v.1.117  
changed lines
  Added in v.1.117.2.2