[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.312 and 1.312.2.3

version 1.312, 2005/07/25 11:59:40 version 1.312.2.3, 2006/11/08 00:44:05
Line 1 
Line 1 
   /* $OpenBSD$ */
 /*  /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>   * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland   * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Line 41 
Line 42 
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */   */
   
 #include "includes.h"  #include <sys/types.h>
 RCSID("$OpenBSD$");  #include <sys/ioctl.h>
   #include <sys/wait.h>
   #include <sys/tree.h>
   #include <sys/stat.h>
   #include <sys/socket.h>
   #include <sys/time.h>
   
   #include <errno.h>
   #include <signal.h>
   #include <fcntl.h>
   #include <netdb.h>
   #include <paths.h>
   #include <pwd.h>
   #include <signal.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <unistd.h>
   
 #include <openssl/dh.h>  #include <openssl/dh.h>
 #include <openssl/bn.h>  #include <openssl/bn.h>
 #include <openssl/md5.h>  #include <openssl/md5.h>
 #include <openssl/rand.h>  #include <openssl/rand.h>
   
   #include "xmalloc.h"
 #include "ssh.h"  #include "ssh.h"
 #include "ssh1.h"  #include "ssh1.h"
 #include "ssh2.h"  #include "ssh2.h"
 #include "xmalloc.h"  
 #include "rsa.h"  #include "rsa.h"
 #include "sshpty.h"  #include "sshpty.h"
 #include "packet.h"  #include "packet.h"
 #include "log.h"  #include "log.h"
   #include "buffer.h"
 #include "servconf.h"  #include "servconf.h"
 #include "uidswap.h"  #include "uidswap.h"
 #include "compat.h"  #include "compat.h"
 #include "buffer.h"  
 #include "bufaux.h"  
 #include "cipher.h"  #include "cipher.h"
 #include "kex.h"  
 #include "key.h"  #include "key.h"
   #include "kex.h"
 #include "dh.h"  #include "dh.h"
 #include "myproposal.h"  #include "myproposal.h"
 #include "authfile.h"  #include "authfile.h"
 #include "pathnames.h"  #include "pathnames.h"
 #include "atomicio.h"  #include "atomicio.h"
 #include "canohost.h"  #include "canohost.h"
   #include "hostfile.h"
 #include "auth.h"  #include "auth.h"
 #include "misc.h"  #include "misc.h"
 #include "msg.h"  #include "msg.h"
Line 79 
Line 97 
 #include "session.h"  #include "session.h"
 #include "monitor_mm.h"  #include "monitor_mm.h"
 #include "monitor.h"  #include "monitor.h"
   #ifdef GSSAPI
   #include "ssh-gss.h"
   #endif
 #include "monitor_wrap.h"  #include "monitor_wrap.h"
 #include "monitor_fdpass.h"  #include "monitor_fdpass.h"
   #include "version.h"
   
 #ifdef LIBWRAP  #ifdef LIBWRAP
 #include <tcpd.h>  #include <tcpd.h>
Line 196 
Line 218 
 int startup_pipe;               /* in child */  int startup_pipe;               /* in child */
   
 /* variables used for privilege separation */  /* variables used for privilege separation */
 int use_privsep;  int use_privsep = -1;
 struct monitor *pmonitor = NULL;  struct monitor *pmonitor = NULL;
   
 /* global authentication context */  /* global authentication context */
 Authctxt *the_authctxt = NULL;  Authctxt *the_authctxt = NULL;
   
   /* sshd_config buffer */
   Buffer cfg;
   
 /* message to be displayed after login */  /* message to be displayed after login */
 Buffer loginmsg;  Buffer loginmsg;
   
Line 241 
Line 266 
  * 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).
  */   */
   
   /*ARGSUSED*/
 static void  static void
 sighup_handler(int sig)  sighup_handler(int sig)
 {  {
Line 270 
Line 297 
 /*  /*
  * Generic signal handler for terminating signals in the master daemon.   * Generic signal handler for terminating signals in the master daemon.
  */   */
   /*ARGSUSED*/
 static void  static void
 sigterm_handler(int sig)  sigterm_handler(int sig)
 {  {
Line 280 
Line 308 
  * SIGCHLD handler.  This is called whenever a child dies.  This will then   * SIGCHLD handler.  This is called whenever a child dies.  This will then
  * reap any zombies left by exited children.   * reap any zombies left by exited children.
  */   */
   /*ARGSUSED*/
 static void  static void
 main_sigchld_handler(int sig)  main_sigchld_handler(int sig)
 {  {
Line 298 
Line 327 
 /*  /*
  * Signal handler for the alarm after the login grace period has expired.   * Signal handler for the alarm after the login grace period has expired.
  */   */
   /*ARGSUSED*/
 static void  static void
 grace_alarm_handler(int sig)  grace_alarm_handler(int sig)
 {  {
         /* XXX no idea how fix this signal handler */  
   
         if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0)          if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0)
                 kill(pmonitor->m_pid, SIGALRM);                  kill(pmonitor->m_pid, SIGALRM);
   
         /* Log error and exit. */          /* Log error and exit. */
         fatal("Timeout before authentication for %s", get_remote_ipaddr());          sigdie("Timeout before authentication for %s", get_remote_ipaddr());
 }  }
   
 /*  /*
Line 340 
Line 368 
         arc4random_stir();          arc4random_stir();
 }  }
   
   /*ARGSUSED*/
 static void  static void
 key_regeneration_alarm(int sig)  key_regeneration_alarm(int sig)
 {  {
Line 624 
Line 653 
 {  {
         if (authctxt->pw->pw_uid == 0 || options.use_login) {          if (authctxt->pw->pw_uid == 0 || options.use_login) {
                 /* File descriptor passing is broken or root login */                  /* File descriptor passing is broken or root login */
                 monitor_apply_keystate(pmonitor);  
                 use_privsep = 0;                  use_privsep = 0;
                 return;                  goto skip;
         }          }
   
         /* Authentication complete */  
         alarm(0);  
         if (startup_pipe != -1) {  
                 close(startup_pipe);  
                 startup_pipe = -1;  
         }  
   
         /* New socket pair */          /* New socket pair */
         monitor_reinit(pmonitor);          monitor_reinit(pmonitor);
   
Line 660 
Line 681 
         /* Drop privileges */          /* Drop privileges */
         do_setusercontext(authctxt->pw);          do_setusercontext(authctxt->pw);
   
    skip:
         /* It is safe now to apply the key state */          /* It is safe now to apply the key state */
         monitor_apply_keystate(pmonitor);          monitor_apply_keystate(pmonitor);
   
Line 854 
Line 876 
         debug3("%s: done", __func__);          debug3("%s: done", __func__);
 }  }
   
   /* Accept a connection from inetd */
   static void
   server_accept_inetd(int *sock_in, int *sock_out)
   {
           int fd;
   
           startup_pipe = -1;
           if (rexeced_flag) {
                   close(REEXEC_CONFIG_PASS_FD);
                   *sock_in = *sock_out = dup(STDIN_FILENO);
                   if (!debug_flag) {
                           startup_pipe = dup(REEXEC_STARTUP_PIPE_FD);
                           close(REEXEC_STARTUP_PIPE_FD);
                   }
           } else {
                   *sock_in = dup(STDIN_FILENO);
                   *sock_out = dup(STDOUT_FILENO);
           }
           /*
            * We intentionally do not close the descriptors 0, 1, and 2
            * as our code for setting the descriptors won't work if
            * ttyfd happens to be one of those.
            */
           if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
                   dup2(fd, STDIN_FILENO);
                   dup2(fd, STDOUT_FILENO);
                   if (fd > STDOUT_FILENO)
                           close(fd);
           }
           debug("inetd sockets after dupping: %d, %d", *sock_in, *sock_out);
   }
   
 /*  /*
    * Listen for TCP connections
    */
   static void
   server_listen(void)
   {
           int ret, listen_sock, on = 1;
           struct addrinfo *ai;
           char ntop[NI_MAXHOST], strport[NI_MAXSERV];
   
           for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
                   if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
                           continue;
                   if (num_listen_socks >= MAX_LISTEN_SOCKS)
                           fatal("Too many listen sockets. "
                               "Enlarge MAX_LISTEN_SOCKS");
                   if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen,
                       ntop, sizeof(ntop), strport, sizeof(strport),
                       NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
                           error("getnameinfo failed: %.100s",
                               (ret != EAI_SYSTEM) ? gai_strerror(ret) :
                               strerror(errno));
                           continue;
                   }
                   /* Create socket for listening. */
                   listen_sock = socket(ai->ai_family, ai->ai_socktype,
                       ai->ai_protocol);
                   if (listen_sock < 0) {
                           /* kernel may not support ipv6 */
                           verbose("socket: %.100s", strerror(errno));
                           continue;
                   }
                   if (set_nonblock(listen_sock) == -1) {
                           close(listen_sock);
                           continue;
                   }
                   /*
                    * Set socket options.
                    * Allow local port reuse in TIME_WAIT.
                    */
                   if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
                       &on, sizeof(on)) == -1)
                           error("setsockopt SO_REUSEADDR: %s", strerror(errno));
   
                   debug("Bind to port %s on %s.", strport, ntop);
   
                   /* Bind the socket to the desired port. */
                   if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) {
                           error("Bind to port %s on %s failed: %.200s.",
                               strport, ntop, strerror(errno));
                           close(listen_sock);
                           continue;
                   }
                   listen_socks[num_listen_socks] = listen_sock;
                   num_listen_socks++;
   
                   /* Start listening on the port. */
                   if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0)
                           fatal("listen on [%s]:%s: %.100s",
                               ntop, strport, strerror(errno));
                   logit("Server listening on %s port %s.", ntop, strport);
           }
           freeaddrinfo(options.listen_addrs);
   
           if (!num_listen_socks)
                   fatal("Cannot bind any address.");
   }
   
   /*
    * The main TCP accept loop. Note that, for the non-debug case, returns
    * from this function are in a forked subprocess.
    */
   static void
   server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
   {
           fd_set *fdset;
           int i, j, ret, maxfd;
           int key_used = 0, startups = 0;
           int startup_p[2] = { -1 , -1 };
           struct sockaddr_storage from;
           socklen_t fromlen;
           pid_t pid;
   
           /* setup fd set for accept */
           fdset = NULL;
           maxfd = 0;
           for (i = 0; i < num_listen_socks; i++)
                   if (listen_socks[i] > maxfd)
                           maxfd = listen_socks[i];
           /* pipes connected to unauthenticated childs */
           startup_pipes = xcalloc(options.max_startups, sizeof(int));
           for (i = 0; i < options.max_startups; i++)
                   startup_pipes[i] = -1;
   
           /*
            * Stay listening for connections until the system crashes or
            * the daemon is killed with a signal.
            */
           for (;;) {
                   if (received_sighup)
                           sighup_restart();
                   if (fdset != NULL)
                           xfree(fdset);
                   fdset = (fd_set *)xcalloc(howmany(maxfd + 1, NFDBITS),
                       sizeof(fd_mask));
   
                   for (i = 0; i < num_listen_socks; i++)
                           FD_SET(listen_socks[i], fdset);
                   for (i = 0; i < options.max_startups; i++)
                           if (startup_pipes[i] != -1)
                                   FD_SET(startup_pipes[i], fdset);
   
                   /* Wait in select until there is a connection. */
                   ret = select(maxfd+1, fdset, NULL, NULL, NULL);
                   if (ret < 0 && errno != EINTR)
                           error("select: %.100s", strerror(errno));
                   if (received_sigterm) {
                           logit("Received signal %d; terminating.",
                               (int) received_sigterm);
                           close_listen_socks();
                           unlink(options.pid_file);
                           exit(255);
                   }
                   if (key_used && key_do_regen) {
                           generate_ephemeral_server_key();
                           key_used = 0;
                           key_do_regen = 0;
                   }
                   if (ret < 0)
                           continue;
   
                   for (i = 0; i < options.max_startups; i++)
                           if (startup_pipes[i] != -1 &&
                               FD_ISSET(startup_pipes[i], fdset)) {
                                   /*
                                    * the read end of the pipe is ready
                                    * if the child has closed the pipe
                                    * after successful authentication
                                    * or if the child has died
                                    */
                                   close(startup_pipes[i]);
                                   startup_pipes[i] = -1;
                                   startups--;
                           }
                   for (i = 0; i < num_listen_socks; i++) {
                           if (!FD_ISSET(listen_socks[i], fdset))
                                   continue;
                           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;
                           }
                           if (unset_nonblock(*newsock) == -1) {
                                   close(*newsock);
                                   continue;
                           }
                           if (drop_connection(startups) == 1) {
                                   debug("drop connection #%d", startups);
                                   close(*newsock);
                                   continue;
                           }
                           if (pipe(startup_p) == -1) {
                                   close(*newsock);
                                   continue;
                           }
   
                           if (rexec_flag && socketpair(AF_UNIX,
                               SOCK_STREAM, 0, config_s) == -1) {
                                   error("reexec socketpair: %s",
                                       strerror(errno));
                                   close(*newsock);
                                   close(startup_p[0]);
                                   close(startup_p[1]);
                                   continue;
                           }
   
                           for (j = 0; j < options.max_startups; j++)
                                   if (startup_pipes[j] == -1) {
                                           startup_pipes[j] = startup_p[0];
                                           if (maxfd < startup_p[0])
                                                   maxfd = startup_p[0];
                                           startups++;
                                           break;
                                   }
   
                           /*
                            * Got connection.  Fork a child to handle it, unless
                            * we are in debugging mode.
                            */
                           if (debug_flag) {
                                   /*
                                    * In debugging mode.  Close the listening
                                    * socket, and start processing the
                                    * connection without forking.
                                    */
                                   debug("Server will not fork when running in debugging mode.");
                                   close_listen_socks();
                                   *sock_in = *newsock;
                                   *sock_out = *newsock;
                                   close(startup_p[0]);
                                   close(startup_p[1]);
                                   startup_pipe = -1;
                                   pid = getpid();
                                   if (rexec_flag) {
                                           send_rexec_state(config_s[0],
                                               &cfg);
                                           close(config_s[0]);
                                   }
                                   break;
                           }
   
                           /*
                            * Normal production daemon.  Fork, and have
                            * the child process the connection. The
                            * parent continues listening.
                            */
                           if ((pid = fork()) == 0) {
                                   /*
                                    * Child.  Close the listening and
                                    * max_startup sockets.  Start using
                                    * the accepted socket. Reinitialize
                                    * logging (since our pid has changed).
                                    * We break out of the loop to handle
                                    * the connection.
                                    */
                                   startup_pipe = startup_p[1];
                                   close_startup_pipes();
                                   close_listen_socks();
                                   *sock_in = *newsock;
                                   *sock_out = *newsock;
                                   log_init(__progname,
                                       options.log_level,
                                       options.log_facility,
                                       log_stderr);
                                   if (rexec_flag)
                                           close(config_s[0]);
                                   break;
                           }
   
                           /* Parent.  Stay in the loop. */
                           if (pid < 0)
                                   error("fork: %.100s", strerror(errno));
                           else
                                   debug("Forked child %ld.", (long)pid);
   
                           close(startup_p[1]);
   
                           if (rexec_flag) {
                                   send_rexec_state(config_s[0], &cfg);
                                   close(config_s[0]);
                                   close(config_s[1]);
                           }
   
                           /*
                            * Mark that the key has been used (it
                            * was "given" to the child).
                            */
                           if ((options.protocol & SSH_PROTO_1) &&
                               key_used == 0) {
                                   /* Schedule server key regeneration alarm. */
                                   signal(SIGALRM, key_regeneration_alarm);
                                   alarm(options.key_regeneration_time);
                                   key_used = 1;
                           }
   
                           close(*newsock);
   
                           /*
                            * Ensure that our random state differs
                            * from that of the child
                            */
                           arc4random_stir();
                   }
   
                   /* child process check (or debug mode) */
                   if (num_listen_socks < 0)
                           break;
           }
   }
   
   
   /*
  * Main program for the daemon.   * Main program for the daemon.
  */   */
 int  int
