]> andersk Git - openssh.git/blobdiff - sshd.c
- Check for libwrap if --with-tcp-wrappers option specified. Suggestion
[openssh.git] / sshd.c
diff --git a/sshd.c b/sshd.c
index 2af9b6af3d8cb2474e629d39fbf9e7e749f0b938..0024440ed693855de09894d0695ec176a7173b73 100644 (file)
--- a/sshd.c
+++ b/sshd.c
@@ -11,7 +11,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id$");
+RCSID("$OpenBSD: sshd.c,v 1.80 2000/01/20 15:19:22 markus Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -45,6 +45,16 @@ 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.
+ */
+#ifdef IPV4_DEFAULT
+int IPv4or6 = AF_INET;
+#else
+int IPv4or6 = AF_UNSPEC;
+#endif
+
 /*
  * 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
@@ -65,12 +75,18 @@ char *av0;
 /* Saved arguments to main(). */
 char **saved_argv;
 
-/* This is set to the socket that the server is listening; this is used in
-   the SIGHUP signal handler. */
-int listen_sock;
+/*
+ * The sockets that the server is listening; this is used in the SIGHUP
+ * signal handler.
+ */
+#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, sshd will skip the version-number exchange */
+/*
+ * the client's version string, passed by sshd2 in compat mode. if != NULL,
+ * sshd will skip the version-number exchange
+ */
 char *client_version_string = NULL;
 
 /* Flags set in auth-rsa from authorized_keys flags.  These are set in auth-rsa.c. */
@@ -88,19 +104,23 @@ struct envstring *custom_environment = NULL;
 /* Session id for the current session. */
 unsigned char session_id[16];
 
-/* Any really sensitive data in the application is contained in this structure.
-   The idea is that this structure could be locked into memory so that the
-   pages do not get written into swap.  However, there are some problems.
-   The private key contains BIGNUMs, and we do not (in principle) have
-   access to the internals of them, and locking just the structure is not
-   very useful.  Currently, memory locking is not implemented. */
+/*
+ * Any really sensitive data in the application is contained in this
+ * structure. The idea is that this structure could be locked into memory so
+ * that the pages do not get written into swap.  However, there are some
+ * problems. The private key contains BIGNUMs, and we do not (in principle)
+ * have access to the internals of them, and locking just the structure is
+ * not very useful.  Currently, memory locking is not implemented.
+ */
 struct {
        RSA *private_key;        /* Private part of server key. */
        RSA *host_key;           /* Private part of host key. */
 } sensitive_data;
 
-/* Flag indicating whether the current session key has been used.  This flag
-   is set whenever the key is used, and cleared when the key is regenerated. */
+/*
+ * Flag indicating whether the current session key has been used.  This flag
+ * is set whenever the key is used, and cleared when the key is regenerated.
+ */
 int key_used = 0;
 
 /* This is set to true when SIGHUP is received. */
@@ -111,8 +131,8 @@ int received_sighup = 0;
 RSA *public_key;
 
 /* Prototypes for various functions defined later in this file. */
-void do_connection();
-void do_authentication(char *user);
+void do_ssh_kex();
+void do_authentication();
 void do_authloop(struct passwd * pw);
 void do_fake_authloop(char *user);
 void do_authenticated(struct passwd * pw);
@@ -127,136 +147,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);
-void do_pam_account_and_session(char *username, char *remote_user, 
-         const char *remote_host);
-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));
-               }
-       }
-}
-
-void do_pam_account_and_session(char *username, char *remote_user, 
-        const char *remote_host)
+/*
+ * Close all listening sockets
+ */
+void
+close_listen_socks(void)
 {
-       int pam_retval;
-
-       if (remote_host != NULL) {
-               debug("PAM setting rhost to \"%.200s\"", remote_host);
-               pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST, remote_host);
-               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);
-       }
-
-       pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
-       if (pam_retval != PAM_SUCCESS) {
-               log("PAM session setup failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
-               do_fake_authloop(username);
-       }
+       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;
@@ -278,7 +179,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);
@@ -293,7 +194,7 @@ void
 sigterm_handler(int sig)
 {
        log("Received signal %d; terminating.", sig);
-       close(listen_sock);
+       close_listen_socks();
        exit(255);
 }
 
@@ -400,10 +301,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 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;
@@ -411,6 +314,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;
@@ -423,8 +329,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;
@@ -445,7 +357,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);
@@ -466,7 +381,7 @@ main(int ac, char **av)
                        fprintf(stderr, "sshd version %s\n", SSH_VERSION);
                        fprintf(stderr, "Usage: %s [options]\n", av0);
                        fprintf(stderr, "Options:\n");
-                       fprintf(stderr, "  -f file    Configuration file (default %s/sshd_config)\n", ETCDIR);
+                       fprintf(stderr, "  -f file    Configuration file (default %s)\n", SERVER_CONFIG_FILE);
                        fprintf(stderr, "  -d         Debugging mode\n");
                        fprintf(stderr, "  -i         Started from inetd\n");
                        fprintf(stderr, "  -q         Quiet (no logging)\n");
@@ -475,11 +390,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)
@@ -499,18 +425,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);
 
@@ -599,41 +518,75 @@ 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));
-
-               /* Initialize the socket address. */
-               memset(&sin, 0, sizeof(sin));
-               sin.sin_family = AF_INET;
-               sin.sin_addr = options.listen_addr;
-               sin.sin_port = htons(options.port);
-
-               /* Bind the socket to the desired 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) &&
+                                (!ai->ai_next)) {
+                               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 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. */
+                       /*
+                        * Record our pid in /etc/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(SSH_DAEMON_PID_FILE, "w");
                        if (f) {
                                fprintf(f, "%u\n", (unsigned int) getpid());
@@ -641,10 +594,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();
 
@@ -666,46 +615,74 @@ main(int ac, char **av)
                /* Arrange SIGCHLD to be caught. */
                signal(SIGCHLD, main_sigchld_handler);
 
