- Merged more OpenBSD CVS changes:
        [auth-krb4.c]
          - disconnect if getpeername() fails
          - missing xfree(*client)
        [canohost.c]
          - disconnect if getpeername() fails
          - fix comment: we _do_ disconnect if ip-options are set
        [sshd.c]
          - disconnect if getpeername() fails
          - move checking of remote port to central place
        [auth-rhosts.c] move checking of remote port to central place
        [log-server.c] avoid extra fd per sshd, from millert@
        [readconf.c] print _all_ bad config-options in ssh(1), too
        [readconf.h] print _all_ bad config-options in ssh(1), too
        [ssh.c] print _all_ bad config-options in ssh(1), too
        [sshconnect.c] disconnect if getpeername() fails
 - OpenBSD's changes to sshd.c broke the PAM stuff, re-merged it.
diff --git a/ChangeLog b/ChangeLog
index 5289943..d1c75cc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,23 @@
  - Changed to ssh-add.c broke askpass support. Revised it to be a little more
    modular. 
  - Revised autoconf support for enabling/disabling askpass support.
+ - Merged more OpenBSD CVS changes:
+	[auth-krb4.c]
+	  - disconnect if getpeername() fails
+	  - missing xfree(*client)
+	[canohost.c]
+	  - disconnect if getpeername() fails
+	  - fix comment: we _do_ disconnect if ip-options are set
+	[sshd.c]
+	  - disconnect if getpeername() fails
+	  - move checking of remote port to central place
+	[auth-rhosts.c] move checking of remote port to central place
+	[log-server.c] avoid extra fd per sshd, from millert@
+	[readconf.c] print _all_ bad config-options in ssh(1), too
+	[readconf.h] print _all_ bad config-options in ssh(1), too
+	[ssh.c] print _all_ bad config-options in ssh(1), too
+	[sshconnect.c] disconnect if getpeername() fails
+ - OpenBSD's changes to sshd.c broke the PAM stuff, re-merged it.
 
 19991114
  - Solaris compilation fixes (still imcomplete)
diff --git a/auth-krb4.c b/auth-krb4.c
index 0320523..72acd47 100644
--- a/auth-krb4.c
+++ b/auth-krb4.c
@@ -6,7 +6,7 @@
 
    Kerberos v4 authentication and ticket-passing routines.
 
-   $Id: auth-krb4.c,v 1.3 1999/11/11 06:57:39 damien Exp $
+   $Id: auth-krb4.c,v 1.4 1999/11/15 04:25:10 damien Exp $
 */
 
 #include "includes.h"
@@ -89,8 +89,10 @@
     debug("getsockname failed: %.100s", strerror(errno));
   r = sizeof(foreign);
   memset(&foreign, 0, sizeof(foreign));
-  if (getpeername(s, (struct sockaddr *)&foreign, &r) < 0)
+  if (getpeername(s, (struct sockaddr *)&foreign, &r) < 0) {
     debug("getpeername failed: %.100s", strerror(errno));
+    fatal_cleanup();
+  }
   
   instance[0] = '*'; instance[1] = 0;
   
@@ -110,6 +112,7 @@
     packet_send_debug("Kerberos V4 .klogin authorization failed!");
     log("Kerberos V4 .klogin authorization failed for %s to account %s",
 	*client, server_user);
+    xfree(*client);
     return 0;
   }
   /* Increment the checksum, and return it encrypted with the session key. */
diff --git a/auth-rhosts.c b/auth-rhosts.c
index 7e5614c..8f6655d 100644
--- a/auth-rhosts.c
+++ b/auth-rhosts.c
@@ -16,7 +16,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: auth-rhosts.c,v 1.2 1999/11/12 04:19:27 damien Exp $");
+RCSID("$Id: auth-rhosts.c,v 1.3 1999/11/15 04:25:10 damien Exp $");
 
 #include "packet.h"
 #include "ssh.h"
@@ -161,7 +161,6 @@
   extern ServerOptions options;
   char buf[1024];
   const char *hostname, *ipaddr;
-  int port;
   struct stat st;
   static const char *rhosts_files[] = { ".shosts", ".rhosts", NULL };
   unsigned int rhosts_file_index;
@@ -190,21 +189,6 @@
   /* Get the name, address, and port of the remote host.  */
   hostname = get_canonical_hostname();
   ipaddr = get_remote_ipaddr();
-  port = get_remote_port();
-
-  /* Check that the connection comes from a privileged port.
-     Rhosts authentication only makes sense for priviledged programs.
-     Of course, if the intruder has root access on his local machine,
-     he can connect from any port.  So do not use .rhosts
-     authentication from machines that you do not trust. */
-  if (port >= IPPORT_RESERVED ||
-      port < IPPORT_RESERVED / 2)
-    {
-      log("Connection from %.100s from nonpriviledged port %d",
-	  hostname, port);
-      packet_send_debug("Your ssh client is not running as root.");
-      return 0;
-    }
 
   /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
   if (pw->pw_uid != 0)
diff --git a/canohost.c b/canohost.c
index 85d9729..08f7987 100644
--- a/canohost.c
+++ b/canohost.c
@@ -14,7 +14,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: canohost.c,v 1.1 1999/10/27 03:42:43 damien Exp $");
+RCSID("$Id: canohost.c,v 1.2 1999/11/15 04:25:10 damien Exp $");
 
 #include "packet.h"
 #include "xmalloc.h"
