]> andersk Git - openssh.git/blobdiff - sshd.c
- Merged OpenBSD IPv6 patch:
[openssh.git] / sshd.c
diff --git a/sshd.c b/sshd.c
index 03a9788eaf022a1f31a6ddd3597c8548ab30fb94..0eaffebd4d51e28525420a9a6f44388ff32d7ced 100644 (file)
--- a/sshd.c
+++ b/sshd.c
 #include "includes.h"
 RCSID("$Id$");
 
-#ifdef HAVE_POLL_H
-# include <poll.h>
-#else /* HAVE_POLL_H */
-# ifdef HAVE_SYS_POLL_H
-#  include <sys/poll.h>
-# endif /* HAVE_SYS_POLL_H */
-#endif /* HAVE_POLL_H */
-
 #include "xmalloc.h"
 #include "rsa.h"
 #include "ssh.h"
@@ -53,6 +45,12 @@ ServerOptions options;
 /* Name of the server configuration 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
  * mode is enabled, extra debugging output will be sent to the system
@@ -74,10 +72,12 @@ char *av0;
 char **saved_argv;
 
 /*
- * This is set to the socket that the server is listening; this is used in
- * the SIGHUP signal handler.
+ * The sockets that the server is listening; this is used in the SIGHUP
+ * 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,
@@ -143,162 +143,17 @@ void do_child(const char *command, struct passwd * pw, const char *term,
              const char *display, const char *auth_proto,
              const char *auth_data, const char *ttyname);
 
-#ifdef HAVE_LIBPAM
-static int pamconv(int num_msg, const struct pam_message **msg,
-         struct pam_response **resp, void *appdata_ptr);
-int do_pam_auth(const char *user, const char *password);
-void do_pam_account(char *username, char *remote_user);
-void do_pam_session(char *username, char *ttyname);
-void pam_cleanup_proc(void *context);
-
-static struct pam_conv conv = {
-       pamconv,
-       NULL
-};
-struct pam_handle_t *pamh = NULL;
-const char *pampasswd = NULL;
-char *pamconv_msg = NULL;
-
-static int pamconv(int num_msg, const struct pam_message **msg,
-       struct pam_response **resp, void *appdata_ptr)
-{
-       struct pam_response *reply;
-       int count;
-       size_t msg_len;
-       char *p;
-
-       /* PAM will free this later */
-       reply = malloc(num_msg * sizeof(*reply));
-       if (reply == NULL)
-               return PAM_CONV_ERR; 
-
-       for(count = 0; count < num_msg; count++) {
-               switch (msg[count]->msg_style) {
-                       case PAM_PROMPT_ECHO_OFF:
-                               if (pampasswd == NULL) {
-                                       free(reply);
-                                       return PAM_CONV_ERR;
-                               }
-                               reply[count].resp_retcode = PAM_SUCCESS;
-                               reply[count].resp = xstrdup(pampasswd);
-                               break;
-
-                       case PAM_TEXT_INFO:
-                               reply[count].resp_retcode = PAM_SUCCESS;
-                               reply[count].resp = xstrdup("");
-
-                               if (msg[count]->msg == NULL)
-                                       break;
-
-                               debug("Adding PAM message: %s", msg[count]->msg);
-
-                               msg_len = strlen(msg[count]->msg);
-                               if (pamconv_msg) {
-                                       size_t n = strlen(pamconv_msg);
-                                       pamconv_msg = xrealloc(pamconv_msg, n + msg_len + 2);
-                                       p = pamconv_msg + n;
-                               } else {
-                                       pamconv_msg = p = xmalloc(msg_len + 2);
-                               }
-                               memcpy(p, msg[count]->msg, msg_len);
-                               p[msg_len] = '\n';
-                               p[msg_len + 1] = '\0';
-                               break;
-
-                       case PAM_PROMPT_ECHO_ON:
-                       case PAM_ERROR_MSG:
-                       default:
-                               free(reply);
-                               return PAM_CONV_ERR;
-               }
-       }
-
-       *resp = reply;
-
-       return PAM_SUCCESS;
-}
-
-void pam_cleanup_proc(void *context)
-{
-       int pam_retval;
-
-       if (pamh != NULL)
-       {
-               pam_retval = pam_close_session((pam_handle_t *)pamh, 0);
-               if (pam_retval != PAM_SUCCESS) {
-                       log("Cannot close PAM session: %.200s", 
-                       PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
-               }
-
-               pam_retval = pam_end((pam_handle_t *)pamh, pam_retval);
-               if (pam_retval != PAM_SUCCESS) {
-                       log("Cannot release PAM authentication: %.200s", 
-                       PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
-               }
-       }
-}
-
-int do_pam_auth(const char *user, const char *password)
-{
-       int pam_retval;
-       
-       pampasswd = password;
-       
-       pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
-       if (pam_retval == PAM_SUCCESS) {
-               log("PAM Password authentication accepted for user \"%.100s\"", user);
-               return 1;
-       } else {
-               log("PAM Password authentication for \"%.100s\" failed: %s", 
-                       user, PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
-               return 0;
-       }
-}
-
-void do_pam_account(char *username, char *remote_user)
-{
-       int pam_retval;
-
-       debug("PAM setting rhost to \"%.200s\"", get_canonical_hostname());
-       pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST, 
-               get_canonical_hostname());
-       if (pam_retval != PAM_SUCCESS) {
-               log("PAM set rhost failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
-               do_fake_authloop(username);
-       }
-
-       if (remote_user != NULL) {
-               debug("PAM setting ruser to \"%.200s\"", remote_user);
-               pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user);
-               if (pam_retval != PAM_SUCCESS) {
-                       log("PAM set ruser failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
-                       do_fake_authloop(username);
-               }
-       }
-
-       pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0);
-       if (pam_retval != PAM_SUCCESS) {
-               log("PAM rejected by account configuration: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
-               do_fake_authloop(username);
-       }
-}
-
-void do_pam_session(char *username, char *ttyname)
+/*
+ * Close all listening sockets
+ */
+void
+close_listen_socks(void)
 {
-       int pam_retval;
-
-       if (ttyname != NULL) {
-               debug("PAM setting tty to \"%.200s\"", ttyname);
-               pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_TTY, ttyname);
-               if (pam_retval != PAM_SUCCESS)
-                       fatal("PAM set tty failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
-       }
-
-       pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
-       if (pam_retval != PAM_SUCCESS)
-               fatal("PAM session setup failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
+       int i;
+       for (i = 0; i < num_listen_socks; i++)
+               close(listen_socks[i]);
+       num_listen_socks = -1;
 }
-#endif /* HAVE_LIBPAM */
 
 /*
  * Signal handler for SIGHUP.  Sshd execs itself when it receives SIGHUP;
@@ -320,7 +175,7 @@ void
 sighup_restart()
 {
        log("Received SIGHUP; restarting.");
-       close(listen_sock);
+       close_listen_socks();
        execv(saved_argv[0], saved_argv);
        log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno));
        exit(1);
@@ -335,7 +190,7 @@ void
 sigterm_handler(int sig)
 {
        log("Received signal %d; terminating.", sig);
-       close(listen_sock);
+       close_listen_socks();
        exit(255);
 }
 
@@ -442,11 +297,12 @@ main(int ac, char **av)
 {
        extern char *optarg;
        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 silentrsa = 0;
-       struct pollfd fds;
-       struct sockaddr_in sin;
+       fd_set *fdset;
+       struct sockaddr_storage from;
        char buf[100];                  /* Must not be larger than remote_version. */
        char remote_version[100];       /* Must be at least as big as buf. */
        const char *remote_ip;
@@ -454,6 +310,9 @@ main(int ac, char **av)
        char *comment;
        FILE *f;
        struct linger linger;
+       struct addrinfo *ai;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+       int listen_sock, maxfd;
 
        /* Save argv[0]. */
        saved_argv = av;
@@ -466,8 +325,14 @@ main(int ac, char **av)
        initialize_server_options(&options);
 
        /* 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) {
+               case '4':
+                       IPv4or6 = AF_INET;
+                       break;
+               case '6':
+                       IPv4or6 = AF_INET6;
+                       break;
                case 'f':
                        config_file_name = optarg;
                        break;
@@ -488,7 +353,10 @@ main(int ac, char **av)
                        options.server_key_bits = atoi(optarg);
                        break;
                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;
                case 'g':
                        options.login_grace_time = atoi(optarg);
@@ -507,6 +375,9 @@ main(int ac, char **av)
                case '?':
                default:
                        fprintf(stderr, "sshd version %s\n", SSH_VERSION);
+#ifdef RSAREF
+                       fprintf(stderr, "Compiled with RSAref.\n");
+#endif
                        fprintf(stderr, "Usage: %s [options]\n", av0);
                        fprintf(stderr, "Options:\n");
                        fprintf(stderr, "  -f file    Configuration file (default %s)\n", SERVER_CONFIG_FILE);
@@ -518,11 +389,22 @@ main(int ac, char **av)
                        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, "  -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);
                }
        }
 
+       /*
+        * 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 */
        if (rsa_alive() == 0) {
                if (silentrsa == 0)
@@ -542,18 +424,11 @@ main(int ac, char **av)
                fprintf(stderr, "Bad server key size.\n");
                exit(1);
        }
-       if (options.port < 1 || options.port > 65535) {
-               fprintf(stderr, "Bad port number.\n");
-               exit(1);
-       }
        /* Check that there are no remaining arguments. */
        if (optind < ac) {
                fprintf(stderr, "Extra argument %s.\n", av[optind]);
                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);
 
@@ -642,32 +517,66 @@ main(int ac, char **av)
                arc4random_stir();
                log("RSA key generation complete.");
        } else {
-               /* Create socket for listening. */
-               listen_sock = socket(AF_INET, SOCK_STREAM, 0);
-               if (listen_sock < 0)
-                       fatal("socket: %.100s", strerror(errno));
-
-               /* 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));
-
-               memset(&sin, 0, sizeof(sin));
-               sin.sin_family = AF_INET;
-               sin.sin_addr = options.listen_addr;
-               sin.sin_port = htons(options.port);
-
-               if (bind(listen_sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
-                       error("bind: %.100s", strerror(errno));
-                       shutdown(listen_sock, SHUT_RDWR);
-                       close(listen_sock);
-                       fatal("Bind to port %d failed.", options.port);
+               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 (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));
+
+                       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. */
+                       log("Server listening on %s port %s.", ntop, strport);
+                       if (listen(listen_sock, 5) < 0)
+                               fatal("listen: %.100s", strerror(errno));
+
                }
+               freeaddrinfo(options.listen_addrs);
+
+               if (!num_listen_socks)
+                       fatal("Cannot bind any address.");
+
                if (!debug_flag) {
                        /*
                         * Record our pid in /etc/sshd_pid to make it easier
@@ -683,10 +592,6 @@ main(int ac, char **av)
                        }
                }
 
-               log("Server listening on port %d.", options.port);
-               if (listen(listen_sock, 5) < 0)
-                       fatal("listen: %.100s", strerror(errno));
-
                public_key = RSA_new();
                sensitive_data.private_key = RSA_new();
 
@@ -708,6 +613,14 @@ main(int ac, char **av)
                /* Arrange SIGCHLD to be caught. */
                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
                 * the daemon is killed with a signal.
@@ -715,26 +628,28 @@ main(int ac, char **av)
                for (;;) {
                        if (received_sighup)
                                sighup_restart();
-                       /* Wait in poll until there is a connection. */
-                       memset(&fds, 0, sizeof(fds));
-                       fds.fd = listen_sock;
-                       fds.events = POLLIN;
-                       if (poll(&fds, 1, -1) == -1) {
-                               if (errno == EINTR)
-                                       continue;
-                               fatal("poll: %.100s", strerror(errno));
-                               /*NOTREACHED*/
-                       }
-                       if (fds.revents == 0)
+                       /* Wait in select until there is a connection. */
+                       memset(fdset, 0, fdsetsz);
+                       for (i = 0; i < num_listen_socks; i++)
+                               FD_SET(listen_socks[i], fdset);
+                       if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) {
+                               if (errno != EINTR)
+                                       error("select: %.100s", strerror(errno));
                                continue;
-                       aux = sizeof(sin);
-                       newsock = accept(listen_sock, (struct sockaddr *) & sin, &aux);
-                       if (received_sighup)
-                               sighup_restart();
-                       if (newsock < 0) {
-                               if (errno == EINTR)
+                       }
+                       for (i = 0; i < num_listen_socks; i++) {
+                               if (!FD_ISSET(listen_socks[i], fdset))
                                        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;
+                       }
+                       if (fcntl(newsock, F_SETFL, 0) < 0) {
+                               error("newsock del O_NONBLOCK: %s", strerror(errno));
                                continue;
                        }
                        /*
@@ -748,7 +663,7 @@ main(int ac, char **av)
                                 * connection without forking.
                                 */
                                debug("Server will not fork when running in debugging mode.");
-                               close(listen_sock);
+                               close_listen_socks();
                                sock_in = newsock;
                                sock_out = newsock;
                                pid = getpid();
@@ -765,7 +680,7 @@ main(int ac, char **av)
                                         * accepted socket.  Reinitialize logging (since our pid has
                                         * changed).  We break out of the loop to handle the connection.
                                         */
-                                       close(listen_sock);
+                                       close_listen_socks();
                                        sock_in = newsock;
                                        sock_out = newsock;
                                        log_init(av0, options.log_level, options.log_facility, log_stderr);
@@ -786,6 +701,10 @@ main(int ac, char **av)
 
                        /* Close the new socket (the child is now taking care of it). */
                        close(newsock);
+                       } /* for (i = 0; i < num_listen_socks; i++) */
+                       /* child process check (or debug mode) */
+                       if (num_listen_socks < 0)
+                               break;
                }
        }
 
@@ -824,6 +743,7 @@ main(int ac, char **av)
 
        /* Check whether logins are denied from this host. */
 #ifdef LIBWRAP
+       /* XXX LIBWRAP noes not know about IPv6 */
        {
                struct request_info req;
 
@@ -835,12 +755,11 @@ main(int ac, char **av)
                        close(sock_out);
                        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. */
        verbose("Connection from %.500s port %d", remote_ip, remote_port);
-#endif /* LIBWRAP */
 
        /*
         * We don\'t want to listen forever unless the other side
@@ -862,12 +781,12 @@ main(int ac, char **av)
                snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
                         PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
                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. */
                for (i = 0; i < sizeof(buf) - 1; i++) {
                        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') {
                                buf[i] = '\n';
                                buf[i + 1] = 0;
@@ -894,7 +813,7 @@ main(int ac, char **av)
                close(sock_in);
                close(sock_out);
                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",
              remote_major, remote_minor, remote_version);
@@ -905,8 +824,7 @@ main(int ac, char **av)
                close(sock_in);
                close(sock_out);
                fatal("Protocol major versions differ for %s: %d vs. %d",
-                     get_remote_ipaddr(),
-                     PROTOCOL_MAJOR, remote_major);
+                     remote_ip, PROTOCOL_MAJOR, remote_major);
        }
        /* Check that the client has sufficiently high software version. */
        if (remote_major == 1 && remote_minor < 3)
@@ -931,6 +849,14 @@ main(int ac, char **av)
                options.rhosts_authentication = 0;
                options.rhosts_rsa_authentication = 0;
        }
