]> andersk Git - openssh.git/blobdiff - sshd.c
- Merged OpenBSD CVS changes
[openssh.git] / sshd.c
diff --git a/sshd.c b/sshd.c
index 54a4c043a4898bda557e49ae22932b77b3300f95..cbd555f093166876dafdcbc93e06f21d373b990a 100644 (file)
--- a/sshd.c
+++ b/sshd.c
@@ -32,6 +32,10 @@ RCSID("$Id$");
 #include "uidswap.h"
 #include "compat.h"
 
+#ifdef HAVE_MAILLOCK_H
+# include <maillock.h>
+#endif
+
 #ifdef LIBWRAP
 #include <tcpd.h>
 #include <syslog.h>
@@ -43,12 +47,8 @@ int deny_severity = LOG_WARNING;
 #define O_NOCTTY       0
 #endif
 
-#ifdef KRB4
-char *ticket = NULL;
-#endif /* KRB4 */
-
 /* Local Xauthority file. */
-char *xauthfile = NULL;
+static char *xauthfile = NULL;
 
 /* Server configuration options. */
 ServerOptions options;
@@ -65,6 +65,9 @@ int debug_flag = 0;
 /* Flag indicating that the daemon is being started from inetd. */
 int inetd_flag = 0;
 
+/* debug goes to stderr unless inetd_flag is set */
+int log_stderr = 0;
+
 /* argv[0] without path. */
 char *av0;
 
@@ -115,9 +118,10 @@ int received_sighup = 0;
 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,
