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

Diff for /src/usr.bin/ssh/sshd.c between version 1.74 and 1.75

version 1.74, 1999/12/12 19:20:03 version 1.75, 2000/01/04 00:08:01
Line 47 
Line 47 
 /* Name of the server configuration file. */  /* Name of the server configuration file. */
 char *config_file_name = SERVER_CONFIG_FILE;  char *config_file_name = SERVER_CONFIG_FILE;
   
   /*
    * Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
    * Default value is AF_UNSPEC means both IPv4 and IPv6.
    */
   int IPv4or6 = AF_UNSPEC;
   
 /*  /*
  * Debug mode flag.  This can be set on the command line.  If debug   * Debug mode flag.  This can be set on the command line.  If debug
  * mode is enabled, extra debugging output will be sent to the system   * mode is enabled, extra debugging output will be sent to the system
Line 68 
Line 74 
 char **saved_argv;  char **saved_argv;
   
 /*  /*
  * This is set to the socket that the server is listening; this is used in   * The sockets that the server is listening; this is used in the SIGHUP
  * the SIGHUP signal handler.   * signal handler.
  */   */
 int listen_sock;  #define MAX_LISTEN_SOCKS        16
   int listen_socks[MAX_LISTEN_SOCKS];
   int num_listen_socks = 0;
   
 /*  /*
  * the client's version string, passed by sshd2 in compat mode. if != NULL,   * the client's version string, passed by sshd2 in compat mode. if != NULL,
Line 138 
Line 146 
               const char *auth_data, const char *ttyname);                const char *auth_data, const char *ttyname);
   
 /*  /*
    * Close all listening sockets
    */
   void
   close_listen_socks(void)
   {
           int i;
           for (i = 0; i < num_listen_socks; i++)
                   close(listen_socks[i]);
           num_listen_socks = -1;
   }
   
   /*
  * Signal handler for SIGHUP.  Sshd execs itself when it receives SIGHUP;   * Signal handler for SIGHUP.  Sshd execs itself when it receives SIGHUP;
  * the effect is to reread the configuration file (and to regenerate   * the effect is to reread the configuration file (and to regenerate
  * the server key).   * the server key).
Line 157 
Line 177 
 sighup_restart()  sighup_restart()
 {  {
         log("Received SIGHUP; restarting.");          log("Received SIGHUP; restarting.");
         close(listen_sock);          close_listen_socks();
         execv(saved_argv[0], saved_argv);          execv(saved_argv[0], saved_argv);
         log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno));          log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno));
         exit(1);          exit(1);
Line 172 
Line 192 
 sigterm_handler(int sig)  sigterm_handler(int sig)
 {  {
         log("Received signal %d; terminating.", sig);          log("Received signal %d; terminating.", sig);
         close(listen_sock);          close_listen_socks();
         exit(255);          exit(255);
 }  }
   
Line 279 
Line 299 
 {  {
         extern char *optarg;          extern char *optarg;
         extern int optind;          extern int optind;
         int opt, aux, sock_in, sock_out, newsock, i, pid, on = 1;          int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, pid, on = 1;
           socklen_t fromlen;
         int remote_major, remote_minor;          int remote_major, remote_minor;
         int silentrsa = 0;          int silentrsa = 0;
         struct pollfd fds;          fd_set *fdset;
         struct sockaddr_in sin;          struct sockaddr_storage from;
         char buf[100];                  /* Must not be larger than remote_version. */          char buf[100];                  /* Must not be larger than remote_version. */
         char remote_version[100];       /* Must be at least as big as buf. */          char remote_version[100];       /* Must be at least as big as buf. */
         const char *remote_ip;          const char *remote_ip;
Line 291 
Line 312 
         char *comment;          char *comment;
         FILE *f;          FILE *f;
         struct linger linger;          struct linger linger;
           struct addrinfo *ai;
           char ntop[NI_MAXHOST], strport[NI_MAXSERV];
           int listen_sock, maxfd;
   
         /* Save argv[0]. */          /* Save argv[0]. */
         saved_argv = av;          saved_argv = av;
