[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.112 and 1.112.2.2

version 1.112, 2003/06/28 16:23:06 version 1.112.2.2, 2004/08/19 22:37:31
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 89 
Line 91 
 /* Flag indicating that stdin should be redirected from /dev/null. */  /* Flag indicating that stdin should be redirected from /dev/null. */
 extern int stdin_null_flag;  extern int stdin_null_flag;
   
   /* Flag indicating that no shell has been requested */
   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 124 
Line 132 
 static int connection_out;      /* Connection to server (output). */  static int connection_out;      /* Connection to server (output). */
 static int need_rekeying;       /* Set to non-zero if rekeying is requested. */  static int need_rekeying;       /* Set to non-zero if rekeying is requested. */
 static int session_closed = 0;  /* In SSH2: login session closed. */  static int session_closed = 0;  /* In SSH2: login session closed. */
   static int server_alive_timeouts = 0;
   
 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;
                 fatal_remove_cleanup((void (*) (void *)) leave_non_blocking, NULL);  
         }          }
 }  }
   
Line 149 
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));
         fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL);  
 }  }
   
 /*  /*
Line 290 
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 312 
Line 324 
         }          }
 }  }
   
   static void
   client_global_request_reply(int type, u_int32_t seq, void *ctxt)
   {
           server_alive_timeouts = 0;
           client_global_request_reply_fwd(type, seq, ctxt);
   }
   
   static void
   server_alive_check(void)
   {
           if (++server_alive_timeouts > options.server_alive_count_max)
                   packet_disconnect("Timeout, server not responding.");
           packet_start(SSH2_MSG_GLOBAL_REQUEST);
           packet_put_cstring("keepalive@openssh.com");
           packet_put_char(1);     /* boolean: want reply */
           packet_send();
   }
   
 /*  /*
  * 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;
           int ret;
   
         /* Add any selections by the channel mechanism. */          /* Add any selections by the channel mechanism. */
         channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying);          channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying);
   
Line 359 
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
          * event pending. Note: if you want to implement SSH_MSG_IGNORE           * event pending.
          * messages to fool traffic analysis, this might be the place to do  
          * it: just have a random timeout for the select, and send a random  
          * SSH_MSG_IGNORE packet when the timeout expires.  
          */           */
   
         if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) {          if (options.server_alive_interval == 0 || !compat20)
                   tvp = NULL;
           else {
                   tv.tv_sec = options.server_alive_interval;
                   tv.tv_usec = 0;
                   tvp = &tv;
           }
           ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
           if (ret < 0) {
                 char buf[100];                  char buf[100];
   
                 /*                  /*
Line 385 
Line 425 
                 snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));                  snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
                 buffer_append(&stderr_buffer, buf, strlen(buf));                  buffer_append(&stderr_buffer, buf, strlen(buf));
                 quit_pending = 1;                  quit_pending = 1;
         }          } else if (ret == 0)
                   server_alive_check();
 }  }
   
 static void  static void
Line 472 
Line 513 
 }  }
   
 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;
           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;
           }
   
           allowed = 1;
           if (options.control_master == 2) {
                   char *p, prompt[1024];
   
                   allowed = 0;
                   snprintf(prompt, sizeof(prompt),
                       "Allow shared connection to %s? ", host);
                   p = read_passphrase(prompt, RP_USE_ASKPASS|RP_ALLOW_EOF);
                   if (p != NULL) {
                           /*
                            * Accept empty responses and responses consisting
                            * of the word "yes" as affirmative.
                            */
                           if (*p == '\0' || *p == '\n' ||
                               strcasecmp(p, "yes") == 0)
                                   allowed = 1;
                           xfree(p);
                   }
           }
   
           unset_nonblock(client_fd);
   
           buffer_init(&m);
   
           buffer_put_int(&m, allowed);
           buffer_put_int(&m, getpid());
           if (ssh_msg_send(client_fd, /* version */0, &m) == -1) {
                   error("%s: client msg_send failed", __func__);
                   close(client_fd);
                   buffer_free(&m);
                   return;
           }
           buffer_clear(&m);
   
           if (!allowed) {
                   error("Refused control connection");
                   close(client_fd);
                   buffer_free(&m);
                   return;
           }
   
           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)) != 0) {
                   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 = buffer_get_int(&m);
           cctx->want_subsys = buffer_get_int(&m);
           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));
   
           buffer_clear(&m);
           if (ssh_msg_send(client_fd, /* version */0, &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);
                   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;
         u_short fwd_port, fwd_host_port;          u_short fwd_port, fwd_host_port;
         char buf[1024], sfwd_port[6], sfwd_host_port[6];          char buf[1024], sfwd_port[6], sfwd_host_port[6];
           int delete = 0;
         int local = 0;          int local = 0;
   
         leave_raw_mode();          leave_raw_mode();
Line 487 
Line 745 
                 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 &&                  if (sscanf(s, "%5[0-9]", sfwd_host_port) != 1) {
             sscanf(s, "%5[0-9]/%255[^/]/%5[0-9]",                          logit("Bad forwarding specification.");
             sfwd_port, buf, sfwd_host_port) != 3) {  
                 logit("Bad forwarding specification.");  
                 goto out;  
         }  
         if ((fwd_port = a2port(sfwd_port)) == 0 ||  
             (fwd_host_port = a2port(sfwd_host_port)) == 0) {  
                 logit("Bad forwarding port(s).");  
                 goto out;  
         }  
         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                  if ((fwd_host_port = a2port(sfwd_host_port)) == 0) {
                 channel_request_remote_forwarding(fwd_port, buf,                          logit("Bad forwarding port(s).");
                     fwd_host_port);                          goto out;
         logit("Forwarding port.");                  }
                   channel_request_rforward_cancel(fwd_host_port);
           } else {
                   if (sscanf(s, "%5[0-9]:%255[^:]:%5[0-9]",
                       sfwd_port, buf, sfwd_host_port) != 3 &&
                       sscanf(s, "%5[0-9]/%255[^/]/%5[0-9]",
                       sfwd_port, buf, sfwd_host_port) != 3) {
                           logit("Bad forwarding specification.");
                           goto out;
                   }
                   if ((fwd_port = a2port(sfwd_port)) == 0 ||
                       (fwd_host_port = a2port(sfwd_host_port)) == 0) {
                           logit("Bad forwarding port(s).");
                           goto out;
                   }
                   if (local) {
                           if (channel_setup_local_fwd_listener(fwd_port, buf,
                               fwd_host_port, options.gateway_ports) < 0) {
                                   logit("Port forwarding failed.");
                                   goto out;
                           }
                   } else
                           channel_request_remote_forwarding(fwd_port, buf,
                               fwd_host_port);
                   logit("Forwarding port.");
           }
   
 out:  out:
         signal(SIGINT, handler);          signal(SIGINT, handler);
         enter_raw_mode();          enter_raw_mode();