@@ -129,11 +133,12 @@ void do_exec_no_pty(const char *command, struct passwd *pw,
 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(char *username, char *remote_user
+               const char *remote_host);
 void pam_cleanup_proc(void *context);
 
 static struct pam_conv conv = {
@@ -142,12 +147,15 @@ static struct pam_conv conv = {
 };
 struct pam_handle_t *pamh = NULL;
 const char *pampasswd = NULL;
+char *pamconv_msg = NULL;
 
 static int pamconv(int num_msg, const struct pam_message **msg,
                    struct pam_response **resp, void *appdata_ptr)
 {
-  int count = 0;
-  struct pam_response *reply = NULL;
+  struct pam_response *reply;
+  int count;
+  size_t msg_len;
+  char *p;
 
   /* PAM will free this later */
   reply = malloc(num_msg * sizeof(*reply));
@@ -171,6 +179,23 @@ static int pamconv(int num_msg, const struct pam_message **msg,
       case PAM_TEXT_INFO:
         reply[count].resp_retcode = PAM_SUCCESS;
         reply[count].resp = xstrdup("");
+       
+       if (msg[count]->msg == NULL)
+           break;
+       debug("Adding PAM message: %s", msg[count]->msg);
+
+       msg_len = strlen(msg[count]->msg);
+       if (pamconv_msg)
+       {
+         size_t n = strlen(pamconv_msg);
+         pamconv_msg = xrealloc(pamconv_msg, n + msg_len + 2);
+         p = pamconv_msg + n;
+       }
+       else
+         pamconv_msg = p = xmalloc(msg_len + 2);
+       memcpy(p, msg[count]->msg, msg_len);
+       p[msg_len] = '\n';
+       p[msg_len + 1] = '\0';
         break;
 
       case PAM_PROMPT_ECHO_ON:
@@ -188,41 +213,65 @@ static int pamconv(int num_msg, const struct pam_message **msg,
 
 void pam_cleanup_proc(void *context)
 {
-  int retval;
+  int pam_retval;
   
   if (pamh != NULL)
   {
-    retval = pam_close_session((pam_handle_t *)pamh, 0);
-        
-    if (pam_end((pam_handle_t *)pamh, retval) != PAM_SUCCESS)
-      log("Cannot release PAM authentication.");
+    pam_retval = pam_close_session((pam_handle_t *)pamh, 0);
+    if (pam_retval != PAM_SUCCESS)
+    {
+      log("Cannot close PAM session: %.200s", 
+          pam_strerror((pam_handle_t *)pamh, pam_retval));
+    }
+     
+    pam_retval = pam_end((pam_handle_t *)pamh, pam_retval);
+    if (pam_retval != PAM_SUCCESS)
+    {
+      log("Cannot release PAM authentication: %.200s", 
+          pam_strerror((pam_handle_t *)pamh, pam_retval));
+    }
   }
 }
 
-void do_pam_account_and_session(const char *username, const char *password, const char *remote_user, const char *remote_host)
+void do_pam_account_and_session(char *username, char *remote_user, 
+    const char *remote_host)
 {
-  if (remote_host && (PAM_SUCCESS != pam_set_item((pam_handle_t *)pamh, PAM_RHOST, remote_host)))
+  int pam_retval;
+  
+  if (remote_host != NULL)
   {
-    log("PAM setup failed.");
-        eat_packets_and_disconnect(username);
+    debug("PAM setting rhost to \"%.200s\"", remote_host);
+    pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST, remote_host);
+    if (pam_retval != PAM_SUCCESS)
+    {
+      log("PAM set rhost failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
+          do_fake_authloop(username);
+    }
   }
-
-  if (remote_user && (PAM_SUCCESS != pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user)))
+  
+  if (remote_user != NULL)
   {
-    log("PAM setup failed.");
-        eat_packets_and_disconnect(username);
+    debug("PAM setting ruser to \"%.200s\"", remote_user);
+    pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user);
+    if (pam_retval != PAM_SUCCESS)
+    {
+      log("PAM set ruser failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
+          do_fake_authloop(username);
+    }
   }
-    
-  if (PAM_SUCCESS != pam_acct_mgmt((pam_handle_t *)pamh, 0))
+  
+  pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0);
+  if (pam_retval != PAM_SUCCESS)
   {
-    log("PAM rejected by account configuration.");
-        eat_packets_and_disconnect(username);
+    log("PAM rejected by account configuration: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
+        do_fake_authloop(username);
   }
 
-  if (PAM_SUCCESS != pam_open_session((pam_handle_t *)pamh, 0))
+  pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
+  if (pam_retval != PAM_SUCCESS)
   {
-    log("PAM session setup failed.");
-        eat_packets_and_disconnect(username);
+    log("PAM session setup failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
+        do_fake_authloop(username);
   }
 }
 #endif /* HAVE_LIBPAM */
@@ -332,6 +381,7 @@ main(int ac, char **av)
   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;
@@ -356,6 +406,7 @@ main(int ac, char **av)
          break;
        case 'd':
          debug_flag = 1;
+         options.log_level = SYSLOG_LEVEL_DEBUG;
          break;
        case 'i':
          inetd_flag = 1;
@@ -364,7 +415,7 @@ main(int ac, char **av)
           silentrsa = 1;
          break;
        case 'q':
-         options.quiet_mode = 1;
+         options.log_level = SYSLOG_LEVEL_QUIET;
          break;
        case 'b':
          options.server_key_bits = atoi(optarg);
@@ -434,32 +485,29 @@ main(int ac, char **av)
       exit(1);
     }
 
-  /* Initialize the log (it is reinitialized below in case we forked). */
-  log_init(av0, debug_flag && !inetd_flag, 
-          debug_flag || options.fascist_logging, 
-          options.quiet_mode, options.log_facility);
+  /* Force logging to stderr while loading the private host key
+     unless started from inetd */
+  log_init(av0, options.log_level, options.log_facility, !inetd_flag);
 
   debug("sshd version %.100s", SSH_VERSION);
 
   sensitive_data.host_key = RSA_new();
+  errno = 0;
   /* Load the host key.  It must have empty passphrase. */
   if (!load_private_key(options.host_key_file, "", 
                        sensitive_data.host_key, &comment))
     {
-      if (debug_flag)
-       fprintf(stderr, "Could not load host key: %s: %s\n",
-               options.host_key_file, strerror(errno));
-      else
-       {
-         int err = errno;
-         log_init(av0, !inetd_flag, 1, 0, options.log_facility);
-         error("Could not load host key: %.200s: %.100s", 
-               options.host_key_file, strerror(err));
-       }
+      error("Could not load host key: %.200s: %.100s", 
+           options.host_key_file, strerror(errno));
       exit(1);
     }
   xfree(comment);
 
+  /* Initialize the log (it is reinitialized below in case we forked). */
+  if (debug_flag && !inetd_flag)
+    log_stderr = 1;
+  log_init(av0, options.log_level, options.log_facility, log_stderr);
+
   /* If not in debugging mode, and not started from inetd, disconnect from
      the controlling terminal, and fork.  The original process exits. */
   if (!debug_flag && !inetd_flag)
@@ -482,9 +530,7 @@ main(int ac, char **av)
     }
 
   /* Reinitialize the log (because of the fork above). */
-  log_init(av0, debug_flag && !inetd_flag, 
-          debug_flag || options.fascist_logging, 
-          options.quiet_mode, options.log_facility);
+  log_init(av0, options.log_level, options.log_facility, log_stderr);
 
   /* Check that server and host key lengths differ sufficiently.  This is
      necessary to make double encryption work with rsaref.  Oh, I hate
@@ -652,9 +698,7 @@ main(int ac, char **av)
                  close(listen_sock);
                  sock_in = newsock;
                  sock_out = newsock;
-                 log_init(av0, debug_flag && !inetd_flag, 
-                          options.fascist_logging || debug_flag, 
-                          options.quiet_mode, options.log_facility);
+                  log_init(av0, options.log_level, options.log_facility, log_stderr);
                  break;
                }
            }
@@ -699,6 +743,8 @@ main(int ac, char **av)
      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
   {
@@ -712,13 +758,11 @@ main(int ac, char **av)
       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
@@ -791,11 +835,23 @@ main(int ac, char **av)
     }
   }
 
+  /* 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. */
@@ -815,8 +871,10 @@ main(int ac, char **av)
     
     if (pamh != NULL)
     {
+          debug("Closing PAM session.");
       retval = pam_close_session((pam_handle_t *)pamh, 0);
 
+          debug("Terminating PAM library.");
       if (pam_end((pam_handle_t *)pamh, retval) != PAM_SUCCESS)
         log("Cannot release PAM authentication.");
         
@@ -834,9 +892,10 @@ main(int ac, char **av)
    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;
+  int i, len;
   BIGNUM *session_key_int;
   unsigned char session_key[SSH_SESSION_KEY_LENGTH];
   unsigned char check_bytes[8];
@@ -939,8 +998,14 @@ void do_connection(int privileged_port)
   if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0)
     {
       /* Private key has bigger modulus. */
-      assert(BN_num_bits(sensitive_data.private_key->n) >= 
-            BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED);
+      if (BN_num_bits(sensitive_data.private_key->n) < 
+         BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
+        fatal("do_connection: private_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",
+             BN_num_bits(sensitive_data.private_key->n),
+              BN_num_bits(sensitive_data.host_key->n),
+             SSH_KEY_BITS_RESERVED);
+      }
+
       rsa_private_decrypt(session_key_int, session_key_int,
                          sensitive_data.private_key);
       rsa_private_decrypt(session_key_int, session_key_int,
@@ -949,9 +1014,13 @@ void do_connection(int privileged_port)
   else
     {
       /* Host key has bigger modulus (or they are equal). */
-      assert(BN_num_bits(sensitive_data.host_key->n) >= 
-            BN_num_bits(sensitive_data.private_key->n) +
-            SSH_KEY_BITS_RESERVED);
+      if (BN_num_bits(sensitive_data.host_key->n) < 
+         BN_num_bits(sensitive_data.private_key->n) + SSH_KEY_BITS_RESERVED) {
+        fatal("do_connection: host_key %d < private_key %d + SSH_KEY_BITS_RESERVED %d",
+             BN_num_bits(sensitive_data.host_key->n),
+              BN_num_bits(sensitive_data.private_key->n),
+             SSH_KEY_BITS_RESERVED);
+      }
       rsa_private_decrypt(session_key_int, session_key_int,
                          sensitive_data.host_key);
       rsa_private_decrypt(session_key_int, session_key_int,
@@ -960,17 +1029,19 @@ void do_connection(int privileged_port)
 
   /* Compute session id for this session. */
   compute_session_id(session_id, check_bytes,
-                    BN_num_bits(sensitive_data.host_key->n),
                     sensitive_data.host_key->n, 
-                    BN_num_bits(sensitive_data.private_key->n),
                     sensitive_data.private_key->n);
 
   /* Extract session key from the decrypted integer.  The key is in the 
      least significant 256 bits of the integer; the first byte of the 
      key is in the highest bits. */
   BN_mask_bits(session_key_int, sizeof(session_key) * 8);
-  assert(BN_num_bytes(session_key_int) == sizeof(session_key));
-  BN_bn2bin(session_key_int, session_key);
+  len = BN_num_bytes(session_key_int);
+  if (len < 0 || len > sizeof(session_key))
+    fatal("do_connection: bad len: session_key_int %d > sizeof(session_key) %d",
+         len, sizeof(session_key));
+  memset(session_key, 0, sizeof(session_key));
+  BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len);
   
   /* Xor the first 16 bytes of the session key with the session id. */
   for (i = 0; i < 16; i++)
@@ -981,8 +1052,7 @@ void do_connection(int privileged_port)
   
   /* Set the session key.  From this on all communications will be
      encrypted. */
-  packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, 
-                           cipher_type, 0);
+  packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type);
   
   /* Destroy our copy of the session key.  It is no longer needed. */
   memset(session_key, 0, sizeof(session_key));
@@ -1012,7 +1082,7 @@ void do_connection(int privileged_port)
 
   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
@@ -1095,23 +1165,13 @@ allowed_user(struct passwd *pw)
 
 /* 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 AFS
   /* If machine has AFS, set process authentication group. */
   if (k_hasafs()) {
@@ -1123,8 +1183,8 @@ do_authentication(char *user, int privileged_port)
   /* 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);
@@ -1136,15 +1196,17 @@ do_authentication(char *user, int privileged_port)
   pw = &pwcopy;
 
 #ifdef HAVE_LIBPAM
-  if (PAM_SUCCESS != pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh))
   {
-    packet_start(SSH_SMSG_FAILURE);
-    packet_send();
-    packet_write_wait();
-    packet_disconnect("PAM initialisation failed.");
-  }
+    int pam_retval;
+        
+    debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
 
-  fatal_add_cleanup(&pam_cleanup_proc, NULL); 
+    pam_retval = pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh);
+    if (pam_retval != PAM_SUCCESS)
+      fatal("PAM initialisation failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
+
+    fatal_add_cleanup(&pam_cleanup_proc, NULL);
+  }
 #endif
 
   /* If we are not running as root, the user must have the same uid as the
@@ -1163,315 +1225,273 @@ do_authentication(char *user, int privileged_port)
     {
       /* 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 {
+      /* Loop until the user has been authenticated or the connection is closed,
+         do_authloop() returns only if authentication is successfull */
+      do_authloop(pw);
     }
-  else
+
+  /* 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)
     {
-      /* Indicate that authentication is needed. */
-      packet_start(SSH_SMSG_FAILURE);
-      packet_send();
-      packet_write_wait();
+      if (forced_command)
+       log("Root login accepted for forced command.");
+      else
+       packet_disconnect("ROOT LOGIN REFUSED FROM %.200s", 
+                         get_canonical_hostname());
     }
 
-  /* 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)
-       {
+  /* The user has been authenticated and accepted. */
+  packet_start(SSH_SMSG_SUCCESS);
+  packet_send();
+  packet_write_wait();
 
-#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;
+  /* 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 bits;
+  BIGNUM *client_host_key_e, *client_host_key_n;
+  BIGNUM *n;
+  char *client_user = NULL, *password = NULL;
+  int plen, dlen, nlen, ulen, elen;
+#ifdef HAVE_LIBPAM
+  int pam_retval;
+#endif /* HAVE_LIBPAM */
+
+  /* Indicate that authentication is needed. */
+  packet_start(SSH_SMSG_FAILURE);
+  packet_send();
+  packet_write_wait();
 
-       case SSH_CMSG_HAVE_AFS_TOKEN:
-         if (!options.afs_token_passing || !k_hasafs()) {
+  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("AFS token passing disabled.");
+           log("Kerberos tgt 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(user, pw->pw_uid, token_string))
-             debug("AFS token REFUSED for %s", user);
-           xfree(token_string);
-           continue;
-         }
+       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);
            
-           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());
-           }
+#ifdef KRB4
+      case SSH_CMSG_AUTH_KERBEROS:
+       if (!options.kerberos_authentication)
+         {
+           /* packet_get_all(); */
+           log("Kerberos authentication disabled.");
+           break;
          }
-         break;
-#endif /* KRB4 */
+       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);
          