Line 303 
Line 327 
         initialize_server_options(&options);          initialize_server_options(&options);
   
         /* Parse command-line arguments. */          /* Parse command-line arguments. */
         while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ")) != EOF) {          while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ46")) != EOF) {
                 switch (opt) {                  switch (opt) {
                   case '4':
                           IPv4or6 = AF_INET;
                           break;
                   case '6':
                           IPv4or6 = AF_INET6;
                           break;
                 case 'f':                  case 'f':
                         config_file_name = optarg;                          config_file_name = optarg;
                         break;                          break;
Line 325 
Line 355 
                         options.server_key_bits = atoi(optarg);                          options.server_key_bits = atoi(optarg);
                         break;                          break;
                 case 'p':                  case 'p':
                         options.port = atoi(optarg);                          options.ports_from_cmdline = 1;
                           if (options.num_ports >= MAX_PORTS)
                                   fatal("too many ports.\n");
                           options.ports[options.num_ports++] = atoi(optarg);
                         break;                          break;
                 case 'g':                  case 'g':
                         options.login_grace_time = atoi(optarg);                          options.login_grace_time = atoi(optarg);
Line 355 
Line 388 
                         fprintf(stderr, "  -g seconds Grace period for authentication (default: 300)\n");                          fprintf(stderr, "  -g seconds Grace period for authentication (default: 300)\n");
                         fprintf(stderr, "  -b bits    Size of server RSA key (default: 768 bits)\n");                          fprintf(stderr, "  -b bits    Size of server RSA key (default: 768 bits)\n");
                         fprintf(stderr, "  -h file    File from which to read host key (default: %s)\n",                          fprintf(stderr, "  -h file    File from which to read host key (default: %s)\n",
                                 HOST_KEY_FILE);                              HOST_KEY_FILE);
                           fprintf(stderr, "  -4         Use IPv4 only\n");
                           fprintf(stderr, "  -6         Use IPv6 only\n");
                         exit(1);                          exit(1);
                 }                  }
         }          }
   
           /*
            * Force logging to stderr until we have loaded the private host
            * key (unless started from inetd)
            */
           log_init(av0,
               options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
               options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
               !inetd_flag);
   
         /* check if RSA support exists */          /* check if RSA support exists */
         if (rsa_alive() == 0) {          if (rsa_alive() == 0) {
                 if (silentrsa == 0)                  if (silentrsa == 0)
Line 379 
Line 423 
                 fprintf(stderr, "Bad server key size.\n");                  fprintf(stderr, "Bad server key size.\n");
                 exit(1);                  exit(1);
         }          }
         if (options.port < 1 || options.port > 65535) {  
                 fprintf(stderr, "Bad port number.\n");  
                 exit(1);  
         }  
         /* Check that there are no remaining arguments. */          /* Check that there are no remaining arguments. */
         if (optind < ac) {          if (optind < ac) {
                 fprintf(stderr, "Extra argument %s.\n", av[optind]);                  fprintf(stderr, "Extra argument %s.\n", av[optind]);
                 exit(1);                  exit(1);
         }          }
         /* Force logging to stderr while loading the private host key  
            unless started from inetd */  
         log_init(av0, options.log_level, options.log_facility, !inetd_flag);  
   
         debug("sshd version %.100s", SSH_VERSION);          debug("sshd version %.100s", SSH_VERSION);
   