@@ -35,9 +35,8 @@
   memset(&from, 0, sizeof(from));
   if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0)
     {
-      error("getpeername failed: %.100s", strerror(errno));
-      strlcpy(name, "UNKNOWN", sizeof name);
-      goto check_ip_options;
+      debug("getpeername failed: %.100s", strerror(errno));
+      fatal_cleanup();
     }
   
   /* Map the IP address to a host name. */
@@ -99,7 +98,7 @@
 
  check_ip_options:
   
-  /* If IP options are supported, make sure there are none (log and clear
+  /* If IP options are supported, make sure there are none (log and disconnect
      them if any are found).  Basically we are worried about source routing;
      it can be used to pretend you are somebody (ip-address) you are not.
      That itself may be "almost acceptable" under certain circumstances,
@@ -184,8 +183,8 @@
   memset(&from, 0, sizeof(from));
   if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0)
     {
-      error("getpeername failed: %.100s", strerror(errno));
-      return NULL;
+      debug("getpeername failed: %.100s", strerror(errno));
+      fatal_cleanup();
     }
 
   /* Get the IP address in ascii. */
@@ -207,8 +206,8 @@
   memset(&from, 0, sizeof(from));
   if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0)
     {
-      error("getpeername failed: %.100s", strerror(errno));
-      return 0;
+      debug("getpeername failed: %.100s", strerror(errno));
+      fatal_cleanup();
     }
 
   /* Return port number. */
diff --git a/log-server.c b/log-server.c
index 6642dbe..805df6b 100644
--- a/log-server.c
+++ b/log-server.c
@@ -15,7 +15,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: log-server.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
+RCSID("$Id: log-server.c,v 1.3 1999/11/15 04:25:10 damien Exp $");
 
 #include <syslog.h>
 #include "packet.h"
@@ -24,6 +24,7 @@
 
 static LogLevel log_level = SYSLOG_LEVEL_INFO;
 static int log_on_stderr = 0;
+static int log_facility = LOG_AUTH;
 
 /* Initialize the log.
      av0	program name (should be argv[0])
@@ -33,7 +34,6 @@
 
 void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
 {
-  int log_facility;
   
   switch (level)
     {
@@ -93,8 +93,6 @@
     }
 
   log_on_stderr = on_stderr;
-  closelog(); /* Close any previous log. */
-  openlog(av0, LOG_PID, log_facility);
 }
 
 #define MSGBUFSIZE 1024
@@ -106,6 +104,7 @@
   char fmtbuf[MSGBUFSIZE];
   char *txt = NULL;
   int pri = LOG_INFO;
+  extern char *__progname;
 
   if (level > log_level)
     return;
@@ -143,5 +142,7 @@
   }
   if (log_on_stderr)
     fprintf(stderr, "%s\n", msgbuf);
+  openlog(__progname, LOG_PID, log_facility);
   syslog(pri, "%.500s", msgbuf);
+  closelog();
 }
diff --git a/readconf.c b/readconf.c
index 2a99266..b341322 100644
--- a/readconf.c
+++ b/readconf.c
@@ -14,7 +14,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: readconf.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
+RCSID("$Id: readconf.c,v 1.3 1999/11/15 04:25:10 damien Exp $");
 
 #include "ssh.h"
 #include "cipher.h"
@@ -88,6 +88,7 @@
 
 typedef enum
 {
+  oBadOption,
   oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
   oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
 #ifdef KRB4
@@ -222,16 +223,16 @@
     if (strcmp(cp, keywords[i].name) == 0)
       return keywords[i].opcode;
 
-  fatal("%.200s line %d: Bad configuration option.",
-	filename, linenum);
-  /*NOTREACHED*/
-  return 0;
+  fprintf(stderr, "%s: line %d: Bad configuration option: %s\n", 
+	  filename, linenum, cp);
+  return oBadOption;
 }
 
 /* Processes a single option line as used in the configuration files.
    This only sets those values that have not already been set. */
 
-void process_config_line(Options *options, const char *host,
+int
+process_config_line(Options *options, const char *host,
 			 char *line, const char *filename, int linenum,
 			 int *activep)
 {
@@ -241,7 +242,7 @@
   /* Skip leading whitespace. */
   cp = line + strspn(line, WHITESPACE);
   if (!*cp || *cp == '\n' || *cp == '#')
-    return;
+    return 0;
 
   /* Get the keyword. (Each line is supposed to begin with a keyword). */
   cp = strtok(cp, WHITESPACE);
@@ -256,7 +257,9 @@
 
   switch (opcode)
     {
-
+    case oBadOption:
+      return -1;		/* don't panic, but count bad options */
+      /*NOTREACHED*/
     case oForwardAgent:
       intptr = &options->forward_agent;
     parse_flag:
@@ -426,7 +429,7 @@
 	*charptr = string;
       else
 	xfree(string);
-      return;
+      return 0;
 
     case oPort:
       intptr = &options->port;
@@ -533,7 +536,7 @@
 	    break;
 	  }
       /* Avoid garbage check below, as strtok already returned NULL. */
-      return;
+      return 0;
 
     case oEscapeChar:
       intptr = &options->escape_char;
@@ -561,13 +564,14 @@
       break;
       
     default:
-      fatal("parse_config_file: Unimplemented opcode %d", opcode);
+      fatal("process_config_line: Unimplemented opcode %d", opcode);
     }
   
   /* Check that there is no garbage at end of line. */
   if (strtok(NULL, WHITESPACE) != NULL)
     fatal("%.200s line %d: garbage at end of line.",
 	  filename, linenum);
+  return 0;
 }
 
 
