- (djm) Big OpenBSD sync:
   - markus@cvs.openbsd.org  2000/09/30 10:27:44
     [log.c]
     allow loglevel debug
   - markus@cvs.openbsd.org  2000/10/03 11:59:57
     [packet.c]
     hmac->mac
   - markus@cvs.openbsd.org  2000/10/03 12:03:03
     [auth-krb4.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c auth-rsa.c auth1.c]
     move fake-auth from auth1.c to individual auth methods, disables s/key in
     debug-msg
   - markus@cvs.openbsd.org  2000/10/03 12:16:48
     ssh.c
     do not resolve canonname, i have no idea why this was added oin ossh
   - markus@cvs.openbsd.org  2000/10/09 15:30:44
     ssh-keygen.1 ssh-keygen.c
     -X now reads private ssh.com DSA keys, too.
   - markus@cvs.openbsd.org  2000/10/09 15:32:34
     auth-options.c
     clear options on every call.
   - markus@cvs.openbsd.org  2000/10/09 15:51:00
     authfd.c authfd.h
     interop with ssh-agent2, from <res@shore.net>
   - markus@cvs.openbsd.org  2000/10/10 14:20:45
     compat.c
     use rexexp for version string matching
   - provos@cvs.openbsd.org  2000/10/10 22:02:18
     [kex.c kex.h myproposal.h ssh.h ssh2.h sshconnect2.c sshd.c dh.c dh.h]
     First rough implementation of the diffie-hellman group exchange.  The
     client can ask the server for bigger groups to perform the diffie-hellman
     in, thus increasing the attack complexity when using ciphers with longer
     keys.  University of Windsor provided network, T the company.
   - markus@cvs.openbsd.org  2000/10/11 13:59:52
     [auth-rsa.c auth2.c]
     clear auth options unless auth sucessfull
   - markus@cvs.openbsd.org  2000/10/11 14:00:27
     [auth-options.h]
     clear auth options unless auth sucessfull
   - markus@cvs.openbsd.org  2000/10/11 14:03:27
     [scp.1 scp.c]
     support 'scp -o' with help from mouring@pconline.com
   - markus@cvs.openbsd.org  2000/10/11 14:11:35
     [dh.c]
     Wall
   - markus@cvs.openbsd.org  2000/10/11 14:14:40
     [auth.h auth2.c readconf.c readconf.h readpass.c servconf.c servconf.h]
     [ssh.h sshconnect2.c sshd_config auth2-skey.c cli.c cli.h]
     add support for s/key (kbd-interactive) to ssh2, based on work by
     mkiernan@avantgo.com and me
   - markus@cvs.openbsd.org  2000/10/11 14:27:24
     [auth.c auth1.c auth2.c authfile.c cipher.c cipher.h kex.c kex.h]
     [myproposal.h packet.c readconf.c session.c ssh.c ssh.h sshconnect1.c]
     [sshconnect2.c sshd.c]
     new cipher framework
   - markus@cvs.openbsd.org  2000/10/11 14:45:21
     [cipher.c]
     remove DES
   - markus@cvs.openbsd.org  2000/10/12 03:59:20
     [cipher.c cipher.h sshconnect1.c sshconnect2.c sshd.c]
     enable DES in SSH-1 clients only
   - markus@cvs.openbsd.org  2000/10/12 08:21:13
     [kex.h packet.c]
     remove unused
   - markus@cvs.openbsd.org  2000/10/13 12:34:46
     [sshd.c]
     Kludge for F-Secure Macintosh < 1.0.2; appro@fy.chalmers.se
   - markus@cvs.openbsd.org  2000/10/13 12:59:15
     [cipher.c cipher.h myproposal.h  rijndael.c rijndael.h]
     rijndael/aes support
   - markus@cvs.openbsd.org  2000/10/13 13:10:54
     [sshd.8]
     more info about -V
   - markus@cvs.openbsd.org  2000/10/13 13:12:02
     [myproposal.h]
     prefer no compression