Line 479 
Line 516 
                 arc4random_stir();                  arc4random_stir();
                 log("RSA key generation complete.");                  log("RSA key generation complete.");
         } else {          } else {
                 /* Create socket for listening. */                  for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
                 listen_sock = socket(AF_INET, SOCK_STREAM, 0);                          if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
                 if (listen_sock < 0)                                  continue;
                         fatal("socket: %.100s", strerror(errno));                          if (num_listen_socks >= MAX_LISTEN_SOCKS)
                                   fatal("Too many listen sockets. "
                                       "Enlarge MAX_LISTEN_SOCKS");
                           if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
                               ntop, sizeof(ntop), strport, sizeof(strport),
                               NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
                                   error("getnameinfo failed");
                                   continue;
                           }
                           /* Create socket for listening. */
                           listen_sock = socket(ai->ai_family, SOCK_STREAM, 0);
                           if (listen_sock < 0) {
                                   /* kernel may not support ipv6 */
                                   verbose("socket: %.100s", strerror(errno));
                                   continue;
                           }
                           if (fcntl(listen_sock, F_SETFL, O_NONBLOCK) < 0) {
                                   error("listen_sock O_NONBLOCK: %s", strerror(errno));
                                   close(listen_sock);
                                   continue;
                           }
                           /*
                            * Set socket options.  We try to make the port
                            * reusable and have it close as fast as possible
                            * without waiting in unnecessary wait states on
                            * close.
                            */
                           setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
                               (void *) &on, sizeof(on));
                           linger.l_onoff = 1;
                           linger.l_linger = 5;
                           setsockopt(listen_sock, SOL_SOCKET, SO_LINGER,
                               (void *) &linger, sizeof(linger));
   
                 /* Set socket options.  We try to make the port reusable                          debug("Bind to port %s on %s.", strport, ntop);
                    and have it close as fast as possible without waiting  
                    in unnecessary wait states on close. */  
                 setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on,  
                            sizeof(on));  
                 linger.l_onoff = 1;  
                 linger.l_linger = 5;  
                 setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *) &linger,  
                            sizeof(linger));  
   
                 memset(&sin, 0, sizeof(sin));                          /* Bind the socket to the desired port. */
                 sin.sin_family = AF_INET;                          if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) {
                 sin.sin_addr = options.listen_addr;                                  error("Bind to port %s on %s failed: %.200s.",
                 sin.sin_port = htons(options.port);                                      strport, ntop, strerror(errno));
                                   close(listen_sock);
                                   continue;
                           }
                           listen_socks[num_listen_socks] = listen_sock;
                           num_listen_socks++;
   
                 if (bind(listen_sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {                          /* Start listening on the port. */
                         error("bind: %.100s", strerror(errno));                          log("Server listening on %s port %s.", ntop, strport);
                         shutdown(listen_sock, SHUT_RDWR);                          if (listen(listen_sock, 5) < 0)
                         close(listen_sock);                                  fatal("listen: %.100s", strerror(errno));
                         fatal("Bind to port %d failed.", options.port);  
                 }                  }
                   freeaddrinfo(options.listen_addrs);
   
                   if (!num_listen_socks)
                           fatal("Cannot bind any address.");
   
                 if (!debug_flag) {                  if (!debug_flag) {
                         /*                          /*
                          * Record our pid in /etc/sshd_pid to make it easier                           * Record our pid in /etc/sshd_pid to make it easier
Line 520 
Line 591 
                         }                          }
                 }                  }
   
                 log("Server listening on port %d.", options.port);  
                 if (listen(listen_sock, 5) < 0)  
                         fatal("listen: %.100s", strerror(errno));  
   
                 public_key = RSA_new();                  public_key = RSA_new();
                 sensitive_data.private_key = RSA_new();                  sensitive_data.private_key = RSA_new();
   
Line 545 
Line 612 
                 /* Arrange SIGCHLD to be caught. */                  /* Arrange SIGCHLD to be caught. */
                 signal(SIGCHLD, main_sigchld_handler);                  signal(SIGCHLD, main_sigchld_handler);
   
                   /* setup fd set for listen */
                   maxfd = 0;
                   for (i = 0; i < num_listen_socks; i++)
                           if (listen_socks[i] > maxfd)
                                   maxfd = listen_socks[i];
                   fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
                   fdset = (fd_set *)xmalloc(fdsetsz);
   
                 /*                  /*
                  * Stay listening for connections until the system crashes or                   * Stay listening for connections until the system crashes or
                  * the daemon is killed with a signal.                   * the daemon is killed with a signal.
Line 552 
Line 627 
                 for (;;) {                  for (;;) {
                         if (received_sighup)                          if (received_sighup)
                                 sighup_restart();                                  sighup_restart();
                         /* Wait in poll until there is a connection. */                          /* Wait in select until there is a connection. */
                         memset(&fds, 0, sizeof(fds));                          memset(fdset, 0, fdsetsz);
                         fds.fd = listen_sock;                          for (i = 0; i < num_listen_socks; i++)
                         fds.events = POLLIN;                                  FD_SET(listen_socks[i], fdset);
                         if (poll(&fds, 1, -1) == -1) {                          if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) {
                                 if (errno == EINTR)                                  if (errno != EINTR)
                                         continue;                                          error("select: %.100s", strerror(errno));
                                 fatal("poll: %.100s", strerror(errno));  
                                 /*NOTREACHED*/  
                         }  
                         if (fds.revents == 0)  
                                 continue;                                  continue;
                         aux = sizeof(sin);                          }
                         newsock = accept(listen_sock, (struct sockaddr *) & sin, &aux);                          for (i = 0; i < num_listen_socks; i++) {
                         if (received_sighup)                                  if (!FD_ISSET(listen_socks[i], fdset))
                                 sighup_restart();  
                         if (newsock < 0) {  
                                 if (errno == EINTR)  
                                         continue;                                          continue;
                                 error("accept: %.100s", strerror(errno));                          fromlen = sizeof(from);
                           newsock = accept(listen_socks[i], (struct sockaddr *)&from,
                               &fromlen);
                           if (newsock < 0) {
                                   if (errno != EINTR && errno != EWOULDBLOCK)
                                           error("accept: %.100s", strerror(errno));
                                 continue;                                  continue;
                         }                          }
                           if (fcntl(newsock, F_SETFL, 0) < 0) {
                                   error("newsock del O_NONBLOCK: %s", strerror(errno));
                                   continue;
                           }
                         /*                          /*
                          * Got connection.  Fork a child to handle it, unless                           * Got connection.  Fork a child to handle it, unless
                          * we are in debugging mode.                           * we are in debugging mode.
Line 585 
Line 662 
                                  * connection without forking.                                   * connection without forking.
                                  */                                   */
                                 debug("Server will not fork when running in debugging mode.");                                  debug("Server will not fork when running in debugging mode.");
                                 close(listen_sock);                                  close_listen_socks();
                                 sock_in = newsock;                                  sock_in = newsock;
                                 sock_out = newsock;                                  sock_out = newsock;
                                 pid = getpid();                                  pid = getpid();
Line 602 
Line 679 
                                          * accepted socket.  Reinitialize logging (since our pid has                                           * accepted socket.  Reinitialize logging (since our pid has
                                          * changed).  We break out of the loop to handle the connection.                                           * changed).  We break out of the loop to handle the connection.
                                          */                                           */
                                         close(listen_sock);                                          close_listen_socks();
                                         sock_in = newsock;                                          sock_in = newsock;
                                         sock_out = newsock;                                          sock_out = newsock;
                                         log_init(av0, options.log_level, options.log_facility, log_stderr);                                          log_init(av0, options.log_level, options.log_facility, log_stderr);
Line 623 
Line 700 
   
                         /* Close the new socket (the child is now taking care of it). */                          /* Close the new socket (the child is now taking care of it). */
                         close(newsock);                          close(newsock);
                           } /* for (i = 0; i < num_listen_socks; i++) */
                           /* child process check (or debug mode) */
                           if (num_listen_socks < 0)
                                   break;
                 }                  }
         }          }
   