-               /* Stay listening for connections until the system crashes
-                  or the daemon is killed with a signal. */
+               /* 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.
+                */
                for (;;) {
                        if (received_sighup)
                                sighup_restart();
-                       /* Wait in accept until there is a connection. */
-                       aux = sizeof(sin);
-                       newsock = accept(listen_sock, (struct sockaddr *) & sin, &aux);
-                       if (received_sighup)
-                               sighup_restart();
-                       if (newsock < 0) {
-                               if (errno == EINTR)
+                       /* 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;
+                       }
+                       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;
                        }
-                       /* Got connection.  Fork a child to handle it,
-                          unless we are in debugging mode. */
+                       if (fcntl(newsock, F_SETFL, 0) < 0) {
+                               error("newsock del O_NONBLOCK: %s", strerror(errno));
+                               continue;
+                       }
+                       /*
+                        * Got connection.  Fork a child to handle it, unless
+                        * we are in debugging mode.
+                        */
                        if (debug_flag) {
-                               /* In debugging mode.  Close the listening
-                                  socket, and start processing the
-                                  connection without forking. */
+                               /*
+                                * 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_sock);
+                               close_listen_socks();
                                sock_in = newsock;
                                sock_out = newsock;
                                pid = getpid();
                                break;
                        } else {
-                               /* Normal production daemon.  Fork, and
-                                  have the child process the connection.
-                                  The parent continues listening. */
+                               /*
+                                * Normal production daemon.  Fork, and have
+                                * the child process the connection. The
+                                * parent continues listening.
+                                */
                                if ((pid = fork()) == 0) {
-                                       /* Child.  Close the listening
-                                          socket, and start using the
-                                          accepted socket.  Reinitialize
-                                          logging (since our pid has
-                                          changed).  We break out of the
-                                          loop to handle the connection. */
-                                       close(listen_sock);
+                                       /*
+                                        * Child.  Close the listening socket, and start using the
+                                        * accepted socket.  Reinitialize logging (since our pid has
+                                        * changed).  We break out of the loop to handle the connection.
+                                        */
+                                       close_listen_socks();
                                        sock_in = newsock;
                                        sock_out = newsock;
                                        log_init(av0, options.log_level, options.log_facility, log_stderr);
@@ -726,14 +703,20 @@ 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;
                }
        }
 
        /* This is the child processing a new connection. */
 
-       /* Disable the key regeneration alarm.  We will not regenerate the
-          key since we are no longer in a position to give it to anyone.
-          We will not restart on SIGHUP since it no longer makes sense. */
+       /*
+        * Disable the key regeneration alarm.  We will not regenerate the
+        * key since we are no longer in a position to give it to anyone. We
+        * will not restart on SIGHUP since it no longer makes sense.
+        */
        alarm(0);
        signal(SIGALRM, SIG_DFL);
        signal(SIGHUP, SIG_DFL);
@@ -741,17 +724,20 @@ main(int ac, char **av)
        signal(SIGQUIT, SIG_DFL);
        signal(SIGCHLD, SIG_DFL);
 
-       /* Set socket options for the connection.  We want the socket to
-          close as fast as possible without waiting for anything.  If the
-          connection is not a socket, these will do nothing. */
-       /* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
-          sizeof(on)); */
+       /*
+        * Set socket options for the connection.  We want the socket to
+        * close as fast as possible without waiting for anything.  If the
+        * connection is not a socket, these will do nothing.
+        */
+       /* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
        linger.l_onoff = 1;
        linger.l_linger = 5;
        setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
 
-       /* Register our connection.  This turns encryption off because we
-          do not have a key. */
+       /*
+        * Register our connection.  This turns encryption off because we do
+        * not have a key.
+        */
        packet_set_connection(sock_in, sock_out);
 
        remote_port = get_remote_port();
@@ -759,6 +745,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;
 
@@ -770,19 +757,20 @@ 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
-          successfully authenticates itself.  So we set up an alarm which
-          is cleared after successful authentication.  A limit of zero
-          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 are about to discover the bug. */
+       /*
+        * We don\'t want to listen forever unless the other side
+        * successfully authenticates itself.  So we set up an alarm which is
+        * cleared after successful authentication.  A limit of zero
+        * 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
+        * are about to discover the bug.
+        */
        signal(SIGALRM, grace_alarm_handler);
        if (!debug_flag)
                alarm(options.login_grace_time);
@@ -794,13 +782,17 @@ main(int ac, char **av)
                /* Send our protocol version identification. */
                snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
                         PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
-               if (write(sock_out, buf, strlen(buf)) != strlen(buf))
-                       fatal("Could not write ident string to %s.", get_remote_ipaddr());
+               if (atomicio(write, sock_out, buf, strlen(buf)) != strlen(buf)) {
+                       log("Could not write ident string to %s.", remote_ip);
+                       fatal_cleanup();
+               }
 
                /* 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());
+                       if (read(sock_in, &buf[i], 1) != 1) {
+                               log("Did not receive ident string from %s.", remote_ip);
+                               fatal_cleanup();
+                       }
                        if (buf[i] == '\r') {
                                buf[i] = '\n';
                                buf[i + 1] = 0;
@@ -815,53 +807,68 @@ main(int ac, char **av)
                buf[sizeof(buf) - 1] = 0;
        }
 
-       /* Check that the versions match.  In future this might accept
-          several versions and set appropriate flags to handle them. */
+       /*
+        * Check that the versions match.  In future this might accept
+        * several versions and set appropriate flags to handle them.
+        */
        if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
-                  remote_version) != 3) {
-               const char *s = "Protocol mismatch.\n";
-               (void) write(sock_out, s, strlen(s));
+           remote_version) != 3) {
+               char *s = "Protocol mismatch.\n";
+
+               (void) atomicio(write, sock_out, s, strlen(s));
                close(sock_in);
                close(sock_out);
-               fatal("Bad protocol version identification '%.100s' from %s",
-                     buf, get_remote_ipaddr());
+               log("Bad protocol version identification '%.100s' from %s",
+                   buf, remote_ip);
+               fatal_cleanup();
        }
        debug("Client protocol version %d.%d; client software version %.100s",
              remote_major, remote_minor, remote_version);
        if (remote_major != PROTOCOL_MAJOR) {
-               const char *s = "Protocol major versions differ.\n";
-               (void) write(sock_out, s, strlen(s));
+               char *s = "Protocol major versions differ.\n";
+
+               (void) atomicio(write, sock_out, s, strlen(s));
                close(sock_in);
                close(sock_out);
-               fatal("Protocol major versions differ for %s: %d vs. %d",
-                     get_remote_ipaddr(),
-                     PROTOCOL_MAJOR, remote_major);
+               log("Protocol major versions differ for %s: %d vs. %d",
+                   remote_ip, PROTOCOL_MAJOR, remote_major);
+               fatal_cleanup();
        }
        /* Check that the client has sufficiently high software version. */
        if (remote_major == 1 && remote_minor < 3)
                packet_disconnect("Your ssh version is too old and is no longer supported.  Please install a newer version.");
 
        if (remote_major == 1 && remote_minor == 3) {
+               /* note that this disables agent-forwarding */
                enable_compat13();
-               if (strcmp(remote_version, "OpenSSH-1.1") != 0) {
-                       debug("Agent forwarding disabled, remote version is not compatible.");
-                       no_agent_forwarding_flag = 1;
-               }
        }
