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

Diff for /src/usr.bin/ssh/ssh.c between version 1.201 and 1.201.2.2

version 1.201, 2003/09/01 18:15:50 version 1.201.2.2, 2004/08/19 22:37:32
Line 13 
Line 13 
  * called by a name other than "ssh" or "Secure Shell".   * called by a name other than "ssh" or "Secure Shell".
  *   *
  * Copyright (c) 1999 Niels Provos.  All rights reserved.   * Copyright (c) 1999 Niels Provos.  All rights reserved.
  * Copyright (c) 2000, 2001, 2002 Markus Friedl.  All rights reserved.   * Copyright (c) 2000, 2001, 2002, 2003 Markus Friedl.  All rights reserved.
  *   *
  * Modified to work with SSL by Niels Provos <provos@citi.umich.edu>   * Modified to work with SSL by Niels Provos <provos@citi.umich.edu>
  * in Canada (German citizen).   * in Canada (German citizen).
Line 53 
Line 53 
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "packet.h"  #include "packet.h"
 #include "buffer.h"  #include "buffer.h"
   #include "bufaux.h"
 #include "channels.h"  #include "channels.h"
 #include "key.h"  #include "key.h"
 #include "authfd.h"  #include "authfd.h"
 #include "authfile.h"  #include "authfile.h"
 #include "pathnames.h"  #include "pathnames.h"
   #include "dispatch.h"
 #include "clientloop.h"  #include "clientloop.h"
 #include "log.h"  #include "log.h"
 #include "readconf.h"  #include "readconf.h"
 #include "sshconnect.h"  #include "sshconnect.h"
 #include "tildexpand.h"  
 #include "dispatch.h"  
 #include "misc.h"  #include "misc.h"
 #include "kex.h"  #include "kex.h"
 #include "mac.h"  #include "mac.h"
 #include "sshtty.h"  #include "sshpty.h"
   #include "match.h"
   #include "msg.h"
   #include "monitor_fdpass.h"
   
 #ifdef SMARTCARD  #ifdef SMARTCARD
 #include "scard.h"  #include "scard.h"
