[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.209.2.2 and 1.210

version 1.209.2.2, 2005/03/10 17:15:05 version 1.210, 2004/04/18 23:10:26
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 "sshpty.h"  #include "sshtty.h"
 #include "match.h"  
 #include "msg.h"  
 #include "monitor_fdpass.h"  
 #include "uidswap.h"  
   
 #ifdef SMARTCARD  #ifdef SMARTCARD
 #include "scard.h"  #include "scard.h"
Line 141 
Line 137 
 /* 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;  
   
 /* Multiplexing control command */  
 static u_int mux_command = SSHMUX_COMMAND_OPEN;  
   
 /* 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,          fprintf(stderr,
 "usage: ssh [-1246AaCfgkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n"  "usage: ssh [-1246AaCfghkNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n"
 "           [-D port] [-e escape_char] [-F configfile]\n"  "           [-D port] [-e escape_char] [-F configfile] [-i identity_file]\n"
 "           [-i identity_file] [-L [bind_address:]port:host:hostport]\n"  "           [-L port:host:hostport] [-l login_name] [-m mac_spec] [-o option]\n"
 "           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n"  "           [-p port] [-R port:host:hostport] [user@]hostname [command]\n"
 "           [-R [bind_address:]port:host:hostport] [-S ctl_path]\n"  
 "           [user@]hostname [command]\n"  
         );          );
         exit(1);          exit(1);
 }  }
Line 170 
Line 154 
 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 179 
Line 162 
 main(int ac, char **av)  main(int ac, char **av)
 {  {
         int i, opt, exit_status;          int i, opt, exit_status;
           u_short fwd_port, fwd_host_port;
           char sfwd_port[6], sfwd_host_port[6];
         char *p, *cp, *line, buf[256];          char *p, *cp, *line, buf[256];
         struct stat st;          struct stat st;
         struct passwd *pw;          struct passwd *pw;
         int dummy;          int dummy;
         extern int optind, optreset;          extern int optind, optreset;
         extern char *optarg;          extern char *optarg;
         Forward fwd;  
   
         /*          /*
          * Save the original real uid.  It will be needed later (uid-swapping           * Save the original real uid.  It will be needed later (uid-swapping
Line 235 
Line 219 
   
 again:  again:
         while ((opt = getopt(ac, av,          while ((opt = getopt(ac, av,
             "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNO:PR:S:TVXY")) != -1) {              "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVXY")) != -1) {
                 switch (opt) {                  switch (opt) {
                 case '1':                  case '1':
                         options.protocol = SSH_PROTO_1;                          options.protocol = SSH_PROTO_1;
Line 269 
Line 253 
                 case 'g':                  case 'g':
                         options.gateway_ports = 1;                          options.gateway_ports = 1;
                         break;                          break;
                 case 'O':  
                         if (strcmp(optarg, "check") == 0)  
                                 mux_command = SSHMUX_COMMAND_ALIVE_CHECK;  
                         else if (strcmp(optarg, "exit") == 0)  
                                 mux_command = SSHMUX_COMMAND_TERMINATE;  
                         else  
                                 fatal("Invalid multiplex command.");  
                         break;  
                 case 'P':       /* deprecated */                  case 'P':       /* deprecated */
                         options.use_privileged_port = 0;                          options.use_privileged_port = 0;
                         break;                          break;
Line 292 
Line 268 
                 case 'i':                  case 'i':
                         if (stat(optarg, &st) < 0) {                          if (stat(optarg, &st) < 0) {
                                 fprintf(stderr, "Warning: Identity file %s "                                  fprintf(stderr, "Warning: Identity file %s "
                                     "not accessible: %s.\n", optarg,                                      "does not exist.\n", optarg);
                                     strerror(errno));  
                                 break;                                  break;
                         }                          }
                         if (options.num_identity_files >=                          if (options.num_identity_files >=
Line 324 
Line 299 
                                         options.log_level++;                                          options.log_level++;
                                 break;                                  break;
                         }                          }
                         /* FALLTHROUGH */                          /* fallthrough */
                 case 'V':                  case 'V':
                         fprintf(stderr, "%s, %s\n",                          fprintf(stderr, "%s, %s\n",
                             SSH_VERSION, SSLeay_version(SSLEAY_VERSION));                              SSH_VERSION, SSLeay_version(SSLEAY_VERSION));
Line 353 
Line 328 
                         if (ciphers_valid(optarg)) {                          if (ciphers_valid(optarg)) {
                                 /* SSH2 only */                                  /* SSH2 only */
                                 options.ciphers = xstrdup(optarg);                                  options.ciphers = xstrdup(optarg);
                                 options.cipher = SSH_CIPHER_INVALID;                                  options.cipher = SSH_CIPHER_ILLEGAL;
                         } else {                          } else {
                                 /* SSH1 only */                                  /* SSH1 only */
                                 options.cipher = cipher_number(optarg);                                  options.cipher = cipher_number(optarg);
Line 380 
Line 355 
                                 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 396 
Line 367 
                         break;                          break;
   
                 case 'L':                  case 'L':
                         if (parse_forward(&fwd, optarg))                  case 'R':
                                 add_local_forward(&options, &fwd);                          if (sscanf(optarg, "%5[0-9]:%255[^:]:%5[0-9]",
                         else {                              sfwd_port, buf, sfwd_host_port) != 3 &&
                               sscanf(optarg, "%5[0-9]/%255[^/]/%5[0-9]",
                               sfwd_port, buf, sfwd_host_port) != 3) {
                                 fprintf(stderr,                                  fprintf(stderr,
                                     "Bad local forwarding specification '%s'\n",                                      "Bad forwarding specification '%s'\n",
                                     optarg);                                      optarg);
                                 exit(1);                                  usage();
                                   /* NOTREACHED */
                         }                          }
                         break;                          if ((fwd_port = a2port(sfwd_port)) == 0 ||
                               (fwd_host_port = a2port(sfwd_host_port)) == 0) {
                 case 'R':  
                         if (parse_forward(&fwd, optarg)) {  
                                 add_remote_forward(&options, &fwd);  
                         } else {  
                                 fprintf(stderr,                                  fprintf(stderr,
                                     "Bad remote forwarding specification "                                      "Bad forwarding port(s) '%s'\n", optarg);
                                     "'%s'\n", optarg);  
                                 exit(1);                                  exit(1);
                         }                          }
                           if (opt == 'L')
                                   add_local_forward(&options, fwd_port, buf,
                                       fwd_host_port);
                           else if (opt == 'R')
                                   add_remote_forward(&options, fwd_port, buf,
                                       fwd_host_port);
                         break;                          break;
   
                 case 'D':                  case 'D':
                         cp = p = xstrdup(optarg);                          fwd_port = a2port(optarg);
                         memset(&fwd, '\0', sizeof(fwd));                          if (fwd_port == 0) {
                         fwd.connect_host = "socks";  
                         if ((fwd.listen_host = hpdelim(&cp)) == NULL) {  
                                 fprintf(stderr, "Bad dynamic forwarding "  
                                     "specification '%.100s'\n", optarg);  
                                 exit(1);  
                         }  
                         if (cp != NULL) {  
                                 fwd.listen_port = a2port(cp);  
                                 fwd.listen_host = cleanhostname(fwd.listen_host);  
                         } else {  
                                 fwd.listen_port = a2port(fwd.listen_host);  
                                 fwd.listen_host = "";  
                         }  
   
                         if (fwd.listen_port == 0) {  
                                 fprintf(stderr, "Bad dynamic port '%s'\n",                                  fprintf(stderr, "Bad dynamic port '%s'\n",
                                     optarg);                                      optarg);
                                 exit(1);                                  exit(1);
                         }                          }
                         add_local_forward(&options, &fwd);                          add_local_forward(&options, fwd_port, "socks", 0);
                         xfree(p);  
                         break;                          break;
   
                 case 'C':                  case 'C':
Line 464 
Line 423 
                 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 563 
Line 517 
          * 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, 0))                  if (!read_config_file(config, host, &options, 0), 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  {
Line 572 
Line 526 
                 (void)read_config_file(buf, host, &options, 1);                  (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,                  (void)read_config_file(_PATH_HOST_CONFIG_FILE, host,
                     &options, 0);                      &options, 0);
         }          }
   
Line 601 
Line 555 
             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,
Line 659 
Line 606 
          * user's home directory if it happens to be on a NFS volume where           * user's home directory if it happens to be on a NFS volume where
          * root is mapped to nobody.           * root is mapped to nobody.
          */           */
         if (original_effective_uid == 0) {          seteuid(original_real_uid);
                 PRIV_START;          setuid(original_real_uid);
                 permanently_set_uid(pw);  
         }  
   
         /*          /*
          * Now that we are back to our own permissions, create ~/.ssh           * Now that we are back to our own permissions, create ~/.ssh
Line 718 
Line 663 
         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
Line 820 
Line 762 
          * for the local connection.           * for the local connection.
          */           */
         if (!got_data) {          if (!got_data) {
                 u_int32_t rnd = 0;                  u_int32_t rand = 0;
   
                 logit("Warning: No xauth data; "                  logit("Warning: No xauth data; "
                     "using fake authentication data for X11 forwarding.");                      "using fake authentication data for X11 forwarding.");
                 strlcpy(proto, SSH_X11_PROTO, sizeof proto);                  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)
                                 rnd = arc4random();                                  rand = arc4random();
                         snprintf(data + 2 * i, sizeof data - 2 * i, "%02x",                          snprintf(data + 2 * i, sizeof data - 2 * i, "%02x",
                             rnd & 0xff);                              rand & 0xff);
                         rnd >>= 8;                          rand >>= 8;
                 }                  }
         }          }
 }  }