-       /* Check that the connection comes from a privileged port.  Rhosts-
-          and Rhosts-RSA-Authentication only make sense from priviledged
-          programs.  Of course, if the intruder has root access on his
-          local machine, he can connect from any port.  So do not use
-          these authentication methods from machines that you do not trust. */
+       /*
+        * Check that the connection comes from a privileged port.  Rhosts-
+        * and Rhosts-RSA-Authentication only make sense from priviledged
+        * programs.  Of course, if the intruder has root access on his local
+        * machine, he can connect from any port.  So do not use these
+        * authentication methods from machines that you do not trust.
+        */
        if (remote_port >= IPPORT_RESERVED ||
            remote_port < IPPORT_RESERVED / 2) {
                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. */
-       do_connection();
+       /* perform the key exchange */
+       do_ssh_kex();
+
+       /* authenticate user and start session */
+       do_authentication();
 
 #ifdef KRB4
        /* Cleanup user's ticket cache file. */
@@ -876,64 +883,52 @@ 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);
 }
 
 /*
- * Process an incoming connection.  Protocol version identifiers have already
- * been exchanged.  This sends server key and performs the key exchange.
- * Server and host keys will no longer be needed after this functions.
+ * SSH1 key exchange
  */
 void
-do_connection()
+do_ssh_kex()
 {
        int i, len;
+       int plen, slen;
        BIGNUM *session_key_int;
        unsigned char session_key[SSH_SESSION_KEY_LENGTH];
-       unsigned char check_bytes[8];
-       char *user;
+       unsigned char cookie[8];
        unsigned int cipher_type, auth_mask, protocol_flags;
-       int plen, slen;
        u_int32_t rand = 0;
 
-       /* Generate check bytes that the client must send back in the user
-          packet in order for it to be accepted; this is used to defy ip
-          spoofing attacks.  Note that this only works against somebody
-          doing IP spoofing from a remote machine; any machine on the
-          local network can still see outgoing packets and catch the
-          random cookie.  This only affects rhosts authentication, and
-          this is one of the reasons why it is inherently insecure. */
+       /*
+        * Generate check bytes that the client must send back in the user
+        * packet in order for it to be accepted; this is used to defy ip
+        * spoofing attacks.  Note that this only works against somebody
+        * doing IP spoofing from a remote machine; any machine on the local
+        * network can still see outgoing packets and catch the random
+        * cookie.  This only affects rhosts authentication, and this is one
+        * of the reasons why it is inherently insecure.
+        */
        for (i = 0; i < 8; i++) {
                if (i % 4 == 0)
                        rand = arc4random();
-               check_bytes[i] = rand & 0xff;
+               cookie[i] = rand & 0xff;
                rand >>= 8;
        }
 
-       /* Send our public key.  We include in the packet 64 bits of
-          random data that must be matched in the reply in order to
-          prevent IP spoofing. */
+       /*
+        * Send our public key.  We include in the packet 64 bits of random
+        * data that must be matched in the reply in order to prevent IP
+        * spoofing.
+        */
        packet_start(SSH_SMSG_PUBLIC_KEY);
        for (i = 0; i < 8; i++)
-               packet_put_char(check_bytes[i]);
+               packet_put_char(cookie[i]);
 
        /* Store our public server RSA key. */
        packet_put_int(BN_num_bits(public_key->n));
@@ -987,13 +982,16 @@ do_connection()
        /* Read clients reply (cipher type and session key). */
        packet_read_expect(&plen, SSH_CMSG_SESSION_KEY);
 
-       /* Get cipher type. */
+       /* Get cipher type and check whether we accept this. */
        cipher_type = packet_get_char();
 
+        if (!(cipher_mask() & (1 << cipher_type)))
+               packet_disconnect("Warning: client selects unsupported cipher.");
+
        /* Get check bytes from the packet.  These must match those we
           sent earlier with the public key packet. */
        for (i = 0; i < 8; i++)
-               if (check_bytes[i] != packet_get_char())
+               if (cookie[i] != packet_get_char())
                        packet_disconnect("IP Spoofing check bytes do not match.");
 
        debug("Encryption type: %.200s", cipher_name(cipher_type));
@@ -1002,14 +1000,15 @@ do_connection()
        session_key_int = BN_new();
        packet_get_bignum(session_key_int, &slen);
 
-       /* Get protocol flags. */
        protocol_flags = packet_get_int();
        packet_set_protocol_flags(protocol_flags);
 
        packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY);
 
-       /* Decrypt it using our private server key and private host key
-          (key with larger modulus first). */
+       /*
+        * Decrypt it using our private server key and private host key (key
+        * with larger modulus first).
+        */
        if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) {
                /* Private key has bigger modulus. */
                if (BN_num_bits(sensitive_data.private_key->n) <
@@ -1040,14 +1039,20 @@ do_connection()
                                    sensitive_data.private_key);
        }
 
-       /* Compute session id for this session. */
-       compute_session_id(session_id, check_bytes,
+       compute_session_id(session_id, cookie,
                           sensitive_data.host_key->n,
                           sensitive_data.private_key->n);
 
-       /* Extract session key from the decrypted integer.  The key is in
-          the least significant 256 bits of the integer; the first byte
-          of the key is in the highest bits. */
+       /* Destroy the private and public keys.  They will no longer be needed. */
+       RSA_free(public_key);
+       RSA_free(sensitive_data.private_key);
+       RSA_free(sensitive_data.host_key);
+
+       /*
+        * Extract session key from the decrypted integer.  The key is in the
+        * least significant 256 bits of the integer; the first byte of the
+        * key is in the highest bits.
+        */
        BN_mask_bits(session_key_int, sizeof(session_key) * 8);
        len = BN_num_bytes(session_key_int);
        if (len < 0 || len > sizeof(session_key))
@@ -1057,13 +1062,13 @@ do_connection()
        memset(session_key, 0, sizeof(session_key));
        BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len);
 
+       /* Destroy the decrypted integer.  It is no longer needed. */
+       BN_clear_free(session_key_int);
+
        /* Xor the first 16 bytes of the session key with the session id. */
        for (i = 0; i < 16; i++)
                session_key[i] ^= session_id[i];
 
-       /* Destroy the decrypted integer.  It is no longer needed. */
-       BN_clear_free(session_key_int);
-
        /* Set the session key.  From this on all communications will be encrypted. */
        packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type);
 
@@ -1076,27 +1081,9 @@ do_connection()
        packet_start(SSH_SMSG_SUCCESS);
        packet_send();
        packet_write_wait();
-
-       /* Get the name of the user that we wish to log in as. */
-       packet_read_expect(&plen, SSH_CMSG_USER);
-
-       /* Get the user name. */
-       {
-               int ulen;
-               user = packet_get_string(&ulen);
-               packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
-       }
-
-       /* Destroy the private and public keys.  They will no longer be needed. */
-       RSA_free(public_key);
-       RSA_free(sensitive_data.private_key);
-       RSA_free(sensitive_data.host_key);
-
-       setproctitle("%s", user);
-       /* Do the authentication. */
-       do_authentication(user);
 }
 