Line 137 
Line 140 
 /* pid of proxycommand child process */  /* pid of proxycommand child process */
 pid_t proxy_command_pid = 0;  pid_t proxy_command_pid = 0;
   
   /* fd to control socket */
   int control_fd = -1;
   
   /* Only used in control client mode */
   volatile sig_atomic_t control_client_terminate = 0;
   u_int control_server_pid = 0;
   
 /* Prints a help message to the user.  This function never returns. */  /* Prints a help message to the user.  This function never returns. */
   
 static void  static void
 usage(void)  usage(void)
 {  {
         fprintf(stderr, "Usage: %s [options] host [command]\n", __progname);          fprintf(stderr,
         fprintf(stderr, "Options:\n");  "usage: ssh [-1246AaCfghkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n"
         fprintf(stderr, "  -l user     Log in using this user name.\n");  "           [-D port] [-e escape_char] [-F configfile] [-i identity_file]\n"
         fprintf(stderr, "  -n          Redirect input from " _PATH_DEVNULL ".\n");  "           [-L port:host:hostport] [-l login_name] [-m mac_spec] [-o option]\n"
         fprintf(stderr, "  -F config   Config file (default: ~/%s).\n",  "           [-p port] [-R port:host:hostport] [-S ctl] [user@]hostname [command]\n"
              _PATH_SSH_USER_CONFFILE);          );
         fprintf(stderr, "  -A          Enable authentication agent forwarding.\n");  
         fprintf(stderr, "  -a          Disable authentication agent forwarding (default).\n");  
         fprintf(stderr, "  -X          Enable X11 connection forwarding.\n");  
         fprintf(stderr, "  -x          Disable X11 connection forwarding (default).\n");  
         fprintf(stderr, "  -i file     Identity for public key authentication "  
             "(default: ~/.ssh/identity)\n");  
 #ifdef SMARTCARD  
         fprintf(stderr, "  -I reader   Set smartcard reader.\n");  
 #endif  
         fprintf(stderr, "  -t          Tty; allocate a tty even if command is given.\n");  
         fprintf(stderr, "  -T          Do not allocate a tty.\n");  
         fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");  
         fprintf(stderr, "              Multiple -v increases verbosity.\n");  
         fprintf(stderr, "  -V          Display version number only.\n");  
         fprintf(stderr, "  -q          Quiet; don't display any warning messages.\n");  
         fprintf(stderr, "  -f          Fork into background after authentication.\n");  
         fprintf(stderr, "  -e char     Set escape character; ``none'' = disable (default: ~).\n");  
   
         fprintf(stderr, "  -c cipher   Select encryption algorithm\n");  
         fprintf(stderr, "  -m macs     Specify MAC algorithms for protocol version 2.\n");  
         fprintf(stderr, "  -p port     Connect to this port.  Server must be on the same port.\n");  
         fprintf(stderr, "  -L listen-port:host:port   Forward local port to remote address\n");  
         fprintf(stderr, "  -R listen-port:host:port   Forward remote port to local address\n");  
         fprintf(stderr, "              These cause %s to listen for connections on a port, and\n", __progname);  
         fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");  
         fprintf(stderr, "  -D port     Enable dynamic application-level port forwarding.\n");  
         fprintf(stderr, "  -C          Enable compression.\n");  
         fprintf(stderr, "  -N          Do not execute a shell or command.\n");  
         fprintf(stderr, "  -g          Allow remote hosts to connect to forwarded ports.\n");  
         fprintf(stderr, "  -1          Force protocol version 1.\n");  
         fprintf(stderr, "  -2          Force protocol version 2.\n");  
         fprintf(stderr, "  -4          Use IPv4 only.\n");  
         fprintf(stderr, "  -6          Use IPv6 only.\n");  
         fprintf(stderr, "  -o 'option' Process the option as if it was read from a configuration file.\n");  
         fprintf(stderr, "  -s          Invoke command (mandatory) as SSH2 subsystem.\n");  
         fprintf(stderr, "  -b addr     Local IP address.\n");  
         exit(1);          exit(1);
 }  }
   
 static int ssh_session(void);  static int ssh_session(void);
 static int ssh_session2(void);  static int ssh_session2(void);
 static void load_public_identity_files(void);  static void load_public_identity_files(void);
   static void control_client(const char *path);
   
 /*  /*
  * Main program for the ssh client.   * Main program for the ssh client.
Line 200 
Line 175 
         int i, opt, exit_status;          int i, opt, exit_status;
         u_short fwd_port, fwd_host_port;          u_short fwd_port, fwd_host_port;
         char sfwd_port[6], sfwd_host_port[6];          char sfwd_port[6], sfwd_host_port[6];
         char *p, *cp, buf[256];          char *p, *cp, *line, buf[256];
         struct stat st;          struct stat st;
         struct passwd *pw;          struct passwd *pw;
         int dummy;          int dummy;
Line 255 
Line 230 
   
 again:  again:
         while ((opt = getopt(ac, av,          while ((opt = getopt(ac, av,
             "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVX")) != -1) {              "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNPR:S:TVXY")) != -1) {
                 switch (opt) {                  switch (opt) {
                 case '1':                  case '1':
                         options.protocol = SSH_PROTO_1;                          options.protocol = SSH_PROTO_1;
Line 282 
Line 257 
                 case 'X':                  case 'X':
                         options.forward_x11 = 1;                          options.forward_x11 = 1;
                         break;                          break;
                   case 'Y':
                           options.forward_x11 = 1;
                           options.forward_x11_trusted = 1;
                           break;
                 case 'g':                  case 'g':
                         options.gateway_ports = 1;                          options.gateway_ports = 1;
                         break;                          break;
Line 295 
Line 274 
                         options.forward_agent = 1;                          options.forward_agent = 1;
                         break;                          break;
                 case 'k':                  case 'k':
                         /* ignored for backward compatibility */                          options.gss_deleg_creds = 0;
                         break;                          break;
                 case 'i':                  case 'i':
                         if (stat(optarg, &st) < 0) {                          if (stat(optarg, &st) < 0) {
Line 333 
Line 312 
                         }                          }
                         /* fallthrough */                          /* fallthrough */
                 case 'V':                  case 'V':
                         fprintf(stderr,                          fprintf(stderr, "%s, %s\n",
                             "%s, SSH protocols %d.%d/%d.%d, %s\n",                              SSH_VERSION, SSLeay_version(SSLEAY_VERSION));
                             SSH_VERSION,  
                             PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1,  
                             PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2,  
                             SSLeay_version(SSLEAY_VERSION));  
                         if (opt == 'V')                          if (opt == 'V')
                                 exit(0);                                  exit(0);
                         break;                          break;
