*** /tmp/T0a001Hd	Fri Jul 24 15:57:24 1998
--- auth-passwd.c	Fri Jul 24 15:51:27 1998
***************
*** 165,170 ****
--- 172,179 ----
  #include <nfs/nfs.h>
  #include <nfs/nfssys.h>
  
+ extern ServerOptions options;
+ 
  void nfs_revauth(uid_t uid)
  {
    struct nfs_revauth_args _nfssysarg;
***************
*** 335,340 ****
--- 344,352 ----
    /* Set packet.data so that we do not free bogus memory below */
    packet.data = 0;
    
+   if (!c)
+     return -1;
+ 
    /* get the server principal for the local host */
    /* (use defaults of "host" and canonicalized local name) */
    krbval = krb5_sname_to_principal(c, 0, 0, KRB5_NT_SRV_HST, &princ);
***************
*** 465,495 ****
  krb5_preauthtype * preauth = preauth_list;
  #endif /* KERBEROS */
  
- /* Tries to authenticate the user using password.  Returns true if
-    authentication succeeds. */
  #ifdef KERBEROS
! int auth_password(const char *server_user, const char *password,
! 		  krb5_principal client)
! #else  /* KERBEROS */
! int auth_password(const char *server_user, const char *password)
! #endif /* KERBEROS */
  {
- #if defined(_AIX) && defined(HAVE_AUTHENTICATE)
-   char *message;
-   int reenter;
- 
-   reenter = 1;
-   if (authenticate(server_user, password, &reenter, &message) == 0)
-     {
-       return 1;
-     }
-   else
-     {
-       return 0;
-     }
- #else /* _AIX41 && HAVE_AUTHENTICATE */
- 
- #ifdef KERBEROS
    krb5_error_code problem;
    int krb5_options = KDC_OPT_RENEWABLE | KDC_OPT_FORWARDABLE;
    krb5_deltat rlife = 0;
--- 477,486 ----
  krb5_preauthtype * preauth = preauth_list;
  #endif /* KERBEROS */
  
  #ifdef KERBEROS
! int auth_password_krb(const char *server_user, const char *password,
! 		  krb5_principal client, struct passwd *pw)
  {
    krb5_error_code problem;
    int krb5_options = KDC_OPT_RENEWABLE | KDC_OPT_FORWARDABLE;
    krb5_deltat rlife = 0;
***************
*** 499,651 ****
    krb5_ccache ccache;
    char ccname[80];
    int results;
- #endif  /* KERBEROS */
-   extern ServerOptions options;
-   extern char *crypt(const char *key, const char *salt);
-   struct passwd *pw;
-   char *encrypted_password;
-   char correct_passwd[200];
-   char *saved_pw_name, *saved_pw_passwd;
  
!   memset(correct_passwd, 255, sizeof(correct_passwd));
!   if (*password == '\0' && options.permit_empty_passwd == 0)
!   {
!       packet_send_debug("Server does not permit empty password login.");
!       return 0;
!   }
  
!   /* Get the encrypted password for the user. */
!   pw = getpwnam(server_user);
!   if (!pw)
!     return 0;
!   saved_pw_name = xstrdup(pw->pw_name);
!   saved_pw_passwd = xstrdup(pw->pw_passwd);
!   
! #if defined(KERBEROS)
!   if (options.kerberos_authentication)
!     {
! #if defined(KRB5)
!       sprintf(ccname, "FILE:/tmp/krb5cc_l%d", getpid());
        
!       if (problem = krb5_cc_resolve(ssh_context, ccname, &ccache))
! 	goto errout2;
        
!       if (problem = krb5_cc_initialize(ssh_context, ccache, client))
! 	goto errout;
        
!       problem =
! 	krb5_build_principal_ext(ssh_context, &server,
! 				 krb5_princ_realm(ssh_context, client)->length,
! 				 krb5_princ_realm(ssh_context, client)->data,
! 				 tgtname.length, tgtname.data,
! 				 krb5_princ_realm(ssh_context, client)->length,
! 				 krb5_princ_realm(ssh_context, client)->data,
! 				 0);
!       if (problem)
! 	goto errout;
        
!       memset(&my_creds, 0, sizeof(my_creds));
!       my_creds.client = client;
!       my_creds.server = server;
!       problem = krb5_timeofday(ssh_context, &now);
!       if (problem)
! 	goto errout;
!       my_creds.times.starttime = 0; /* start timer when
! 				       request gets to KDC */
!       my_creds.times.endtime = now + 60*60*10;   /* 10 hours */
        
!       problem = krb5_string_to_deltat("7d", &rlife); /* 7 days renew time */
!       if (problem || rlife == 0)
!         goto errout;
        
!       my_creds.times.renew_till = now + rlife;
        
!       
!       problem = krb5_get_in_tkt_with_password(ssh_context, krb5_options, 0,
! 					      NULL, preauth,
! 					      password, ccache,
! 					      &my_creds, 0);
!       
!       /* If not successful try no preauthentication */
!       if (problem)
! 	problem = krb5_get_in_tkt_with_password(ssh_context,
! 						krb5_options, 0,
! 						NULL, 0,
! 						password, ccache,
! 						&my_creds, 0);
!       krb5_free_principal(ssh_context, server);
!       server = 0;
!       if (problem)
! 	goto errout;
!       else
! 	{
! 	  /* Verify tgt just obtained */
! 	  results = verify_krb_v5_tgt(ssh_context, ccache, &problem);
  	  
! 	  if (results  >= 0)
  	    {
! 	      /* If results is 0 then put out a log message that
! 		 the TGT was not verified, pass this back to the
! 		 user as well */
! 	      if (results == 0)
! 		{
! 		  log_msg("TGT for user %s was not verified.", server_user);
! 		  packet_send_debug("Kerberos TGT could not be verified.");
! 		}
  	      
!             /* get_name pulls out just the name not the
!                type */
! 	      strcpy(ccname + 5, krb5_cc_get_name(ssh_context, ccache));
! 	      (void) chown(ccname + 5, pw->pw_uid, pw->pw_gid);
  	      
! 	      /* If tgt was passed unlink file */
! 	      if (ticket)
! 		{
! 		  if (strcmp(ticket,"none"))
! 		    /* ticket -> FILE:path */
! 		    unlink(ticket + 5);
! 		  else
!                     ticket = NULL;
  		}
  	      
! 	      ticket = xmalloc(strlen(ccname) + 1);
! 	      (void) sprintf(ticket, "%s", ccname);
  	      
! 	      /* We do not need this so free them up */
! 	      xfree(saved_pw_name);
! 	      xfree(saved_pw_passwd);
! 	      
! 	      return 1;
! 	    }
! 	  if (problem == KRB5_KT_NOTFOUND)
! 	    {
! 	      /* We have potential KDC spoofing here - log it */
! 	      log_msg("WARNING: Verification of TGT indicates potential KDC spoofing: user %s address %s", server_user, get_remote_ipaddr());
! 	      packet_send_debug("Verification of TGT indicates potential KDC spoofing.");
! 	    }
  	}
!     errout:
!       krb5_cc_destroy (ssh_context, ccache);
!     errout2:
!       if (problem)
  	{
! 	  log_msg("Password authentication of user %s using Kerberos failed: %s",
! 		  server_user, error_message(problem));
! 	  if (server) 
! 	    krb5_free_principal(ssh_context, server);
! 	  if (!options.kerberos_or_local_passwd )
! 	    {
! 	      /* We do not need this so free them up */
! 	      xfree(saved_pw_name);
! 	      xfree(saved_pw_passwd);
! 	      return 0;
! 	    }
  	}
- #endif /* KRB5 */
      }
  #endif /* KERBEROS */
    
  #ifdef HAVE_SECURID
    /* Support for Security Dynamics SecurId card.
       Contributed by Donald McKillican <dmckilli@qc.bell.ca>. */
    {
--- 490,622 ----
    krb5_ccache ccache;
    char ccname[80];
    int results;
  
!   if (!ssh_context)
!     return(-1);
  
!   sprintf(ccname, "FILE:/tmp/krb5cc_l%d", getpid());
        
!   if (problem = krb5_cc_resolve(ssh_context, ccname, &ccache))
!     goto errout2;
        
!   if (problem = krb5_cc_initialize(ssh_context, ccache, client))
!     goto errout;
        
!   problem =
!     krb5_build_principal_ext(ssh_context, &server,
! 			     krb5_princ_realm(ssh_context, client)->length,
! 			     krb5_princ_realm(ssh_context, client)->data,
! 			     tgtname.length, tgtname.data,
! 			     krb5_princ_realm(ssh_context, client)->length,
! 			     krb5_princ_realm(ssh_context, client)->data,
! 			     0);
!   if (problem)
!     goto errout;
        
!   memset(&my_creds, 0, sizeof(my_creds));
!   my_creds.client = client;
!   my_creds.server = server;
!   problem = krb5_timeofday(ssh_context, &now);
!   if (problem)
!     goto errout;
!   my_creds.times.starttime = 0; /* start timer when
! 				   request gets to KDC */
!   my_creds.times.endtime = now + 60*60*10;   /* 10 hours */
!   
!   problem = krb5_string_to_deltat("7d", &rlife); /* 7 days renew time */
!   if (problem || rlife == 0)
!     goto errout;
        
!   my_creds.times.renew_till = now + rlife;
        
!   problem = krb5_get_in_tkt_with_password(ssh_context, krb5_options, 0,
! 					  NULL, preauth,
! 					  password, ccache,
! 					  &my_creds, 0);
        
!   /* If not successful try no preauthentication */
!   if (problem)
!     problem = krb5_get_in_tkt_with_password(ssh_context,
! 					    krb5_options, 0,
! 					    NULL, 0,
! 					    password, ccache,
! 					    &my_creds, 0);
!   krb5_free_principal(ssh_context, server);
!   server = 0;
!   if (problem)
!     goto errout;
!   else
!     {
!       /* Verify tgt just obtained */
!       if (options.verifytgt)
! 	results = verify_krb_v5_tgt(ssh_context, ccache, &problem);
  	  
!       if (!options.verifytgt || results  >= 0)
! 	{
! 	  /* If results is 0 then put out a log message that
! 	     the TGT was not verified, pass this back to the
! 	     user as well */
! 	  if (options.verifytgt && results == 0)
  	    {
! 	      log_msg("TGT for user %s was not verified.", server_user);
! 	      packet_send_debug("Kerberos TGT could not be verified.");
! 	    }
  	      
! 	  /* get_name pulls out just the name not the
! 	     type */
! 	  strcpy(ccname + 5, krb5_cc_get_name(ssh_context, ccache));
! 	  (void) chown(ccname + 5, pw->pw_uid, pw->pw_gid);
  	      
! 	  /* If tgt was passed unlink file */
! 	  /* We leak memory here, but only in the fork()'d client */
! 	  if (ticket) {
! 	    krb5_ccache old_ccache = NULL;
! 	    int results;
! 
! 	    if (strcmp(ticket,"none") != 0) {
! 	      results = krb5_cc_resolve(ssh_context, ticket, &old_ccache);
! 	      if (results != 0) {
! 		debug("krb5_cc_resolve failed trying to destroy ticket file %s: %s",
! 		      ticket, error_message(results));
! 	      } else {
! 		results = krb5_cc_destroy (ssh_context, old_ccache);
! 		if (results != 0) {
! 		  debug("krb5_cc_destroy failed trying to destroy ticket file %s: %s",
! 			ticket, error_message(results));
  		}
+ 	      }
+ 	    }
+ 	  }
  	      
! 	  ticket = xmalloc(strlen(ccname) + 1);
! 	  (void) sprintf(ticket, "%s", ccname);
  	      
! 	  return 1;
  	}
!       if (problem == KRB5_KT_NOTFOUND)
  	{
! 	  /* We have potential KDC spoofing here - log it */
! 	  log_msg("WARNING: Verification of TGT indicates potential KDC spoofing: user %s address %s", server_user, get_remote_ipaddr());
! 	  packet_send_debug("Verification of TGT indicates potential KDC spoofing.");
  	}
      }
+  errout:
+   krb5_cc_destroy (ssh_context, ccache);
+  errout2:
+   if (problem)
+     {
+       log_msg("Password authentication of user %s using Kerberos failed: %s",
+ 	      server_user, error_message(problem));
+       if (server) 
+ 	krb5_free_principal(ssh_context, server);
+       return 0;
+     }
+ }
  #endif /* KERBEROS */
    
  #ifdef HAVE_SECURID
+ int auth_password_securid(const char *server_user, const char *password)
+ {
    /* Support for Security Dynamics SecurId card.
       Contributed by Donald McKillican <dmckilli@qc.bell.ca>. */
    {
***************
*** 703,710 ****
--- 674,709 ----
    }
    /* If the user has no SecurID card specified, we fall to normal 
       password code. */
+ }
  #endif /* HAVE_SECURID */
  
+ int auth_password_unix(const char *server_user, const char *password, struct passwd *pw)
+ {
+   extern ServerOptions options;
+   extern char *crypt(const char *key, const char *salt);
+   char *encrypted_password;
+   char correct_passwd[200];
+   char *saved_pw_name, *saved_pw_passwd;
+   int i, retval;
+ 
+   saved_pw_name = xstrdup(pw->pw_name);
+   saved_pw_passwd = xstrdup(pw->pw_passwd);
+ 
+ #if defined(_AIX) && defined(HAVE_AUTHENTICATE)
+   char *message;
+   int reenter;
+ 
+   reenter = 1;
+   if (authenticate(server_user, password, &reenter, &message) == 0)
+     {
+       return 1;
+     }
+   else
+     {
+       return 0;
+     }
+ #else /* _AIX41 && HAVE_AUTHENTICATE */
+ 
    /* Save the encrypted password. */
    strncpy(correct_passwd, saved_pw_passwd, sizeof(correct_passwd));
  
***************
*** 885,888 ****
--- 884,954 ----
    /* Authentication is accepted if the encrypted passwords are identical. */
    return strcmp(encrypted_password, correct_passwd) == 0;
  #endif /* _AIX && HAVE_AUTHENTICATE */
+ }
+ 
+ /* Tries to authenticate the user using password.  Returns true if
+    authentication succeeds. */
+ 
+ #ifdef KERBEROS
+ int auth_password(const char *server_user, const char *password,
+ 		  krb5_principal client)
+ #else  /* KERBEROS */
+ int auth_password(const char *server_user, const char *password)
+ #endif /* KERBEROS */
+ {
+   extern ServerOptions options;
+   extern char *crypt(const char *key, const char *salt);
+   struct passwd *pw;
+   char *encrypted_password;
+   char correct_passwd[200];
+   char *saved_pw_name, *saved_pw_passwd;
+   int i, retval;
+ 
+   memset(correct_passwd, 255, sizeof(correct_passwd));
+   if (*password == '\0' && options.permit_empty_passwd == 0) {
+     packet_send_debug("Server does not permit empty password login.");
+     return 0;
+   }
+   
+   /* Get the encrypted password for the user. */
+   pw = getpwnam(server_user);
+   if (!pw)
+     return 0;
+ 
+   for(i = 0; i != LAST_AUTH; i++) {
+     switch(options.auth_order[i]) {
+       
+ #ifdef KERBEROS
+     case PASS_KRB5:
+       {
+         (ssh_context &&
+ 	 (retval = auth_password_krb(server_user, password, client, pw)));
+         if (retval == 1)
+           return 1;
+         break;
+       }
+ #endif
+ 
+ #ifdef HAVE_SECURID
+     case PASS_SECURID:
+       {
+         retval = auth_password_securid(server_user, password);
+         if (retval == 1)
+           return 1;
+         break;
+       }
+ #endif
+ 
+     case PASS_UNIX:
+       {
+         retval = auth_password_unix(server_user, password, pw);
+         if (retval == 1)
+           return 1;
+         break;
+       }
+     }
+   }
+ 
+   /* Auth Failed... */
+   return 0;
  }
*** /tmp/T0a001Hg	Fri Jul 24 15:57:30 1998
--- auth-rhosts.c	Fri Jul 24 14:24:41 1998
***************
*** 350,357 ****
       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_msg("Connection from %.100s from nonprivileged port %d",
  	  hostname, port);
--- 353,360 ----
       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 (options.require_priv_port && (port >= IPPORT_RESERVED ||
! 				    port < IPPORT_RESERVED / 2))
      {
        log_msg("Connection from %.100s from nonprivileged port %d",
  	  hostname, port);
*** /tmp/T0a001Hj	Fri Jul 24 15:57:38 1998
--- log-server.c	Fri Jul 24 14:22:18 1998
***************
*** 67,72 ****
--- 67,73 ----
  static int log_debug = 0;
  static int log_quiet = 0;
  static int log_on_stderr = 0;
+ extern  krb5_context ssh_context;
  
  /* Initialize the log.
       av0	program name (should be argv[0])
***************
*** 283,296 ****
        /* If you forwarded a ticket you get one shot for proper
  	 authentication. */
        /* If tgt was passed unlink file */
!       if (ticket)
! 	{
! 	  if (strcmp(ticket,"none"))
! 	    /* ticket -> FILE:path */
! 	    unlink(ticket + 5);
! 	  else
! 	    ticket = NULL;
  	}
  #endif /* KERBEROS */
      }
  }
--- 284,308 ----
        /* If you forwarded a ticket you get one shot for proper
  	 authentication. */
        /* If tgt was passed unlink file */
!       /* We leak memory here, but only in the fork()'d client */
!       if (ticket && ssh_context) {
! 	krb5_ccache old_ccache = NULL;
! 	int results;
! 	
! 	if (strcmp(ticket,"none") != 0) {
! 	  results = krb5_cc_resolve(ssh_context, ticket, &old_ccache);
! 	  if (results != 0) {
! 	    debug("krb5_cc_resolve failed trying to destroy ticket file %s: %s",
! 		  ticket, error_message(results));
! 	  } else {
! 	    results = krb5_cc_destroy (ssh_context, old_ccache);
! 	    if (results != 0) {
! 	      debug("krb5_cc_destroy failed trying to destroy ticket file %s: %s",
! 		    ticket, error_message(results));
! 	    }
! 	  }
  	}
+       }
  #endif /* KERBEROS */
      }
  }