+
 /*
  * Check if the user is allowed to log in via ssh. If user is listed in
  * DenyUsers or user's primary group is listed in DenyGroups, false will
@@ -1110,6 +1097,9 @@ allowed_user(struct passwd * pw)
 {
        struct group *grp;
        int i;
+#ifdef WITH_AIXAUTHENTICATE
+       char *loginmsg;
+#endif /* WITH_AIXAUTHENTICATE */
 
        /* Shouldn't be called if pw is NULL, but better safe than sorry... */
        if (!pw)
@@ -1125,8 +1115,7 @@ allowed_user(struct passwd * pw)
                        if (match_pattern(pw->pw_name, options.deny_users[i]))
                                return 0;
        }
-       /* Return false if AllowUsers isn't empty and user isn't listed
-          there */
+       /* Return false if AllowUsers isn't empty and user isn't listed there */
        if (options.num_allow_users > 0) {
                if (!pw->pw_name)
                        return 0;
@@ -1151,8 +1140,10 @@ allowed_user(struct passwd * pw)
                                if (match_pattern(grp->gr_name, options.deny_groups[i]))
                                        return 0;
                }
-               /* Return false if AllowGroups isn't empty and user's
-                  group isn't listed there */
+               /*
+                * Return false if AllowGroups isn't empty and user's group
+                * isn't listed there
+                */
                if (options.num_allow_groups > 0) {
                        if (!grp->gr_name)
                                return 0;
@@ -1165,19 +1156,39 @@ allowed_user(struct passwd * pw)
                                return 0;
                }
        }
+
+#ifdef WITH_AIXAUTHENTICATE
+       if (loginrestrictions(pw->pw_name,S_LOGIN,NULL,&loginmsg) != 0)
+               return 0;
+#endif /* WITH_AIXAUTHENTICATE */
+
        /* We found no reason not to let this user try to log on... */
        return 1;
 }
 
 /*
  * Performs authentication of an incoming connection.  Session key has already
- * been exchanged and encryption is enabled.  User is the user name to log
- * in as (received from the client).
+ * been exchanged and encryption is enabled.
  */
 void
-do_authentication(char *user)
+do_authentication()
 {
        struct passwd *pw, pwcopy;
+       int plen, ulen;
+       char *user;
+
+       /* Get the name of the user that we wish to log in as. */
+       packet_read_expect(&plen, SSH_CMSG_USER);
+
+       /* Get the user name. */
+       user = packet_get_string(&ulen);
+       packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
+
+       setproctitle("%s", user);
+
+#ifdef WITH_AIXAUTHENTICATE
+       char *loginmsg;
+#endif /* WITH_AIXAUTHENTICATE */
 
 #ifdef AFS
        /* If machine has AFS, set process authentication group. */
@@ -1202,22 +1213,14 @@ 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
 
-       /* If we are not running as root, the user must have the same uid
-          as the server. */
+       /*
+        * If we are not running as root, the user must have the same uid as
+        * the server.
+        */
        if (getuid() != 0 && pw->pw_uid != getuid())
                packet_disconnect("Cannot change user when server not running as root.");
 
@@ -1228,7 +1231,11 @@ do_authentication(char *user)
 #ifdef KRB4
            (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
 #endif /* KRB4 */
+#ifdef USE_PAM
+           auth_pam_password(pw, "")) {
+#else /* USE_PAM */
            auth_password(pw, "")) {
+#endif /* USE_PAM */
                /* Authentication with empty password succeeded. */
                log("Login for user %s from %.100s, accepted without authentication.",
                    pw->pw_name, get_remote_ipaddr());
@@ -1248,6 +1255,9 @@ do_authentication(char *user)
                                          get_canonical_hostname());
        }
        /* The user has been authenticated and accepted. */
+#ifdef WITH_AIXAUTHENTICATE
+       loginsuccess(user,get_canonical_hostname(),"ssh",&loginmsg);
+#endif /* WITH_AIXAUTHENTICATE */
        packet_start(SSH_SMSG_SUCCESS);
        packet_send();
        packet_write_wait();
@@ -1276,9 +1286,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);
@@ -1357,10 +1364,12 @@ do_authloop(struct passwd * pw)
                                verbose("Rhosts authentication disabled.");
                                break;
                        }
-                       /* Get client user name.  Note that we just have
-                          to trust the client; this is one reason why
-                          rhosts authentication is insecure. (Another is
-                          IP-spoofing on a local network.) */
+                       /*
+                        * Get client user name.  Note that we just have to
+                        * trust the client; this is one reason why rhosts
+                        * authentication is insecure. (Another is
+                        * IP-spoofing on a local network.)
+                        */
                        client_user = packet_get_string(&ulen);
                        packet_integrity_check(plen, 4 + ulen, type);
 
@@ -1369,9 +1378,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:
@@ -1379,9 +1385,11 @@ do_authloop(struct passwd * pw)
                                verbose("Rhosts with RSA authentication disabled.");
                                break;
                        }
-                       /* Get client user name.  Note that we just have
-                          to trust the client; root on the client machine
-                          can claim to be any user. */
+                       /*
+                        * Get client user name.  Note that we just have to
+                        * trust the client; root on the client machine can
+                        * claim to be any user.
+                        */
                        client_user = packet_get_string(&ulen);
 
                        /* Get the client host key. */
@@ -1402,9 +1410,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:
@@ -1425,33 +1430,24 @@ do_authloop(struct passwd * pw)
                                verbose("Password authentication disabled.");
                                break;
                        }
-                       /* Read user password.  It is in plain text, but
-                          was transmitted over the encrypted channel so
-                          it is not visible to an outside observer. */
+                       /*
+                        * Read user password.  It is in plain text, but was
+                        * transmitted over the encrypted channel so it is
+                        * not visible to an outside observer.
+                        */
                        password = packet_get_string(&dlen);
                        packet_integrity_check(plen, 4 + dlen, type);
 
-#ifdef HAVE_LIBPAM
+#ifdef USE_PAM
                        /* Do PAM auth with password */
-                       pampasswd = password;
-                       pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
-                       if (pam_retval == PAM_SUCCESS) {
-                               log("PAM Password authentication accepted for user \"%.100s\"", pw->pw_name);
-                               authenticated = 1;
-                               break;
-                       }
-
-                       log("PAM Password authentication for \"%.100s\" failed: %s", 
-                               pw->pw_name, PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
-                       break;
-#else /* HAVE_LIBPAM */
+                       authenticated = auth_pam_password(pw, password);
+#else /* USE_PAM */
                        /* Try authentication with the password. */
                        authenticated = auth_password(pw, password);
-
+#endif /* USE_PAM */
                        memset(password, 0, strlen(password));
                        xfree(password);
                        break;
-#endif /* HAVE_LIBPAM */
 
 #ifdef SKEY
                case SSH_CMSG_AUTH_TIS:
@@ -1463,8 +1459,7 @@ do_authloop(struct passwd * pw)
                                        skeyinfo = skey_fake_keyinfo(pw->pw_name);
                                }
                                if (skeyinfo != NULL) {
-                                       /* we send our s/key- in
-                                          tis-challenge messages */
+                                       /* we send our s/key- in tis-challenge messages */
                                        debug("sending challenge '%s'", skeyinfo);
                                        packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
                                        packet_put_string(skeyinfo, strlen(skeyinfo));
@@ -1493,8 +1488,10 @@ do_authloop(struct passwd * pw)
 #endif
 
                default:
-                       /* Any unknown messages will be ignored (and
-                          failure returned) during authentication. */
+                       /*
+                        * Any unknown messages will be ignored (and failure
+                        * returned) during authentication.
+                        */
                        log("Unknown message during authentication: type %d", type);
                        break;
                }