Line 364 
Line 339 
                         if (ciphers_valid(optarg)) {                          if (ciphers_valid(optarg)) {
                                 /* SSH2 only */                                  /* SSH2 only */
                                 options.ciphers = xstrdup(optarg);                                  options.ciphers = xstrdup(optarg);
                                 options.cipher = SSH_CIPHER_ILLEGAL;                                  options.cipher = SSH_CIPHER_INVALID;
                         } else {                          } else {
                                 /* SSH1 only */                                  /* SSH1 only */
                                 options.cipher = cipher_number(optarg);                                  options.cipher = cipher_number(optarg);
Line 391 
Line 366 
                                 exit(1);                                  exit(1);
                         }                          }
                         break;                          break;
                   case 'M':
                           options.control_master =
                               (options.control_master >= 1) ? 2 : 1;
                           break;
                 case 'p':                  case 'p':
                         options.port = a2port(optarg);                          options.port = a2port(optarg);
                         if (options.port == 0) {                          if (options.port == 0) {
Line 450 
Line 429 
                         break;                          break;
                 case 'o':                  case 'o':
                         dummy = 1;                          dummy = 1;
                           line = xstrdup(optarg);
                         if (process_config_line(&options, host ? host : "",                          if (process_config_line(&options, host ? host : "",
                             optarg, "command-line", 0, &dummy) != 0)                              line, "command-line", 0, &dummy) != 0)
                                 exit(1);                                  exit(1);
                           xfree(line);
                         break;                          break;
                 case 's':                  case 's':
                         subsystem_flag = 1;                          subsystem_flag = 1;
                         break;                          break;
                   case 'S':
                           if (options.control_path != NULL)
                                   free(options.control_path);
                           options.control_path = xstrdup(optarg);
                           break;
                 case 'b':                  case 'b':
                         options.bind_address = optarg;                          options.bind_address = optarg;
                         break;                          break;
Line 551 
Line 537 
          * file if the user specifies a config file on the command line.           * file if the user specifies a config file on the command line.
          */           */
         if (config != NULL) {          if (config != NULL) {
                 if (!read_config_file(config, host, &options))                  if (!read_config_file(config, host, &options, 0))
                         fatal("Can't open user config file %.100s: "                          fatal("Can't open user config file %.100s: "
                             "%.100s", config, strerror(errno));                              "%.100s", config, strerror(errno));
         } else  {          } else  {
                 snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,                  snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
                     _PATH_SSH_USER_CONFFILE);                      _PATH_SSH_USER_CONFFILE);
                 (void)read_config_file(buf, host, &options);                  (void)read_config_file(buf, host, &options, 1);
   
                 /* Read systemwide configuration file after use config. */                  /* Read systemwide configuration file after use config. */
                 (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, &options);                  (void)read_config_file(_PATH_HOST_CONFIG_FILE, host,
                       &options, 0);
         }          }
   
         /* Fill configuration defaults. */          /* Fill configuration defaults. */
Line 588 
Line 575 
             strcmp(options.proxy_command, "none") == 0)              strcmp(options.proxy_command, "none") == 0)
                 options.proxy_command = NULL;                  options.proxy_command = NULL;
   
           if (options.control_path != NULL) {
                   options.control_path = tilde_expand_filename(
                      options.control_path, original_real_uid);
           }
           if (options.control_path != NULL && options.control_master == 0)
                   control_client(options.control_path); /* This doesn't return */
   
         /* Open a connection to the remote host. */          /* Open a connection to the remote host. */
         if (ssh_connect(host, &hostaddr, options.port,          if (ssh_connect(host, &hostaddr, options.port,
             options.address_family, options.connection_attempts,              options.address_family, options.connection_attempts,
             original_effective_uid == 0 && options.use_privileged_port,              original_effective_uid == 0 && options.use_privileged_port,
             options.proxy_command) != 0)              options.proxy_command) != 0)