Line 839 
Line 1130 
 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;
         if (in_raw_mode())          leave_raw_mode();
                 leave_raw_mode();  
 }  }
   
 /*  /*
Line 860 
Line 1147 
 {  {
         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 876 
Line 1164 
         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 993 
Line 1283 
                 /* 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 1034 
Line 1327 
         if (!isatty(fileno(stderr)))          if (!isatty(fileno(stderr)))
                 unset_nonblock(fileno(stderr));                  unset_nonblock(fileno(stderr));
   
         if (received_signal) {          /*
                 if (in_non_blocking_mode)       /* XXX */           * If there was no shell or command requested, there will be no remote
                         leave_non_blocking();           * exit status to be returned.  In that case, clear error code if the
                 fatal("Killed by signal %d.", (int) received_signal);           * connection was deliberately terminated at this end.
            */
           if (no_shell_flag && received_signal == SIGTERM) {
                   received_signal = 0;
                   exit_status = 0;
         }          }
   
           if (received_signal)
                   fatal("Killed by signal %d.", (int) received_signal);
   
         /*          /*
          * In interactive mode (with pseudo tty) display a message indicating           * In interactive mode (with pseudo tty) display a message indicating
          * that the connection has been closed.           * that the connection has been closed.
Line 1131 
Line 1431 
         /* Flag that we want to exit. */          /* Flag that we want to exit. */
         quit_pending = 1;          quit_pending = 1;
 }  }
   static void
   client_input_agent_open(int type, u_int32_t seq, void *ctxt)
   {
           Channel *c = NULL;
           int remote_id, sock;
   
           /* Read the remote channel number from the message. */
           remote_id = packet_get_int();
           packet_check_eom();
   
           /*
            * Get a connection to the local authentication agent (this may again
            * get forwarded).
            */
           sock = ssh_get_authentication_socket();
   
           /*
            * If we could not connect the agent, send an error message back to
            * the server. This should never happen unless the agent dies,
            * because authentication forwarding is only enabled if we have an
            * agent.
            */
           if (sock >= 0) {
                   c = channel_new("", SSH_CHANNEL_OPEN, sock, sock,
                       -1, 0, 0, 0, "authentication agent connection", 1);
                   c->remote_id = remote_id;
                   c->force_drain = 1;
           }
           if (c == NULL) {
                   packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
                   packet_put_int(remote_id);
           } else {
                   /* Send a confirmation to the remote host. */
                   debug("Forwarding authentication connection.");
                   packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
                   packet_put_int(remote_id);
                   packet_put_int(c->self);
           }
           packet_send();
   }
   
 static Channel *  static Channel *
 client_request_forwarded_tcpip(const char *request_type, int rchan)  client_request_forwarded_tcpip(const char *request_type, int rchan)
 {  {
Line 1277 
Line 1617 
 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 1287 
Line 1627 
         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 1318 
Line 1662 
   
         rtype = packet_get_string(NULL);          rtype = packet_get_string(NULL);
         want_reply = packet_get_char();          want_reply = packet_get_char();
         debug("client_input_global_request: rtype %s want_reply %d", rtype, want_reply);          debug("client_input_global_request: rtype %s want_reply %d",
               rtype, want_reply);
         if (want_reply) {          if (want_reply) {
                 packet_start(success ?                  packet_start(success ?
                     SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);                      SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
Line 1328 
Line 1673 
         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;
   
           debug2("%s: id %d", __func__, 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 */
           }
   
           /* 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 1366 
Line 1802 
         dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data);          dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data);
   
         dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ?          dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ?
             &auth_input_open_request : &deny_input_open);              &client_input_agent_open : &deny_input_open);
         dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ?          dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ?
             &x11_input_open : &deny_input_open);              &x11_input_open : &deny_input_open);
 }  }
Line 1386 
Line 1822 
                 client_init_dispatch_13();                  client_init_dispatch_13();
         else          else
                 client_init_dispatch_15();                  client_init_dispatch_15();
   }
   
   /* client specific fatal cleanup */
   void
   cleanup_exit(int i)
   {
           leave_raw_mode();
           leave_non_blocking();
           if (options.control_path != NULL && control_fd != -1)
                   unlink(options.control_path);
           _exit(i);
 }  }

Legend:
Removed from v.1.112  
changed lines
  Added in v.1.112.2.2