@@ -1513,22 +1510,22 @@ do_authloop(struct passwd * pw)
                        get_remote_port(),
                        user);
 
-#ifdef HAVE_LIBPAM
-               do_pam_account_and_session(pw->pw_name, client_user,
-                       get_canonical_hostname());
+               if (authenticated) {
+#ifdef USE_PAM
+                       if (!do_pam_account(pw->pw_name, client_user)) {
+                               if (client_user != NULL)
+                                       xfree(client_user);
 
-               /* Clean up */
-               if (client_user != NULL)
-                       xfree(client_user);
-
-               if (password != NULL) {
-                       memset(password, 0, strlen(password));
-                       xfree(password);
+                               do_fake_authloop(pw->pw_name);
+                       }
+#endif /* USE_PAM */
+                       return;
                }
-#endif /* HAVE_LIBPAM */
 
-               if (authenticated)
-                       return;
+               if (client_user != NULL) {
+                       xfree(client_user);
+                       client_user = NULL;
+               }
 
                if (attempt > AUTH_FAIL_MAX)
                        packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
@@ -1559,35 +1556,52 @@ do_fake_authloop(char *user)
        packet_send();
        packet_write_wait();
 
-       /* Keep reading packets, and always respond with a failure.  This
-          is to avoid disclosing whether such a user really exists. */
+       /*
+        * Keep reading packets, and always respond with a failure.  This is
+        * to avoid disclosing whether such a user really exists.
+        */
        for (attempt = 1;; attempt++) {
-               /* Read a packet.  This will not return if the client
-                  disconnects. */
+               /* 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;
-               if (options.password_authentication &&
-                   options.skey_authentication == 1 &&
-                   type == SSH_CMSG_AUTH_PASSWORD &&
-                   (password = packet_get_string(&dlen)) != NULL &&
-                   dlen == 5 &&
-                   strncasecmp(password, "s/key", 5) == 0 &&
+               /* Try to send a fake s/key challenge. */
+               if (options.skey_authentication == 1 &&
                    (skeyinfo = skey_fake_keyinfo(user)) != NULL) {
-                       /* Send a fake s/key challenge. */
-                       packet_send_debug(skeyinfo);
+                       if (type == SSH_CMSG_AUTH_TIS) {
+                               packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
+                               packet_put_string(skeyinfo, strlen(skeyinfo));
+                               packet_send();
+                               packet_write_wait();
+                               continue;
+                       } else if (type == SSH_CMSG_AUTH_PASSWORD &&
+                                  options.password_authentication &&
+                                  (password = packet_get_string(&dlen)) != NULL &&
+                                  dlen == 5 &&
+                                  strncasecmp(password, "s/key", 5) == 0 ) {
+                               packet_send_debug(skeyinfo);
+                       }
                }
 #endif
                if (attempt > AUTH_FAIL_MAX)
                        packet_disconnect(AUTH_FAIL_MSG, user);
 
-               /* Send failure.  This should be indistinguishable from a
-                  failed authentication. */
+               /*
+                * Send failure.  This should be indistinguishable from a
+                * failed authentication.
+                */
                packet_start(SSH_SMSG_FAILURE);
                packet_send();
                packet_write_wait();
+#ifdef WITH_AIXAUTHENTICATE 
+               if (strncmp(get_authname(type),"password",
+                   strlen(get_authname(type))) == 0)
+                       loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
+#endif /* WITH_AIXAUTHENTICATE */
        }
        /* NOTREACHED */
        abort();
@@ -1609,6 +1623,37 @@ xauthfile_cleanup_proc(void *ignore)
        }
 }
 
+struct pty_cleanup_context {
+       const char *ttyname;
+       int pid;
+};
+
+/*
+ * Function to perform cleanup if we get aborted abnormally (e.g., due to a
+ * dropped connection).
+ */
+void 
+pty_cleanup_proc(void *context)
+{
+       struct pty_cleanup_context *cu = context;
+
+       debug("pty_cleanup_proc called");
+
+       /* Record that the user has logged out. */
+       record_logout(cu->pid, cu->ttyname);
+
+       /* Release the pseudo-tty. */
+       pty_release(cu->ttyname);
+}
+
+/* simple cleanup: chown tty slave back to root */
+static void
+pty_release_proc(void *tty)
+{
+       char *ttyname = tty;
+       pty_release(ttyname);
+}
+
 /*
  * Prepares for an interactive session.  This is called after the user has
  * been successfully authenticated.  During this message exchange, pseudo
@@ -1623,26 +1668,28 @@ do_authenticated(struct passwd * pw)
        int have_pty = 0, ptyfd = -1, ttyfd = -1, xauthfd = -1;
        int row, col, xpixel, ypixel, screen;
        char ttyname[64];
-       char *command, *term = NULL, *display = NULL, *proto = NULL,
-       *data = NULL;
-       struct group *grp;
-       gid_t tty_gid;
-       mode_t tty_mode;
+       char *command, *term = NULL, *display = NULL, *proto = NULL, *data = NULL;
        int n_bytes;
 
-       /* Cancel the alarm we set to limit the time taken for
-          authentication. */
+       /*
+        * Cancel the alarm we set to limit the time taken for
+        * authentication.
+        */
        alarm(0);
 
-       /* Inform the channel mechanism that we are the server side and
-          that the client may request to connect to any port at all.
-          (The user could do it anyway, and we wouldn\'t know what is
-          permitted except by the client telling us, so we can equally
-          well trust the client not to request anything bogus.) */
+       /*
+        * Inform the channel mechanism that we are the server side and that
+        * the client may request to connect to any port at all. (The user
+        * could do it anyway, and we wouldn\'t know what is permitted except
+        * by the client telling us, so we can equally well trust the client
+        * not to request anything bogus.)
+        */
        channel_permit_all_opens();
 