+#ifdef KRB4
+       if (!packet_connection_is_ipv4() &&
+           options.kerberos_authentication) {
+               debug("Kerberos Authentication disabled, only available for IPv4.");
+               options.kerberos_authentication = 0;
+       }
+#endif /* KRB4 */
+
        packet_set_nonblocking();
 
        /* Handle the connection. */
@@ -949,22 +875,9 @@ main(int ac, char **av)
        /* The connection has been terminated. */
        verbose("Closing connection to %.100s", remote_ip);
 
-#ifdef HAVE_LIBPAM
-       {
-               int retval;
-
-               if (pamh != NULL) {
-                       debug("Closing PAM session.");
-                       retval = pam_close_session((pam_handle_t *)pamh, 0);
-
-                       debug("Terminating PAM library.");
-                       if (pam_end((pam_handle_t *)pamh, retval) != PAM_SUCCESS)
-                               log("Cannot release PAM authentication.");
-
-                       fatal_remove_cleanup(&pam_cleanup_proc, NULL);
-               }
-       }
-#endif /* HAVE_LIBPAM */
+#ifdef USE_PAM
+       finish_pam();
+#endif /* USE_PAM */
 
        packet_close();
        exit(0);
@@ -1282,18 +1195,8 @@ do_authentication(char *user)
        pwcopy.pw_shell = xstrdup(pw->pw_shell);
        pw = &pwcopy;
 
