[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.30 and 1.31

version 1.30, 1999/11/15 21:05:03 version 1.31, 1999/11/23 22:25:55
Line 28 
Line 28 
 #include "readconf.h"  #include "readconf.h"
 #include "uidswap.h"  #include "uidswap.h"
   
 /* Flag indicating whether debug mode is on.  This can be set on the  /* Flag indicating whether debug mode is on.  This can be set on the command line. */
    command line. */  
 int debug_flag = 0;  int debug_flag = 0;
   
 /* Flag indicating whether to allocate a pseudo tty.  This can be set on the  /* Flag indicating whether to allocate a pseudo tty.  This can be set on the command
    command line, and is automatically set if no command is given on the command     line, and is automatically set if no command is given on the command line. */
    line. */  
 int tty_flag = 0;  int tty_flag = 0;
   
 /* Flag indicating that nothing should be read from stdin.  This can be set  /* Flag indicating that nothing should be read from stdin.  This can be set
Line 81 
Line 79 
 void  void
 usage()  usage()
 {  {
   fprintf(stderr, "Usage: %s [options] host [command]\n", av0);          fprintf(stderr, "Usage: %s [options] host [command]\n", av0);
   fprintf(stderr, "Options:\n");          fprintf(stderr, "Options:\n");
   fprintf(stderr, "  -l user     Log in using this user name.\n");          fprintf(stderr, "  -l user     Log in using this user name.\n");
   fprintf(stderr, "  -n          Redirect input from /dev/null.\n");          fprintf(stderr, "  -n          Redirect input from /dev/null.\n");
   fprintf(stderr, "  -a          Disable authentication agent forwarding.\n");          fprintf(stderr, "  -a          Disable authentication agent forwarding.\n");
 #ifdef AFS  #ifdef AFS
   fprintf(stderr, "  -k          Disable Kerberos ticket and AFS token forwarding.\n");          fprintf(stderr, "  -k          Disable Kerberos ticket and AFS token forwarding.\n");
 #endif /* AFS */  #endif                          /* AFS */
   fprintf(stderr, "  -x          Disable X11 connection forwarding.\n");          fprintf(stderr, "  -x          Disable X11 connection forwarding.\n");
   fprintf(stderr, "  -i file     Identity for RSA authentication (default: ~/.ssh/identity).\n");          fprintf(stderr, "  -i file     Identity for RSA authentication (default: ~/.ssh/identity).\n");
   fprintf(stderr, "  -t          Tty; allocate a tty even if command is given.\n");          fprintf(stderr, "  -t          Tty; allocate a tty even if command is given.\n");
   fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");          fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");
   fprintf(stderr, "  -V          Display version number only.\n");          fprintf(stderr, "  -V          Display version number only.\n");
   fprintf(stderr, "  -P          Don't allocate a privileged port.\n");          fprintf(stderr, "  -P          Don't allocate a privileged port.\n");
   fprintf(stderr, "  -q          Quiet; don't display any warning messages.\n");          fprintf(stderr, "  -q          Quiet; don't display any warning messages.\n");
   fprintf(stderr, "  -f          Fork into background after authentication.\n");          fprintf(stderr, "  -f          Fork into background after authentication.\n");
   fprintf(stderr, "  -e char     Set escape character; ``none'' = disable (default: ~).\n");          fprintf(stderr, "  -e char     Set escape character; ``none'' = disable (default: ~).\n");
   
   fprintf(stderr, "  -c cipher   Select encryption algorithm: "          fprintf(stderr, "  -c cipher   Select encryption algorithm: "
                   "``3des'', "                          "``3des'', "
                   "``blowfish''\n");                          "``blowfish''\n");
   fprintf(stderr, "  -p port     Connect to this port.  Server must be on the same port.\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, "  -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, "  -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", av0);          fprintf(stderr, "              These cause %s to listen for connections on a port, and\n", av0);
   fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");          fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");
   fprintf(stderr, "  -C          Enable compression.\n");          fprintf(stderr, "  -C          Enable compression.\n");
   fprintf(stderr, "  -g          Allow remote hosts to connect to forwarded ports.\n");          fprintf(stderr, "  -g          Allow remote hosts to connect to forwarded ports.\n");
   fprintf(stderr, "  -o 'option' Process the option as if it was read from a configuration file.\n");          fprintf(stderr, "  -o 'option' Process the option as if it was read from a configuration file.\n");
   exit(1);          exit(1);
 }  }
   
 /* Connects to the given host using rsh (or prints an error message and exits  /* Connects to the given host using rsh (or prints an error message and exits
    if rsh is not available).  This function never returns. */     if rsh is not available).  This function never returns. */
   
 void  void
 rsh_connect(char *host, char *user, Buffer *command)  rsh_connect(char *host, char *user, Buffer * command)
 {  {
   char *args[10];          char *args[10];
   int i;          int i;
   
   log("Using rsh.  WARNING: Connection will not be encrypted.");          log("Using rsh.  WARNING: Connection will not be encrypted.");
   /* Build argument list for rsh. */          /* Build argument list for rsh. */
   i = 0;          i = 0;
   args[i++] = _PATH_RSH;          args[i++] = _PATH_RSH;
   args[i++] = host;    /* may have to come after user on some systems */          /* host may have to come after user on some systems */
   if (user)          args[i++] = host;
     {          if (user) {
       args[i++] = "-l";                  args[i++] = "-l";
       args[i++] = user;                  args[i++] = user;
     }  
   if (buffer_len(command) > 0)  
     {  
       buffer_append(command, "\0", 1);  
       args[i++] = buffer_ptr(command);  
     }  
   args[i++] = NULL;  
   if (debug_flag)  
     {  
       for (i = 0; args[i]; i++)  
         {  
           if (i != 0)  
             fprintf(stderr, " ");  
           fprintf(stderr, "%s", args[i]);  
         }          }
       fprintf(stderr, "\n");          if (buffer_len(command) > 0) {
     }                  buffer_append(command, "\0", 1);
   execv(_PATH_RSH, args);                  args[i++] = buffer_ptr(command);
   perror(_PATH_RSH);          }
   exit(1);          args[i++] = NULL;
           if (debug_flag) {
                   for (i = 0; args[i]; i++) {
                           if (i != 0)
                                   fprintf(stderr, " ");
                           fprintf(stderr, "%s", args[i]);
                   }
                   fprintf(stderr, "\n");
           }
           execv(_PATH_RSH, args);
           perror(_PATH_RSH);
           exit(1);
 }  }
   
 /* Main program for the ssh client. */  /* Main program for the ssh client. */
