[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.532 and 1.533

version 1.532, 2019/01/21 10:38:54 version 1.533, 2019/03/01 02:32:39
Line 194 
Line 194 
 /* record remote hostname or ip */  /* record remote hostname or ip */
 u_int utmp_len = HOST_NAME_MAX+1;  u_int utmp_len = HOST_NAME_MAX+1;
   
 /* options.max_startup sized array of fd ints */  /*
    * startup_pipes/flags are used for tracking children of the listening sshd
    * process early in their lifespans. This tracking is needed for three things:
    *
    * 1) Implementing the MaxStartups limit of concurrent unauthenticated
    *    connections.
    * 2) Avoiding a race condition for SIGHUP processing, where child processes
    *    may have listen_socks open that could collide with main listener process
    *    after it restarts.
    * 3) Ensuring that rexec'd sshd processes have received their initial state
    *    from the parent listen process before handling SIGHUP.
    *
    * Child processes signal that they have completed closure of the listen_socks
    * and (if applicable) received their rexec state by sending a char over their
    * sock. Child processes signal that authentication has completed by closing
    * the sock (or by exiting).
    */
 static int *startup_pipes = NULL;  static int *startup_pipes = NULL;
 static int startup_pipe;                /* in child */  static int *startup_flags = NULL;       /* Indicates child closed listener */
   static int startup_pipe = -1;           /* in child */
   
 /* variables used for privilege separation */  /* variables used for privilege separation */
 int use_privsep = -1;  int use_privsep = -1;
Line 850 
Line 867 
 {  {
         int fd;          int fd;
   
         startup_pipe = -1;  
         if (rexeced_flag) {          if (rexeced_flag) {
                 close(REEXEC_CONFIG_PASS_FD);                  close(REEXEC_CONFIG_PASS_FD);
                 *sock_in = *sock_out = dup(STDIN_FILENO);                  *sock_in = *sock_out = dup(STDIN_FILENO);
                 if (!debug_flag) {  
                         startup_pipe = dup(REEXEC_STARTUP_PIPE_FD);  
                         close(REEXEC_STARTUP_PIPE_FD);  
                 }  
         } else {          } else {
                 *sock_in = dup(STDIN_FILENO);                  *sock_in = dup(STDIN_FILENO);
                 *sock_out = dup(STDOUT_FILENO);                  *sock_out = dup(STDOUT_FILENO);
Line 978 
Line 990 
 {  {
         fd_set *fdset;          fd_set *fdset;
         int i, j, ret, maxfd;          int i, j, ret, maxfd;
         int startups = 0;          int startups = 0, listening = 0, lameduck = 0;
         int startup_p[2] = { -1 , -1 };          int startup_p[2] = { -1 , -1 };
           char c = 0;
         struct sockaddr_storage from;          struct sockaddr_storage from;
         socklen_t fromlen;          socklen_t fromlen;
         pid_t pid;          pid_t pid;
Line 992 
Line 1005 
                         maxfd = listen_socks[i];                          maxfd = listen_socks[i];
         /* pipes connected to unauthenticated childs */          /* pipes connected to unauthenticated childs */
         startup_pipes = xcalloc(options.max_startups, sizeof(int));          startup_pipes = xcalloc(options.max_startups, sizeof(int));
           startup_flags = xcalloc(options.max_startups, sizeof(int));
         for (i = 0; i < options.max_startups; i++)          for (i = 0; i < options.max_startups; i++)
                 startup_pipes[i] = -1;                  startup_pipes[i] = -1;
   
Line 1000 
Line 1014 
          * the daemon is killed with a signal.           * the daemon is killed with a signal.
          */           */
         for (;;) {          for (;;) {
                 if (received_sighup)                  if (received_sighup) {
                         sighup_restart();                          if (!lameduck) {
                                   debug("Received SIGHUP; waiting for children");
                                   close_listen_socks();
                                   lameduck = 1;
                           }
                           if (listening <= 0)
                                   sighup_restart();
                   }
                 free(fdset);                  free(fdset);
                 fdset = xcalloc(howmany(maxfd + 1, NFDBITS),                  fdset = xcalloc(howmany(maxfd + 1, NFDBITS),
                     sizeof(fd_mask));                      sizeof(fd_mask));
Line 1027 
Line 1048 
                 if (ret < 0)                  if (ret < 0)
                         continue;                          continue;
   
                 for (i = 0; i < options.max_startups; i++)                  for (i = 0; i < options.max_startups; i++) {
                         if (startup_pipes[i] != -1 &&                          if (startup_pipes[i] == -1 ||
                             FD_ISSET(startup_pipes[i], fdset)) {                              !FD_ISSET(startup_pipes[i], fdset))
                                 /*                                  continue;
                                  * the read end of the pipe is ready                          switch (read(startup_pipes[i], &c, sizeof(c))) {
                                  * if the child has closed the pipe                          case -1:
                                  * after successful authentication                                  if (errno == EINTR || errno == EAGAIN)
                                  * or if the child has died                                          continue;
                                  */                                  if (errno != EPIPE) {
                                           error("%s: startup pipe %d (fd=%d): "
                                               "read %s", __func__, i,
                                               startup_pipes[i], strerror(errno));
                                   }
                                   /* FALLTHROUGH */
                           case 0:
                                   /* child exited or completed auth */
                                 close(startup_pipes[i]);                                  close(startup_pipes[i]);
                                 startup_pipes[i] = -1;                                  startup_pipes[i] = -1;
                                 startups--;                                  startups--;
                                   if (startup_flags[i])
                                           listening--;
                                   break;
                           case 1:
                                   /* child has finished preliminaries */
                                   if (startup_flags[i]) {
                                           listening--;
                                           startup_flags[i] = 0;
                                   }
                                   break;
                         }                          }
                   }
                 for (i = 0; i < num_listen_socks; i++) {                  for (i = 0; i < num_listen_socks; i++) {
                         if (!FD_ISSET(listen_socks[i], fdset))                          if (!FD_ISSET(listen_socks[i], fdset))
                                 continue;                                  continue;
Line 1093 
Line 1132 
                                         if (maxfd < startup_p[0])                                          if (maxfd < startup_p[0])
                                                 maxfd = startup_p[0];                                                  maxfd = startup_p[0];
                                         startups++;                                          startups++;
                                           startup_flags[j] = 1;
                                         break;                                          break;
                                 }                                  }
   
Line 1118 
Line 1158 
                                         send_rexec_state(config_s[0], cfg);                                          send_rexec_state(config_s[0], cfg);
                                         close(config_s[0]);                                          close(config_s[0]);
                                 }                                  }
                                 break;                                  return;
                         }                          }
   
                         /*                          /*
Line 1126 
Line 1166 
                          * the child process the connection. The                           * the child process the connection. The
                          * parent continues listening.                           * parent continues listening.
                          */                           */
                           listening++;
                         if ((pid = fork()) == 0) {                          if ((pid = fork()) == 0) {
                                 /*                                  /*
                                  * Child.  Close the listening and                                   * Child.  Close the listening and
                                  * max_startup sockets.  Start using                                   * max_startup sockets.  Start using
                                  * the accepted socket. Reinitialize                                   * the accepted socket. Reinitialize
                                  * logging (since our pid has changed).                                   * logging (since our pid has changed).
                                  * We break out of the loop to handle                                   * We return from this function to handle
                                  * the connection.                                   * the connection.
                                  */                                   */
                                 startup_pipe = startup_p[1];                                  startup_pipe = startup_p[1];
Line 1146 
Line 1187 
                                     log_stderr);                                      log_stderr);
                                 if (rexec_flag)                                  if (rexec_flag)
                                         close(config_s[0]);                                          close(config_s[0]);
                                 break;                                  else {
                                           /*
                                            * Signal parent that the preliminaries
                                            * for this child are complete. For the
                                            * re-exec case, this happens after the
                                            * child has received the rexec state
                                            * from the server.
                                            */
                                           (void)atomicio(vwrite, startup_pipe,
                                               "\0", 1);
                                   }
                                   return;
                         }                          }
   
                         /* Parent.  Stay in the loop. */                          /* Parent.  Stay in the loop. */
Line 1164 
Line 1216 
                         }                          }
                         close(*newsock);                          close(*newsock);
                 }                  }
   
                 /* child process check (or debug mode) */  
                 if (num_listen_socks < 0)  
                         break;  
         }          }
 }  }
   
Line 1456 
Line 1504 
         /* Fetch our configuration */          /* Fetch our configuration */
         if ((cfg = sshbuf_new()) == NULL)          if ((cfg = sshbuf_new()) == NULL)
                 fatal("%s: sshbuf_new failed", __func__);                  fatal("%s: sshbuf_new failed", __func__);
         if (rexeced_flag)          if (rexeced_flag) {
                 recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg);                  recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg);
                   if (!debug_flag) {
                           startup_pipe = dup(REEXEC_STARTUP_PIPE_FD);
                           close(REEXEC_STARTUP_PIPE_FD);
                           /*
                            * Signal parent that this child is at a point where
                            * they can go away if they have a SIGHUP pending.
                            */
                           (void)atomicio(vwrite, startup_pipe, "\0", 1);
                   }
           }
         else if (strcasecmp(config_file_name, "none") != 0)          else if (strcasecmp(config_file_name, "none") != 0)
                 load_server_config(config_file_name, cfg);                  load_server_config(config_file_name, cfg);
   

Legend:
Removed from v.1.532  
changed lines
  Added in v.1.533