-#ifdef HAVE_LIBPAM
-       {
-               int pam_retval;
-
-               debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
-
-               pam_retval = pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh);
-               if (pam_retval != PAM_SUCCESS)
-                       fatal("PAM initialisation failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
-
-               fatal_add_cleanup(&pam_cleanup_proc, NULL);
-       }
+#ifdef USE_PAM
+       start_pam(pw);
 #endif
 
        /*
@@ -1310,11 +1213,11 @@ do_authentication(char *user)
 #ifdef KRB4
            (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
 #endif /* KRB4 */
-#ifdef HAVE_LIBPAM
-           do_pam_auth(pw->pw_name, "")) {
-#else /* HAVE_LIBPAM */
+#ifdef USE_PAM
+           auth_pam_password(pw, "")) {
+#else /* USE_PAM */
            auth_password(pw, "")) {
-#endif /* HAVE_LIBPAM */
+#endif /* USE_PAM */
                /* Authentication with empty password succeeded. */
                log("Login for user %s from %.100s, accepted without authentication.",
                    pw->pw_name, get_remote_ipaddr());
@@ -1362,9 +1265,6 @@ do_authloop(struct passwd * pw)
        int plen, dlen, nlen, ulen, elen;
        int type = 0;
        void (*authlog) (const char *fmt,...) = verbose;
-#ifdef HAVE_LIBPAM
-       int pam_retval;
-#endif /* HAVE_LIBPAM */
 
        /* Indicate that authentication is needed. */
        packet_start(SSH_SMSG_FAILURE);
@@ -1457,9 +1357,6 @@ do_authloop(struct passwd * pw)
                        authenticated = auth_rhosts(pw, client_user);
 
                        snprintf(user, sizeof user, " ruser %s", client_user);
-#ifndef HAVE_LIBPAM
-                       xfree(client_user);
-#endif /* HAVE_LIBPAM */
                        break;
 
                case SSH_CMSG_AUTH_RHOSTS_RSA:
@@ -1492,9 +1389,6 @@ do_authloop(struct passwd * pw)
                        BN_clear_free(client_host_key_n);
 
                        snprintf(user, sizeof user, " ruser %s", client_user);
-#ifndef HAVE_LIBPAM
-                       xfree(client_user);
-#endif /* HAVE_LIBPAM */
                        break;
 
                case SSH_CMSG_AUTH_RSA:
@@ -1523,13 +1417,13 @@ do_authloop(struct passwd * pw)
                        password = packet_get_string(&dlen);
                        packet_integrity_check(plen, 4 + dlen, type);
 
-#ifdef HAVE_LIBPAM
+#ifdef USE_PAM
                        /* Do PAM auth with password */
-                       authenticated = do_pam_auth(pw->pw_name, password);
-#else /* HAVE_LIBPAM */
+                       authenticated = auth_pam_password(pw, password);
+#else /* USE_PAM */
                        /* Try authentication with the password. */
                        authenticated = auth_password(pw, password);
-#endif /* HAVE_LIBPAM */
+#endif /* USE_PAM */
                        memset(password, 0, strlen(password));
                        xfree(password);
                        break;
@@ -1595,29 +1489,24 @@ do_authloop(struct passwd * pw)
                        get_remote_port(),
                        user);
 