diff --git a/auth1.c b/auth1.c
index 99639b5..520da64 100644
--- a/auth1.c
+++ b/auth1.c
@@ -10,28 +10,31 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth1.c,v 1.4 2000/09/07 20:27:49 deraadt Exp $");
-
-#include "xmalloc.h"
-#include "rsa.h"
-#include "ssh.h"
-#include "packet.h"
-#include "buffer.h"
-#include "cipher.h"
-#include "mpaux.h"
-#include "servconf.h"
-#include "compat.h"
-#include "auth.h"
-#include "session.h"
+RCSID("$OpenBSD: auth1.c,v 1.6 2000/10/11 20:27:23 markus Exp $");
 
 #ifdef HAVE_OSF_SIA
 # include <sia.h>
 # include <siad.h>
 #endif
 
+#include "xmalloc.h"
+#include "rsa.h"
+#include "ssh.h"
+#include "packet.h"
+#include "buffer.h"
+#include "mpaux.h"
+#include "servconf.h"
+#include "compat.h"
+#include "auth.h"
+#include "session.h"
+
 /* import */
 extern ServerOptions options;
 extern char *forced_command;
+
+#ifdef WITH_AIXAUTHENTICATE
+extern char *aixloginmsg;
+#endif /* WITH_AIXAUTHENTICATE */
 #ifdef HAVE_OSF_SIA
 extern int saved_argc;
 extern char **saved_argv;
@@ -67,89 +70,21 @@
 }
 
 /*
- * The user does not exist or access is denied,
- * but fake indication that authentication is needed.
+ * read packets and try to authenticate local user 'luser'.
+ * return if authentication is successfull. not that pw == NULL
+ * if the user does not exists or is not allowed to login.
+ * each auth method has to 'fake' authentication for nonexisting
+ * users.
  */
 void