Line 661 
Line 742 
   
         /* Check whether logins are denied from this host. */          /* Check whether logins are denied from this host. */
 #ifdef LIBWRAP  #ifdef LIBWRAP
           /* XXX LIBWRAP noes not know about IPv6 */
         {          {
                 struct request_info req;                  struct request_info req;
   
Line 672 
Line 754 
                         close(sock_out);                          close(sock_out);
                         refuse(&req);                          refuse(&req);
                 }                  }
                 verbose("Connection from %.500s port %d", eval_client(&req), remote_port);  /*XXX IPv6 verbose("Connection from %.500s port %d", eval_client(&req), remote_port); */
         }          }
 #else  #endif /* LIBWRAP */
         /* Log the connection. */          /* Log the connection. */
         verbose("Connection from %.500s port %d", remote_ip, remote_port);          verbose("Connection from %.500s port %d", remote_ip, remote_port);
 #endif /* LIBWRAP */  
   
         /*          /*
          * We don\'t want to listen forever unless the other side           * We don\'t want to listen forever unless the other side
Line 699 
Line 780 
                 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",                  snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
                          PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);                           PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
                 if (atomicio(write, sock_out, buf, strlen(buf)) != strlen(buf))                  if (atomicio(write, sock_out, buf, strlen(buf)) != strlen(buf))
                         fatal("Could not write ident string to %s.", get_remote_ipaddr());                          fatal("Could not write ident string to %s.", remote_ip);
   
                 /* Read other side\'s version identification. */                  /* Read other side\'s version identification. */
                 for (i = 0; i < sizeof(buf) - 1; i++) {                  for (i = 0; i < sizeof(buf) - 1; i++) {
                         if (read(sock_in, &buf[i], 1) != 1)                          if (read(sock_in, &buf[i], 1) != 1)
                                 fatal("Did not receive ident string from %s.", get_remote_ipaddr());                                  fatal("Did not receive ident string from %s.", remote_ip);
                         if (buf[i] == '\r') {                          if (buf[i] == '\r') {
                                 buf[i] = '\n';                                  buf[i] = '\n';
                                 buf[i + 1] = 0;                                  buf[i + 1] = 0;
Line 731 
Line 812 
                 close(sock_in);                  close(sock_in);
                 close(sock_out);                  close(sock_out);
                 fatal("Bad protocol version identification '%.100s' from %s",                  fatal("Bad protocol version identification '%.100s' from %s",
                       buf, get_remote_ipaddr());                        buf, remote_ip);
         }          }
         debug("Client protocol version %d.%d; client software version %.100s",          debug("Client protocol version %d.%d; client software version %.100s",
               remote_major, remote_minor, remote_version);                remote_major, remote_minor, remote_version);
Line 742 
Line 823 
                 close(sock_in);                  close(sock_in);
                 close(sock_out);                  close(sock_out);
                 fatal("Protocol major versions differ for %s: %d vs. %d",                  fatal("Protocol major versions differ for %s: %d vs. %d",
                       get_remote_ipaddr(),                        remote_ip, PROTOCOL_MAJOR, remote_major);
                       PROTOCOL_MAJOR, remote_major);  
         }          }
         /* Check that the client has sufficiently high software version. */          /* Check that the client has sufficiently high software version. */
         if (remote_major == 1 && remote_minor < 3)          if (remote_major == 1 && remote_minor < 3)