@@ -580,6 +584,7 @@
   FILE *f;
   char line[1024];
   int active, linenum;
+  int bad_options = 0;
 
   /* Open the file. */
   f = fopen(filename, "r");
@@ -596,10 +601,13 @@
     {
       /* Update line number counter. */
       linenum++;
-
-      process_config_line(options, host, line, filename, linenum, &active);
+      if (process_config_line(options, host, line, filename, linenum, &active) != 0)
+	bad_options++;
     }
   fclose(f);
+  if (bad_options > 0)
+    fatal("%s: terminating, %d bad configuration options\n", 
+          filename, bad_options);
 }
 
 /* Initializes options to special values that indicate that they have not
diff --git a/readconf.h b/readconf.h
index 8839a1b..d2d387d 100644
--- a/readconf.h
+++ b/readconf.h
@@ -13,7 +13,7 @@
 
 */
 
-/* RCSID("$Id: readconf.h,v 1.2 1999/11/11 06:57:39 damien Exp $"); */
+/* RCSID("$Id: readconf.h,v 1.3 1999/11/15 04:25:10 damien Exp $"); */
 
 #ifndef READCONF_H
 #define READCONF_H
@@ -92,8 +92,9 @@
 void fill_default_options(Options *options);
 
 /* Processes a single option line as used in the configuration files. 
-   This only sets those values that have not already been set. */
-void process_config_line(Options *options, const char *host,
+   This only sets those values that have not already been set.
+   Returns 0 for legal options */
+int process_config_line(Options *options, const char *host,
 			 char *line, const char *filename, int linenum,
 			 int *activep);
 
diff --git a/ssh.c b/ssh.c
index a8a806b..2f3b5fc 100644
--- a/ssh.c
+++ b/ssh.c
@@ -18,7 +18,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: ssh.c,v 1.7 1999/11/13 02:28:45 damien Exp $");
+RCSID("$Id: ssh.c,v 1.8 1999/11/15 04:25:10 damien Exp $");
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -383,8 +383,9 @@
 
 	case 'o':
 	  dummy = 1;
-	  process_config_line(&options, host ? host : "", optarg,
-			      "command-line", 0, &dummy);
+	  if (process_config_line(&options, host ? host : "", optarg,
+			          "command-line", 0, &dummy) != 0)
+            exit(1);
 	  break;
 
 	default:
diff --git a/sshconnect.c b/sshconnect.c
index 0331845..f984bca 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -15,7 +15,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: sshconnect.c,v 1.7 1999/11/12 23:51:58 damien Exp $");
+RCSID("$Id: sshconnect.c,v 1.8 1999/11/15 04:25:10 damien Exp $");
 
 #ifdef HAVE_OPENSSL
 #include <openssl/bn.h>
@@ -730,8 +730,10 @@
   r = sizeof(foreign);
   memset(&foreign, 0, sizeof(foreign));
    if (getpeername(packet_get_connection_in(),
-		   (struct sockaddr *)&foreign, &r) < 0)
+		   (struct sockaddr *)&foreign, &r) < 0) {
      debug("getpeername failed: %s", strerror(errno));
+     fatal_cleanup();
+   }
    
    /* Get server reply. */
    type = packet_read(&plen);
diff --git a/sshd.c b/sshd.c
index b975c8d..a0cc466 100644
--- a/sshd.c
+++ b/sshd.c
@@ -18,7 +18,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: sshd.c,v 1.17 1999/11/12 04:19:27 damien Exp $");
+RCSID("$Id: sshd.c,v 1.18 1999/11/15 04:25:10 damien Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -114,9 +114,10 @@
 RSA *public_key;
 
 /* Prototypes for various functions defined later in this file. */
-void do_connection(int privileged_port);
-void do_authentication(char *user, int privileged_port);
-void eat_packets_and_disconnect(const char *user);
+void do_connection();
+void do_authentication(char *user);
+void do_authloop(struct passwd *pw);
+void do_fake_authloop(char *user);
 void do_authenticated(struct passwd *pw);
 void do_exec_pty(const char *command, int ptyfd, int ttyfd, 
 		 const char *ttyname, struct passwd *pw, const char *term,
@@ -128,11 +129,12 @@
 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(const char *username, const char *password, 
-                           const char *remote_user, const char *remote_host);
+		struct pam_response **resp, void *appdata_ptr);
+void do_pam_account_and_session(const char *username, 
+		const char *remote_user, const char *remote_host);
 void pam_cleanup_proc(void *context);
 
 static struct pam_conv conv = {
@@ -228,7 +230,7 @@
   }
 }
 