-#ifndef HAVE_LIBPAM
-               if (authenticated)
-                       return;
-
-               if (attempt > AUTH_FAIL_MAX)
-                       packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
-#else /* HAVE_LIBPAM */
                if (authenticated) {
-                       do_pam_account(pw->pw_name, client_user);
-
-                       if (client_user != NULL)
-                               xfree(client_user);
+#ifdef USE_PAM
+                       if (!do_pam_account(pw->pw_name, client_user))
+                       {
+                               if (client_user != NULL)
+                                       xfree(client_user);
 
+                               do_fake_authloop(pw->pw_name);
+                       }
+#endif /* USE_PAM */
                        return;
                }
 
-               if (attempt > AUTH_FAIL_MAX) {
-                       if (client_user != NULL)
-                               xfree(client_user);
+               if (client_user != NULL)
+                       xfree(client_user);
 
+               if (attempt > AUTH_FAIL_MAX)
                        packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
-               }
-#endif /* HAVE_LIBPAM */
 
                /* Send a message indicating that the authentication attempt failed. */
                packet_start(SSH_SMSG_FAILURE);
@@ -1652,8 +1541,10 @@ do_fake_authloop(char *user)
        for (attempt = 1;; attempt++) {
                /* Read a packet.  This will not return if the client disconnects. */
                int plen;
+#ifndef SKEY
+               (void)packet_read(&plen);
+#else /* SKEY */
                int type = packet_read(&plen);
-#ifdef SKEY
                int dlen;
                char *password, *skeyinfo;
                /* Try to send a fake s/key challenge. */
@@ -1823,10 +1714,10 @@ do_authenticated(struct passwd * pw)
                        /* Indicate that we now have a pty. */
                        have_pty = 1;
 
-#ifdef HAVE_LIBPAM
+#ifdef USE_PAM
                        /* do the pam_open_session since we have the pty */
-                       do_pam_session(pw->pw_name,ttyname);
-#endif /* HAVE_LIBPAM */
+                       do_pam_session(pw->pw_name, ttyname);
+#endif /* USE_PAM */
 
                        break;
 
@@ -1903,6 +1794,9 @@ do_authenticated(struct passwd * pw)
                        packet_set_interactive(have_pty || display != NULL,
                                               options.keepalives);
 
+#ifdef USE_PAM
+                       do_pam_setcred();
+#endif /* USE_PAM */
                        if (forced_command != NULL)
                                goto do_forced_command;
                        debug("Forking shell.");
@@ -1918,6 +1812,9 @@ do_authenticated(struct passwd * pw)
                        packet_set_interactive(have_pty || display != NULL,
                                               options.keepalives);
 
+#ifdef USE_PAM
+                       do_pam_setcred();
+#endif /* USE_PAM */
                        if (forced_command != NULL)
                                goto do_forced_command;
                        /* Get command from the packet. */
@@ -2126,8 +2023,8 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
        char line[256];
        struct stat st;
        int quiet_login;
-       struct sockaddr_in from;
-       int fromlen;
+       struct sockaddr_storage from;
+       socklen_t fromlen;
        struct pty_cleanup_context cleanup_context;
 
        /* Get remote host name. */
@@ -2188,17 +2085,16 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
                }
                /* Record that there was a login on that terminal. */
                record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname,