-       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.) */
+         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)
          {
-           int dlen;
-           client_user = packet_get_string(&dlen);
-           packet_integrity_check(plen, 4 + dlen, type);
+           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);
 
-         /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
-         if (auth_rhosts(pw, client_user, options.ignore_rhosts,
-                         options.strict_modes))
-           {
-             /* Authentication accepted. */
-             log("Rhosts authentication accepted for %.100s, remote %.100s on %.700s.",
-                 user, client_user, get_canonical_hostname());
-             authenticated = 1;
+       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);
+       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;
-           }
-
+       break;
+  
+      case SSH_CMSG_AUTH_RHOSTS_RSA:
+       if (!options.rhosts_rsa_authentication)
          {
-           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);
+           log("Rhosts with RSA authentication disabled.");
+           break;
          }
-
-         /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
-         if (auth_rhosts_rsa(pw, client_user,
-                             client_host_key_bits, client_host_key_e,
-                             client_host_key_n, options.ignore_rhosts,
-                             options.strict_modes))
-           {
-             /* 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);
+  
+       /* 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();
+       bits = packet_get_int();
+       packet_get_bignum(client_host_key_e, &elen);
+       packet_get_bignum(client_host_key_n, &nlen);
+
+        if (bits != BN_num_bits(client_host_key_n))
+          error("Warning: keysize mismatch for client_host_key: "
+               "actual %d, announced %d", BN_num_bits(client_host_key_n), bits);
+       packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
+  
+       authenticated = auth_rhosts_rsa(pw, client_user,
+                                       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);
+       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, options.strict_modes))
-             { 
-               /* 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. */
+       BN_clear_free(client_host_key_e);
+       BN_clear_free(client_host_key_n);
+       break;
+       
+      case SSH_CMSG_AUTH_RSA:
+       if (!options.rsa_authentication)
          {
-           int passw_len;
-           password = packet_get_string(&passw_len);
-           packet_integrity_check(plen, 4 + passw_len, type);
+           log("RSA authentication disabled.");
+           break;
          }
-
-#ifdef HAVE_LIBPAM
-          pampasswd = password;
   
-          if (PAM_SUCCESS == pam_authenticate((pam_handle_t *)pamh, 0))
-          {
-            log("PAM Password authentication accepted for %.100s.", user);
-            authenticated = 1;
-            break;
-          } else
+       /* RSA authentication requested. */
+       n = BN_new();
+       packet_get_bignum(n, &nlen);
+       packet_integrity_check(plen, nlen, type);
+
+       authenticated = auth_rsa(pw, n);
+       log("RSA authentication %s for %.100s.",
+           authenticated ? "accepted" : "failed",
+           pw->pw_name);
+       BN_clear_free(n);
+       break;
+  
+      case SSH_CMSG_AUTH_PASSWORD:
+       if (!options.password_authentication)
          {
-           log("PAM Password authentication for %.100s failed.", user);
-            break;
+           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 auth with password */
+        pampasswd = password;
+        pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
+        if (pam_retval == PAM_SUCCESS)
+        {
+          log("PAM Password authentication accepted for user \"%.100s\"", pw->pw_name);
+          authenticated = 1;
+          break;
+        }
+
+        log("PAM Password authentication for \"%.100s\" failed: %s", 
+            pw->pw_name, pam_strerror((pam_handle_t *)pamh, pam_retval));
+        break;
 #else /* HAVE_LIBPAM */
-         /* 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;
+       /* Try authentication with the password. */
+       authenticated = auth_password(pw, password);
+       log("Password authentication %s for %.100s.",
+           authenticated ? "accepted" : "failed",
+           pw->pw_name);
+
+       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)
+  
+      case SSH_CMSG_AUTH_TIS:
+       /* TIS Authentication is unsupported */
+       log("TIS authentication disabled.");
        break;
-
-      /* Send a message indicating that the authentication attempt failed. */
-      packet_start(SSH_SMSG_FAILURE);
-      packet_send();
-      packet_write_wait();
-
-      if (++authentication_failures >= MAX_AUTH_FAILURES) {
-       packet_disconnect("Too many authentication failures for %.100s from %.200s", 
-          pw->pw_name, get_canonical_hostname());
+  
+      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. */
       }
-    }
 