Line 843 
Line 785 
   
         /* Initiate local TCP/IP port forwardings. */          /* Initiate local TCP/IP port forwardings. */
         for (i = 0; i < options.num_local_forwards; i++) {          for (i = 0; i < options.num_local_forwards; i++) {
                 debug("Local connections to %.200s:%d forwarded to remote "                  debug("Connections to local port %d forwarded to remote address %.200s:%d",
                     "address %.200s:%d",                      options.local_forwards[i].port,
                     (options.local_forwards[i].listen_host == NULL) ?                      options.local_forwards[i].host,
                     (options.gateway_ports ? "*" : "LOCALHOST") :                      options.local_forwards[i].host_port);
                     options.local_forwards[i].listen_host,  
                     options.local_forwards[i].listen_port,  
                     options.local_forwards[i].connect_host,  
                     options.local_forwards[i].connect_port);  
                 success += channel_setup_local_fwd_listener(                  success += channel_setup_local_fwd_listener(
                     options.local_forwards[i].listen_host,                      options.local_forwards[i].port,
                     options.local_forwards[i].listen_port,                      options.local_forwards[i].host,
                     options.local_forwards[i].connect_host,                      options.local_forwards[i].host_port,
                     options.local_forwards[i].connect_port,  
                     options.gateway_ports);                      options.gateway_ports);
         }          }
         if (i > 0 && success == 0)          if (i > 0 && success == 0)
