[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.2.2 and 1.113

version 1.112.2.2, 2004/08/19 22:37:31 version 1.113, 2003/09/19 17:43:35
Line 79 
Line 79 
 #include "clientloop.h"  #include "clientloop.h"
 #include "authfd.h"  #include "authfd.h"
 #include "atomicio.h"  #include "atomicio.h"
 #include "sshpty.h"  #include "sshtty.h"
 #include "misc.h"  #include "misc.h"
 #include "monitor_fdpass.h"  #include "readpass.h"
 #include "match.h"  
 #include "msg.h"  
   
 /* import options */  /* import options */
 extern Options options;  extern Options options;
Line 91 
Line 89 
 /* 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 132 
Line 124 
 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) {
                 unset_nonblock(fileno(stdin));                  (void) fcntl(fileno(stdin), F_SETFL, 0);
                 in_non_blocking_mode = 0;                  in_non_blocking_mode = 0;
         }          }
 }  }
Line 168 
Line 148 
 enter_non_blocking(void)  enter_non_blocking(void)
 {  {
         in_non_blocking_mode = 1;          in_non_blocking_mode = 1;
         set_nonblock(fileno(stdin));          (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
 }  }
   
 /*  /*
Line 308 
Line 288 
         /** 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_send_window_changes();                  channel_request_start(session_ident, "window-change", 0);
                   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 324 
Line 310 
         }          }
 }  }
   
 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, u_int *nallocp, int rekeying)      int *maxfdp, 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 391 
Line 357 
         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.           * event pending. Note: if you want to implement SSH_MSG_IGNORE
            * 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 (options.server_alive_interval == 0 || !compat20)          if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) {
                 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 425 
Line 383 
                 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 513 
Line 470 
 }  }
   
 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 745 
Line 485 
                 goto out;                  goto out;
         while (*s && isspace(*s))          while (*s && isspace(*s))
                 s++;                  s++;
         if (*s == '-')          if (*s == 0)
                 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 == 'L')          if (s[1] == 'L')
                 local = 1;                  local = 1;
         if (local && delete) {          if (!local && !compat20) {
                 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 (delete) {          if (sscanf(s, "%5[0-9]:%255[^:]:%5[0-9]",
                 if (sscanf(s, "%5[0-9]", sfwd_host_port) != 1) {              sfwd_port, buf, sfwd_host_port) != 3 &&
                         logit("Bad forwarding specification.");              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;                          goto out;
                 }                  }
                 if ((fwd_host_port = a2port(sfwd_host_port)) == 0) {          } else
                         logit("Bad forwarding port(s).");                  channel_request_remote_forwarding(fwd_port, buf,
                         goto out;                      fwd_host_port);
                 }          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 1130 
Line 837 
 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 1147 
Line 857 
 {  {
         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;          int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0;
         u_int nalloc = 0;  
         char buf[100];          char buf[100];
   
         debug("Entering interactive session.");          debug("Entering interactive session.");
Line 1164 
Line 873 
         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 1283 
Line 990 
                 /* 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 1327 
Line 1031 
         if (!isatty(fileno(stderr)))          if (!isatty(fileno(stderr)))
                 unset_nonblock(fileno(stderr));                  unset_nonblock(fileno(stderr));
   
         /*  
          * If there was no shell or command requested, there will be no remote  
          * exit status to be returned.  In that case, clear error code if the  
          * connection was deliberately terminated at this end.  
          */  
         if (no_shell_flag && received_signal == SIGTERM) {  
                 received_signal = 0;  
                 exit_status = 0;  
         }  
   
         if (received_signal)          if (received_signal)
                 fatal("Killed by signal %d.", (int) received_signal);                  fatal("Killed by signal %d.", (int) received_signal);
   
Line 1431 
Line 1125 
         /* 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 1617 
Line 1271 
 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 exitval, id, reply, success = 0;          int id, reply, success = 0;
         char *rtype;          char *rtype;
   
         id = packet_get_int();          id = packet_get_int();
Line 1627 
Line 1281 
         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 (id == -1) {          if (session_ident == -1) {
                 error("client_input_channel_req: request for channel -1");                  error("client_input_channel_req: no channel %d", session_ident);
         } else if ((c = channel_lookup(id)) == NULL) {          } else if (id != session_ident) {
                   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) {
                 exitval = packet_get_int();                  success = 1;
                 if (id == session_ident) {                  exit_status = packet_get_int();
                         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(id);                  packet_put_int(c->remote_id);
                 packet_send();                  packet_send();
         }          }
         xfree(rtype);          xfree(rtype);
Line 1662 
Line 1312 
   
         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",          debug("client_input_global_request: rtype %s want_reply %d", rtype, want_reply);
             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 1673 
Line 1322 
         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 1802 
Line 1360 
         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 ?
             &client_input_agent_open : &deny_input_open);              &auth_input_open_request : &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 1826 
Line 1384 
   
 /* client specific fatal cleanup */  /* client specific fatal cleanup */
 void  void
 cleanup_exit(int i)  fatal(const char *fmt,...)
 {  {
           va_list args;
   
           va_start(args, fmt);
           do_log(SYSLOG_LEVEL_FATAL, fmt, args);
           va_end(args);
         leave_raw_mode();          leave_raw_mode();
         leave_non_blocking();          leave_non_blocking();
         if (options.control_path != NULL && control_fd != -1)          _exit(255);
                 unlink(options.control_path);  
         _exit(i);  
 }  }

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