Line 862 
Line 1200 
 {  {
         extern char *optarg;          extern char *optarg;
         extern int optind;          extern int optind;
         int opt, j, i, fdsetsz, on = 1;          int opt, i, on = 1;
         int sock_in = -1, sock_out = -1, newsock = -1;          int sock_in = -1, sock_out = -1, newsock = -1;
         pid_t pid;  
         socklen_t fromlen;  
         fd_set *fdset;  
         struct sockaddr_storage from;  
         const char *remote_ip;          const char *remote_ip;
         int remote_port;          int remote_port;
         FILE *f;  
         struct addrinfo *ai;  
         char ntop[NI_MAXHOST], strport[NI_MAXSERV];  
         char *line;          char *line;
         int listen_sock, maxfd;          int config_s[2] = { -1 , -1 };
         int startup_p[2] = { -1 , -1 }, config_s[2] = { -1 , -1 };  
         int startups = 0;  
         Key *key;          Key *key;
         Authctxt *authctxt;          Authctxt *authctxt;
         int ret, key_used = 0;  
         Buffer cfg;  
   
         /* Save argv. */          /* Save argv. */
         saved_argv = av;          saved_argv = av;
         rexec_argc = ac;          rexec_argc = ac;
   
           /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
           sanitise_stdfd();
   
         /* Initialize configuration options to their default values. */          /* Initialize configuration options to their default values. */
         initialize_server_options(&options);          initialize_server_options(&options);
   
Line 931 
Line 1261 
                         options.log_level = SYSLOG_LEVEL_QUIET;                          options.log_level = SYSLOG_LEVEL_QUIET;
                         break;                          break;
                 case 'b':                  case 'b':
                         options.server_key_bits = atoi(optarg);                          options.server_key_bits = (int)strtonum(optarg, 256,
                               32768, NULL);
                         break;                          break;
                 case 'p':                  case 'p':
                         options.ports_from_cmdline = 1;                          options.ports_from_cmdline = 1;
Line 968 
Line 1299 
                         test_flag = 1;                          test_flag = 1;
                         break;                          break;
                 case 'u':                  case 'u':
                         utmp_len = atoi(optarg);                          utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL);
                         if (utmp_len > MAXHOSTNAMELEN) {                          if (utmp_len > MAXHOSTNAMELEN) {
                                 fprintf(stderr, "Invalid utmp length.\n");                                  fprintf(stderr, "Invalid utmp length.\n");
                                 exit(1);                                  exit(1);
Line 977 
Line 1308 
                 case 'o':                  case 'o':
                         line = xstrdup(optarg);                          line = xstrdup(optarg);
                         if (process_server_config_line(&options, line,                          if (process_server_config_line(&options, line,
                             "command-line", 0) != 0)                              "command-line", 0, NULL, NULL, NULL, NULL) != 0)
                                 exit(1);                                  exit(1);
                         xfree(line);                          xfree(line);
                         break;                          break;
Line 1021 
Line 1352 
         else          else
                 load_server_config(config_file_name, &cfg);                  load_server_config(config_file_name, &cfg);
   
         parse_server_config(&options,          parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name,
             rexeced_flag ? "rexec" : config_file_name, &cfg);              &cfg, NULL, NULL, NULL);
   
         if (!rexec_flag)  
                 buffer_free(&cfg);  
   
         /* Fill in default values for those options not explicitly set. */          /* Fill in default values for those options not explicitly set. */
         fill_default_server_options(&options);          fill_default_server_options(&options);
   
Line 1042 
Line 1370 
         debug("sshd version %.100s", SSH_VERSION);          debug("sshd version %.100s", SSH_VERSION);
   
         /* load private host keys */          /* load private host keys */
         sensitive_data.host_keys = xmalloc(options.num_host_key_files *          sensitive_data.host_keys = xcalloc(options.num_host_key_files,
             sizeof(Key *));              sizeof(Key *));
         for (i = 0; i < options.num_host_key_files; i++)          for (i = 0; i < options.num_host_key_files; i++)
                 sensitive_data.host_keys[i] = NULL;                  sensitive_data.host_keys[i] = NULL;
Line 1108 
Line 1436 
         }          }
   
         if (use_privsep) {          if (use_privsep) {
                 struct passwd *pw;  
                 struct stat st;                  struct stat st;
   
                 if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL)                  if (getpwnam(SSH_PRIVSEP_USER) == NULL)
                         fatal("Privilege separation user %s does not exist",                          fatal("Privilege separation user %s does not exist",
                             SSH_PRIVSEP_USER);                              SSH_PRIVSEP_USER);
                 if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) ||                  if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) ||