-  /* Check if the user is logging in as root and root logins are disallowed. */
-  if (pw->pw_uid == 0 && !options.permit_root_login)
-    {
-      if (forced_command)
-       log("Root login accepted for forced command.", forced_command);
-      else
-       packet_disconnect("ROOT LOGIN REFUSED FROM %.200s", 
-                         get_canonical_hostname());
-    }
+    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, password, client_user, get_canonical_hostname());
+  do_pam_account_and_session(pw->pw_name, client_user, get_canonical_hostname());
 
   /* Clean up */
   if (client_user != NULL)
@@ -1483,65 +1503,68 @@ do_authentication(char *user, int privileged_port)
     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);
-    }
-#endif /* SKEY */
-    /* Send failure.  This should be indistinguishable from a failed
-       authentication. */
-    packet_start(SSH_SMSG_FAILURE);
-    packet_send();
-    packet_write_wait();
-    if (++authentication_failures >= MAX_AUTH_FAILURES)
-        {
-      packet_disconnect("Too many authentication failures for %.100s from %.200s", 
-                              user, get_canonical_hostname());
+      /* 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();
     }
-  }
   /*NOTREACHED*/
   abort();
 }
 
+
+/* Remove local Xauthority file. */
+static void
+xauthfile_cleanup_proc(void *ignore)
+{
+  debug("xauthfile_cleanup_proc called");
+
+  if (xauthfile != NULL) {
+    unlink(xauthfile);
+    xfree(xauthfile);
+    xauthfile = NULL;
+  }
+}
+
 /* Prepares for an interactive session.  This is called after the user has
    been successfully authenticated.  During this message exchange, pseudo
    terminals are allocated, X11, TCP/IP, and authentication agent forwardings
@@ -1697,6 +1720,7 @@ void do_authenticated(struct passwd *pw)
          if ((xauthfd = mkstemp(xauthfile)) != -1) {
            fchown(xauthfd, pw->pw_uid, pw->pw_gid);
            close(xauthfd);
+            fatal_add_cleanup(xauthfile_cleanup_proc, NULL);
          }
          else {
            xfree(xauthfile);
@@ -1842,8 +1866,7 @@ void do_exec_no_pty(const char *command, struct passwd *pw,
   if ((pid = fork()) == 0)
     {
       /* Child.  Reinitialize the log since the pid has changed. */