*** /tmp/T0a001Hm	Fri Jul 24 15:57:48 1998
--- servconf.c	Fri Jul 24 15:52:14 1998
***************
*** 85,91 ****
  {
    memset(options, 0, sizeof(*options));
    options->port = -1;
-   options->listen_addr.s_addr = INADDR_ANY;
    options->host_key_file = NULL;
    options->random_seed_file = NULL;
    options->pid_file = NULL;
--- 94,99 ----
***************
*** 137,142 ****
--- 145,155 ----
    options->check_mail = -1;
    options->password_expire_warning_days = -1;
    options->account_expire_warning_days = -1;
+   options->auth_order[0] = LAST_AUTH;
+   options->kdestroy = -1;
+   options->verifytgt = -1;
+   options->listen_addr[0].s_addr = INADDR_ANY;
+   options->require_priv_port = -1;
  }
  
  void fill_default_server_options(ServerOptions *options)
***************
*** 237,242 ****
--- 250,266 ----
      options->password_expire_warning_days = 14;
    if (options->account_expire_warning_days == -1)
      options->account_expire_warning_days = 14;
+   if (options->auth_order[0] == LAST_AUTH)
+     {
+       options->auth_order[0] = PASS_UNIX;
+       options->auth_order[1] = LAST_AUTH;
+     }
+   if (options->kdestroy == -1)
+     options->kdestroy = 1;
+   if (options->verifytgt == -1)
+     options->verifytgt = 0;
+   if (options->require_priv_port == -1)
+     options->require_priv_port = 1;
  }
  
  #define WHITESPACE " \t\r\n="