Line 696 
Line 690 
         exit_status = compat20 ? ssh_session2() : ssh_session();          exit_status = compat20 ? ssh_session2() : ssh_session();
         packet_close();          packet_close();
   
           if (options.control_path != NULL && control_fd != -1)
                   unlink(options.control_path);
   
         /*          /*
          * Send SIGHUP to proxy command if used. We don't wait() in           * Send SIGHUP to proxy command if used. We don't wait() in
          * case it hangs and instead rely on init to reap the child           * case it hangs and instead rely on init to reap the child
          */           */
         if (proxy_command_pid > 1)          if (proxy_command_pid > 1)
Line 706 
Line 703 
         return exit_status;          return exit_status;
 }  }
   
   #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
   
 static void  static void
 x11_get_proto(char **_proto, char **_data)  x11_get_proto(char **_proto, char **_data)
 {  {
           char cmd[1024];
         char line[512];          char line[512];
           char xdisplay[512];
         static char proto[512], data[512];          static char proto[512], data[512];
         FILE *f;          FILE *f;
         int got_data = 0, i;          int got_data = 0, generated = 0, do_unlink = 0, i;
         char *display;          char *display, *xauthdir, *xauthfile;
         struct stat st;          struct stat st;
   
           xauthdir = xauthfile = NULL;
         *_proto = proto;          *_proto = proto;
         *_data = data;          *_data = data;
         proto[0] = data[0] = '\0';          proto[0] = data[0] = '\0';
   
         if (!options.xauth_location ||          if (!options.xauth_location ||
             (stat(options.xauth_location, &st) == -1)) {              (stat(options.xauth_location, &st) == -1)) {
                 debug("No xauth program.");                  debug("No xauth program.");
Line 727 
Line 730 
                         debug("x11_get_proto: DISPLAY not set");                          debug("x11_get_proto: DISPLAY not set");
                         return;                          return;
                 }                  }
                 /* Try to get Xauthority information for the display. */                  /*
                 if (strncmp(display, "localhost:", 10) == 0)                   * Handle FamilyLocal case where $DISPLAY does
                         /*                   * not match an authorization entry.  For this we
                          * Handle FamilyLocal case where $DISPLAY does                   * just try "xauth list unix:displaynum.screennum".
                          * not match an authorization entry.  For this we                   * XXX: "localhost" match to determine FamilyLocal
                          * just try "xauth list unix:displaynum.screennum".                   *      is not perfect.
                          * XXX: "localhost" match to determine FamilyLocal                   */
                          *      is not perfect.                  if (strncmp(display, "localhost:", 10) == 0) {
                          */                          snprintf(xdisplay, sizeof(xdisplay), "unix:%s",
                         snprintf(line, sizeof line, "%s list unix:%s 2>"                              display + 10);
                             _PATH_DEVNULL, options.xauth_location, display+10);                          display = xdisplay;
                 else                  }
                         snprintf(line, sizeof line, "%s list %.200s 2>"                  if (options.forward_x11_trusted == 0) {
                             _PATH_DEVNULL, options.xauth_location, display);                          xauthdir = xmalloc(MAXPATHLEN);
                 debug2("x11_get_proto: %s", line);                          xauthfile = xmalloc(MAXPATHLEN);
                 f = popen(line, "r");                          strlcpy(xauthdir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);
                           if (mkdtemp(xauthdir) != NULL) {
                                   do_unlink = 1;
                                   snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile",
                                       xauthdir);
                                   snprintf(cmd, sizeof(cmd),
                                       "%s -f %s generate %s " SSH_X11_PROTO
                                       " untrusted timeout 1200 2>" _PATH_DEVNULL,
                                       options.xauth_location, xauthfile, display);
                                   debug2("x11_get_proto: %s", cmd);
                                   if (system(cmd) == 0)
                                           generated = 1;
                           }
                   }
                   snprintf(cmd, sizeof(cmd),
                       "%s %s%s list %s . 2>" _PATH_DEVNULL,
                       options.xauth_location,
                       generated ? "-f " : "" ,
                       generated ? xauthfile : "",
                       display);
                   debug2("x11_get_proto: %s", cmd);
                   f = popen(cmd, "r");
                 if (f && fgets(line, sizeof(line), f) &&                  if (f && fgets(line, sizeof(line), f) &&
                     sscanf(line, "%*s %511s %511s", proto, data) == 2)                      sscanf(line, "%*s %511s %511s", proto, data) == 2)
                         got_data = 1;                          got_data = 1;
                 if (f)                  if (f)
                         pclose(f);                          pclose(f);
         }          }
   
           if (do_unlink) {
                   unlink(xauthfile);
                   rmdir(xauthdir);
           }
           if (xauthdir)
                   xfree(xauthdir);
           if (xauthfile)
                   xfree(xauthfile);
   
         /*          /*
          * If we didn't get authentication data, just make up some           * If we didn't get authentication data, just make up some
          * data.  The forwarding code will check the validity of the           * data.  The forwarding code will check the validity of the
Line 758 
Line 792 
          * for the local connection.           * for the local connection.
          */           */
         if (!got_data) {          if (!got_data) {
                 u_int32_t rand = 0;                  u_int32_t rnd = 0;
   
                 logit("Warning: No xauth data; using fake authentication data for X11 forwarding.");                  logit("Warning: No xauth data; "
                 strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);                      "using fake authentication data for X11 forwarding.");
                   strlcpy(proto, SSH_X11_PROTO, sizeof proto);
                 for (i = 0; i < 16; i++) {                  for (i = 0; i < 16; i++) {
                         if (i % 4 == 0)                          if (i % 4 == 0)
                                 rand = arc4random();                                  rnd = arc4random();
                         snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);                          snprintf(data + 2 * i, sizeof data - 2 * i, "%02x",
                         rand >>= 8;                              rnd & 0xff);
                           rnd >>= 8;
                 }                  }
         }          }
 }  }