Line 863 
Line 800 
   
         /* Initiate remote TCP/IP port forwardings. */          /* Initiate remote TCP/IP port forwardings. */
         for (i = 0; i < options.num_remote_forwards; i++) {          for (i = 0; i < options.num_remote_forwards; i++) {
                 debug("Remote connections from %.200s:%d forwarded to "                  debug("Connections to remote port %d forwarded to local address %.200s:%d",
                     "local address %.200s:%d",                      options.remote_forwards[i].port,
                     options.remote_forwards[i].listen_host,                      options.remote_forwards[i].host,
                     options.remote_forwards[i].listen_port,                      options.remote_forwards[i].host_port);
                     options.remote_forwards[i].connect_host,  
                     options.remote_forwards[i].connect_port);  
                 channel_request_remote_forwarding(                  channel_request_remote_forwarding(
                     options.remote_forwards[i].listen_host,                      options.remote_forwards[i].port,
                     options.remote_forwards[i].listen_port,                      options.remote_forwards[i].host,
                     options.remote_forwards[i].connect_host,                      options.remote_forwards[i].host_port);
                     options.remote_forwards[i].connect_port);  
         }          }
 }  }
   
Line 1025 
Line 959 
 }  }
   
 static void  static void
 ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt)  client_subsystem_reply(int type, u_int32_t seq, void *ctxt)
 {  {
         int id, len;          int id, len;
   
Line 1049 
Line 983 
                 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].listen_port,              options.remote_forwards[i].port,
             options.remote_forwards[i].connect_host,              options.remote_forwards[i].host,
             options.remote_forwards[i].connect_port);              options.remote_forwards[i].host_port);
         if (type == SSH2_MSG_REQUEST_FAILURE)          if (type == SSH2_MSG_REQUEST_FAILURE)
                 logit("Warning: remote port forwarding failed for listen "                  logit("Warning: remote port forwarding failed for listen port %d",
                     "port %d", options.remote_forwards[i].listen_port);                      options.remote_forwards[i].port);
 }  }
   
   /* request pty/x11/agent/tcpfwd/shell for channel */
 static void  static void
 ssh_control_listener(void)  ssh_session2_setup(int id, void *arg)
 {  {
         struct sockaddr_un addr;          int len;
         mode_t old_umask;          int interactive = 0;
           struct termios tio;
   
         if (options.control_path == NULL || options.control_master <= 0)          debug2("ssh_session2_setup: id %d", id);
                 return;  
   
         memset(&addr, '\0', sizeof(addr));          if (tty_flag) {
         addr.sun_family = AF_UNIX;                  struct winsize ws;
         addr.sun_len = offsetof(struct sockaddr_un, sun_path) +                  char *cp;
             strlen(options.control_path) + 1;                  cp = getenv("TERM");
                   if (!cp)
                           cp = "";
                   /* Store window size in the packet. */
                   if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
                           memset(&ws, 0, sizeof(ws));
   
         if (strlcpy(addr.sun_path, options.control_path,                  channel_request_start(id, "pty-req", 0);
             sizeof(addr.sun_path)) >= sizeof(addr.sun_path))                  packet_put_cstring(cp);
                 fatal("ControlPath too long");                  packet_put_int(ws.ws_col);
                   packet_put_int(ws.ws_row);
         if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)                  packet_put_int(ws.ws_xpixel);
                 fatal("%s socket(): %s\n", __func__, strerror(errno));                  packet_put_int(ws.ws_ypixel);
                   tio = get_saved_tio();
         old_umask = umask(0177);                  tty_make_modes(/*ignored*/ 0, &tio);
         if (bind(control_fd, (struct sockaddr*)&addr, addr.sun_len) == -1) {                  packet_send();
                 control_fd = -1;                  interactive = 1;
                 if (errno == EINVAL)                  /* XXX wait for reply */
                         fatal("ControlSocket %s already exists",  
                             options.control_path);  
                 else  
                         fatal("%s bind(): %s\n", __func__, strerror(errno));  
         }          }
         umask(old_umask);          if (options.forward_x11 &&
               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 1120 
Line 1042 
                 packet_send();                  packet_send();
         }          }
   
         client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),          len = buffer_len(&command);
             NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply);          if (len > 0) {
                   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 1167 
Line 1108 
   
         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, NULL);                  channel_register_confirm(c->self, ssh_session2_setup);
   
         return c->self;          return c->self;
 }  }