***************
*** 255,261 ****
    sKerberosTgtPassing, sAllowTcpForwarding, sAllowUsers, sDenyUsers,
    sXauthPath, sCheckMail, sDenyGroups, sAllowGroups, sIgnoreRootRhosts,
    sAllowSHosts, sDenySHosts, sPasswordExpireWarningDays,
!   sAccountExpireWarningDays
  #ifdef F_SECURE_COMMERCIAL
  
  
--- 279,286 ----
    sKerberosTgtPassing, sAllowTcpForwarding, sAllowUsers, sDenyUsers,
    sXauthPath, sCheckMail, sDenyGroups, sAllowGroups, sIgnoreRootRhosts,
    sAllowSHosts, sDenySHosts, sPasswordExpireWarningDays,
!   sAccountExpireWarningDays,
!   sAuthOrder, sKdestroy, sVerifyTGT, sRequirePrivPort
  #ifdef F_SECURE_COMMERCIAL
  
  
***************
*** 321,326 ****
--- 346,355 ----
    { "checkmail", sCheckMail },
    { "passwordexpirewarningdays", sPasswordExpireWarningDays },
    { "accountexpirewarningdays", sAccountExpireWarningDays },
+   { "authorder", sAuthOrder },
+   { "kdestroy", sKdestroy },
+   { "verifytgt", sVerifyTGT },
+   { "requireprivport", sRequirePrivPort },
    { NULL, 0 }
  };
  
***************
*** 344,349 ****
--- 373,390 ----
    { NULL, 0 }
  };
  
+ static struct
+ {
+   const char *name;
+   AuthType type;
+ } auth_types[] =
+ {
+   { "password_krb5", PASS_KRB5 },
+   { "password_unix", PASS_UNIX },
+   { "password_securid", PASS_SECURID },
+   { NULL, 0 }
+ };
+ 
  /* Returns the number of the token pointed to by cp of length len.
     Never returns if the token is not known. */
  
***************
*** 368,374 ****
    FILE *f;
    char line[1024];
    char *cp, **charptr;
!   int linenum, *intptr, i, value;
    ServerOpCodes opcode;
  
    f = fopen(filename, "r");
--- 409,415 ----
    FILE *f;
    char line[1024];
    char *cp, **charptr;