Line 953 
Line 989 
 }  }
   
 static void  static void
 client_subsystem_reply(int type, u_int32_t seq, void *ctxt)  ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt)
 {  {
         int id, len;          int id, len;
   
Line 968 
Line 1004 
 }  }
   
 void  void
 client_global_request_reply(int type, u_int32_t seq, void *ctxt)  client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt)
 {  {
         int i;          int i;
   
         i = client_global_request_id++;          i = client_global_request_id++;
         if (i >= options.num_remote_forwards) {          if (i >= options.num_remote_forwards)
                 debug("client_global_request_reply: too many replies %d > %d",  
                     i, options.num_remote_forwards);  
                 return;                  return;
         }  
         debug("remote forward %s for: listen %d, connect %s:%d",          debug("remote forward %s for: listen %d, connect %s:%d",
             type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",              type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
             options.remote_forwards[i].port,              options.remote_forwards[i].port,
Line 988 
Line 1021 
                     options.remote_forwards[i].port);                      options.remote_forwards[i].port);
 }  }
   
 /* request pty/x11/agent/tcpfwd/shell for channel */  
 static void  static void
 ssh_session2_setup(int id, void *arg)  ssh_control_listener(void)
 {  {
         int len;          struct sockaddr_un addr;
         int interactive = 0;          mode_t old_umask;
         struct termios tio;  
   
         debug2("ssh_session2_setup: id %d", id);          if (options.control_path == NULL || options.control_master <= 0)
                   return;
   
         if (tty_flag) {          memset(&addr, '\0', sizeof(addr));
                 struct winsize ws;          addr.sun_family = AF_UNIX;
                 char *cp;          addr.sun_len = offsetof(struct sockaddr_un, sun_path) +
                 cp = getenv("TERM");              strlen(options.control_path) + 1;
                 if (!cp)  
                         cp = "";  
                 /* Store window size in the packet. */  
                 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)  
                         memset(&ws, 0, sizeof(ws));  
   
                 channel_request_start(id, "pty-req", 0);          if (strlcpy(addr.sun_path, options.control_path,
                 packet_put_cstring(cp);              sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
                 packet_put_int(ws.ws_col);                  fatal("ControlPath too long");
                 packet_put_int(ws.ws_row);  
                 packet_put_int(ws.ws_xpixel);          if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
                 packet_put_int(ws.ws_ypixel);                  fatal("%s socket(): %s\n", __func__, strerror(errno));
                 tio = get_saved_tio();  
                 tty_make_modes(/*ignored*/ 0, &tio);          old_umask = umask(0177);
                 packet_send();          if (bind(control_fd, (struct sockaddr*)&addr, addr.sun_len) == -1) {
                 interactive = 1;                  control_fd = -1;
                 /* XXX wait for reply */                  if (errno == EINVAL)
                           fatal("ControlSocket %s already exists",
                               options.control_path);
                   else
                           fatal("%s bind(): %s\n", __func__, strerror(errno));
         }          }
         if (options.forward_x11 &&          umask(old_umask);
             getenv("DISPLAY") != NULL) {  
           if (listen(control_fd, 64) == -1)
                   fatal("%s listen(): %s\n", __func__, strerror(errno));
   
           set_nonblock(control_fd);
   }
   
   /* request pty/x11/agent/tcpfwd/shell for channel */
   static void
   ssh_session2_setup(int id, void *arg)
   {
           extern char **environ;
   
           int interactive = tty_flag;
           if (options.forward_x11 && getenv("DISPLAY") != NULL) {
                 char *proto, *data;                  char *proto, *data;
                 /* Get reasonable local authentication information. */                  /* Get reasonable local authentication information. */
                 x11_get_proto(&proto, &data);                  x11_get_proto(&proto, &data);
Line 1039 
Line 1084 
                 packet_send();                  packet_send();
         }          }
   
         len = buffer_len(&command);          client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
         if (len > 0) {              NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply);
                 if (len > 900)  
                         len = 900;  
                 if (subsystem_flag) {  
                         debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command));  
                         channel_request_start(id, "subsystem", /*want reply*/ 1);  
                         /* register callback for reply */  
                         /* XXX we assume that client_loop has already been called */  
                         dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply);  
                         dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply);  
                 } else {  
                         debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));  
                         channel_request_start(id, "exec", 0);  
                 }  
                 packet_put_string(buffer_ptr(&command), buffer_len(&command));  
                 packet_send();  
         } else {  
                 channel_request_start(id, "shell", 0);  
                 packet_send();  
         }  
   
         packet_set_interactive(interactive);          packet_set_interactive(interactive);
 }  }