Line 1128 
Line 1455 
                 exit(0);                  exit(0);
   
         if (rexec_flag) {          if (rexec_flag) {
                 rexec_argv = xmalloc(sizeof(char *) * (rexec_argc + 2));                  rexec_argv = xcalloc(rexec_argc + 2, sizeof(char *));
                 for (i = 0; i < rexec_argc; i++) {                  for (i = 0; i < rexec_argc; i++) {
                         debug("rexec_argv[%d]='%s'", i, saved_argv[i]);                          debug("rexec_argv[%d]='%s'", i, saved_argv[i]);
                         rexec_argv[i] = saved_argv[i];                          rexec_argv[i] = saved_argv[i];
Line 1148 
Line 1475 
          * exits.           * exits.
          */           */
         if (!(debug_flag || inetd_flag || no_daemon_flag)) {          if (!(debug_flag || inetd_flag || no_daemon_flag)) {
 #ifdef TIOCNOTTY  
                 int fd;                  int fd;
 #endif /* TIOCNOTTY */  
                 if (daemon(0, 0) < 0)                  if (daemon(0, 0) < 0)
                         fatal("daemon() failed: %.200s", strerror(errno));                          fatal("daemon() failed: %.200s", strerror(errno));
   
                 /* Disconnect from the controlling tty. */                  /* Disconnect from the controlling tty. */
 #ifdef TIOCNOTTY  
                 fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);                  fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
                 if (fd >= 0) {                  if (fd >= 0) {
                         (void) ioctl(fd, TIOCNOTTY, NULL);                          (void) ioctl(fd, TIOCNOTTY, NULL);
                         close(fd);                          close(fd);
                 }                  }
 #endif /* TIOCNOTTY */  
         }          }
         /* Reinitialize the log (because of the fork above). */          /* Reinitialize the log (because of the fork above). */
         log_init(__progname, options.log_level, options.log_facility, log_stderr);          log_init(__progname, options.log_level, options.log_facility, log_stderr);
Line 1176 
Line 1500 
         /* ignore SIGPIPE */          /* ignore SIGPIPE */
         signal(SIGPIPE, SIG_IGN);          signal(SIGPIPE, SIG_IGN);
   
         /* Start listening for a socket, unless started from inetd. */          /* Get a connection, either from inetd or a listening TCP socket */
         if (inetd_flag) {          if (inetd_flag) {
                 int fd;                  server_accept_inetd(&sock_in, &sock_out);
   
                 startup_pipe = -1;  
                 if (rexeced_flag) {  
                         close(REEXEC_CONFIG_PASS_FD);  
                         sock_in = sock_out = dup(STDIN_FILENO);  
                         if (!debug_flag) {  
                                 startup_pipe = dup(REEXEC_STARTUP_PIPE_FD);  
                                 close(REEXEC_STARTUP_PIPE_FD);  
                         }  
                 } else {  
                         sock_in = dup(STDIN_FILENO);  
                         sock_out = dup(STDOUT_FILENO);  
                 }  
                 /*  
                  * We intentionally do not close the descriptors 0, 1, and 2  
                  * as our code for setting the descriptors won't work if  
                  * ttyfd happens to be one of those.  
                  */  
                 if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {  
                         dup2(fd, STDIN_FILENO);  
                         dup2(fd, STDOUT_FILENO);  
                         if (fd > STDOUT_FILENO)  
                                 close(fd);  
                 }  
                 debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);  
                 if ((options.protocol & SSH_PROTO_1) &&                  if ((options.protocol & SSH_PROTO_1) &&
                     sensitive_data.server_key == NULL)                      sensitive_data.server_key == NULL)
                         generate_ephemeral_server_key();                          generate_ephemeral_server_key();
         } else {          } else {
                 for (ai = options.listen_addrs; ai; ai = ai->ai_next) {                  server_listen();
                         if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)  
                                 continue;  
                         if (num_listen_socks >= MAX_LISTEN_SOCKS)  
                                 fatal("Too many listen sockets. "  
                                     "Enlarge MAX_LISTEN_SOCKS");  
                         if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen,  
                             ntop, sizeof(ntop), strport, sizeof(strport),  
                             NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {  
                                 error("getnameinfo failed: %.100s",  
                                     (ret != EAI_SYSTEM) ? gai_strerror(ret) :  
                                     strerror(errno));  
                                 continue;  
                         }  
                         /* Create socket for listening. */  
                         listen_sock = socket(ai->ai_family, ai->ai_socktype,  
                             ai->ai_protocol);  
                         if (listen_sock < 0) {  
                                 /* kernel may not support ipv6 */  
                                 verbose("socket: %.100s", strerror(errno));  
                                 continue;  
                         }  
                         if (set_nonblock(listen_sock) == -1) {  
                                 close(listen_sock);  
                                 continue;  
                         }  
                         /*  
                          * Set socket options.  
                          * Allow local port reuse in TIME_WAIT.  
                          */  
                         if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,  
                             &on, sizeof(on)) == -1)  
                                 error("setsockopt SO_REUSEADDR: %s", strerror(errno));  
   
                         debug("Bind to port %s on %s.", strport, ntop);  
   
                         /* Bind the socket to the desired port. */  
                         if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) {  
                                 error("Bind to port %s on %s failed: %.200s.",  
                                     strport, ntop, strerror(errno));  
                                 close(listen_sock);  
                                 continue;  
                         }  
                         listen_socks[num_listen_socks] = listen_sock;  
                         num_listen_socks++;  
   
                         /* Start listening on the port. */  
                         logit("Server listening on %s port %s.", ntop, strport);  
                         if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0)  
                                 fatal("listen: %.100s", strerror(errno));  
   
                 }  
                 freeaddrinfo(options.listen_addrs);  
   
                 if (!num_listen_socks)  
                         fatal("Cannot bind any address.");  
   
                 if (options.protocol & SSH_PROTO_1)                  if (options.protocol & SSH_PROTO_1)
                         generate_ephemeral_server_key();                          generate_ephemeral_server_key();
   
                 /*  
                  * Arrange to restart on SIGHUP.  The handler needs  
                  * listen_sock.  
                  */  
                 signal(SIGHUP, sighup_handler);                  signal(SIGHUP, sighup_handler);
                   signal(SIGCHLD, main_sigchld_handler);
                 signal(SIGTERM, sigterm_handler);                  signal(SIGTERM, sigterm_handler);
                 signal(SIGQUIT, sigterm_handler);                  signal(SIGQUIT, sigterm_handler);
   
                 /* Arrange SIGCHLD to be caught. */                  /*
                 signal(SIGCHLD, main_sigchld_handler);                   * Write out the pid file after the sigterm handler
                    * is setup and the listen sockets are bound
                 /* Write out the pid file after the sigterm handler is setup */                   */
                 if (!debug_flag) {                  if (!debug_flag) {
                         /*                          FILE *f = fopen(options.pid_file, "w");
                          * Record our pid in /var/run/sshd.pid to make it  
                          * easier to kill the correct sshd.  We don't want to  
                          * do this before the bind above because the bind will  
                          * fail if there already is a daemon, and this will  
                          * overwrite any old pid in the file.  
                          */  
                         f = fopen(options.pid_file, "w");  
                         if (f == NULL) {                          if (f == NULL) {
                                 error("Couldn't create pid file \"%s\": %s",                                  error("Couldn't create pid file \"%s\": %s",
                                     options.pid_file, strerror(errno));                                      options.pid_file, strerror(errno));
Line 1299 
Line 1534 
                         }                          }
                 }                  }
   
                 /* setup fd set for listen */                  /* Accept a connection and return in a forked child */
                 fdset = NULL;                  server_accept_loop(&sock_in, &sock_out,
                 maxfd = 0;                      &newsock, config_s);
                 for (i = 0; i < num_listen_socks; i++)  
                         if (listen_socks[i] > maxfd)  
                                 maxfd = listen_socks[i];  
                 /* pipes connected to unauthenticated childs */  
                 startup_pipes = xmalloc(options.max_startups * sizeof(int));  
                 for (i = 0; i < options.max_startups; i++)  
                         startup_pipes[i] = -1;  
   
                 /*  
                  * Stay listening for connections until the system crashes or  
                  * the daemon is killed with a signal.  
                  */  
                 for (;;) {  
                         if (received_sighup)  
                                 sighup_restart();  
                         if (fdset != NULL)  
                                 xfree(fdset);  
                         fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);  
                         fdset = (fd_set *)xmalloc(fdsetsz);  
                         memset(fdset, 0, fdsetsz);  
   
                         for (i = 0; i < num_listen_socks; i++)  
                                 FD_SET(listen_socks[i], fdset);  
                         for (i = 0; i < options.max_startups; i++)  
                                 if (startup_pipes[i] != -1)  
                                         FD_SET(startup_pipes[i], fdset);  
   
                         /* Wait in select until there is a connection. */  
                         ret = select(maxfd+1, fdset, NULL, NULL, NULL);  
                         if (ret < 0 && errno != EINTR)  
                                 error("select: %.100s", strerror(errno));  
                         if (received_sigterm) {  
                                 logit("Received signal %d; terminating.",  
                                     (int) received_sigterm);  
                                 close_listen_socks();  
                                 unlink(options.pid_file);  
                                 exit(255);  
                         }  
                         if (key_used && key_do_regen) {  
                                 generate_ephemeral_server_key();  
                                 key_used = 0;  
                                 key_do_regen = 0;  
                         }  
                         if (ret < 0)  
                                 continue;  
   
                         for (i = 0; i < options.max_startups; i++)  
                                 if (startup_pipes[i] != -1 &&  
                                     FD_ISSET(startup_pipes[i], fdset)) {  
                                         /*  
                                          * the read end of the pipe is ready  
                                          * if the child has closed the pipe  
                                          * after successful authentication  
                                          * or if the child has died  
                                          */  
                                         close(startup_pipes[i]);  
                                         startup_pipes[i] = -1;  
                                         startups--;  
                                 }  
                         for (i = 0; i < num_listen_socks; i++) {  
                                 if (!FD_ISSET(listen_socks[i], fdset))  
                                         continue;  
                                 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;  
                                 }  
                                 if (unset_nonblock(newsock) == -1) {  
                                         close(newsock);  
                                         continue;  
                                 }  
                                 if (drop_connection(startups) == 1) {  
                                         debug("drop connection #%d", startups);  
                                         close(newsock);  
                                         continue;  
                                 }  
                                 if (pipe(startup_p) == -1) {  
                                         close(newsock);  
                                         continue;  
                                 }  
   
                                 if (rexec_flag && socketpair(AF_UNIX,  
                                     SOCK_STREAM, 0, config_s) == -1) {  
                                         error("reexec socketpair: %s",  
                                             strerror(errno));  
                                         close(newsock);  
                                         close(startup_p[0]);  
                                         close(startup_p[1]);  
                                         continue;  
                                 }  
   
                                 for (j = 0; j < options.max_startups; j++)  
                                         if (startup_pipes[j] == -1) {  
                                                 startup_pipes[j] = startup_p[0];  
                                                 if (maxfd < startup_p[0])  
                                                         maxfd = startup_p[0];  
                                                 startups++;  
                                                 break;  
                                         }  
   
                                 /*  
                                  * Got connection.  Fork a child to handle it, unless  
                                  * we are in debugging mode.  
                                  */  
                                 if (debug_flag) {  
                                         /*  
                                          * In debugging mode.  Close the listening  
                                          * socket, and start processing the  
                                          * connection without forking.  
                                          */  
                                         debug("Server will not fork when running in debugging mode.");  
                                         close_listen_socks();  
                                         sock_in = newsock;  
                                         sock_out = newsock;  
                                         close(startup_p[0]);  
                                         close(startup_p[1]);  
                                         startup_pipe = -1;  
                                         pid = getpid();  
                                         if (rexec_flag) {  
                                                 send_rexec_state(config_s[0],  
                                                     &cfg);  
                                                 close(config_s[0]);  
                                         }  
                                         break;  
                                 } else {  
                                         /*  
                                          * Normal production daemon.  Fork, and have  
                                          * the child process the connection. The  
                                          * parent continues listening.  
                                          */  
                                         if ((pid = fork()) == 0) {  
                                                 /*  
                                                  * Child.  Close the listening and max_startup  
                                                  * sockets.  Start using the accepted socket.  
                                                  * Reinitialize logging (since our pid has  
                                                  * changed).  We break out of the loop to handle  
                                                  * the connection.  
                                                  */  
                                                 startup_pipe = startup_p[1];  
                                                 close_startup_pipes();  
                                                 close_listen_socks();  
                                                 sock_in = newsock;  
                                                 sock_out = newsock;  
                                                 log_init(__progname, options.log_level, options.log_facility, log_stderr);  
                                                 if (rexec_flag)  
                                                         close(config_s[0]);  
                                                 break;  
                                         }  
                                 }  
   
                                 /* Parent.  Stay in the loop. */  
                                 if (pid < 0)  
                                         error("fork: %.100s", strerror(errno));  
                                 else  
                                         debug("Forked child %ld.", (long)pid);  
   
                                 close(startup_p[1]);  
   
                                 if (rexec_flag) {  
                                         send_rexec_state(config_s[0], &cfg);  
                                         close(config_s[0]);  
                                         close(config_s[1]);  
                                 }  
   
                                 /* Mark that the key has been used (it was "given" to the child). */  
                                 if ((options.protocol & SSH_PROTO_1) &&  
                                     key_used == 0) {  
                                         /* Schedule server key regeneration alarm. */  
                                         signal(SIGALRM, key_regeneration_alarm);  
                                         alarm(options.key_regeneration_time);  
                                         key_used = 1;  
                                 }  
   
                                 arc4random_stir();  
   
                                 /* Close the new socket (the child is now taking care of it). */  
                                 close(newsock);  
                         }  
                         /* child process check (or debug mode) */  
                         if (num_listen_socks < 0)  
                                 break;  
                 }  
         }          }
   
         /* This is the child processing a new connection. */          /* This is the child processing a new connection. */