!   int linenum, *intptr, i, value, addrnum;
    ServerOpCodes opcode;
  
    f = fopen(filename, "r");
***************
*** 379,384 ****
--- 420,427 ----
      }
  
    linenum = 0;
+   addrnum = 0;
+ 
    while (fgets(line, sizeof(line), f))
      {
        linenum++;
***************
*** 455,465 ****
  		      filename, linenum);
  	      exit(1);
  	    }
  #ifdef BROKEN_INET_ADDR
! 	  options->listen_addr.s_addr = inet_network(cp);
  #else /* BROKEN_INET_ADDR */
! 	  options->listen_addr.s_addr = inet_addr(cp);
  #endif /* BROKEN_INET_ADDR */
  	  break;
  
  	case sHostKeyFile:
--- 498,518 ----
  		      filename, linenum);
  	      exit(1);
  	    }
+ 	  while (cp) {
+ 	    if (addrnum >= MAX_LISTEN_ADDRS)
+ 	      {
+ 		fprintf(stderr, "%s line %d: too many listen addresses (%d).\n",
+ 			filename, linenum, addrnum);
+ 		exit(1);
+ 	      }
  #ifdef BROKEN_INET_ADDR
! 	    options->listen_addr[addrnum].s_addr = inet_network(cp);
  #else /* BROKEN_INET_ADDR */
! 	    options->listen_addr[addrnum].s_addr = inet_addr(cp);
  #endif /* BROKEN_INET_ADDR */
+ 	    addrnum++;
+ 	    cp = strtok(NULL, WHITESPACE);
+ 	  }
  	  break;
  
  	case sHostKeyFile:
***************
*** 817,822 ****
--- 870,911 ----
  	  intptr = &options->account_expire_warning_days;
  	  goto parse_int;
  
+ 	case sAuthOrder:
+ 	  {
+ 	    int j;
+ 
+ 	    j = 0;
+ 
+ 	    while ((cp = strtok(NULL, WHITESPACE)))
+ 	      {
+ 		for(i = 0; cp[i]; i++)
+ 		  cp[i] = tolower(cp[i]);
+ 		for (i = 0; auth_types[i].name; i++)
+ 		  if (strcmp(auth_types[i].name, cp) == 0)
+ 		    break;
+ 		if (!auth_types[i].name)
+ 		  {
+ 		    fprintf(stderr, "%s line %d: unsupported authentication type %s\n",
+ 			    filename, linenum, cp);
+ 		    exit(1);
+ 		  }
+ 		options->auth_order[j++] = auth_types[i].type;
+ 	      }
+ 	    options->auth_order[j] = LAST_AUTH;
+ 	    break;
+ 	  }
+ 
+ 	case sKdestroy:
+ 	  intptr = &options->kdestroy;
+ 	  goto parse_flag;
+ 
+ 	case sVerifyTGT:
+ 	  intptr = &options->verifytgt;
+ 	  goto parse_flag;
+ 	case sRequirePrivPort:
+ 	  intptr = &options->require_priv_port;
+ 	  goto parse_flag;
+ 
  #ifdef F_SECURE_COMMERCIAL
  
  
***************
*** 887,891 ****
--- 976,983 ----
  	  exit(1);
  	}
      }
+   if (addrnum == 0)
+     addrnum++;
+   options->num_listen_addrs = addrnum;
    fclose(f);
  }
*** /tmp/T0a001Hp	Fri Jul 24 15:57:55 1998
--- servconf.h	Fri Jul 24 15:46:11 1998
***************
*** 75,80 ****
--- 82,88 ----
  #define MAX_DENY_USERS		256 /* Max # users on deny list. */
  #define MAX_ALLOW_GROUPS	256 /* Max # groups on allow list. */
  #define MAX_DENY_GROUPS		256 /* Max # groups on deny list. */
+ #define MAX_LISTEN_ADDRS	246 /* Max # of Addrs to listen on */
  
  #ifdef F_SECURE_COMMERCIAL
  #define MAX_ALLOW_FORWD_TO	256 /* Max # forwardingto on allow list. */