Line 1105 
Line 1131 
   
         channel_send_open(c->self);          channel_send_open(c->self);
         if (!no_shell_flag)          if (!no_shell_flag)
                 channel_register_confirm(c->self, ssh_session2_setup);                  channel_register_confirm(c->self, ssh_session2_setup, NULL);
   
         return c->self;          return c->self;
 }  }
Line 1117 
Line 1143 
   
         /* XXX should be pre-session */          /* XXX should be pre-session */
         ssh_init_forwarding();          ssh_init_forwarding();
           ssh_control_listener();
   
         if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))          if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
                 id = ssh_session2_open();                  id = ssh_session2_open();
Line 1169 
Line 1196 
                 options.identity_files[i] = filename;                  options.identity_files[i] = filename;
                 options.identity_keys[i] = public;                  options.identity_keys[i] = public;
         }          }
   }
   
   static void
   control_client_sighandler(int signo)
   {
           control_client_terminate = signo;
   }
   
   static void
   control_client_sigrelay(int signo)
   {
           if (control_server_pid > 1)
                   kill(control_server_pid, signo);
   }
   
   static int
   env_permitted(char *env)
   {
           int i;
           char name[1024], *cp;
   
           strlcpy(name, env, sizeof(name));
           if ((cp = strchr(name, '=')) == NULL)
                   return (0);
   
           *cp = '\0';
   
           for (i = 0; i < options.num_send_env; i++)
                   if (match_pattern(name, options.send_env[i]))
                           return (1);
   
           return (0);
   }
   
   static void
   control_client(const char *path)
   {
           struct sockaddr_un addr;
           int i, r, sock, exitval, num_env;
           Buffer m;
           char *cp;
           extern char **environ;
   
           memset(&addr, '\0', sizeof(addr));
           addr.sun_family = AF_UNIX;
           addr.sun_len = offsetof(struct sockaddr_un, sun_path) +
               strlen(path) + 1;
   
           if (strlcpy(addr.sun_path, path,
               sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
                   fatal("ControlPath too long");
   
           if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
                   fatal("%s socket(): %s", __func__, strerror(errno));
   
           if (connect(sock, (struct sockaddr*)&addr, addr.sun_len) == -1)
                   fatal("Couldn't connect to %s: %s", path, strerror(errno));
   
           if ((cp = getenv("TERM")) == NULL)
                   cp = "";
   
           buffer_init(&m);
   
           /* Get PID of controlee */
           if (ssh_msg_recv(sock, &m) == -1)
                   fatal("%s: msg_recv", __func__);
           if (buffer_get_char(&m) != 0)
                   fatal("%s: wrong version", __func__);
           /* Connection allowed? */
           if (buffer_get_int(&m) != 1)
                   fatal("Connection to master denied");
           control_server_pid = buffer_get_int(&m);
   
           buffer_clear(&m);
           buffer_put_int(&m, tty_flag);
           buffer_put_int(&m, subsystem_flag);
           buffer_put_cstring(&m, cp);
   
           buffer_append(&command, "\0", 1);
           buffer_put_cstring(&m, buffer_ptr(&command));
   
           if (options.num_send_env == 0 || environ == NULL) {
                   buffer_put_int(&m, 0);
           } else {
                   /* Pass environment */
                   num_env = 0;
                   for (i = 0; environ[i] != NULL; i++)
                           if (env_permitted(environ[i]))
                                   num_env++; /* Count */
   
                   buffer_put_int(&m, num_env);
   
                   for (i = 0; environ[i] != NULL && num_env >= 0; i++)
                           if (env_permitted(environ[i])) {
                                   num_env--;
                                   buffer_put_cstring(&m, environ[i]);
                           }
           }
   
           if (ssh_msg_send(sock, /* version */0, &m) == -1)
                   fatal("%s: msg_send", __func__);
   
           mm_send_fd(sock, STDIN_FILENO);
           mm_send_fd(sock, STDOUT_FILENO);
           mm_send_fd(sock, STDERR_FILENO);
   
           /* Wait for reply, so master has a chance to gather ttymodes */
           buffer_clear(&m);
           if (ssh_msg_recv(sock, &m) == -1)
                   fatal("%s: msg_recv", __func__);
           if (buffer_get_char(&m) != 0)
                   fatal("%s: master returned error", __func__);
           buffer_free(&m);
   
           signal(SIGINT, control_client_sighandler);
           signal(SIGTERM, control_client_sighandler);
           signal(SIGWINCH, control_client_sigrelay);
   
           if (tty_flag)
                   enter_raw_mode();
   
           /* Stick around until the controlee closes the client_fd */
           exitval = 0;
           for (;!control_client_terminate;) {
                   r = read(sock, &exitval, sizeof(exitval));
                   if (r == 0) {
                           debug2("Received EOF from master");
                           break;
                   }
                   if (r > 0)
                           debug2("Received exit status from master %d", exitval);
                   if (r == -1 && errno != EINTR)
                           fatal("%s: read %s", __func__, strerror(errno));
           }
   
           if (control_client_terminate)
                   debug2("Exiting on signal %d", control_client_terminate);
   
           close(sock);
   
           leave_raw_mode();
   
           if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
                   fprintf(stderr, "Connection to master closed.\r\n");
   
           exit(exitval);
 }  }

Legend:
Removed from v.1.201  
changed lines
  Added in v.1.201.2.2