-void do_pam_account_and_session(const char *username, const char *password, const char *remote_user, const char *remote_host)
+void do_pam_account_and_session(const char *username, const char *remote_user, const char *remote_host)
 {
   int pam_retval;
   
@@ -239,7 +241,7 @@
     if (pam_retval != PAM_SUCCESS)
     {
       log("PAM set rhost failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
-	   eat_packets_and_disconnect(username);
+	   do_fake_authloop(username);
     }
   }
   
@@ -250,7 +252,7 @@
     if (pam_retval != PAM_SUCCESS)
     {
       log("PAM set ruser failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
-	   eat_packets_and_disconnect(username);
+	   do_fake_authloop(username);
     }
   }
   
@@ -258,14 +260,14 @@
   if (pam_retval != PAM_SUCCESS)
   {
     log("PAM rejected by account configuration: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
-	 eat_packets_and_disconnect(username);
+	 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));
-	 eat_packets_and_disconnect(username);
+	 do_fake_authloop(username);
   }
 }
 #endif /* HAVE_LIBPAM */
@@ -375,6 +377,7 @@
   struct sockaddr_in sin;
   char buf[100]; /* Must not be larger than remote_version. */
   char remote_version[100]; /* Must be at least as big as buf. */
+  int remote_port;
   char *comment;
   FILE *f;
   struct linger linger;
@@ -742,6 +745,8 @@
      have a key. */
   packet_set_connection(sock_in, sock_out);
 
+  remote_port = get_remote_port();
+
   /* Check whether logins are denied from this host. */
 #ifdef LIBWRAP
   {
@@ -755,13 +760,11 @@
       close(sock_out);
       refuse(&req);
     }
-    log("Connection from %.500s port %d",
-	eval_client(&req), get_remote_port());
+    log("Connection from %.500s port %d", eval_client(&req), remote_port);
   }
 #else
   /* Log the connection. */
-  log("Connection from %.100s port %d", 
-      get_remote_ipaddr(), get_remote_port());
+  log("Connection from %.100s port %d", get_remote_ipaddr(), remote_port);
 #endif /* LIBWRAP */
 
   /* We don\'t want to listen forever unless the other side successfully
@@ -834,11 +837,23 @@
     }
   }
 
+  /* 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;
+    }
+
   packet_set_nonblocking();
   
-  /* Handle the connection.   We pass as argument whether the connection
-     came from a privileged port. */
-  do_connection(get_remote_port() < IPPORT_RESERVED);
+  /* Handle the connection. */
+  do_connection();
 
 #ifdef KRB4
   /* Cleanup user's ticket cache file. */
@@ -879,7 +894,8 @@
    been exchanged.  This sends server key and performs the key exchange.
    Server and host keys will no longer be needed after this functions. */
 
-void do_connection(int privileged_port)
+void
+do_connection()
 {
   int i, len;
   BIGNUM *session_key_int;
@@ -1071,7 +1087,7 @@
 
   setproctitle("%s", user);
   /* Do the authentication. */
-  do_authentication(user, privileged_port);
+  do_authentication(user);
 }
 
 /* Check if the user is allowed to log in via ssh. If user is listed in
@@ -1154,26 +1170,13 @@
 
 /* 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 clinet).  Privileged_port is true if the
-   connection comes from a privileged port (used for .rhosts authentication).*/
-
-#define MAX_AUTH_FAILURES 5
+   in as (received from the client). */
 
 void