***************
*** 83,92 ****
  #define MAX_DENY_FORWD_PORT	256 /* Max # forwardingport on deny list. */
  #endif /* F_SECURE_COMMERCIAL */
  
  typedef struct
  {
    int port;			/* Port number to listen on. */
-   struct in_addr listen_addr;	/* Address on which the server listens. */
    char *host_key_file;		/* File containing host key. */
    char *random_seed_file;	/* File containing random seed. */
    char *pid_file;		/* File containing process ID number. */
--- 91,101 ----
  #define MAX_DENY_FORWD_PORT	256 /* Max # forwardingport on deny list. */
  #endif /* F_SECURE_COMMERCIAL */
  
+ typedef enum { PASS_KRB5, PASS_UNIX, PASS_SECURID, LAST_AUTH } AuthType;
+ 
  typedef struct
  {
    int port;			/* Port number to listen on. */
    char *host_key_file;		/* File containing host key. */
    char *random_seed_file;	/* File containing random seed. */
    char *pid_file;		/* File containing process ID number. */
***************
*** 157,162 ****
--- 166,177 ----
  #endif /* F_SECURE_COMMERCIAL */
    int password_expire_warning_days;
    int account_expire_warning_days;
+   struct in_addr listen_addr[MAX_LISTEN_ADDRS];
+   int num_listen_addrs;
+   int kdestroy;
+   int verifytgt;
+   int require_priv_port;
+   AuthType auth_order[LAST_AUTH + 1];
  } ServerOptions;
  
  /* Initializes the server options to special values that indicate that they
*** /tmp/T0a001Ht	Fri Jul 24 15:58:09 1998
--- sshconnect.c	Fri Jul 24 15:44:35 1998
***************
*** 332,338 ****
  
  /* Creates a (possibly privileged) socket for use as the ssh connection. */
  
! int ssh_create_socket(uid_t original_real_uid, int privileged)
  {
    int sock;
  
--- 346,352 ----
  
  /* Creates a (possibly privileged) socket for use as the ssh connection. */
  
! int ssh_create_socket(uid_t original_real_uid, int privileged, int *hport)
  {
    int sock;
  
***************
*** 340,348 ****
       bind our own socket to a privileged port. */
    if (privileged)
      {
-       struct sockaddr_in sin;
        int p;
!       for (p = 1023; p > 512; p--)
  	{
  	  sock = socket(AF_INET, SOCK_STREAM, 0);
  	  if (sock < 0)
--- 354,372 ----
       bind our own socket to a privileged port. */
    if (privileged)
      {
        int p;
!       struct sockaddr_in sin;
! 
!       /* under some operating systems, we can re-bind a port that is still in
! 	 a wait state, which will cause repeated connections to the same host
! 	 to fail. We use hport as state, so we don't re-use the same priviledged
! 	 port when we re-try. Otherwise, we'd try the same (sip,sport,dip,dport)
! 	 4-tuple over and over, and keep failing until the TCP timeout cleaned up
! 	 the old socket */
! 	 
!       if (*hport == 0)
! 	*hport = 1024;
!       for (p = *hport - 1; p > 512; p--)
  	{
  	  sock = socket(AF_INET, SOCK_STREAM, 0);
  	  if (sock < 0)
***************
*** 354,359 ****
--- 378,385 ----
  	  sin.sin_addr.s_addr = INADDR_ANY;
  	  sin.sin_port = htons(p);
  
+ 	  *hport = p;
+ 
  	  /* Try to bind the socket to the privileged port. */
  #if defined(SOCKS) && !defined(HAVE_SOCKS_H)
  	  if (Rbind(sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
***************
*** 394,400 ****
  		int anonymous, uid_t original_real_uid, 
  		const char *proxy_command, RandomState *random_state)
  {
!   int sock = -1, attempt, i;
    int on = 1;
    struct servent *sp;
    struct hostent *hp;
--- 420,426 ----
  		int anonymous, uid_t original_real_uid, 
  		const char *proxy_command, RandomState *random_state)
  {
!   int sock = -1, attempt, i, hport;
    int on = 1;
    struct servent *sp;
    struct hostent *hp;
***************
*** 450,458 ****
        if ((hostaddr.sin_addr.s_addr & 0xffffffff) != 0xffffffff)
  	{ 
  	  /* Create a socket. */
  	  sock = ssh_create_socket(original_real_uid, 
! 				   !anonymous && geteuid() == UID_ROOT);
!       
  	  /* Valid numeric IP address */
  	  debug("Connecting to %.100s port %d.", 
  		inet_ntoa(hostaddr.sin_addr), port);
--- 476,486 ----
        if ((hostaddr.sin_addr.s_addr & 0xffffffff) != 0xffffffff)
  	{ 
  	  /* Create a socket. */
+ 	  if (attempt == 0)
+ 	    hport = 0;
  	  sock = ssh_create_socket(original_real_uid, 
! 				   !anonymous && geteuid() == UID_ROOT, &hport);
! 
  	  /* Valid numeric IP address */
  	  debug("Connecting to %.100s port %d.", 
  		inet_ntoa(hostaddr.sin_addr), port);
***************
*** 482,488 ****
  	    {
  	      struct hostent *hp_static;
  
! #if defined(SOCKS5) && !defined(HAVE_SOCKS_H)
  	      hp_static = Rgethostbyname(host);
  #else
  	      hp_static = gethostbyname(host);
--- 510,518 ----
  	    {
  	      struct hostent *hp_static;
  
! 	      /* socksified gethostbyname always succeeds, screwing up
! 		 error handling. So don't do it unless you _really_ mean it */
! #if defined(SOCKS5) && !defined(HAVE_SOCKS_H) && defined(USE_SOCKS_GETHOST)
  	      hp_static = Rgethostbyname(host);
  #else
  	      hp_static = gethostbyname(host);
***************
*** 525,532 ****
  		    host, inet_ntoa(hostaddr.sin_addr), port);
  
  	      /* Create a socket for connecting. */
  	      sock = ssh_create_socket(original_real_uid, 
! 				       !anonymous && geteuid() == UID_ROOT);
  
  	      /* Connect to the host. */
  #if defined(SOCKS) && !defined(HAVE_SOCKS_H)
--- 555,564 ----
  		    host, inet_ntoa(hostaddr.sin_addr), port);
  
  	      /* Create a socket for connecting. */
+ 	      if (attempt == 0)
+ 		hport = 0;
  	      sock = ssh_create_socket(original_real_uid, 
! 				       !anonymous && geteuid() == UID_ROOT, &hport);
  
  	      /* Connect to the host. */
  #if defined(SOCKS) && !defined(HAVE_SOCKS_H)
***************
*** 927,933 ****
  }
  
  #ifdef KERBEROS
! int try_kerberos_authentication(void)
  {
  #ifdef KRB5
    char *remotehost;
--- 959,965 ----
  }
  
  #ifdef KERBEROS
! int try_kerberos_authentication(char *host)
  {
  #ifdef KRB5
    char *remotehost;
***************
*** 937,954 ****
    krb5_ccache ccache;
    krb5_creds creds;
    krb5_creds * new_creds = 0;
!   int ap_opts, ret_stat = 0;
    krb5_keyblock   *session_key = 0;
    krb5_ap_rep_enc_part *repl = 0;
    struct sockaddr_in local, foreign;
    
    memset(&auth, 0 , sizeof(auth));
    remotehost = (char *) get_canonical_hostname();
    if (!ssh_context)
      {
        if ((r = krb5_init_context(&ssh_context)))
! 	fatal("Kerberos V5: %s while initializing krb5.", error_message(r));
!       krb5_init_ets(ssh_context);
      }
    
    if ((r = krb5_cc_default(ssh_context, &ccache)))
--- 969,1003 ----
    krb5_ccache ccache;
    krb5_creds creds;
    krb5_creds * new_creds = 0;
!   int ap_opts, ret_stat = 0, retval;
    krb5_keyblock   *session_key = 0;
    krb5_ap_rep_enc_part *repl = 0;
    struct sockaddr_in local, foreign;
+   struct hostent *hp;
+   char name[255];
    
    memset(&auth, 0 , sizeof(auth));
+ 
+ #ifdef SOCKS
+ #if (defined(SOCKS5) && defined(USE_SOCKS_GETHOST))
+   if (hp = Rgethostbyname(host)) {
+ #else
+   if (hp = gethostbyname(host)) {
+ #endif
+     strncpy(name, hp->h_name, sizeof(name));
+     remotehost = name;
+   } else {
+     remotehost = (char *) get_canonical_hostname();
+   }
+ #else
    remotehost = (char *) get_canonical_hostname();
+ #endif
+ 
    if (!ssh_context)
      {
        if ((r = krb5_init_context(&ssh_context)))
! 	log_msg("Kerberos V5: %s while initializing krb5.", error_message(r));
!       goto cleanup;
      }
    
    if ((r = krb5_cc_default(ssh_context, &ccache)))
***************
*** 1103,1110 ****
    if (!ssh_context)
      {
        if ((r = krb5_init_context(&ssh_context)))
! 	fatal("Kerberos V5: %s while initializing krb5.", error_message(r));
!       krb5_init_ets(ssh_context);
      }
    if (!auth_context)
      {
--- 1152,1159 ----
    if (!ssh_context)
      {
        if ((r = krb5_init_context(&ssh_context)))
! 	log_msg("Kerberos V5: %s while initializing krb5.", error_message(r));
!       return 0;
      }
    if (!auth_context)
      {
***************
*** 1657,1663 ****
      {
        debug("Trying Kerberos V5 authentication.");
  #endif
!       if (try_kerberos_authentication()) {
          /* The server should respond with success or failure. */
          type = packet_read();
          if (type == SSH_SMSG_SUCCESS)
--- 1706,1712 ----
      {
        debug("Trying Kerberos V5 authentication.");
  #endif
!       if (try_kerberos_authentication(host)) {
          /* The server should respond with success or failure. */
          type = packet_read();
          if (type == SSH_SMSG_SUCCESS)
*** /tmp/T0a001Hw	Fri Jul 24 15:58:18 1998
--- sshd.c	Fri Jul 24 15:49:47 1998
***************
*** 551,557 ****
  
  /* This is set to the socket that the server is listening; this is used in
     the SIGHUP signal handler. */
! int listen_sock;
  
  /* This is not really needed, and could be eliminated if server-specific
     and client-specific code were removed from newchannels.c */
--- 559,565 ----
  
  /* This is set to the socket that the server is listening; this is used in
     the SIGHUP signal handler. */
! int listen_sock[MAX_LISTEN_ADDRS];
  
  /* This is not really needed, and could be eliminated if server-specific
     and client-specific code were removed from newchannels.c */
***************
*** 640,647 ****
  
  void sighup_restart(void)
  {
    log_msg("Received SIGHUP; restarting.");
!   close(listen_sock);
    execvp(saved_argv[0], saved_argv);
    log_msg("RESTART FAILED: av[0]='%s', error: %s.", 
        saved_argv[0], strerror(errno));
--- 648,659 ----
  
  void sighup_restart(void)
  {
+   int i;
+ 
    log_msg("Received SIGHUP; restarting.");
!   for(i=0; i<options.num_listen_addrs; i++) {
!     close(listen_sock[i]);
!   }
    execvp(saved_argv[0], saved_argv);
    log_msg("RESTART FAILED: av[0]='%s', error: %s.", 
        saved_argv[0], strerror(errno));
***************
*** 654,661 ****
  
  RETSIGTYPE sigterm_handler(int sig)
  {
    log_msg("Received signal %d; terminating.", sig);
!   close(listen_sock);
    exit(255);
  }
  
--- 666,677 ----
  
  RETSIGTYPE sigterm_handler(int sig)
  {
+   int i;
+ 
    log_msg("Received signal %d; terminating.", sig);
!   for(i=0; i<options.num_listen_addrs; i++) {
!     close(listen_sock[i]);
!   }
    exit(255);
  }
  
***************
*** 1009,1047 ****
      }
    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));
  #if defined(SO_LINGER) && defined(ENABLE_SO_LINGER)
!       linger.l_onoff = 1;
!       linger.l_linger = 15;
!       setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *)&linger, 
! 		 sizeof(linger));
  #endif /* SO_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, 2);
! 	  close(listen_sock);
! 	  fatal("Bind to port %d failed: %.200s.", options.port,
! 		strerror(errno));
! 	}
  
        if (!debug_flag)
  	{
  	  /* Record our pid in /etc/sshd_pid to make it easier to kill the
--- 1025,1074 ----
      }
    else
      {
+       int i;
+ 
        /* Create socket for listening. */
!       for(i=0; i<options.num_listen_addrs; i++) {
! 	listen_sock[i] = socket(AF_INET, SOCK_STREAM, 0);
! 	if (listen_sock[i] < 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[i], SOL_SOCKET, SO_REUSEADDR, (void *)&on, 
! 		   sizeof(on));
  #if defined(SO_LINGER) && defined(ENABLE_SO_LINGER)
! 	linger.l_onoff = 1;
! 	linger.l_linger = 15;
! 	setsockopt(listen_sock[i], SOL_SOCKET, SO_LINGER, (void *)&linger, 
! 		   sizeof(linger));
  #endif /* SO_LINGER */
  
! 	/* Initialize the socket address. */
! 	memset(&sin, 0, sizeof(sin));
! 	sin.sin_family = AF_INET;
! 	sin.sin_addr = options.listen_addr[i];
! 	sin.sin_port = htons(options.port);
  
! 	/* Bind the socket to the desired port. */
! 	if (bind(listen_sock[i], (struct sockaddr *)&sin, sizeof(sin)) < 0)
! 	  {
! 	    error("bind: %.100s", strerror(errno));
! 	    shutdown(listen_sock[i], 2);
! 	    close(listen_sock[i]);
! 	    fatal("Bind to interface %s port %d failed: %.200s.",
! 		  inet_ntoa(options.listen_addr[i]), options.port,
! 		  strerror(errno));
! 	  }
  
+ 	/* Start listening on the port. */
+ 	log_msg("Server listening on address %s port %d.",
+ 		inet_ntoa(options.listen_addr[i]), options.port);
+ 	if (listen(listen_sock[i], 1024) < 0)
+ 	  fatal("listen: %.100s", strerror(errno));
+       }
+ 
        if (!debug_flag)
  	{
  	  /* Record our pid in /etc/sshd_pid to make it easier to kill the
***************
*** 1056,1066 ****
  	    }
  	}
  
-       /* Start listening on the port. */
-       log_msg("Server listening on port %d.", options.port);
-       if (listen(listen_sock, 5) < 0)
- 	fatal("listen: %.100s", strerror(errno));
- 
        /* Generate an rsa key. */
        log_msg("Generating %d bit RSA key.", options.server_key_bits);
        rsa_generate_key(&sensitive_data.private_key, &public_key,
--- 1083,1088 ----
***************
*** 1098,1106 ****
  	  krb5_error_code r;
  	  
  	  if ((r = krb5_init_context(&ssh_context)))
! 	    fatal("Kerberos V5: %s while initializing krb5.",
  		  error_message(r));
- 	  krb5_init_ets(ssh_context);
  	}
  #endif
  #endif
--- 1120,1127 ----
  	  krb5_error_code r;
  	  
  	  if ((r = krb5_init_context(&ssh_context)))
! 	    log_msg("Kerberos V5: %s while initializing krb5.",
  		  error_message(r));
  	}
  #endif
  #endif
***************
*** 1109,1122 ****
  	 daemon is killed with a signal. */
        for (;;)
  	{
  	  if (received_sighup)
  	    sighup_restart();
  	  
  	  /* Wait in select until there is a connection. */
  	  FD_ZERO(&fdset);
! 	  FD_SET(listen_sock, &fdset);
! 	  ret = select(listen_sock + 1, &fdset, NULL, NULL, NULL);
! 	  if (ret < 0 || !FD_ISSET(listen_sock, &fdset))
  	    {
  	      if (errno == EINTR)
  		continue;
--- 1130,1148 ----
  	 daemon is killed with a signal. */
        for (;;)
  	{
+ 	  int i;
+ 
  	  if (received_sighup)
  	    sighup_restart();
  	  
  	  /* Wait in select until there is a connection. */
  	  FD_ZERO(&fdset);
! 	  for (i=0; i<options.num_listen_addrs; i++) {
! 	    FD_SET(listen_sock[i], &fdset);
! 	  }
! 	  ret = select(listen_sock[options.num_listen_addrs-1] + 1,
! 		       &fdset, NULL, NULL, NULL);
! 	  if (ret < 0)
  	    {
  	      if (errno == EINTR)
  		continue;
***************
*** 1123,1183 ****
  	      error("select: %.100s", strerror(errno));
  	      continue;
  	    }
- 	  
- 	  aux = sizeof(sin);
- 	  newsock = accept(listen_sock, (struct sockaddr *)&sin, &aux);
- 	  if (newsock < 0)
- 	    {
- 	      if (errno == EINTR)
- 		continue;
- 	      error("accept: %.100s", 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. */
! 	      debug("Server will not fork when running in debugging mode.");
! 	      close(listen_sock);
! 	      sock_in = newsock;
! 	      sock_out = newsock;
! 	      pid = getpid();
! #ifdef LIBWRAP
! 	      {
! 		struct request_info req;
! 		
! 		signal(SIGCHLD, SIG_DFL);
! 		
! 		request_init(&req, RQ_DAEMON, av0, RQ_FILE, newsock, NULL);
! 		fromhost(&req);
! 		if (!hosts_access(&req))
! 		  refuse(&req);
! 	      }
! #endif /* LIBWRAP */
! 	      break;
! 	    }
! 	  else
! 	    {
! 	      /* Normal production daemon.  Fork, and have the child process
! 		 the connection.  The parent continues listening. */
! 	      if ((pid = fork()) == 0)
! 		{ 
! 		  /* Child.  Close the listening 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);
  		  sock_in = newsock;
  		  sock_out = newsock;
  #ifdef LIBWRAP
  		  {
  		    struct request_info req;
  		    
  		    signal(SIGCHLD, SIG_DFL);
! 		    
  		    request_init(&req, RQ_DAEMON, av0, RQ_FILE, newsock, NULL);
  		    fromhost(&req);
  		    if (!hosts_access(&req))
--- 1149,1190 ----
  	      error("select: %.100s", strerror(errno));
  	      continue;
  	    }
  
! 	  for (i=0; i<options.num_listen_addrs; i++) {
! 	    int foundsock;
! 
! 	    if (FD_ISSET(listen_sock[i], &fdset)) {
! 	      aux = sizeof(sin);
! 	      newsock = accept(listen_sock[i], (struct sockaddr *)&sin, &aux);
! 	      if (newsock < 0)
! 		{
! 		  if (errno == EINTR)
! 		    continue;
! 		  error("accept: %.100s", strerror(errno));
! 		  continue;
! 		}
! 
! 	      /* Got connection.  Fork a child to handle it, unless we are in
! 		 debugging mode. */
! 	      if (debug_flag)
! 		{
! 		  int j;
! 
! 		  /* In debugging mode.  Close the listening socket, and start
! 		     processing the connection without forking. */
! 		  debug("Server will not fork when running in debugging mode.");
! 		  for(j=0; j<options.num_listen_addrs; j++) {
! 		    close(listen_sock[j]);
! 		  }
  		  sock_in = newsock;
  		  sock_out = newsock;
+ 		  pid = getpid();
  #ifdef LIBWRAP
  		  {
  		    struct request_info req;
  		    
  		    signal(SIGCHLD, SIG_DFL);
! 		
  		    request_init(&req, RQ_DAEMON, av0, RQ_FILE, newsock, NULL);
  		    fromhost(&req);
  		    if (!hosts_access(&req))
***************
*** 1184,1211 ****
  		      refuse(&req);
  		  }
  #endif /* LIBWRAP */
- 
- 		  log_init(av0, debug_flag && !inetd_flag, 
- 			   options.fascist_logging || debug_flag, 
- 			   options.quiet_mode, options.log_facility);
  		  break;
  		}
! 	    }
  
! 	  /* Parent.  Stay in the loop. */
! 	  if (pid < 0)
! 	    error("fork: %.100s", strerror(errno));
! 	  else
! 	    debug("Forked child %d.", pid);
  
! 	  /* Mark that the key has been used (it was "given" to the child). */
! 	  key_used = 1;
  
! 	  random_acquire_light_environmental_noise(&sensitive_data.
! 						   random_state);
  	  
! 	  /* Close the new socket (the child is now taking care of it). */
! 	  close(newsock);
  	}
      }
    
--- 1191,1254 ----
  		      refuse(&req);
  		  }
  #endif /* LIBWRAP */
  		  break;
  		}
! 	      else
! 		{
! 		  /* Normal production daemon.  Fork, and have the child process
! 		     the connection.  The parent continues listening. */
! 		  if ((pid = fork()) == 0)
! 		    { 
! 		      int j;
  
! 		      /* 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. */
! 		      for(j=0; j<options.num_listen_addrs; j++) {
! 			close(listen_sock[j]);
! 		      }
! 		      sock_in = newsock;
! 		      sock_out = newsock;
! #ifdef LIBWRAP
! 		      {
! 			struct request_info req;
! 		    
! 			signal(SIGCHLD, SIG_DFL);
! 		    
! 			request_init(&req, RQ_DAEMON, av0, RQ_FILE, newsock, NULL);
! 			fromhost(&req);
! 			if (!hosts_access(&req))
! 			  refuse(&req);
! 		      }
! #endif /* LIBWRAP */
  
! 		      log_init(av0, debug_flag && !inetd_flag, 
! 			       options.fascist_logging || debug_flag, 
! 			       options.quiet_mode, options.log_facility);
! 		      break;
! 		    } else {
  
! 		      /* Parent.  Stay in the loop. */
! 		      if (pid < 0)
! 			error("fork: %.100s", strerror(errno));
! 		      else
! 			debug("Forked child %d.", pid);
! 
! 		      /* Mark that the key has been used (it was "given" to the child). */
! 		      key_used = 1;
! 
! 		      random_acquire_light_environmental_noise(&sensitive_data.
! 							       random_state);
  	  
! 		      /* Close the new socket (the child is now taking care of it). */
! 		      close(newsock);
! 		    }
! 		}
! 	    }
! 	  }
! 	  if (debug_flag || pid == 0)
!             break;
  	}
      }
    
***************
*** 1375,1381 ****
    
    /* Handle the connection.   We pass as argument whether the connection
       came from a privileged port. */
!   do_connection(get_remote_port() < 1024);
  
    /* Try to remove authentication socket and directory */
    auth_delete_socket(NULL);
--- 1418,1424 ----
    
    /* Handle the connection.   We pass as argument whether the connection
       came from a privileged port. */
!   do_connection(!options.require_priv_port || get_remote_port() < 1024);
  
    /* Try to remove authentication socket and directory */
    auth_delete_socket(NULL);
***************
*** 2136,2159 ****
        krb5_error_code r;
        
        if ((r = krb5_init_context(&ssh_context)))
! 	fatal("Kerberos V5: %s while initializing krb5.",
  	      error_message(r));
-       krb5_init_ets(ssh_context);
      }
!   debug("Connection attempt for %.100s from %s.", user, 
! 	get_canonical_hostname());
!   
!   if (strchr(user,'@') || strchr(user,'%'))
!     {
!       if (strchr(user,'%'))
! 	*strchr(user,'%') = '@';
        krb5_parse_name(ssh_context, user, &client);
!       if (!(krb5_aname_to_localname(ssh_context, client,
! 				    sizeof(kuser), kuser)))
! 	user = kuser;
!     }
!   else 
!     krb5_parse_name(ssh_context, user, &client);
  #endif /* defined(KERBEROS) && defined(KRB5) */
  			 
    /* Verify that the user is a valid user.  We disallow usernames starting
--- 2179,2203 ----
        krb5_error_code r;
        
        if ((r = krb5_init_context(&ssh_context)))
! 	log_msg("Kerberos V5: %s while initializing krb5.",
  	      error_message(r));
      }
!   if (ssh_context) {
!     debug("Connection attempt for %.100s from %s.", user, 
! 	  get_canonical_hostname());
!     
!     if (strchr(user,'@') || strchr(user,'%'))
!       {
! 	if (strchr(user,'%'))
! 	  *strchr(user,'%') = '@';
! 	krb5_parse_name(ssh_context, user, &client);
! 	if (!(krb5_aname_to_localname(ssh_context, client,
! 				      sizeof(kuser), kuser)))
! 	  user = kuser;
!       }
!     else 
        krb5_parse_name(ssh_context, user, &client);
!   }
  #endif /* defined(KERBEROS) && defined(KRB5) */
  			 
    /* Verify that the user is a valid user.  We disallow usernames starting
***************
*** 2192,2218 ****
  
    debug("Attempting authentication for %.100s.", user);
  
! #if defined (KERBEROS) && defined (KRB5)
!   if (!options.kerberos_authentication && options.password_authentication &&
!       auth_password(user, "", 0))
! #else /* defined(KERBEROS) && defined(KRB5) */
!   /* If the user has no password, accept authentication immediately. */
!   if (options.password_authentication && auth_password(user, ""))
! #endif /* defined(KERBEROS) && defined(KRB5) */
!     {
!       /* 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();
!     }
  
    /* Loop until the user has been authenticated or the connection is closed. */
    while (!authenticated)
--- 2236,2245 ----
  
    debug("Attempting authentication for %.100s.", user);
  
!   /* Indicate that authentication is needed. */
!   packet_start(SSH_SMSG_FAILURE);
!   packet_send();
!   packet_write_wait();
  
    /* Loop until the user has been authenticated or the connection is closed. */
    while (!authenticated)
***************
*** 2226,2232 ****
  #ifdef KERBEROS_TGT_PASSING
  #ifdef KRB5
  	case SSH_CMSG_HAVE_KERBEROS_TGT:
! 	  if (!options.kerberos_tgt_passing || 
  	      (!(options.kerberos_authentication || 
  		 options.password_authentication ||
  		 options.rsa_authentication)))
--- 2253,2259 ----
  #ifdef KERBEROS_TGT_PASSING
  #ifdef KRB5
  	case SSH_CMSG_HAVE_KERBEROS_TGT:
! 	  if (!ssh_context || !options.kerberos_tgt_passing || 
  	      (!(options.kerberos_authentication || 
  		 options.password_authentication ||
  		 options.rsa_authentication)))
***************
*** 2252,2258 ****
  #ifdef KERBEROS
  #ifdef KRB5
  	case SSH_CMSG_AUTH_KERBEROS:
! 	  if (!options.kerberos_authentication)
  	    {
  	      packet_get_all();
  	      log_msg("Kerberos authentication disabled.");
--- 2279,2285 ----
  #ifdef KERBEROS
  #ifdef KRB5
  	case SSH_CMSG_AUTH_KERBEROS:
! 	  if (!ssh_context || !options.kerberos_authentication)
  	    {
  	      packet_get_all();
  	      log_msg("Kerberos authentication disabled.");
***************
*** 2632,2643 ****
        /* If you forwarded a ticket you get one shot for proper
           authentication. */
        /* If tgt was passed unlink file */
!       if (ticket){
!           if (strcmp(ticket,"none"))
!  	    /* ticket -> FILE:path */
!  	    unlink(ticket + 5);
!           else
!             ticket = NULL;
        }
  #endif /* KERBEROS */
        
--- 2659,2682 ----
        /* If you forwarded a ticket you get one shot for proper
           authentication. */
        /* If tgt was passed unlink file */
!       /* We leak memory here, but only in the fork()'d child */
!       if (ticket && ssh_context){
! 	krb5_ccache old_ccache = NULL;
! 	int results;
! 
! 	if (strcmp(ticket,"none") != 0) {
! 	  results = krb5_cc_resolve(ssh_context, ticket, &old_ccache);
! 	  if (results != 0) {
! 	    debug("krb5_cc_resolve failed trying to destroy ticket file %s: %s",
! 		  ticket, error_message(results));
! 	  } else {
! 	    results = krb5_cc_destroy (ssh_context, old_ccache);
! 	    if (results != 0) {
! 	      debug("krb5_cc_destroy failed trying to destroy ticket file %s: %s",
! 		    ticket, error_message(results));
! 	    }
! 	  }
! 	}
        }
  #endif /* KERBEROS */
        
***************
*** 3161,3166 ****
--- 3200,3209 ----
  void pty_cleanup_proc(void *context)
  {
    struct pty_cleanup_context *cu = context;
+ #ifdef KERBEROS
+   krb5_ccache ccache = NULL;
+   int retval;
+ #endif
  
    if (cu->alread_cleaned)
      {
***************
*** 3175,3180 ****
--- 3218,3246 ----
        
        /* Release the pseudo-tty. */
        pty_release(cu->ttyname);
+ 
+ #ifdef KERBEROS
+       /* Clean up ticket */
+       /* We leak memory here, but only in the fork()'d child */
+       if (ticket && ssh_context && options.kdestroy){
+ 	krb5_ccache old_ccache = NULL;
+ 	int results;
+ 
+ 	if (strcmp(ticket,"none") != 0) {
+ 	  results = krb5_cc_resolve(ssh_context, ticket, &old_ccache);
+ 	  if (results != 0) {
+ 	    debug("krb5_cc_resolve failed trying to destroy ticket file %s: %s",
+ 		  ticket, error_message(results));
+ 	  } else {
+ 	    results = krb5_cc_destroy (ssh_context, old_ccache);
+ 	    if (results != 0) {
+ 	      debug("krb5_cc_destroy failed trying to destroy ticket file %s: %s",
+ 		    ticket, error_message(results));
+ 	    }
+ 	  }
+ 	}
+       }
+ #endif /* KERBEROS */
        
        cu->alread_cleaned = 1;
      }
***************
*** 4143,4149 ****
  #ifdef KERBEROS
    /* Set KRBTKFILE to point to our ticket */
  #ifdef KRB5
!   if (ticket)
      child_set_env(&env, &envsize, "KRB5CCNAME", ticket);
  #endif /* KRB5 */
  #endif /* KERBEROS */
--- 4209,4215 ----
  #ifdef KERBEROS
    /* Set KRBTKFILE to point to our ticket */
  #ifdef KRB5
!   if (ticket && strcmp(ticket, "none"))
      child_set_env(&env, &envsize, "KRB5CCNAME", ticket);
  #endif /* KRB5 */
  #endif /* KERBEROS */
*** /tmp/T0a001Xt	Fri Jul 24 17:29:06 1998
--- sshd.8.in	Fri Jul 24 17:28:21 1998
***************
*** 410,415 ****
--- 413,425 ----
  restrictions.
  
  .TP
+ .B AuthOrder
+ Specifies the order in which password authentication methods will be tried.
+ Valid values are "password_krb5" (kerberos v5), "password_securid",
+ and "password_unix". Multiple values should be seperated by whitespace. The
+ default is "password_unix".
+ 
+ .TP
  .B CheckMail
  Specifies whether
  .B sshd
***************
*** 514,519 ****
--- 524,534 ----
  .BR IgnoreRhosts .
  
  .TP
+ .B KDestroy
+ Specifies whether sshd should destroy kerberos tickets on exit.
+ Defaults to "yes".
+ 
+ .TP
  .B KeepAlive
  Specifies whether the system should send keepalive messages to the
  other side.  If they are sent, death of the connection or crash of one
***************
*** 559,566 ****
  
  .TP
  .B ListenAddress
! Specifies the ip address of the interface where the sshd server socket
! is bind.
  
  .TP
  .B LoginGraceTime
--- 574,581 ----
  
  .TP
  .B ListenAddress
! Specifies the ip address(es) of the interface(s) where the sshd server socket
! is bound.
  
  .TP
  .B LoginGraceTime
***************
*** 638,643 ****
--- 653,663 ----
  .IR @ETCDIR@/ssh_random_seed ".
  
  .TP
+ .B RequirePrivPort
+ Specifies whether or not sshd requires connections to come from a priveledged port
+ for Rhosts and RSA based authentication methods. Defaults to "yes".
+ 
+ .TP
  .B RhostsAuthentication
  Specifies whether authentication using rhosts or /etc/hosts.equiv
  files is sufficient.  Normally, this method should not be permitted
***************
*** 692,697 ****
--- 712,722 ----
  of the number to make it octal. Default is to not set umask at all.
  
  .TP
+ .B VerifyTGT
+ Specifies whether sshd verifies the Kerberos ticket granting ticket or not. This
+ can break some kerberos implementations. Defaults to "no".
+ 
+ .TP
  .B X11Forwarding
  Specifies whether X11 forwarding is permitted.  The default is "yes".
  Note that disabling X11 forwarding does not improve security in any