-      log_init(av0, debug_flag && !inetd_flag, debug_flag, 
-              options.quiet_mode, options.log_facility);
+      log_init(av0, options.log_level, options.log_facility, log_stderr);
 
       /* Create a new session and process group since the 4.4BSD setlogin()
         affects the entire process group. */
@@ -1925,11 +1948,6 @@ void pty_cleanup_proc(void *context)
 
   debug("pty_cleanup_proc called");
 
-#if defined(KRB4)
-  /* Destroy user's ticket cache file. */
-  (void) dest_tkt();
-#endif /* KRB4 */
-  
   /* Record that the user has logged out. */
   record_logout(cu->pid, cu->ttyname);
 
@@ -1977,8 +1995,7 @@ void do_exec_pty(const char *command, int ptyfd, int ttyfd,
       pid = getpid();
 
       /* Child.  Reinitialize the log because the pid has changed. */
-      log_init(av0, debug_flag && !inetd_flag, debug_flag, options.quiet_mode, 
-              options.log_facility);
+      log_init(av0, options.log_level, options.log_facility, log_stderr);
 
       /* Close the master side of the pseudo tty. */
       close(ptyfd);
@@ -2009,8 +2026,10 @@ void do_exec_pty(const char *command, int ptyfd, int ttyfd,
        {
          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. */
@@ -2020,7 +2039,13 @@ void do_exec_pty(const char *command, int ptyfd, int ttyfd,
       /* Check if .hushlogin exists. */
       snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
       quiet_login = stat(line, &st) >= 0;
-      
+
+#ifdef HAVE_LIBPAM
+      /* output the results of the pamconv() */
+      if (!quiet_login && pamconv_msg != NULL)
+       fprintf(stderr, pamconv_msg);
+#endif
+       
       /* If the user has logged in before, display the time of last login. 
          However, don't display anything extra if a command has been 
         specified (so that ssh can be used to execute commands on a remote
@@ -2209,6 +2234,7 @@ void do_child(const char *command, struct passwd *pw, const char *term,
   struct stat st;
   char *argv[10];
 
+#ifndef HAVE_LIBPAM /* pam_nologin handles this */
   /* Check /etc/nologin. */
   f = fopen("/etc/nologin", "r");
   if (f)
@@ -2219,6 +2245,13 @@ void do_child(const char *command, struct passwd *pw, const char *term,
       if (pw->pw_uid != 0)
        exit(254);
     }
+#endif /* HAVE_LIBPAM */
+
+#ifdef HAVE_SETLOGIN
+  /* Set login name in the kernel. */
+  if (setlogin(pw->pw_name) < 0)
+    error("setlogin failed: %s", strerror(errno));
+#endif /* HAVE_SETLOGIN */
 
   /* Set uid, gid, and groups. */
   /* Login(1) does this as well, and it needs uid 0 for the "-h" switch,
@@ -2324,8 +2357,12 @@ void do_child(const char *command, struct passwd *pw, const char *term,
     child_set_env(&env, &envsize, "DISPLAY", display);
 
 #ifdef KRB4
-  if (ticket)
-    child_set_env(&env, &envsize, "KRBTKFILE", ticket);
+  {
+    extern char *ticket;
+    
+    if (ticket)
+      child_set_env(&env, &envsize, "KRBTKFILE", ticket);
+  }
 #endif /* KRB4 */
 
 #ifdef HAVE_LIBPAM
@@ -2333,10 +2370,10 @@ void do_child(const char *command, struct passwd *pw, const char *term,
   {
     char *equal_sign, var_name[256], var_val[256];
     long this_var;
-    char **pam_env = pam_getenvlist(pamh);
+    char **pam_env = pam_getenvlist((pam_handle_t *)pamh);
     for(this_var = 0; pam_env && pam_env[this_var]; this_var++)
       {
-        if(strlen(pam_env[this_var]) < sizeof(var_name))
+        if(strlen(pam_env[this_var]) < (sizeof(var_name) - 1))
           if((equal_sign = strstr(pam_env[this_var], "=")) != NULL)
             {
               memset(var_name, 0, sizeof(var_name));
@@ -2511,7 +2548,7 @@ void do_child(const char *command, struct passwd *pw, const char *term,
       } else {
         /* Launch login(1). */
 
-        execl("/usr/bin/login", "login", "-h", get_remote_ipaddr(), "-p", "-f", "--", pw->pw_name, NULL);
+        execl(LOGIN_PROGRAM, "login", "-h", get_remote_ipaddr(), "-p", "-f", "--", pw->pw_name, NULL);
 
         /* Login couldn't be executed, die. */
 
This page took 0.080139 seconds and 4 git commands to generate.