-       /* We stay in this loop until the client requests to execute a
-          shell or a command. */
+       /*
+        * We stay in this loop until the client requests to execute a shell
+        * or a command.
+        */
        while (1) {
                int plen, dlen;
 
@@ -1674,37 +1721,25 @@ do_authenticated(struct passwd * pw)
                        debug("Allocating pty.");
 
                        /* Allocate a pty and open it. */
-                       if (!pty_allocate(&ptyfd, &ttyfd, ttyname)) {
+                       if (!pty_allocate(&ptyfd, &ttyfd, ttyname,
+                           sizeof(ttyname))) {
                                error("Failed to allocate pty.");
                                goto fail;
                        }
-                       /* Determine the group to make the owner of the tty. */
-                       grp = getgrnam("tty");
-                       if (grp) {
-                               tty_gid = grp->gr_gid;
-                               tty_mode = S_IRUSR | S_IWUSR | S_IWGRP;
-                       } else {
-                               tty_gid = pw->pw_gid;
-                               tty_mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
-                       }
-
-                       /* Change ownership of the tty. */
-                       if (chown(ttyname, pw->pw_uid, tty_gid) < 0)
-                               fatal("chown(%.100s, %d, %d) failed: %.100s",
-                                     ttyname, pw->pw_uid, tty_gid, strerror(errno));
-                       if (chmod(ttyname, tty_mode) < 0)
-                               fatal("chmod(%.100s, 0%o) failed: %.100s",
-                                     ttyname, tty_mode, strerror(errno));
+                       fatal_add_cleanup(pty_release_proc, (void *)ttyname);
+                       pty_setowner(pw, ttyname);
 
                        /* Get TERM from the packet.  Note that the value may be of arbitrary length. */
                        term = packet_get_string(&dlen);
                        packet_integrity_check(dlen, strlen(term), type);
-                       /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */
+
                        /* Remaining bytes */
                        n_bytes = plen - (4 + dlen + 4 * 4);
 
-                       if (strcmp(term, "") == 0)
+                       if (strcmp(term, "") == 0) {
+                               xfree(term);
                                term = NULL;
+                       }
 
                        /* Get window size from the packet. */
                        row = packet_get_int();
@@ -1744,7 +1779,7 @@ do_authenticated(struct passwd * pw)
                                screen = packet_get_int();
                        else
                                screen = 0;
-                       display = x11_create_display_inet(screen);
+                       display = x11_create_display_inet(screen, options.x11_display_offset);
                        if (!display)
                                goto fail;
 
@@ -1767,7 +1802,7 @@ do_authenticated(struct passwd * pw)
 #endif /* XAUTH_PATH */
 
                case SSH_CMSG_AGENT_REQUEST_FORWARDING:
-                       if (no_agent_forwarding_flag) {
+                       if (no_agent_forwarding_flag || compat13) {
                                debug("Authentication agent forwarding not permitted for this authentication.");
                                goto fail;
                        }
@@ -1826,8 +1861,10 @@ do_authenticated(struct passwd * pw)
                        return;
 
                default:
-                       /* Any unknown messages in this phase are ignored,
-                          and a failure message is returned. */
+                       /*
+                        * Any unknown messages in this phase are ignored,
+                        * and a failure message is returned.
+                        */
                        log("Unknown packet type received after authentication: %d", type);
                        goto fail;
                }
@@ -1852,8 +1889,10 @@ fail:
                continue;
 
 do_forced_command:
-               /* There is a forced command specified for this login.
-                  Execute it. */
+               /*
+                * There is a forced command specified for this login.
+                * Execute it.
+                */
                debug("Executing forced command: %.900s", forced_command);
                if (have_pty)
                        do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
@@ -1892,19 +1931,27 @@ do_exec_no_pty(const char *command, struct passwd * pw,
 
        setproctitle("%s@notty", pw->pw_name);
 
+#ifdef USE_PAM
+                       do_pam_setcred();
+#endif /* USE_PAM */
+
        /* Fork the child. */
        if ((pid = fork()) == 0) {
                /* Child.  Reinitialize the log since the pid has changed. */
                log_init(av0, options.log_level, options.log_facility, log_stderr);
 
-               /* Create a new session and process group since the 4.4BSD
-                  setlogin() affects the entire process group. */
+               /*
+                * Create a new session and process group since the 4.4BSD
+                * setlogin() affects the entire process group.
+                */
                if (setsid() < 0)
                        error("setsid failed: %.100s", strerror(errno));
 
 #ifdef USE_PIPES
-               /* Redirect stdin.  We close the parent side of the socket
-                  pair, and make the child side the standard input. */
+               /*
+                * Redirect stdin.  We close the parent side of the socket
+                * pair, and make the child side the standard input.
+                */
                close(pin[1]);
                if (dup2(pin[0], 0) < 0)
                        perror("dup2 stdin");
@@ -1922,9 +1969,11 @@ do_exec_no_pty(const char *command, struct passwd * pw,
                        perror("dup2 stderr");
                close(perr[1]);
 #else /* USE_PIPES */
-               /* Redirect stdin, stdout, and stderr.  Stdin and stdout
-                  will use the same socket, as some programs
-                  (particularly rdist) seem to depend on it. */
+               /*
+                * Redirect stdin, stdout, and stderr.  Stdin and stdout will
+                * use the same socket, as some programs (particularly rdist)
+                * seem to depend on it.
+                */
                close(inout[1]);
                close(err[1]);
                if (dup2(inout[0], 0) < 0)      /* stdin */
@@ -1955,36 +2004,15 @@ do_exec_no_pty(const char *command, struct passwd * pw,
        close(inout[0]);
        close(err[0]);
 
-       /* Enter the interactive session.  Note: server_loop must be able
-          to handle the case that fdin and fdout are the same. */
+       /*
+        * Enter the interactive session.  Note: server_loop must be able to
+        * handle the case that fdin and fdout are the same.
+        */
        server_loop(pid, inout[1], inout[1], err[1]);
        /* server_loop has closed inout[1] and err[1]. */
 #endif /* USE_PIPES */
 }
 
-struct pty_cleanup_context {
-       const char *ttyname;
-       int pid;
-};
-
-/*
- * Function to perform cleanup if we get aborted abnormally (e.g., due to a
- * dropped connection).
- */
-void 
-pty_cleanup_proc(void *context)
-{
-       struct pty_cleanup_context *cu = context;
-
-       debug("pty_cleanup_proc called");
-
-       /* Record that the user has logged out. */
-       record_logout(cu->pid, cu->ttyname);
-
-       /* Release the pseudo-tty. */
-       pty_release(cu->ttyname);
-}
-
 /*
  * This is called to fork and execute a command when we have a tty.  This
  * will call do_child from the child, and server_loop from the parent after
@@ -2005,21 +2033,28 @@ 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. */
        hostname = get_canonical_hostname();
 
-       /* Get the time when the user last logged in.  Buf will be set to
-          contain the hostname the last login was from. */
+       /*
+        * Get the time when the user last logged in.  Buf will be set to
+        * contain the hostname the last login was from.
+        */
        if (!options.use_login) {
                last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
                                                      buf, sizeof(buf));
        }
        setproctitle("%s@%s", pw->pw_name, strrchr(ttyname, '/') + 1);
 
+#ifdef USE_PAM
+                       do_pam_session(pw->pw_name, ttyname);
+                       do_pam_setcred();
+#endif /* USE_PAM */
+
        /* Fork the child. */
        if ((pid = fork()) == 0) {
                pid = getpid();
@@ -2049,9 +2084,11 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
                /* Close the extra descriptor for the pseudo tty. */
                close(ttyfd);
 
-               /* Get IP address of client.  This is needed because we
-                  want to record where the user logged in from.  If the
-                  connection is not a socket, let the ip address be 0.0.0.0. */
+               /*
+                * Get IP address of client.  This is needed because we want
+                * to record where the user logged in from.  If the
+                * connection is not a socket, let the ip address be 0.0.0.0.
+                */
                memset(&from, 0, sizeof(from));
                if (packet_get_connection_in() == packet_get_connection_out()) {
                        fromlen = sizeof(from);
@@ -2063,24 +2100,25 @@ 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
-
-               /* If the user has logged in before, display the time of
-                  last login. However, don't display anything extra if a
-                  command has been specified (so that ssh can be used to
-                  execute commands on a remote machine without users
-                  knowing they are going to another machine). Login(1)
-                  will do this for us as well, so check if login(1) is used */
+#ifdef USE_PAM
+               if (!quiet_login)
+                       print_pam_messages();
+#endif /* USE_PAM */
+
+               /*
+                * If the user has logged in before, display the time of last
+                * login. However, don't display anything extra if a command
+                * has been specified (so that ssh can be used to execute
+                * commands on a remote machine without users knowing they
+                * are going to another machine). Login(1) will do this for
+                * us as well, so check if login(1) is used
+                */
                if (command == NULL && last_login_time != 0 && !quiet_login &&
                    !options.use_login) {
                        /* Convert the date to a string. */
@@ -2095,10 +2133,12 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
                        else
                                printf("Last login: %s from %s\r\n", time_string, buf);
                }
-               /* Print /etc/motd unless a command was specified or
-                  printing it was disabled in server options or login(1)
-                  will be used.  Note that some machines appear to print
-                  it in /etc/profile or similar. */
+               /*
+                * Print /etc/motd unless a command was specified or printing
+                * it was disabled in server options or login(1) will be
+                * used.  Note that some machines appear to print it in
+                * /etc/profile or similar.
+                */
                if (command == NULL && options.print_motd && !quiet_login &&
                    !options.use_login) {
                        /* Print /etc/motd if it exists. */
@@ -2118,18 +2158,23 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
        /* Parent.  Close the slave side of the pseudo tty. */
        close(ttyfd);
 
-       /* Create another descriptor of the pty master side for use as the
-          standard input.  We could use the original descriptor, but this
-          simplifies code in server_loop.  The descriptor is bidirectional. */
-       fdout = dup(ptyfd);
-       if (fdout < 0)
-               packet_disconnect("dup failed: %.100s", strerror(errno));
-
-       /* Add a cleanup function to clear the utmp entry and record logout
-          time in case we call fatal() (e.g., the connection gets closed). */
+       /*
+        * Add a cleanup function to clear the utmp entry and record logout
+        * time in case we call fatal() (e.g., the connection gets closed).
+        */
        cleanup_context.pid = pid;
        cleanup_context.ttyname = ttyname;
        fatal_add_cleanup(pty_cleanup_proc, (void *) &cleanup_context);
+       fatal_remove_cleanup(pty_release_proc, (void *) ttyname);
+
+       /*
+        * Create another descriptor of the pty master side for use as the
+        * standard input.  We could use the original descriptor, but this
+        * simplifies code in server_loop.  The descriptor is bidirectional.
+        */
+       fdout = dup(ptyfd);
+       if (fdout < 0)
+               packet_disconnect("dup failed: %.100s", strerror(errno));
 
        /* Enter interactive session. */
        server_loop(pid, ptyfd, fdout, -1);
@@ -2144,9 +2189,11 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
        /* Release the pseudo-tty. */
        pty_release(ttyname);
 
-       /* Close the server side of the socket pairs.  We must do this
-          after the pty cleanup, so that another process doesn't get this
-          pty while we're still cleaning up. */
+       /*
+        * Close the server side of the socket pairs.  We must do this after
+        * the pty cleanup, so that another process doesn't get this pty
+        * while we're still cleaning up.
+        */
        close(ptyfd);
        close(fdout);
 }
@@ -2162,19 +2209,21 @@ child_set_env(char ***envp, unsigned int *envsizep, const char *name,
        unsigned int i, namelen;
        char **env;
 
-       /* Find the slot where the value should be stored.  If the
-          variable already exists, we reuse the slot; otherwise we append
-          a new slot at the end of the array, expanding if necessary. */
+       /*
+        * Find the slot where the value should be stored.  If the variable
+        * already exists, we reuse the slot; otherwise we append a new slot
+        * at the end of the array, expanding if necessary.
+        */
        env = *envp;
        namelen = strlen(name);
        for (i = 0; env[i]; i++)
                if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
                        break;
        if (env[i]) {
-               /* Name already exists.  Reuse the slot. */
+               /* Reuse the slot. */
                xfree(env[i]);
        } else {
-               /* New variable.  Expand the array if necessary. */
+               /* New variable.  Expand if necessary. */
                if (i >= (*envsizep) - 1) {
                        (*envsizep) += 50;
                        env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
@@ -2202,43 +2251,63 @@ read_environment_file(char ***env, unsigned int *envsize,
        char buf[4096];
        char *cp, *value;
 
-       /* Open the environment file. */
        f = fopen(filename, "r");
        if (!f)
                return;
 
-       /* Process each line. */
        while (fgets(buf, sizeof(buf), f)) {
-               /* Skip leading whitespace. */
-               for (cp = buf; *cp == ' ' || *cp == '\t'; cp++);
-
-               /* Ignore empty and comment lines. */
+               for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
                if (!*cp || *cp == '#' || *cp == '\n')
                        continue;
-
-               /* Remove newline. */
                if (strchr(cp, '\n'))
                        *strchr(cp, '\n') = '\0';
-
-               /* Find the equals sign.  Its lack indicates badly
-                  formatted line. */
                value = strchr(cp, '=');
                if (value == NULL) {
                        fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
                        continue;
                }
-               /* Replace the equals sign by nul, and advance value to
-                  the value string. */
+               /* Replace the equals sign by nul, and advance value to the value string. */
                *value = '\0';
                value++;
-
-               /* Set the value in environment. */
                child_set_env(env, envsize, cp, value);
        }
-
        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
@@ -2258,7 +2327,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) {
@@ -2269,13 +2338,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"
@@ -2299,8 +2366,10 @@ do_child(const char *command, struct passwd * pw, const char *term,
                if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
                        fatal("Failed to set uids to %d.", (int) pw->pw_uid);
        }
-       /* Get the shell from the password data.  An empty shell field is
-          legal, and means /bin/sh. */
+       /*
+        * Get the shell from the password data.  An empty shell field is
+        * legal, and means /bin/sh.
+        */
        shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
 
 #ifdef AFS
@@ -2315,8 +2384,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
        }
 #endif /* AFS */
 
-       /* Initialize the environment.  In the first part we allocate
-          space for all environment variables. */
+       /* Initialize the environment. */
        envsize = 100;
        env = xmalloc(envsize * sizeof(char *));
        env[0] = NULL;
@@ -2335,7 +2403,6 @@ do_child(const char *command, struct passwd * pw, const char *term,
                /* Normal systems set SHELL by default. */
                child_set_env(&env, &envsize, "SHELL", shell);
        }
-       /* Let it inherit timezone if we have one. */
        if (getenv("TZ"))
                child_set_env(&env, &envsize, "TZ", getenv("TZ"));
 
@@ -2354,23 +2421,29 @@ do_child(const char *command, struct passwd * pw, const char *term,
                xfree(ce);
        }
 
-       /* Set SSH_CLIENT. */
        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);
 
-       /* Set SSH_TTY if we have a pty. */
        if (ttyname)
                child_set_env(&env, &envsize, "SSH_TTY", ttyname);
-
-       /* Set TERM if we have a pty. */
        if (term)
                child_set_env(&env, &envsize, "TERM", term);
-
-       /* Set DISPLAY if we have one. */
        if (display)
                child_set_env(&env, &envsize, "DISPLAY", display);
 
+#ifdef _AIX
+       {
+           char *authstate,*krb5cc;
+
+          if ((authstate = getenv("AUTHSTATE")) != NULL)
+                child_set_env(&env,&envsize,"AUTHSTATE",authstate);
+
+          if ((krb5cc = getenv("KRB5CCNAME")) != NULL)
+                child_set_env(&env,&envsize,"KRB5CCNAME",krb5cc);
+       }
+#endif
+
 #ifdef KRB4
        {
                extern char *ticket;
@@ -2380,72 +2453,63 @@ 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))
-                       {
-                               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 */
 
-       /* Set XAUTHORITY to always be a local file. */
        if (xauthfile)
                child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
 
-       /* Set variable for forwarded authentication connection, if we
-          have one. */
        if (auth_get_socket_name() != NULL)
                child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
                              auth_get_socket_name());
 
-       /* Read $HOME/.ssh/environment. */
+       read_environment_file(&env,&envsize,"/etc/environment");
+
+       /* read $HOME/.ssh/environment. */
        if (!options.use_login) {
                snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir);
                read_environment_file(&env, &envsize, buf);
        }
-       /* If debugging, dump the environment to stderr. */
        if (debug_flag) {
+               /* dump the environment */
                fprintf(stderr, "Environment:\n");
                for (i = 0; env[i]; i++)
                        fprintf(stderr, "  %.200s\n", env[i]);
        }
-       /* Close the connection descriptors; note that this is the child,
-          and the server will still have the socket open, and it is
-          important that we do not shutdown it.  Note that the
-          descriptors cannot be closed before building the environment,
-          as we call get_remote_ipaddr there. */
+       /*
+        * Close the connection descriptors; note that this is the child, and
+        * the server will still have the socket open, and it is important
+        * that we do not shutdown it.  Note that the descriptors cannot be
+        * closed before building the environment, as we call
+        * get_remote_ipaddr there.
+        */
        if (packet_get_connection_in() == packet_get_connection_out())
                close(packet_get_connection_in());
        else {
                close(packet_get_connection_in());
                close(packet_get_connection_out());
        }
-       /* Close all descriptors related to channels.  They will still
-          remain open in the parent. */
+       /*
+        * Close all descriptors related to channels.  They will still remain
+        * open in the parent.
+        */
+       /* XXX better use close-on-exec? -markus */
        channel_close_all();
 
-       /* Close any extra file descriptors.  Note that there may still be
-          descriptors left by system functions.  They will be closed
-          later. */
+       /*
+        * Close any extra file descriptors.  Note that there may still be
+        * 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 hanging around in clients.  Note that we want to do this
-          after initgroups, because at least on Solaris 2.3 it leaves
-          file descriptors open. */
+       /*
+        * Close any extra open file descriptors so that we don\'t have them
+        * hanging around in clients.  Note that we want to do this after
+        * initgroups, because at least on Solaris 2.3 it leaves file
+        * descriptors open.
+        */
        for (i = 3; i < 64; i++)
                close(i);
 
@@ -2454,12 +2518,16 @@ do_child(const char *command, struct passwd * pw, const char *term,
                fprintf(stderr, "Could not chdir to home directory %s: %s\n",
                        pw->pw_dir, strerror(errno));
 
-       /* Must take new environment into use so that .ssh/rc, /etc/sshrc
-          and xauth are run in the proper environment. */
+       /*
+        * Must take new environment into use so that .ssh/rc, /etc/sshrc and
+        * xauth are run in the proper environment.
+        */
        environ = env;
 
-       /* Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found
-          first in this order). */
+       /*
+        * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
+        * in this order).
+        */
        if (!options.use_login) {
                if (stat(SSH_USER_RC, &st) >= 0) {
                        if (debug_flag)
@@ -2486,8 +2554,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
                }
 #ifdef XAUTH_PATH
                else {
-                       /* Add authority data to .Xauthority if
-                          appropriate. */
+                       /* Add authority data to .Xauthority if appropriate. */
                        if (auth_proto != NULL && auth_data != NULL) {
                                if (debug_flag)
                                        fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n",
@@ -2510,15 +2577,19 @@ do_child(const char *command, struct passwd * pw, const char *term,
                else
                        cp = shell;
        }
-       /* If we have no command, execute the shell.  In this case, the
-          shell name to be passed in argv[0] is preceded by '-' to
-          indicate that this is a login shell. */
+       /*
+        * If we have no command, execute the shell.  In this case, the shell
+        * name to be passed in argv[0] is preceded by '-' to indicate that
+        * this is a login shell.
+        */
        if (!command) {
                if (!options.use_login) {
                        char buf[256];
 
-                       /* Check for mail if we have a tty and it was
-                          enabled in server options. */
+                       /*
+                        * Check for mail if we have a tty and it was enabled
+                        * in server options.
+                        */
                        if (ttyname && options.check_mail) {
                                char *mailbox;
                                struct stat mailstat;
@@ -2558,8 +2629,10 @@ do_child(const char *command, struct passwd * pw, const char *term,
                        exit(1);
                }
        }
-       /* Execute the command using the user's shell.  This uses the -c
-          option to execute the command. */
+       /*
+        * Execute the command using the user's shell.  This uses the -c
+        * option to execute the command.
+        */
        argv[0] = (char *) cp;
        argv[1] = "-c";
        argv[2] = (char *) command;
This page took 0.128866 seconds and 4 git commands to generate.