Line 1568 
Line 1618 
                 debug("get_remote_port failed");                  debug("get_remote_port failed");
                 cleanup_exit(255);                  cleanup_exit(255);
         }          }
   
           /*
            * We use get_canonical_hostname with usedns = 0 instead of
            * get_remote_ipaddr here so IP options will be checked.
            */
           (void) get_canonical_hostname(0);
           /*
            * The rest of the code depends on the fact that
            * get_remote_ipaddr() caches the remote ip, even if
            * the socket goes away.
            */
         remote_ip = get_remote_ipaddr();          remote_ip = get_remote_ipaddr();
   
 #ifdef LIBWRAP  #ifdef LIBWRAP
Line 1591 
Line 1652 
         verbose("Connection from %.500s port %d", remote_ip, remote_port);          verbose("Connection from %.500s port %d", remote_ip, remote_port);
   
         /*          /*
          * We don\'t want to listen forever unless the other side           * We don't want to listen forever unless the other side
          * successfully authenticates itself.  So we set up an alarm which is           * successfully authenticates itself.  So we set up an alarm which is
          * cleared after successful authentication.  A limit of zero           * cleared after successful authentication.  A limit of zero
          * indicates no limit. Note that we don\'t set the alarm in debugging           * indicates no limit. Note that we don't set the alarm in debugging
          * mode; it is just annoying to have the server exit just when you           * mode; it is just annoying to have the server exit just when you
          * are about to discover the bug.           * are about to discover the bug.
          */           */