Line 158 
Line 153 
 int  int
 main(int ac, char **av)  main(int ac, char **av)
 {  {
   int i, opt, optind, type, exit_status, ok, fwd_port, fwd_host_port, authfd;          int i, opt, optind, type, exit_status, ok, fwd_port, fwd_host_port,
   char *optarg, *cp, buf[256];           authfd;
   Buffer command;          char *optarg, *cp, buf[256];
   struct winsize ws;          Buffer command;
   struct stat st;          struct winsize ws;
   struct passwd *pw, pwcopy;          struct stat st;
   int interactive = 0, dummy;          struct passwd *pw, pwcopy;
   uid_t original_effective_uid;          int interactive = 0, dummy;
   int plen;          uid_t original_effective_uid;
           int plen;
   
   /* Save the original real uid.  It will be needed later (uid-swapping may          /* Save the original real uid.  It will be needed later
      clobber the real uid).  */             (uid-swapping may clobber the real uid).  */
   original_real_uid = getuid();          original_real_uid = getuid();
   original_effective_uid = geteuid();          original_effective_uid = geteuid();
   
   /* If we are installed setuid root be careful to not drop core. */          /* If we are installed setuid root be careful to not drop core. */
   if (original_real_uid != original_effective_uid)          if (original_real_uid != original_effective_uid) {
     {                  struct rlimit rlim;
       struct rlimit rlim;                  rlim.rlim_cur = rlim.rlim_max = 0;
       rlim.rlim_cur = rlim.rlim_max = 0;                  if (setrlimit(RLIMIT_CORE, &rlim) < 0)
       if (setrlimit(RLIMIT_CORE, &rlim) < 0)                          fatal("setrlimit failed: %.100s", strerror(errno));
         fatal("setrlimit failed: %.100s", strerror(errno));          }
     }          /* Use uid-swapping to give up root privileges for the duration of
              option processing.  We will re-instantiate the rights when we
              are ready to create the privileged port, and will permanently
              drop them when the port has been created (actually, when the
              connection has been made, as we may need to create the port
              several times). */
           temporarily_use_uid(original_real_uid);
   
   /* Use uid-swapping to give up root privileges for the duration of option          /* Set our umask to something reasonable, as some files are
      processing.  We will re-instantiate the rights when we are ready to             created with the default umask.  This will make them
      create the privileged port, and will permanently drop them when the             world-readable but writable only by the owner, which is ok for
      port has been created (actually, when the connection has been made, as             all files for which we don't set the modes explicitly. */
      we may need to create the port several times). */          umask(022);
   temporarily_use_uid(original_real_uid);  
   
   /* Set our umask to something reasonable, as some files are created with          /* Save our own name. */
      the default umask.  This will make them world-readable but writable          av0 = av[0];
      only by the owner, which is ok for all files for which we don't set  
      the modes explicitly. */  
   umask(022);  
   
   /* Save our own name. */  
   av0 = av[0];  
   
   /* Initialize option structure to indicate that no values have been set. */          /* Initialize option structure to indicate that no values have been set. */
   initialize_options(&options);          initialize_options(&options);
   
   /* Parse command-line arguments. */          /* Parse command-line arguments. */
   host = NULL;          host = NULL;
   
   /* If program name is not one of the standard names, use it as host name. */          /* If program name is not one of the standard names, use it as host name. */
   if (strchr(av0, '/'))          if (strchr(av0, '/'))
     cp = strrchr(av0, '/') + 1;                  cp = strrchr(av0, '/') + 1;
   else          else
     cp = av0;                  cp = av0;
   if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 &&          if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 &&
       strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0)              strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0)
     host = cp;                  host = cp;
   
   for (optind = 1; optind < ac; optind++)  
     {  
       if (av[optind][0] != '-')  
         {  
           if (host)  
             break;  
           if ((cp = strchr(av[optind], '@'))) {  
             options.user = av[optind];  
             *cp = '\0';  
             host = ++cp;  
           }  
           else  
             host = av[optind];  
           continue;  
         }  
       opt = av[optind][1];  
       if (!opt)  
         usage();  
       if (strchr("eilcpLRo", opt)) /* options with arguments */  
         {  
           optarg = av[optind] + 2;  
           if (strcmp(optarg, "") == 0)  
             {  
               if (optind >= ac - 1)  
                 usage();  
               optarg = av[++optind];  
             }  
         }  
       else  
         {  
           if (av[optind][2])  
             usage();  
           optarg = NULL;  
         }  
       switch (opt)  
         {  
         case 'n':  
           stdin_null_flag = 1;  
           break;  
   
         case 'f':          for (optind = 1; optind < ac; optind++) {
           fork_after_authentication_flag = 1;                  if (av[optind][0] != '-') {
           stdin_null_flag = 1;                          if (host)
           break;                                  break;
                           if ((cp = strchr(av[optind], '@'))) {
                                   options.user = av[optind];
                                   *cp = '\0';
                                   host = ++cp;
                           } else
                                   host = av[optind];
                           continue;
                   }
                   opt = av[optind][1];
                   if (!opt)
                           usage();
                   if (strchr("eilcpLRo", opt)) {  /* options with arguments */
                           optarg = av[optind] + 2;
                           if (strcmp(optarg, "") == 0) {
                                   if (optind >= ac - 1)
                                           usage();
                                   optarg = av[++optind];
                           }
                   } else {
                           if (av[optind][2])
                                   usage();
                           optarg = NULL;
                   }
                   switch (opt) {
                   case 'n':
                           stdin_null_flag = 1;
                           break;
   
         case 'x':                  case 'f':
           options.forward_x11 = 0;                          fork_after_authentication_flag = 1;
           break;                          stdin_null_flag = 1;
                           break;
   
         case 'X':                  case 'x':
           options.forward_x11 = 1;                          options.forward_x11 = 0;
           break;                          break;
   
         case 'g':                  case 'X':
           options.gateway_ports = 1;                          options.forward_x11 = 1;
           break;                          break;
   
         case 'P':                  case 'g':
           options.use_privileged_port = 0;                          options.gateway_ports = 1;
           break;                          break;
   
         case 'a':                  case 'P':
           options.forward_agent = 0;                          options.use_privileged_port = 0;
           break;                          break;
   
                   case 'a':
                           options.forward_agent = 0;
                           break;
 #ifdef AFS  #ifdef AFS
         case 'k':                  case 'k':
           options.kerberos_tgt_passing = 0;                          options.kerberos_tgt_passing = 0;
           options.afs_token_passing = 0;                          options.afs_token_passing = 0;
           break;                          break;
 #endif  #endif
         case 'i':                  case 'i':
           if (stat(optarg, &st) < 0)                          if (stat(optarg, &st) < 0) {
             {                                  fprintf(stderr, "Warning: Identity file %s does not exist.\n",
               fprintf(stderr, "Warning: Identity file %s does not exist.\n",                                          optarg);
                       optarg);                                  break;
               break;                          }
             }                          if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
           if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)                                  fatal("Too many identity files specified (max %d)",
             fatal("Too many identity files specified (max %d)",                                        SSH_MAX_IDENTITY_FILES);
                   SSH_MAX_IDENTITY_FILES);                          options.identity_files[options.num_identity_files++] =
           options.identity_files[options.num_identity_files++] =                                  xstrdup(optarg);
             xstrdup(optarg);                          break;
           break;  
   
         case 't':                  case 't':
           tty_flag = 1;                          tty_flag = 1;
           break;                          break;
   
         case 'v':                  case 'v':
         case 'V':                  case 'V':
           fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",                          fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
                   SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);                              SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
           fprintf(stderr, "Compiled with SSL.\n");                          fprintf(stderr, "Compiled with SSL.\n");
           if (opt == 'V')                          if (opt == 'V')
             exit(0);                                  exit(0);
           debug_flag = 1;                          debug_flag = 1;
           options.log_level = SYSLOG_LEVEL_DEBUG;                          options.log_level = SYSLOG_LEVEL_DEBUG;
           break;                          break;
   
         case 'q':                  case 'q':
           options.log_level = SYSLOG_LEVEL_QUIET;                          options.log_level = SYSLOG_LEVEL_QUIET;
           break;                          break;
   
         case 'e':                  case 'e':
           if (optarg[0] == '^' && optarg[2] == 0 &&                          if (optarg[0] == '^' && optarg[2] == 0 &&
               (unsigned char)optarg[1] >= 64 && (unsigned char)optarg[1] < 128)                              (unsigned char) optarg[1] >= 64 && (unsigned char) optarg[1] < 128)
             options.escape_char = (unsigned char)optarg[1] & 31;                                  options.escape_char = (unsigned char) optarg[1] & 31;
           else                          else if (strlen(optarg) == 1)
             if (strlen(optarg) == 1)                                  options.escape_char = (unsigned char) optarg[0];
               options.escape_char = (unsigned char)optarg[0];                          else if (strcmp(optarg, "none") == 0)
             else                                  options.escape_char = -2;
               if (strcmp(optarg, "none") == 0)                          else {
                 options.escape_char = -2;                                  fprintf(stderr, "Bad escape character '%s'.\n", optarg);
               else                                  exit(1);
                 {                          }
                   fprintf(stderr, "Bad escape character '%s'.\n", optarg);                          break;
                   exit(1);  
                 }  
           break;  
   
         case 'c':                  case 'c':
           options.cipher = cipher_number(optarg);                          options.cipher = cipher_number(optarg);
           if (options.cipher == -1)                          if (options.cipher == -1) {
             {                                  fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
               fprintf(stderr, "Unknown cipher type '%s'\n", optarg);                                  exit(1);
               exit(1);                          }
             }                          break;
           break;  
   
         case 'p':                  case 'p':
           options.port = atoi(optarg);                          options.port = atoi(optarg);
           if (options.port < 1 || options.port > 65535)                          if (options.port < 1 || options.port > 65535) {
             {                                  fprintf(stderr, "Bad port %s.\n", optarg);
               fprintf(stderr, "Bad port %s.\n", optarg);                                  exit(1);
               exit(1);                          }
             }                          break;
           break;  
   
         case 'l':                  case 'l':
           options.user = optarg;                          options.user = optarg;
           break;                          break;
   
         case 'R':                  case 'R':
           if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,                          if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
                      &fwd_host_port) != 3)                                     &fwd_host_port) != 3) {
             {                                  fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
               fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);                                  usage();
               usage();                                  /* NOTREACHED */
               /*NOTREACHED*/                          }
             }                          add_remote_forward(&options, fwd_port, buf, fwd_host_port);
           add_remote_forward(&options, fwd_port, buf, fwd_host_port);                          break;
           break;  
   
         case 'L':                  case 'L':
           if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,                          if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
                      &fwd_host_port) != 3)                                     &fwd_host_port) != 3) {
             {                                  fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
               fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);                                  usage();
               usage();                                  /* NOTREACHED */
               /*NOTREACHED*/                          }
             }                          add_local_forward(&options, fwd_port, buf, fwd_host_port);
           add_local_forward(&options, fwd_port, buf, fwd_host_port);                          break;
           break;  
   
         case 'C':                  case 'C':
           options.compression = 1;                          options.compression = 1;
           break;                          break;
   
         case 'o':                  case 'o':
           dummy = 1;                          dummy = 1;
           if (process_config_line(&options, host ? host : "", optarg,                          if (process_config_line(&options, host ? host : "", optarg,
                                   "command-line", 0, &dummy) != 0)                                           "command-line", 0, &dummy) != 0)
             exit(1);                                  exit(1);
           break;                          break;
   
         default:                  default:
           usage();                          usage();
                   }
         }          }
     }  
   
  /* Check that we got a host name. */          /* Check that we got a host name. */
   if (!host)          if (!host)
     usage();                  usage();
   
   /* check if RSA support exists */          /* check if RSA support exists */
   if (rsa_alive() == 0) {          if (rsa_alive() == 0) {
     extern char *__progname;                  extern char *__progname;
   
     fprintf(stderr,                  fprintf(stderr,
       "%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",                          "%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
       __progname);                          __progname);
     exit(1);                  exit(1);
   }          }
           /* Initialize the command to execute on remote host. */
           buffer_init(&command);
   
   /* Initialize the command to execute on remote host. */          /* Save the command to execute on the remote host in a buffer.
   buffer_init(&command);             There is no limit on the length of the command, except by the
              maximum packet size.  Also sets the tty flag if there is no
   /* Save the command to execute on the remote host in a buffer.  There is             command. */
      no limit on the length of the command, except by the maximum packet          if (optind == ac) {
      size.  Also sets the tty flag if there is no command. */                  /* No command specified - execute shell on a tty. */
   if (optind == ac)                  tty_flag = 1;
     {          } else {
       /* No command specified - execute shell on a tty. */                  /* A command has been specified.  Store it into the
       tty_flag = 1;                     buffer. */
     }                  for (i = optind; i < ac; i++) {
   else                          if (i > optind)
     {                                  buffer_append(&command, " ", 1);
       /* A command has been specified.  Store it into the buffer. */                          buffer_append(&command, av[i], strlen(av[i]));
       for (i = optind; i < ac; i++)                  }
         {  
           if (i > optind)  
             buffer_append(&command, " ", 1);  
           buffer_append(&command, av[i], strlen(av[i]));  
         }          }
     }  
   
   /* Cannot fork to background if no command. */          /* Cannot fork to background if no command. */
   if (fork_after_authentication_flag && buffer_len(&command) == 0)          if (fork_after_authentication_flag && buffer_len(&command) == 0)
     fatal("Cannot fork into background without a command to execute.");                  fatal("Cannot fork into background without a command to execute.");
   
   /* Allocate a tty by default if no command specified. */  
   if (buffer_len(&command) == 0)  
     tty_flag = 1;  
   
   /* Do not allocate a tty if stdin is not a tty. */          /* Allocate a tty by default if no command specified. */
   if (!isatty(fileno(stdin)))          if (buffer_len(&command) == 0)
     {                  tty_flag = 1;
       if (tty_flag)  
         fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");  
       tty_flag = 0;  
     }  
   
   /* Get user data. */          /* Do not allocate a tty if stdin is not a tty. */
   pw = getpwuid(original_real_uid);          if (!isatty(fileno(stdin))) {
   if (!pw)                  if (tty_flag)
     {                          fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
       fprintf(stderr, "You don't exist, go away!\n");                  tty_flag = 0;
       exit(1);          }
     }          /* Get user data. */
           pw = getpwuid(original_real_uid);
   /* Take a copy of the returned structure. */          if (!pw) {
   memset(&pwcopy, 0, sizeof(pwcopy));                  fprintf(stderr, "You don't exist, go away!\n");
   pwcopy.pw_name = xstrdup(pw->pw_name);                  exit(1);
   pwcopy.pw_passwd = xstrdup(pw->pw_passwd);          }
   pwcopy.pw_uid = pw->pw_uid;          /* Take a copy of the returned structure. */
   pwcopy.pw_gid = pw->pw_gid;          memset(&pwcopy, 0, sizeof(pwcopy));
   pwcopy.pw_dir = xstrdup(pw->pw_dir);          pwcopy.pw_name = xstrdup(pw->pw_name);
   pwcopy.pw_shell = xstrdup(pw->pw_shell);          pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
   pw = &pwcopy;          pwcopy.pw_uid = pw->pw_uid;
           pwcopy.pw_gid = pw->pw_gid;
           pwcopy.pw_dir = xstrdup(pw->pw_dir);
           pwcopy.pw_shell = xstrdup(pw->pw_shell);
           pw = &pwcopy;
   
   /* Initialize "log" output.  Since we are the client all output actually          /* Initialize "log" output.  Since we are the client all output
      goes to the terminal. */             actually goes to the terminal. */
   log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);          log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
   
   /* Read per-user configuration file. */          /* Read per-user configuration file. */
   snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE);          snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE);
   read_config_file(buf, host, &options);          read_config_file(buf, host, &options);
   
   /* Read systemwide configuration file. */          /* Read systemwide configuration file. */
   read_config_file(HOST_CONFIG_FILE, host, &options);          read_config_file(HOST_CONFIG_FILE, host, &options);
   
   /* Fill configuration defaults. */          /* Fill configuration defaults. */
   fill_default_options(&options);          fill_default_options(&options);
   
   /* reinit */          /* reinit */
   log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);          log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
   
   if (options.user == NULL)          if (options.user == NULL)
     options.user = xstrdup(pw->pw_name);                  options.user = xstrdup(pw->pw_name);
   
   if (options.hostname != NULL)          if (options.hostname != NULL)
     host = options.hostname;                  host = options.hostname;
   
   /* Find canonic host name. */          /* Find canonic host name. */
   if (strchr(host, '.') == 0)          if (strchr(host, '.') == 0) {
     {                  struct hostent *hp = gethostbyname(host);
       struct hostent *hp = gethostbyname(host);                  if (hp != 0) {
       if (hp != 0)                          if (strchr(hp->h_name, '.') != 0)
         {                                  host = xstrdup(hp->h_name);
           if (strchr(hp->h_name, '.') != 0)                          else if (hp->h_aliases != 0
             host = xstrdup(hp->h_name);                                   && hp->h_aliases[0] != 0
           else if (hp->h_aliases != 0                                   && strchr(hp->h_aliases[0], '.') != 0)
                    && hp->h_aliases[0] != 0                                  host = xstrdup(hp->h_aliases[0]);
                    && strchr(hp->h_aliases[0], '.') != 0)                  }
             host = xstrdup(hp->h_aliases[0]);  
         }          }
     }          /* Disable rhosts authentication if not running as root. */
           if (original_effective_uid != 0 || !options.use_privileged_port) {
                   options.rhosts_authentication = 0;
                   options.rhosts_rsa_authentication = 0;
           }
           /* If using rsh has been selected, exec it now (without trying
              anything else).  Note that we must release privileges first. */
           if (options.use_rsh) {
                   /* Restore our superuser privileges.  This must be done
                      before permanently setting the uid. */
                   restore_uid();
   
   /* Disable rhosts authentication if not running as root. */                  /* Switch to the original uid permanently. */
   if (original_effective_uid != 0 || !options.use_privileged_port)                  permanently_set_uid(original_real_uid);
     {  
       options.rhosts_authentication = 0;  
       options.rhosts_rsa_authentication = 0;  
     }  
   
   /* If using rsh has been selected, exec it now (without trying anything                  /* Execute rsh. */
      else).  Note that we must release privileges first. */                  rsh_connect(host, options.user, &command);
   if (options.use_rsh)                  fatal("rsh_connect returned");
     {          }
       /* Restore our superuser privileges.  This must be done before          /* Restore our superuser privileges. */
          permanently setting the uid. */          restore_uid();
       restore_uid();  
   
       /* Switch to the original uid permanently. */          /* Open a connection to the remote host.  This needs root
       permanently_set_uid(original_real_uid);             privileges if rhosts_{rsa_}authentication is enabled. */
   
       /* Execute rsh. */          ok = ssh_connect(host, &hostaddr, options.port,
       rsh_connect(host, options.user, &command);                           options.connection_attempts,
       fatal("rsh_connect returned");                           !options.rhosts_authentication &&
     }                           !options.rhosts_rsa_authentication,
                            original_real_uid,
                            options.proxy_command);
   
   /* Restore our superuser privileges. */          /* If we successfully made the connection, load the host private
   restore_uid();             key in case we will need it later for combined rsa-rhosts
              authentication. This must be done before releasing extra
              privileges, because the file is only readable by root. */
           if (ok) {
                   host_private_key = RSA_new();
                   if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
                           host_private_key_loaded = 1;
           }
           /* Get rid of any extra privileges that we may have.  We will no
              longer need them.  Also, extra privileges could make it very
              hard to read identity files and other non-world-readable files
              from the user's home directory if it happens to be on a NFS
              volume where root is mapped to nobody. */
   
   /* Open a connection to the remote host.  This needs root privileges if          /* Note that some legacy systems need to postpone the following
      rhosts_{rsa_}authentication is enabled. */             call to permanently_set_uid() until the private hostkey is
              destroyed with RSA_free().  Otherwise the calling user could
              ptrace() the process, read the private hostkey and impersonate
              the host.  OpenBSD does not allow ptracing of setuid processes. */
   
   ok = ssh_connect(host, &hostaddr, options.port, options.connection_attempts,          permanently_set_uid(original_real_uid);
                    !options.rhosts_authentication &&  
                    !options.rhosts_rsa_authentication,  
                    original_real_uid, options.proxy_command);  
   
   /* If we successfully made the connection, load the host private key in          /* Now that we are back to our own permissions, create ~/.ssh
      case we will need it later for combined rsa-rhosts authentication.             directory if it doesn\'t already exist. */
      This must be done before releasing extra privileges, because the file          snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
      is only readable by root. */          if (stat(buf, &st) < 0)
   if (ok)                  if (mkdir(buf, 0755) < 0)
     {                          error("Could not create directory '%.200s'.", buf);
       host_private_key = RSA_new();  
       if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))  
         host_private_key_loaded = 1;  
     }  
   
   /* Get rid of any extra privileges that we may have.  We will no longer need          /* Check if the connection failed, and try "rsh" if appropriate. */
      them.  Also, extra privileges could make it very hard to read identity          if (!ok) {
      files and other non-world-readable files from the user's home directory                  if (options.port != 0)
      if it happens to be on a NFS volume where root is mapped to nobody. */                          log("Secure connection to %.100s on port %d refused%.100s.",
                               host, options.port,
                               options.fallback_to_rsh ? "; reverting to insecure method" : "");
                   else
                           log("Secure connection to %.100s refused%.100s.", host,
                               options.fallback_to_rsh ? "; reverting to insecure method" : "");
   
   /* Note that some legacy systems need to postpone the following call to                  if (options.fallback_to_rsh) {
      permanently_set_uid() until the private hostkey is destroyed with                          rsh_connect(host, options.user, &command);
      RSA_free().  Otherwise the calling user could ptrace() the process,                          fatal("rsh_connect returned");
      read the private hostkey and impersonate the host.  OpenBSD does not                  }
      allow ptracing of setuid processes. */                  exit(1);
   
   permanently_set_uid(original_real_uid);  
   
   /* Now that we are back to our own permissions, create ~/.ssh directory  
      if it doesn\'t already exist. */  
   snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);  
   if (stat(buf, &st) < 0)  
     if (mkdir(buf, 0755) < 0)  
       error("Could not create directory '%.200s'.", buf);  
   
   /* Check if the connection failed, and try "rsh" if appropriate. */  
   if (!ok)  
     {  
       if (options.port != 0)  
         log("Secure connection to %.100s on port %d refused%.100s.",  
             host, options.port,  
             options.fallback_to_rsh ? "; reverting to insecure method" : "");  
       else  
         log("Secure connection to %.100s refused%.100s.", host,  
             options.fallback_to_rsh ? "; reverting to insecure method" : "");  
   
       if (options.fallback_to_rsh)  
         {  
           rsh_connect(host, options.user, &command);  
           fatal("rsh_connect returned");  
         }          }
       exit(1);          /* Expand ~ in options.identity_files. */
     }          for (i = 0; i < options.num_identity_files; i++)
                   options.identity_files[i] =
                           tilde_expand_filename(options.identity_files[i], original_real_uid);
   
   /* Expand ~ in options.identity_files. */          /* Expand ~ in known host file names. */
   for (i = 0; i < options.num_identity_files; i++)          options.system_hostfile = tilde_expand_filename(options.system_hostfile,
     options.identity_files[i] =                                                          original_real_uid);
       tilde_expand_filename(options.identity_files[i], original_real_uid);          options.user_hostfile = tilde_expand_filename(options.user_hostfile,
                                                         original_real_uid);
   
   /* Expand ~ in known host file names. */          /* Log into the remote system.  This never returns if the login fails. */
   options.system_hostfile = tilde_expand_filename(options.system_hostfile,          ssh_login(host_private_key_loaded, host_private_key,
                                                   original_real_uid);                    host, &hostaddr, original_real_uid);
   options.user_hostfile = tilde_expand_filename(options.user_hostfile,  
                                                 original_real_uid);  
   
   /* Log into the remote system.  This never returns if the login fails. */          /* We no longer need the host private key.  Clear it now. */
   ssh_login(host_private_key_loaded, host_private_key,          if (host_private_key_loaded)
             host, &hostaddr, original_real_uid);                  RSA_free(host_private_key);     /* Destroys contents safely */
   
   /* We no longer need the host private key.  Clear it now. */          /* Close connection cleanly after attack. */
   if (host_private_key_loaded)          cipher_attack_detected = packet_disconnect;
     RSA_free(host_private_key); /* Destroys contents safely */  
   
   /* Close connection cleanly after attack. */          /* If requested, fork and let ssh continue in the background. */
   cipher_attack_detected = packet_disconnect;          if (fork_after_authentication_flag) {
                   int ret = fork();
                   if (ret == -1)
                           fatal("fork failed: %.100s", strerror(errno));
                   if (ret != 0)
                           exit(0);
                   setsid();
           }
           /* Enable compression if requested. */
           if (options.compression) {
                   debug("Requesting compression at level %d.", options.compression_level);
   
   /* If requested, fork and let ssh continue in the background. */                  if (options.compression_level < 1 || options.compression_level > 9)
   if (fork_after_authentication_flag)                          fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
     {  
       int ret = fork();  
       if (ret == -1)  
         fatal("fork failed: %.100s", strerror(errno));  
       if (ret != 0)  
         exit(0);  
       setsid();  
     }  
   
   /* Enable compression if requested. */                  /* Send the request. */
   if (options.compression)                  packet_start(SSH_CMSG_REQUEST_COMPRESSION);
     {                  packet_put_int(options.compression_level);
       debug("Requesting compression at level %d.", options.compression_level);                  packet_send();
                   packet_write_wait();
                   type = packet_read(&plen);
                   if (type == SSH_SMSG_SUCCESS)
                           packet_start_compression(options.compression_level);
                   else if (type == SSH_SMSG_FAILURE)
                           log("Warning: Remote host refused compression.");
                   else
                           packet_disconnect("Protocol error waiting for compression response.");
           }
           /* Allocate a pseudo tty if appropriate. */
           if (tty_flag) {
                   debug("Requesting pty.");
   
       if (options.compression_level < 1 || options.compression_level > 9)                  /* Start the packet. */
         fatal("Compression level must be from 1 (fast) to 9 (slow, best).");                  packet_start(SSH_CMSG_REQUEST_PTY);
   
       /* Send the request. */                  /* Store TERM in the packet.  There is no limit on the
       packet_start(SSH_CMSG_REQUEST_COMPRESSION);                     length of the string. */
       packet_put_int(options.compression_level);                  cp = getenv("TERM");
       packet_send();                  if (!cp)
       packet_write_wait();                          cp = "";
       type = packet_read(&plen);                  packet_put_string(cp, strlen(cp));
       if (type == SSH_SMSG_SUCCESS)  
         packet_start_compression(options.compression_level);  
       else if (type == SSH_SMSG_FAILURE)  
         log("Warning: Remote host refused compression.");  
       else  
         packet_disconnect("Protocol error waiting for compression response.");  
     }  
   
   /* Allocate a pseudo tty if appropriate. */                  /* Store window size in the packet. */
   if (tty_flag)                  if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
     {                          memset(&ws, 0, sizeof(ws));
       debug("Requesting pty.");                  packet_put_int(ws.ws_row);
                   packet_put_int(ws.ws_col);
                   packet_put_int(ws.ws_xpixel);
                   packet_put_int(ws.ws_ypixel);
   
       /* Start the packet. */                  /* Store tty modes in the packet. */
       packet_start(SSH_CMSG_REQUEST_PTY);                  tty_make_modes(fileno(stdin));
   
       /* Store TERM in the packet.  There is no limit on the length of the                  /* Send the packet, and wait for it to leave. */
          string. */                  packet_send();
       cp = getenv("TERM");                  packet_write_wait();
       if (!cp)  
         cp = "";  
       packet_put_string(cp, strlen(cp));  
   
       /* Store window size in the packet. */                  /* Read response from the server. */
       if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)                  type = packet_read(&plen);
         memset(&ws, 0, sizeof(ws));                  if (type == SSH_SMSG_SUCCESS)
       packet_put_int(ws.ws_row);                          interactive = 1;
       packet_put_int(ws.ws_col);                  else if (type == SSH_SMSG_FAILURE)
       packet_put_int(ws.ws_xpixel);                          log("Warning: Remote host failed or refused to allocate a pseudo tty.");
       packet_put_int(ws.ws_ypixel);                  else
                           packet_disconnect("Protocol error waiting for pty request response.");
       /* Store tty modes in the packet. */          }
       tty_make_modes(fileno(stdin));          /* Request X11 forwarding if enabled and DISPLAY is set. */
           if (options.forward_x11 && getenv("DISPLAY") != NULL) {
                   char line[512], proto[512], data[512];
                   FILE *f;
                   int forwarded = 0, got_data = 0, i;
   
       /* Send the packet, and wait for it to leave. */  
       packet_send();  
       packet_write_wait();  
   
       /* Read response from the server. */  
       type = packet_read(&plen);  
       if (type == SSH_SMSG_SUCCESS)  
         interactive = 1;  
       else if (type == SSH_SMSG_FAILURE)  
         log("Warning: Remote host failed or refused to allocate a pseudo tty.");  
       else  
         packet_disconnect("Protocol error waiting for pty request response.");  
     }  
   
   /* Request X11 forwarding if enabled and DISPLAY is set. */  
   if (options.forward_x11 && getenv("DISPLAY") != NULL)  
     {  
       char line[512], proto[512], data[512];  
       FILE *f;  
       int forwarded = 0, got_data = 0, i;  
   
 #ifdef XAUTH_PATH  #ifdef XAUTH_PATH
       /* Try to get Xauthority information for the display. */                  /* Try to get Xauthority information for the display. */
       snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null",                  snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null",
               XAUTH_PATH, getenv("DISPLAY"));                           XAUTH_PATH, getenv("DISPLAY"));
       f = popen(line, "r");                  f = popen(line, "r");
       if (f && fgets(line, sizeof(line), f) &&                  if (f && fgets(line, sizeof(line), f) &&
           sscanf(line, "%*s %s %s", proto, data) == 2)                      sscanf(line, "%*s %s %s", proto, data) == 2)
         got_data = 1;                          got_data = 1;
       if (f)                  if (f)
         pclose(f);                          pclose(f);
 #endif /* XAUTH_PATH */  #endif /* XAUTH_PATH */
       /* If we didn't get authentication data, just make up some data.  The                  /* If we didn't get authentication data, just make up some
          forwarding code will check the validity of the response anyway, and                     data.  The forwarding code will check the validity of
          substitute this data.  The X11 server, however, will ignore this                     the response anyway, and substitute this data.  The X11
          fake data and use whatever authentication mechanisms it was using                     server, however, will ignore this fake data and use
          otherwise for the local connection. */                     whatever authentication mechanisms it was using
       if (!got_data)                     otherwise for the local connection. */
         {                  if (!got_data) {
           u_int32_t rand = 0;                          u_int32_t rand = 0;
   
           strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);                          strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);
           for (i = 0; i < 16; i++) {                          for (i = 0; i < 16; i++) {
             if (i % 4 == 0)                                  if (i % 4 == 0)
               rand = arc4random();                                          rand = arc4random();
             snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);                                  snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);
             rand >>= 8;                                  rand >>= 8;
           }                          }
         }                  }
                   /* Got local authentication reasonable information.
                      Request forwarding with authentication spoofing. */
                   debug("Requesting X11 forwarding with authentication spoofing.");
                   x11_request_forwarding_with_spoofing(proto, data);
   
       /* Got local authentication reasonable information.  Request forwarding                  /* Read response from the server. */
          with authentication spoofing. */                  type = packet_read(&plen);
       debug("Requesting X11 forwarding with authentication spoofing.");                  if (type == SSH_SMSG_SUCCESS) {
       x11_request_forwarding_with_spoofing(proto, data);                          forwarded = 1;
                           interactive = 1;
       /* Read response from the server. */                  } else if (type == SSH_SMSG_FAILURE)
       type = packet_read(&plen);                          log("Warning: Remote host denied X11 forwarding.");
       if (type == SSH_SMSG_SUCCESS)                  else
         {                          packet_disconnect("Protocol error waiting for X11 forwarding");
           forwarded = 1;  
           interactive = 1;  
         }          }
       else if (type == SSH_SMSG_FAILURE)          /* Tell the packet module whether this is an interactive session. */
         log("Warning: Remote host denied X11 forwarding.");          packet_set_interactive(interactive, options.keepalives);
       else  
         packet_disconnect("Protocol error waiting for X11 forwarding");  
     }  
   
   /* Tell the packet module whether this is an interactive session. */          /* Clear agent forwarding if we don\'t have an agent. */
   packet_set_interactive(interactive, options.keepalives);          authfd = ssh_get_authentication_socket();
           if (authfd < 0)
                   options.forward_agent = 0;
           else
                   ssh_close_authentication_socket(authfd);
   
   /* Clear agent forwarding if we don\'t have an agent. */          /* Request authentication agent forwarding if appropriate. */
   authfd = ssh_get_authentication_socket();          if (options.forward_agent) {
   if (authfd < 0)                  debug("Requesting authentication agent forwarding.");
     options.forward_agent = 0;                  auth_request_forwarding();
   else  
     ssh_close_authentication_socket(authfd);  
   
   /* Request authentication agent forwarding if appropriate. */                  /* Read response from the server. */
   if (options.forward_agent)                  type = packet_read(&plen);
     {                  packet_integrity_check(plen, 0, type);
       debug("Requesting authentication agent forwarding.");                  if (type != SSH_SMSG_SUCCESS)
       auth_request_forwarding();                          log("Warning: Remote host denied authentication agent forwarding.");
           }
       /* Read response from the server. */          /* Initiate local TCP/IP port forwardings. */
       type = packet_read(&plen);          for (i = 0; i < options.num_local_forwards; i++) {
       packet_integrity_check(plen, 0, type);                  debug("Connections to local port %d forwarded to remote address %.200s:%d",
       if (type != SSH_SMSG_SUCCESS)                        options.local_forwards[i].port,
         log("Warning: Remote host denied authentication agent forwarding.");                        options.local_forwards[i].host,
     }                        options.local_forwards[i].host_port);
                   channel_request_local_forwarding(options.local_forwards[i].port,
                                                    options.local_forwards[i].host,
                                                    options.local_forwards[i].host_port);
           }
   
   /* Initiate local TCP/IP port forwardings. */          /* Initiate remote TCP/IP port forwardings. */
   for (i = 0; i < options.num_local_forwards; i++)          for (i = 0; i < options.num_remote_forwards; i++) {
     {                  debug("Connections to remote port %d forwarded to local address %.200s:%d",
       debug("Connections to local port %d forwarded to remote address %.200s:%d",                        options.remote_forwards[i].port,
             options.local_forwards[i].port, options.local_forwards[i].host,                        options.remote_forwards[i].host,
             options.local_forwards[i].host_port);                        options.remote_forwards[i].host_port);
       channel_request_local_forwarding(options.local_forwards[i].port,                  channel_request_remote_forwarding(options.remote_forwards[i].port,
                                        options.local_forwards[i].host,                                                    options.remote_forwards[i].host,
                                        options.local_forwards[i].host_port);                                                    options.remote_forwards[i].host_port);
     }          }
   
   /* Initiate remote TCP/IP port forwardings. */          /* If a command was specified on the command line, execute the
   for (i = 0; i < options.num_remote_forwards; i++)             command now. Otherwise request the server to start a shell. */
     {          if (buffer_len(&command) > 0) {
       debug("Connections to remote port %d forwarded to local address %.200s:%d",                  int len = buffer_len(&command);
             options.remote_forwards[i].port, options.remote_forwards[i].host,                  if (len > 900)
             options.remote_forwards[i].host_port);                          len = 900;
       channel_request_remote_forwarding(options.remote_forwards[i].port,                  debug("Sending command: %.*s", len, buffer_ptr(&command));
                                         options.remote_forwards[i].host,                  packet_start(SSH_CMSG_EXEC_CMD);
                                         options.remote_forwards[i].host_port);                  packet_put_string(buffer_ptr(&command), buffer_len(&command));
     }                  packet_send();
                   packet_write_wait();
           } else {
                   debug("Requesting shell.");
                   packet_start(SSH_CMSG_EXEC_SHELL);
                   packet_send();
                   packet_write_wait();
           }
   
   /* If a command was specified on the command line, execute the command now.          /* Enter the interactive session. */
      Otherwise request the server to start a shell. */          exit_status = client_loop(tty_flag, tty_flag ? options.escape_char : -1);
   if (buffer_len(&command) > 0)  
     {  
       int len = buffer_len(&command);  
       if (len > 900)  
         len = 900;  
       debug("Sending command: %.*s", len, buffer_ptr(&command));  
       packet_start(SSH_CMSG_EXEC_CMD);  
       packet_put_string(buffer_ptr(&command), buffer_len(&command));  
       packet_send();  
       packet_write_wait();  
     }  
   else  
     {  
       debug("Requesting shell.");  
       packet_start(SSH_CMSG_EXEC_SHELL);  
       packet_send();  
       packet_write_wait();  
     }  
   
   /* Enter the interactive session. */          /* Close the connection to the remote host. */
   exit_status = client_loop(tty_flag, tty_flag ? options.escape_char : -1);          packet_close();
   
   /* Close the connection to the remote host. */          /* Exit with the status returned by the program on the remote side. */
   packet_close();          exit(exit_status);
   
   /* Exit with the status returned by the program on the remote side. */  
   exit(exit_status);  
 }  }

Legend:
Removed from v.1.30  
changed lines
  Added in v.1.31