-do_authentication(char *user, int privileged_port)
+do_authentication(char *user)
 {
-  int type;
-  int authenticated = 0;
-  int authentication_failures = 0;
-  char *password = NULL;
   struct passwd *pw, pwcopy;
-  char *client_user = NULL;
-  unsigned int client_host_key_bits;
-  BIGNUM *client_host_key_e, *client_host_key_n;
-#ifdef HAVE_LIBPAM
-  int pam_retval;
-#endif /* HAVE_LIBPAM */
-  			 
+
 #ifdef AFS
   /* If machine has AFS, set process authentication group. */
   if (k_hasafs()) {
@@ -1185,8 +1188,8 @@
   /* Verify that the user is a valid user. */
   pw = getpwnam(user);
   if (!pw || !allowed_user(pw))
-    eat_packets_and_disconnect(user);
-	   
+    do_fake_authloop(user);
+  
   /* Take a copy of the returned structure. */
   memset(&pwcopy, 0, sizeof(pwcopy));
   pwcopy.pw_name = xstrdup(pw->pw_name);
@@ -1199,13 +1202,11 @@
 
 #ifdef HAVE_LIBPAM
   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)
-  {
-    log("PAM initialisation failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
-    eat_packets_and_disconnect(user);
-  }
- fatal_add_cleanup(&pam_cleanup_proc, NULL);
+
+  if (pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh) != PAM_SUCCESS)
+    fatal("PAM initialisation failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
+
+  fatal_add_cleanup(&pam_cleanup_proc, NULL);
 #endif
 
   /* If we are not running as root, the user must have the same uid as the
@@ -1224,300 +1225,13 @@
     {
       /* Authentication with empty password succeeded. */
       debug("Login for user %.100s accepted without authentication.", user);
-      /* authentication_type = SSH_AUTH_PASSWORD; */
-      authenticated = 1;
-      /* Success packet will be sent after loop below. */
-    }
-  else
-    {
-      /* Indicate that authentication is needed. */
-      packet_start(SSH_SMSG_FAILURE);
-      packet_send();
-      packet_write_wait();
+    } else {
+      /* Loop until the user has been authenticated or the connection is closed,
+         do_authloop() returns only if authentication is successfull */
+      do_authloop(pw);
     }
 
-  /* Loop until the user has been authenticated or the connection is closed. */
-  while (!authenticated)
-    {
-      int plen;
-      /* Get a packet from the client. */
-      type = packet_read(&plen);
-      
-      /* Process the packet. */
-      switch (type)
-	{
-
-#ifdef AFS
-	case SSH_CMSG_HAVE_KERBEROS_TGT:
-	  if (!options.kerberos_tgt_passing)
-	    {
-	      /* packet_get_all(); */
-	      log("Kerberos tgt passing disabled.");
-	      break;
-	    }
-	  else {
-	    /* Accept Kerberos tgt. */
-	    int dlen;
-	    char *tgt = packet_get_string(&dlen);
-	    packet_integrity_check(plen, 4 + dlen, type);
-	    if (!auth_kerberos_tgt(pw, tgt))
-	      debug("Kerberos tgt REFUSED for %s", user);
-	    xfree(tgt);
-	  }
-	  continue;
-
-	case SSH_CMSG_HAVE_AFS_TOKEN:
-	  if (!options.afs_token_passing || !k_hasafs()) {
-	    /* packet_get_all(); */
-	    log("AFS token passing disabled.");
-	    break;
-	  }
-	  else {
-	    /* Accept AFS token. */
-	    int dlen;
-	    char *token_string = packet_get_string(&dlen);
-	    packet_integrity_check(plen, 4 + dlen, type);
-	    if (!auth_afs_token(pw, token_string))
-	      debug("AFS token REFUSED for %s", user);
-	    xfree(token_string);
-	    continue;
-	  }
-#endif /* AFS */
-	  
-#ifdef KRB4
-	case SSH_CMSG_AUTH_KERBEROS:
-	  if (!options.kerberos_authentication)
-	    {
-	      /* packet_get_all(); */
-	      log("Kerberos authentication disabled.");
-	      break;
-	    }
-	  else {
-	    /* Try Kerberos v4 authentication. */
-	    KTEXT_ST auth;
-	    char *tkt_user = NULL;
-	    char *kdata = packet_get_string((unsigned int *)&auth.length);
-	    packet_integrity_check(plen, 4 + auth.length, type);
-
-	    if (auth.length < MAX_KTXT_LEN)
-	      memcpy(auth.dat, kdata, auth.length);
-	    xfree(kdata);
-	    
-	    if (auth_krb4(user, &auth, &tkt_user)) {
-	      /* Client has successfully authenticated to us. */
-	      log("Kerberos authentication accepted %s for account "
-		  "%s from %s", tkt_user, user, get_canonical_hostname());
-	      /* authentication_type = SSH_AUTH_KERBEROS; */
-	      authenticated = 1;
-	      xfree(tkt_user);
-	    }
-	    else {
-	      log("Kerberos authentication failed for account "
-		  "%s from %s", user, get_canonical_hostname());
-	    }
-	  }
-	  break;
-#endif /* KRB4 */
-	  
-	case SSH_CMSG_AUTH_RHOSTS:
-	  if (!options.rhosts_authentication)
-	    {
-	      log("Rhosts authentication disabled.");
-	      break;
-	    }
-
-	  /* Rhosts authentication (also uses /etc/hosts.equiv). */
-	  if (!privileged_port)
-	    {
-	      log("Rhosts authentication not available for connections from unprivileged port.");
-	      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.) */
-	  {
-	    int dlen;
-	    client_user = packet_get_string(&dlen);
-	    packet_integrity_check(plen, 4 + dlen, type);
-	  }
-
-	  /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
-	  if (auth_rhosts(pw, client_user))
-	    {
-	      /* Authentication accepted. */
-	      log("Rhosts authentication accepted for %.100s, remote %.100s on %.700s.",
-		  user, client_user, get_canonical_hostname());
-	      authenticated = 1;
-#ifndef HAVE_LIBPAM
-	      xfree(client_user);
-#endif /* HAVE_LIBPAM */
-	      break;
-	    }
-	  log("Rhosts authentication failed for %.100s, remote %.100s.",
-		user, client_user);
-#ifndef HAVE_LIBPAM
-	  xfree(client_user);
-#endif /* HAVE_LIBPAM */
-	  break;
-
-	case SSH_CMSG_AUTH_RHOSTS_RSA:
-	  if (!options.rhosts_rsa_authentication)
-	    {
-	      log("Rhosts with RSA authentication disabled.");
-	      break;
-	    }
-
-	  /* Rhosts authentication (also uses /etc/hosts.equiv) with RSA
-	     host authentication. */
-	  if (!privileged_port)
-	    {
-	      log("Rhosts authentication not available for connections from unprivileged port.");
-	      break;
-	    }
-
-	  {
-	    int ulen, elen, nlen;
-	    /* 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. */
-	    client_host_key_e = BN_new();
-	    client_host_key_n = BN_new();
-	    client_host_key_bits = packet_get_int();
-	    packet_get_bignum(client_host_key_e, &elen);
-	    packet_get_bignum(client_host_key_n, &nlen);
-
-	    packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
-	  }
-
-	  if (auth_rhosts_rsa(pw, client_user,
-			      client_host_key_bits, client_host_key_e, client_host_key_n))
-	    {
-	      /* Authentication accepted. */
-	      authenticated = 1;
-#ifndef HAVE_LIBPAM
-	      xfree(client_user);
-#endif /* HAVE_LIBPAM */
-	      BN_clear_free(client_host_key_e);
-	      BN_clear_free(client_host_key_n);
-	      break;
-	    }
-	  log("Rhosts authentication failed for %.100s, remote %.100s.",
-		user, client_user);
-#ifndef HAVE_LIBPAM
-          xfree(client_user);
-#endif /* HAVE_LIBPAM */
-	  BN_clear_free(client_host_key_e);
-	  BN_clear_free(client_host_key_n);
-	  break;
-	  
-	case SSH_CMSG_AUTH_RSA:
-	  if (!options.rsa_authentication)
-	    {
-	      log("RSA authentication disabled.");
-	      break;
-	    }
-
-	  /* RSA authentication requested. */
-	  {
-	    int nlen;
-	    BIGNUM *n;
-	    n = BN_new();
-	    packet_get_bignum(n, &nlen);
-
-	    packet_integrity_check(plen, nlen, type);
-	    
-	    if (auth_rsa(pw, n))
-	      { 
-		/* Successful authentication. */
-		BN_clear_free(n);
-		log("RSA authentication for %.100s accepted.", user);
-		authenticated = 1;
-		break;
-	      }
-	    BN_clear_free(n);
-	    log("RSA authentication for %.100s failed.", user);
-	  }
-	  break;
-
-	case SSH_CMSG_AUTH_PASSWORD:
-	  if (!options.password_authentication)
-	    {
-	      log("Password authentication disabled.");
-	      break;
-	    }
-
-	  /* Password authentication requested. */
-	  /* Read user password.  It is in plain text, but was transmitted
-	     over the encrypted channel so it is not visible to an outside
-	     observer. */
-	  {
-	    int passw_len;
-	    password = packet_get_string(&passw_len);
-	    packet_integrity_check(plen, 4 + passw_len, type);
-	  }
-
-#ifdef HAVE_LIBPAM
-          pampasswd = password;
-          
-	  pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
-          if (pam_retval == PAM_SUCCESS)
-          {
-            log("PAM Password authentication accepted for \"%.100s\"", user);
-            authenticated = 1;
-            break;
-          } else
-	  {
- 	    log("PAM Password authentication for \"%.100s\" failed: %s", 
-	        user, pam_strerror((pam_handle_t *)pamh, pam_retval));
-            break;
-	  }
-#else /* HAVE_LIBPAM */
-	  /* Try authentication with the password. */
-	  if (auth_password(pw, password))
-	    {
-	      /* Successful authentication. */
-	      /* Clear the password from memory. */
-	      memset(password, 0, strlen(password));
-	      xfree(password);
-	      log("Password authentication for %.100s accepted.", user);
-	      authenticated = 1;
-	      break;
-	    }
-	  log("Password authentication for %.100s failed.", user);
-	  memset(password, 0, strlen(password));
-	  xfree(password);
-	  break;
-#endif /* HAVE_LIBPAM */
-
-	case SSH_CMSG_AUTH_TIS:
-	  /* TIS Authentication is unsupported */
-	  log("TIS authentication disabled.");
-	  break;
-
-	default:
-	  /* Any unknown messages will be ignored (and failure returned)
-	     during authentication. */
-	  log("Unknown message during authentication: type %d", type);
-	  break; /* Respond with a failure message. */
-	}
-      /* If successfully authenticated, break out of loop. */
-      if (authenticated)
-	break;
-
-      if (++authentication_failures >= MAX_AUTH_FAILURES) {
-	packet_disconnect("Too many authentication failures for %.100s from %.200s", 
-          pw->pw_name, get_canonical_hostname());
-      }
-      /* Send a message indicating that the authentication attempt failed. */
-      packet_start(SSH_SMSG_FAILURE);
-      packet_send();
-      packet_write_wait();
-
-    }
+  /* XXX log unified auth message */
 
   /* Check if the user is logging in as root and root logins are disallowed. */
   if (pw->pw_uid == 0 && !options.permit_root_login)
@@ -1529,8 +1243,245 @@
 			  get_canonical_hostname());
     }
 