Line 1179 
Line 1120 
   
         /* 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 1232 
Line 1172 
                 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, fd, sock, exitval, num_env;  
         Buffer m;  
         char *term;  
         extern char **environ;  
         u_int  flags;  
   
         if (stdin_null_flag) {  
                 if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)  
                         fatal("open(/dev/null): %s", strerror(errno));  
                 if (dup2(fd, STDIN_FILENO) == -1)  
                         fatal("dup2: %s", strerror(errno));  
                 if (fd > STDERR_FILENO)  
                         close(fd);  
         }  
   
         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 ((term = getenv("TERM")) == NULL)  
                 term = "";  
   
         flags = 0;  
         if (tty_flag)  
                 flags |= SSHMUX_FLAG_TTY;  
         if (subsystem_flag)  
                 flags |= SSHMUX_FLAG_SUBSYS;  
   
         buffer_init(&m);  
   
         /* Send our command to server */  
         buffer_put_int(&m, mux_command);  
         buffer_put_int(&m, flags);  
         if (ssh_msg_send(sock, /* version */1, &m) == -1)  
                 fatal("%s: msg_send", __func__);  
         buffer_clear(&m);  
   
         /* Get authorisation status and PID of controlee */  
         if (ssh_msg_recv(sock, &m) == -1)  
                 fatal("%s: msg_recv", __func__);  
         if (buffer_get_char(&m) != 1)  
                 fatal("%s: wrong version", __func__);  
         if (buffer_get_int(&m) != 1)  
                 fatal("Connection to master denied");  
         control_server_pid = buffer_get_int(&m);  
   
         buffer_clear(&m);  
   
         switch (mux_command) {  
         case SSHMUX_COMMAND_ALIVE_CHECK:  
                 fprintf(stderr, "Master running (pid=%d)\r\n",  
                     control_server_pid);  
                 exit(0);  
         case SSHMUX_COMMAND_TERMINATE:  
                 fprintf(stderr, "Exit request sent.\r\n");  
                 exit(0);  
         case SSHMUX_COMMAND_OPEN:  
                 /* continue below */  
                 break;  
         default:  
                 fatal("silly mux_command %d", mux_command);  
         }  
   
         /* SSHMUX_COMMAND_OPEN */  
         buffer_put_cstring(&m, term);  
         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 */1, &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) != 1)  
                 fatal("%s: wrong version", __func__);  
         buffer_free(&m);  
   
         signal(SIGHUP, control_client_sighandler);  
         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.209.2.2  
changed lines
  Added in v.1.210