Line 1892 
Line 1972 
         char line[256];          char line[256];
         struct stat st;          struct stat st;
         int quiet_login;          int quiet_login;
         struct sockaddr_in from;          struct sockaddr_storage from;
         int fromlen;          socklen_t fromlen;
         struct pty_cleanup_context cleanup_context;          struct pty_cleanup_context cleanup_context;
   
         /* Get remote host name. */          /* Get remote host name. */
Line 1954 
Line 2034 
                 }                  }
                 /* Record that there was a login on that terminal. */                  /* Record that there was a login on that terminal. */
                 record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname,                  record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname,
                              &from);                               (struct sockaddr *)&from);
   
                 /* Check if .hushlogin exists. */                  /* Check if .hushlogin exists. */
                 snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);                  snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
Line 2233 
Line 2313 
         }          }
   
         snprintf(buf, sizeof buf, "%.50s %d %d",          snprintf(buf, sizeof buf, "%.50s %d %d",
                  get_remote_ipaddr(), get_remote_port(), options.port);                   get_remote_ipaddr(), get_remote_port(), get_local_port());
         child_set_env(&env, &envsize, "SSH_CLIENT", buf);          child_set_env(&env, &envsize, "SSH_CLIENT", buf);
   
         if (ttyname)          if (ttyname)
Line 2294 
Line 2374 
          * descriptors left by system functions.  They will be closed later.           * descriptors left by system functions.  They will be closed later.
          */           */
         endpwent();          endpwent();
         endhostent();  
   
         /*          /*
          * Close any extra open file descriptors so that we don\'t have them           * Close any extra open file descriptors so that we don\'t have them

Legend:
Removed from v.1.74  
changed lines
  Added in v.1.75