+  /* The user has been authenticated and accepted. */
+  packet_start(SSH_SMSG_SUCCESS);
+  packet_send();
+  packet_write_wait();
+
+  /* Perform session preparation. */
+  do_authenticated(pw);
+}
+
+#define MAX_AUTH_FAILURES 5
+
+/* read packets and try to authenticate local user *pw.
+   return if authentication is successfull */
+void
+do_authloop(struct passwd *pw)
+{
+  int authentication_failures = 0;
+  unsigned int client_host_key_bits;
+  BIGNUM *client_host_key_e, *client_host_key_n;
+  BIGNUM *n;
+  char *client_user, *password;
+  int plen, dlen, nlen, ulen, elen;
+
+  /* Indicate that authentication is needed. */
+  packet_start(SSH_SMSG_FAILURE);
+  packet_send();
+  packet_write_wait();
+
+  for (;;) {
+    int authenticated = 0;
+
+    /* Get a packet from the client. */
+    int type = packet_read(&plen);
+  
+    /* Process the packet. */
+    switch (type)
+      {
+#ifdef AFS
+      case SSH_CMSG_HAVE_KERBEROS_TGT:
+	if (!options.kerberos_tgt_passing)
+	  {
+	    /* packet_get_all(); */
+	    log("Kerberos tgt passing disabled.");
+	    break;
+	  }
+	else {
+	  /* Accept Kerberos tgt. */
+	  char *tgt = packet_get_string(&dlen);
+	  packet_integrity_check(plen, 4 + dlen, type);
+	  if (!auth_kerberos_tgt(pw, tgt))
+	    debug("Kerberos tgt REFUSED for %s", pw->pw_name);
+	  xfree(tgt);
+	}
+	continue;
+  
+      case SSH_CMSG_HAVE_AFS_TOKEN:
+	if (!options.afs_token_passing || !k_hasafs()) {
+	  /* packet_get_all(); */
+	  log("AFS token passing disabled.");
+	  break;
+	}
+	else {
+	  /* Accept AFS token. */
+	  char *token_string = packet_get_string(&dlen);
+	  packet_integrity_check(plen, 4 + dlen, type);
+	  if (!auth_afs_token(pw, token_string))
+	    debug("AFS token REFUSED for %s", pw->pw_name);
+	  xfree(token_string);
+	}
+	continue;
+#endif /* AFS */
+	    
+#ifdef KRB4
+      case SSH_CMSG_AUTH_KERBEROS:
+	if (!options.kerberos_authentication)
+	  {
+	    /* packet_get_all(); */
+	    log("Kerberos authentication disabled.");
+	    break;
+	  }
+	else {
+	  /* Try Kerberos v4 authentication. */
+	  KTEXT_ST auth;
+	  char *tkt_user = NULL;
+	  char *kdata = packet_get_string((unsigned int *)&auth.length);
+	  packet_integrity_check(plen, 4 + auth.length, type);
+  
+	  if (auth.length < MAX_KTXT_LEN)
+	    memcpy(auth.dat, kdata, auth.length);
+	  xfree(kdata);
+	  
+	  authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
+
+	  log("Kerberos authentication %s%s for account %s from %s", 
+	      authenticated ? "accepted " : "failed",
+	      tkt_user != NULL ? tkt_user : "",
+	      pw->pw_name, get_canonical_hostname());
+          if (authenticated)
+	    xfree(tkt_user);
+	}
+	break;
+#endif /* KRB4 */
+	   
+      case SSH_CMSG_AUTH_RHOSTS:
+	if (!options.rhosts_authentication)
+	  {
+	    log("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.) */
+	client_user = packet_get_string(&dlen);
+	packet_integrity_check(plen, 4 + dlen, type);
+  
+	/* Try to authenticate using /etc/hosts.equiv and .rhosts. */
+	authenticated = auth_rhosts(pw, client_user);
+
+	log("Rhosts authentication %s for %.100s, remote %.100s on %.700s.",
+	     authenticated ? "accepted" : "failed",
+	     pw->pw_name, client_user, get_canonical_hostname());
+#ifndef HAVE_LIBPAM
+      	xfree(client_user);
+#endif /* HAVE_LIBPAM */
+	break;
+  
+      case SSH_CMSG_AUTH_RHOSTS_RSA:
+	if (!options.rhosts_rsa_authentication)
+	  {
+	    log("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. */
+	client_user = packet_get_string(&ulen);
+  
+	/* Get the client host key. */
+	client_host_key_e = BN_new();
+	client_host_key_n = BN_new();
+	client_host_key_bits = packet_get_int();
+	packet_get_bignum(client_host_key_e, &elen);
+	packet_get_bignum(client_host_key_n, &nlen);
+  
+	packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
+  
+	authenticated = auth_rhosts_rsa(pw, client_user, client_host_key_bits,
+					client_host_key_e, client_host_key_n);
+	log("Rhosts authentication %s for %.100s, remote %.100s.",
+	     authenticated ? "accepted" : "failed",
+	     pw->pw_name, client_user);
+#ifndef HAVE_LIBPAM
+      	xfree(client_user);
+#endif /* HAVE_LIBPAM */
+	BN_clear_free(client_host_key_e);
+	BN_clear_free(client_host_key_n);
+	break;
+	
+      case SSH_CMSG_AUTH_RSA:
+	if (!options.rsa_authentication)
+	  {
+	    log("RSA authentication disabled.");
+	    break;
+	  }
+  
+	/* RSA authentication requested. */
+	n = BN_new();
+	packet_get_bignum(n, &nlen);
+	packet_integrity_check(plen, nlen, type);
+	authenticated = auth_rsa(pw, n);
+	BN_clear_free(n);
+	log("RSA authentication %s for %.100s.",
+	    authenticated ? "accepted" : "failed",
+	    pw->pw_name);
+	break;
+  
+      case SSH_CMSG_AUTH_PASSWORD:
+	if (!options.password_authentication)
+	  {
+	    log("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. */
+	password = packet_get_string(&dlen);
+	packet_integrity_check(plen, 4 + dlen, type);
+  
 #ifdef HAVE_LIBPAM
-  do_pam_account_and_session(pw->pw_name, password, client_user, get_canonical_hostname());
+      	/* 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\"", user);
+          authenticated = 1;
+          break;
+        }
+	
+ 	log("PAM Password authentication for \"%.100s\" failed: %s", 
+	    user, pam_strerror((pam_handle_t *)pamh, pam_retval));
+        break;
+#else /* HAVE_LIBPAM */
+	/* Try authentication with the password. */
+	authenticated = auth_password(pw, password);
+
+	memset(password, 0, strlen(password));
+	xfree(password);
+	break;
+#endif /* HAVE_LIBPAM */
+  
+      case SSH_CMSG_AUTH_TIS:
+	/* TIS Authentication is unsupported */
+	log("TIS authentication disabled.");
+	break;
+  
+      default:
+	/* Any unknown messages will be ignored (and failure returned)
+	   during authentication. */
+	log("Unknown message during authentication: type %d", type);
+	break; /* Respond with a failure message. */
+      }
+
+    if (authenticated)
+      break;
+    if (++authentication_failures >= MAX_AUTH_FAILURES)
+      packet_disconnect("Too many authentication failures for %.100s from %.200s", 
+			 pw->pw_name, get_canonical_hostname());
+    /* Send a message indicating that the authentication attempt failed. */
+    packet_start(SSH_SMSG_FAILURE);
+    packet_send();
+    packet_write_wait();
+  }
+
+#ifdef HAVE_LIBPAM
+  do_pam_account_and_session(pw->pw_name, client_user, get_canonical_hostname());
 
   /* Clean up */
   if (client_user != NULL)
@@ -1542,65 +1493,55 @@
     xfree(password);
   }
 #endif /* HAVE_LIBPAM */
-
-  /* The user has been authenticated and accepted. */
-  packet_start(SSH_SMSG_SUCCESS);
-  packet_send();
-  packet_write_wait();
-
-  /* Perform session preparation. */
-  do_authenticated(pw);
 }
 
-/* Read authentication messages, but return only failures until */
-/* max auth attempts exceeded, then disconnect */
-void eat_packets_and_disconnect(const char *user)
+/* The user does not exist or access is denied,
+   but fake indication that authentication is needed. */
+void
+do_fake_authloop(char *user)
 {
   int authentication_failures = 0;
-  
+
+  /* Indicate that authentication is needed. */
   packet_start(SSH_SMSG_FAILURE);
   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. */
-  while(1)
-  {
-    /* 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);
-    int passw_len;
-    char *password, *skeyinfo;
-    if (options.password_authentication &&
-        options.skey_authentication == 1 &&
-        type == SSH_CMSG_AUTH_PASSWORD &&
-        (password = packet_get_string(&passw_len)) != NULL &&
-        passw_len == 5 &&
-        strncasecmp(password, "s/key", 5) == 0 &&
-        (skeyinfo = skey_fake_keyinfo(user)) != NULL )
+  for (;;)
     {
-      /* Send a fake s/key challenge. */
-	   packet_send_debug(skeyinfo);
+      /* Read a packet.  This will not return if the client disconnects. */
+      int plen;
+      int type = packet_read(&plen);
+#ifdef SKEY
+      int passw_len;
+      char *password, *skeyinfo;
+      if (options.password_authentication &&
+         options.skey_authentication == 1 &&
+         type == SSH_CMSG_AUTH_PASSWORD &&
+         (password = packet_get_string(&passw_len)) != NULL &&
+         passw_len == 5 &&
+         strncasecmp(password, "s/key", 5) == 0 &&
+         (skeyinfo = skey_fake_keyinfo(user)) != NULL ){
+        /* Send a fake s/key challenge. */
+        packet_send_debug(skeyinfo);
+      }
+#endif
+      if (++authentication_failures >= MAX_AUTH_FAILURES)
+        packet_disconnect("Too many authentication failures for %.100s from %.200s", 
+                          user, get_canonical_hostname());
+      /* Send failure.  This should be indistinguishable from a failed
+         authentication. */
+      packet_start(SSH_SMSG_FAILURE);
+      packet_send();
+      packet_write_wait();
     }
-#endif /* SKEY */
-    if (++authentication_failures >= MAX_AUTH_FAILURES)
-	 {
-      packet_disconnect("Too many authentication failures for %.100s from %.200s", 
-            		       user, get_canonical_hostname());
-    }
-    /* Send failure.  This should be indistinguishable from a failed
-       authentication. */
-    packet_start(SSH_SMSG_FAILURE);
-    packet_send();
-    packet_write_wait();
-  }
   /*NOTREACHED*/
   abort();
 }
 
+
 /* Remove local Xauthority file. */
 static void
 xauthfile_cleanup_proc(void *ignore)
@@ -2075,8 +2016,10 @@
 	{
 	  fromlen = sizeof(from);
 	  if (getpeername(packet_get_connection_in(),
-			  (struct sockaddr *)&from, &fromlen) < 0)
-	    fatal("getpeername: %.100s", strerror(errno));
+			  (struct sockaddr *)&from, &fromlen) < 0) {
+	    debug("getpeername: %.100s", strerror(errno));
+            fatal_cleanup();
+          }
 	}
 
       /* Record that there was a login on that terminal. */