-                            &from);
+                            (struct sockaddr *)&from);
 
                /* Check if .hushlogin exists. */
                snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
                quiet_login = stat(line, &st) >= 0;
 
-#ifdef HAVE_LIBPAM
-               /* output the results of the pamconv() */
-               if (!quiet_login && pamconv_msg != NULL)
-                       fprintf(stderr, pamconv_msg);
-#endif
+#ifdef USE_PAM
+               if (!quiet_login)
+                       print_pam_messages();
+#endif /* USE_PAM */
 
                /*
                 * If the user has logged in before, display the time of last
@@ -2363,6 +2259,39 @@ read_environment_file(char ***env, unsigned int *envsize,
        fclose(f);
 }
 
+#ifdef USE_PAM
+/*
+ * Sets any environment variables which have been specified by PAM
+ */
+void do_pam_environment(char ***env, int *envsize)
+{
+       char *equals, var_name[512], var_val[512];
+       char **pam_env;
+       int i;
+
+       if ((pam_env = fetch_pam_environment()) == NULL)
+               return;
+       
+       for(i = 0; pam_env[i] != NULL; i++) {
+               if ((equals = strstr(pam_env[i], "=")) == NULL)
+                       continue;
+                       
+               if (strlen(pam_env[i]) < (sizeof(var_name) - 1))
+               {
+                       memset(var_name, '\0', sizeof(var_name));
+                       memset(var_val, '\0', sizeof(var_val));
+
+                       strncpy(var_name, pam_env[i], equals - pam_env[i]);
+                       strcpy(var_val, equals + 1);
+
+                       debug("PAM environment: %s=%s", var_name, var_val);
+
+                       child_set_env(env, envsize, var_name, var_val);
+               }
+       }
+}
+#endif /* USE_PAM */
+
 /*
  * Performs common processing for the child, such as setting up the
  * environment, closing extra file descriptors, setting the user and group
@@ -2382,7 +2311,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
        struct stat st;
        char *argv[10];
 
-#ifndef HAVE_LIBPAM /* pam_nologin handles this */
+#ifndef USE_PAM /* pam_nologin handles this */
        /* Check /etc/nologin. */
        f = fopen("/etc/nologin", "r");
        if (f) {
@@ -2393,13 +2322,11 @@ do_child(const char *command, struct passwd * pw, const char *term,
                if (pw->pw_uid != 0)
                        exit(254);
        }
-#endif /* HAVE_LIBPAM */
+#endif /* USE_PAM */
 
-#ifdef HAVE_SETLOGIN
        /* Set login name in the kernel. */
        if (setlogin(pw->pw_name) < 0)
                error("setlogin failed: %s", strerror(errno));
-#endif /* HAVE_SETLOGIN */
 
        /* Set uid, gid, and groups. */
        /* Login(1) does this as well, and it needs uid 0 for the "-h"
@@ -2479,7 +2406,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
        }
 
        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);
 
        if (ttyname)
@@ -2498,26 +2425,10 @@ do_child(const char *command, struct passwd * pw, const char *term,
        }
 #endif /* KRB4 */
 
-#ifdef HAVE_LIBPAM
+#ifdef USE_PAM
        /* Pull in any environment variables that may have been set by PAM. */
-       {
-               char *equals, var_name[512], var_val[512];
-               char **pam_env = pam_getenvlist((pam_handle_t *)pamh);
-               int i;
-               for(i = 0; pam_env && pam_env[i]; i++) {
-                       equals = strstr(pam_env[i], "=");
-                       if ((strlen(pam_env[i]) < (sizeof(var_name) - 1)) && (equals != NULL))
-                       {
-                               debug("PAM environment: %s=%s", var_name, var_val);
-                               memset(var_name, '\0', sizeof(var_name));
-                               memset(var_val, '\0', sizeof(var_val));
-                               strncpy(var_name, pam_env[i], equals - pam_env[i]);
-                               strcpy(var_val, equals + 1);
-                               child_set_env(&env, &envsize, var_name, var_val);
-                       }
-               }
-       }
-#endif /* HAVE_LIBPAM */
+       do_pam_environment(&env, &envsize);
+#endif /* USE_PAM */
 
        if (xauthfile)
                child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
@@ -2562,7 +2473,6 @@ do_child(const char *command, struct passwd * pw, const char *term,
         * descriptors left by system functions.  They will be closed later.
         */
        endpwent();
-       endhostent();
 
        /*
         * Close any extra open file descriptors so that we don\'t have them
This page took 0.572623 seconds and 4 git commands to generate.