-do_fake_authloop1(char *user)
+do_authloop(struct passwd * pw, char *luser)
 {
-	int attempt = 0;
-
-	log("Faking authloop for illegal user %.200s from %.200s port %d",
-	    user,
-	    get_remote_ipaddr(),
-	    get_remote_port());
-
-#ifdef WITH_AIXAUTHENTICATE 
-	loginfailed(user,get_canonical_hostname(),"ssh");
-#endif /* WITH_AIXAUTHENTICATE */
-
-	/* 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.
-	 */
-	for (attempt = 1;; attempt++) {
-		/* Read a packet.  This will not return if the client disconnects. */
-		int plen;
-#ifndef SKEY
-		(void)packet_read(&plen);
-#else /* SKEY */
-		int type = packet_read(&plen);
-		unsigned int dlen;
-		char *password, *skeyinfo;
-		password = NULL;
-		/* Try to send a fake s/key challenge. */
-		if (options.skey_authentication == 1 &&
-		    (skeyinfo = skey_fake_keyinfo(user)) != NULL) {
-			if (type == SSH_CMSG_AUTH_TIS) {
-				packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
-				packet_put_string(skeyinfo, strlen(skeyinfo));
-				packet_send();
-				packet_write_wait();
-				continue;
-			} else if (type == SSH_CMSG_AUTH_PASSWORD &&
-				   options.password_authentication &&
-				   (password = packet_get_string(&dlen)) != NULL &&
-				   dlen == 5 &&
-				   strncasecmp(password, "s/key", 5) == 0 ) {
-				packet_send_debug(skeyinfo);
-			}
-		}
-		if (password != NULL)
-			xfree(password);
-#endif
-		if (attempt > AUTH_FAIL_MAX)
-			packet_disconnect(AUTH_FAIL_MSG, user);
-
-		/*
-		 * Send failure.  This should be indistinguishable from a
-		 * failed authentication.
-		 */
-		packet_start(SSH_SMSG_FAILURE);
-		packet_send();
-		packet_write_wait();
-	}
-	/* NOTREACHED */
-	abort();
-}
-
-/*
- * read packets and try to authenticate local user *pw.
- * return if authentication is successfull
- */
-void
-do_authloop(struct passwd * pw)
-{
+	int authenticated = 0;
 	int attempt = 0;
 	unsigned int bits;
 	RSA *client_host_key;
 	BIGNUM *n;
-	char *client_user = NULL, *password = NULL;
+	char *client_user, *password;
 	char user[1024];
 	unsigned int dlen;
 	int plen, nlen, elen;
@@ -162,8 +97,12 @@
 	packet_send();
 	packet_write_wait();
 
+	client_user = NULL;
+
 	for (attempt = 1;; attempt++) {
-		int authenticated = 0;
+		/* default to fail */
+		authenticated = 0;
+
 		strlcpy(user, "", sizeof user);
 
 		/* Get a packet from the client. */
@@ -174,7 +113,6 @@
 #ifdef AFS
 		case SSH_CMSG_HAVE_KERBEROS_TGT:
 			if (!options.kerberos_tgt_passing) {
-				/* packet_get_all(); */
 				verbose("Kerberos tgt passing disabled.");
 				break;
 			} else {
@@ -182,14 +120,13 @@
 				char *tgt = packet_get_string(&dlen);
 				packet_integrity_check(plen, 4 + dlen, type);
 				if (!auth_kerberos_tgt(pw, tgt))
-					verbose("Kerberos tgt REFUSED for %s", pw->pw_name);
+					verbose("Kerberos tgt REFUSED for %.100s", luser);
 				xfree(tgt);
 			}
 			continue;
 
 		case SSH_CMSG_HAVE_AFS_TOKEN:
 			if (!options.afs_token_passing || !k_hasafs()) {
-				/* packet_get_all(); */
 				verbose("AFS token passing disabled.");
 				break;
 			} else {
@@ -197,7 +134,7 @@
 				char *token_string = packet_get_string(&dlen);
 				packet_integrity_check(plen, 4 + dlen, type);
 				if (!auth_afs_token(pw, token_string))
-					verbose("AFS token REFUSED for %s", pw->pw_name);
+					verbose("AFS token REFUSED for %.100s", luser);
 				xfree(token_string);
 			}
 			continue;
@@ -219,11 +156,12 @@
 					memcpy(auth.dat, kdata, auth.length);
 				xfree(kdata);
 
-				authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
-
-				if (authenticated) {
-					snprintf(user, sizeof user, " tktuser %s", tkt_user);
-					xfree(tkt_user);
+				if (pw != NULL) {
+					authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
+					if (authenticated) {
+						snprintf(user, sizeof user, " tktuser %s", tkt_user);
+						xfree(tkt_user);
+					}
 				}
 			}
 			break;
@@ -243,8 +181,7 @@
 			client_user = packet_get_string(&ulen);
 			packet_integrity_check(plen, 4 + ulen, type);
 
-			/* Try to authenticate using /etc/hosts.equiv and
-			   .rhosts. */
+			/* Try to authenticate using /etc/hosts.equiv and .rhosts. */
 			authenticated = auth_rhosts(pw, client_user);
 
 			snprintf(user, sizeof user, " ruser %s", client_user);
@@ -275,7 +212,7 @@
 			packet_get_bignum(client_host_key->n, &nlen);
 
 			if (bits != BN_num_bits(client_host_key->n))
-				log("Warning: keysize mismatch for client_host_key: "
+				verbose("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);
 
@@ -322,7 +259,7 @@
 				authenticated = 1;
 			}
 #else /* !USE_PAM && !HAVE_OSF_SIA */
-			/* Try authentication with the password. */
+ 			/* Try authentication with the password. */
 			authenticated = auth_password(pw, password);
 #endif /* USE_PAM */
 
@@ -334,16 +271,18 @@
 		case SSH_CMSG_AUTH_TIS:
 			debug("rcvd SSH_CMSG_AUTH_TIS");
 			if (options.skey_authentication == 1) {
-				char *skeyinfo = skey_keyinfo(pw->pw_name);
+				char *skeyinfo = NULL;
+				if (pw != NULL)
+					skey_keyinfo(pw->pw_name);
 				if (skeyinfo == NULL) {
-					debug("generating fake skeyinfo for %.100s.", pw->pw_name);
-					skeyinfo = skey_fake_keyinfo(pw->pw_name);
+					debug("generating fake skeyinfo for %.100s.", luser);
+					skeyinfo = skey_fake_keyinfo(luser);
 				}
 				if (skeyinfo != NULL) {
 					/* we send our s/key- in tis-challenge messages */
 					debug("sending challenge '%s'", skeyinfo);
 					packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
-					packet_put_string(skeyinfo, strlen(skeyinfo));
+					packet_put_cstring(skeyinfo);
 					packet_send();
 					packet_write_wait();
 					continue;
@@ -356,8 +295,9 @@
 				char *response = packet_get_string(&dlen);
 				debug("skey response == '%s'", response);
 				packet_integrity_check(plen, 4 + dlen, type);
-				authenticated = (skey_haskey(pw->pw_name) == 0 &&
-						 skey_passcheck(pw->pw_name, response) != -1);
+				authenticated = (pw != NULL &&
+				    skey_haskey(pw->pw_name) == 0 &&
+				    skey_passcheck(pw->pw_name, response) != -1);
 				xfree(response);
 			}
 			break;
@@ -376,12 +316,14 @@
 			log("Unknown message during authentication: type %d", type);
 			break;
 		}
+		if (authenticated && pw == NULL)
+			fatal("internal error: authenticated for pw == NULL");
 
 #ifdef HAVE_CYGWIN
-		if (authenticated &&
+		if (authenticated && 
 		    !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD,pw->pw_uid)) {
 			packet_disconnect("Authentication rejected for uid %d.",
-					  (int) pw->pw_uid);
+			(int)pw->pw_uid);
 			authenticated = 0;
 		}
 #endif
@@ -391,7 +333,7 @@
 		 * are disallowed.
 		 * Note that root login is allowed for forced commands.
 		 */
-		if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) {
+		if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
 			if (forced_command) {
 				log("Root login accepted for forced command.");
 			} else {
@@ -407,41 +349,33 @@
 		    type == SSH_CMSG_AUTH_PASSWORD)
 			authlog = log;
 
-		authlog("%s %s for %.200s from %.200s port %d%s",
+		authlog("%s %s for %s%.100s from %.200s port %d%s",
 			authenticated ? "Accepted" : "Failed",
 			get_authname(type),
-			pw->pw_uid == 0 ? "ROOT" : pw->pw_name,
+			pw ? "" : "illegal user ",
+			pw && pw->pw_uid == 0 ? "ROOT" : luser,
 			get_remote_ipaddr(),
 			get_remote_port(),
 			user);
 
 #ifdef USE_PAM
-		if (authenticated) {
-			if (!do_pam_account(pw->pw_name, client_user)) {
-				if (client_user != NULL) {
-					xfree(client_user);
-					client_user = NULL;
-				}
-				do_fake_authloop1(pw->pw_name);
-			}
-			return;
-		}
-#else /* USE_PAM */
-		if (authenticated) {
-			return;
-		}
-#endif /* USE_PAM */
+		if (authenticated && !do_pam_account(pw->pw_name, client_user))
+			authenticated = 0;
+#endif
 
 		if (client_user != NULL) {
 			xfree(client_user);
 			client_user = NULL;
 		}
 
+		if (authenticated)
+			return;
+
 		if (attempt > AUTH_FAIL_MAX) {
 #ifdef WITH_AIXAUTHENTICATE 
-			loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
+			loginfailed(user,get_canonical_hostname(),"ssh");
 #endif /* WITH_AIXAUTHENTICATE */
-			packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
+			packet_disconnect(AUTH_FAIL_MSG, luser);
 		}
 
 		/* Send a message indicating that the authentication attempt failed. */
@@ -462,9 +396,6 @@
 	int plen;
 	unsigned int ulen;
 	char *user;
-#ifdef WITH_AIXAUTHENTICATE
-	extern char *aixloginmsg;
-#endif /* WITH_AIXAUTHENTICATE */
 
 	/* Get the name of the user that we wish to log in as. */
 	packet_read_expect(&plen, SSH_CMSG_USER);
@@ -485,38 +416,38 @@
 
 	/* Verify that the user is a valid user. */
 	pw = getpwnam(user);
-	if (!pw || !allowed_user(pw))
-		do_fake_authloop1(user);
-	xfree(user);
-
-	/* Take a copy of the returned structure. */
-	memset(&pwcopy, 0, sizeof(pwcopy));
-	pwcopy.pw_name = xstrdup(pw->pw_name);
-	pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
-	pwcopy.pw_uid = pw->pw_uid;
-	pwcopy.pw_gid = pw->pw_gid;
+	if (pw && allowed_user(pw)) {
+		/* Take a copy of the returned structure. */
+		memset(&pwcopy, 0, sizeof(pwcopy));
+		pwcopy.pw_name = xstrdup(pw->pw_name);
+		pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
+		pwcopy.pw_uid = pw->pw_uid;
+		pwcopy.pw_gid = pw->pw_gid;
 #ifdef HAVE_PW_CLASS_IN_PASSWD
-	pwcopy.pw_class = xstrdup(pw->pw_class);
+		pwcopy.pw_class = xstrdup(pw->pw_class);
 #endif
-	pwcopy.pw_dir = xstrdup(pw->pw_dir);
-	pwcopy.pw_shell = xstrdup(pw->pw_shell);
-	pw = &pwcopy;
+		pwcopy.pw_dir = xstrdup(pw->pw_dir);
+		pwcopy.pw_shell = xstrdup(pw->pw_shell);
+		pw = &pwcopy;
+	} else {
+		pw = NULL;
+	}
 
 #ifdef USE_PAM
-	start_pam(pw);
+	if (pw)
+		start_pam(pw);
 #endif
 
-#ifndef HAVE_CYGWIN
 	/*
 	 * If we are not running as root, the user must have the same uid as
-	 * the server.
-	 * Rule not valid on Windows systems.
+	 * the server. (Unless you are running Windows)
 	 */
-	if (getuid() != 0 && pw->pw_uid != getuid())
+#ifndef HAVE_CYGWIN
+	if (getuid() != 0 && pw && pw->pw_uid != getuid())
 		packet_disconnect("Cannot change user when server not running as root.");
 #endif
 
-	debug("Attempting authentication for %.100s.", pw->pw_name);
+	debug("Attempting authentication for %s%.100s.", pw ? "" : "illegal user ", user);
 
 	/* If the user has no password, accept authentication immediately. */
 	if (options.password_authentication &&
@@ -527,30 +458,33 @@
 	    auth_pam_password(pw, "")) {
 #elif defined(HAVE_OSF_SIA)
 	    (sia_validate_user(NULL, saved_argc, saved_argv, 
-	    get_canonical_hostname(), pw->pw_name, NULL, 0, NULL, 
-	    "") == SIASUCCESS)) {
+	    get_canonical_hostname(), pw->pw_name, NULL, 0, 
+		 NULL, "") == SIASUCCESS)) {
 #else /* !HAVE_OSF_SIA && !USE_PAM */
-	    auth_password(pw, "")) {
+ 	    auth_password(pw, "")) {
 #endif /* USE_PAM */
 		/* Authentication with empty password succeeded. */
 		log("Login for user %s from %.100s, accepted without authentication.",
-		    pw->pw_name, get_remote_ipaddr());
+		    user, get_remote_ipaddr());
 	} else {
 		/* Loop until the user has been authenticated or the
 		   connection is closed, do_authloop() returns only if
 		   authentication is successfull */
-		do_authloop(pw);
+		do_authloop(pw, user);
 	}
+	if (pw == NULL)
+		fatal("internal error, authentication successfull for user '%.100s'", user);
 
 	/* The user has been authenticated and accepted. */
+	packet_start(SSH_SMSG_SUCCESS);
+	packet_send();
+	packet_write_wait();
+
 #ifdef WITH_AIXAUTHENTICATE
 	/* We don't have a pty yet, so just label the line as "ssh" */
 	if (loginsuccess(user,get_canonical_hostname(),"ssh",&aixloginmsg) < 0)
 		aixloginmsg = NULL;
 #endif /* WITH_AIXAUTHENTICATE */
-	packet_start(SSH_SMSG_SUCCESS);
-	packet_send();
-	packet_write_wait();
 
 	/* Perform session preparation. */
 	do_authenticated(pw);