Line 1607 
Line 1668 
         packet_set_nonblocking();          packet_set_nonblocking();
   
         /* allocate authentication context */          /* allocate authentication context */
         authctxt = xmalloc(sizeof(*authctxt));          authctxt = xcalloc(1, sizeof(*authctxt));
         memset(authctxt, 0, sizeof(*authctxt));  
   
         /* XXX global for cleanup, access from other modules */          /* XXX global for cleanup, access from other modules */
         the_authctxt = authctxt;          the_authctxt = authctxt;
Line 1640 
Line 1700 
   
  authenticated:   authenticated:
         /*          /*
            * Cancel the alarm we set to limit the time taken for
            * authentication.
            */
           alarm(0);
           signal(SIGALRM, SIG_DFL);
           authctxt->authenticated = 1;
           if (startup_pipe != -1) {
                   close(startup_pipe);
                   startup_pipe = -1;
           }
   
           /*
          * In privilege separation, we fork another child and prepare           * In privilege separation, we fork another child and prepare
          * file descriptor passing.           * file descriptor passing.
          */           */
Line 1672 
Line 1744 
 {  {
         int rsafail = 0;          int rsafail = 0;
   
         if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) {          if (BN_cmp(sensitive_data.server_key->rsa->n,
               sensitive_data.ssh1_host_key->rsa->n) > 0) {
                 /* Server key has bigger modulus. */                  /* Server key has bigger modulus. */
                 if (BN_num_bits(sensitive_data.server_key->rsa->n) <                  if (BN_num_bits(sensitive_data.server_key->rsa->n) <
                     BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) {                      BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) +
                         fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",                      SSH_KEY_BITS_RESERVED) {
                           fatal("do_connection: %s: "
                               "server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",
                             get_remote_ipaddr(),                              get_remote_ipaddr(),
                             BN_num_bits(sensitive_data.server_key->rsa->n),                              BN_num_bits(sensitive_data.server_key->rsa->n),
                             BN_num_bits(sensitive_data.ssh1_host_key->rsa->n),                              BN_num_bits(sensitive_data.ssh1_host_key->rsa->n),
Line 1691 
Line 1766 
         } else {          } else {
                 /* Host key has bigger modulus (or they are equal). */                  /* Host key has bigger modulus (or they are equal). */
                 if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) <                  if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) <
                     BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) {                      BN_num_bits(sensitive_data.server_key->rsa->n) +
                         fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d",                      SSH_KEY_BITS_RESERVED) {
                           fatal("do_connection: %s: "
                               "host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d",
                             get_remote_ipaddr(),                              get_remote_ipaddr(),
                             BN_num_bits(sensitive_data.ssh1_host_key->rsa->n),                              BN_num_bits(sensitive_data.ssh1_host_key->rsa->n),
                             BN_num_bits(sensitive_data.server_key->rsa->n),                              BN_num_bits(sensitive_data.server_key->rsa->n),
Line 1817 
Line 1894 
          * key is in the highest bits.           * key is in the highest bits.
          */           */
         if (!rsafail) {          if (!rsafail) {
                 BN_mask_bits(session_key_int, sizeof(session_key) * 8);                  (void) BN_mask_bits(session_key_int, sizeof(session_key) * 8);
                 len = BN_num_bytes(session_key_int);                  len = BN_num_bytes(session_key_int);
                 if (len < 0 || (u_int)len > sizeof(session_key)) {                  if (len < 0 || (u_int)len > sizeof(session_key)) {
                         error("do_connection: bad session key len from %s: "                          error("do_ssh1_kex: bad session key len from %s: "
                             "session_key_int %d > sizeof(session_key) %lu",                              "session_key_int %d > sizeof(session_key) %lu",
                             get_remote_ipaddr(), len, (u_long)sizeof(session_key));                              get_remote_ipaddr(), len, (u_long)sizeof(session_key));
                         rsafail++;                          rsafail++;
Line 1913 
Line 1990 
                 myproposal[PROPOSAL_COMP_ALGS_CTOS] =                  myproposal[PROPOSAL_COMP_ALGS_CTOS] =
                 myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com";                  myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com";
         }          }
   
         myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();          myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
   
         /* start key exchange */          /* start key exchange */
Line 1921 
Line 1998 
         kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;          kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
         kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;          kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
         kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;          kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
           kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
         kex->server = 1;          kex->server = 1;
         kex->client_version_string=client_version_string;          kex->client_version_string=client_version_string;
         kex->server_version_string=server_version_string;          kex->server_version_string=server_version_string;

Legend:
Removed from v.1.312  
changed lines
  Added in v.1.312.2.3