- djm@cvs.openbsd.org 2005/05/20 12:57:01;
   [auth1.c] split protocol 1 auth methods into separate functions, makes
   authloop much more readable; fixes and ok markus@ (portable ok &
   polish dtucker@)
diff --git a/ChangeLog b/ChangeLog
index 3cfba58..76e88a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+20050618
+ - (djm) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2005/05/20 12:57:01;
+   [auth1.c] split protocol 1 auth methods into separate functions, makes 
+   authloop much more readable; fixes and ok markus@ (portable ok & 
+   polish dtucker@)
+
 20050617
  - (djm) OpenBSD CVS Sync
    - djm@cvs.openbsd.org 2005/06/16 03:38:36
@@ -2738,4 +2745,4 @@
    - (djm) Trim deprecated options from INSTALL. Mention UsePAM
    - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
 
-$Id: ChangeLog,v 1.3824 2005/06/17 11:15:20 dtucker Exp $
+$Id: ChangeLog,v 1.3825 2005/06/18 21:31:37 djm Exp $
diff --git a/auth1.c b/auth1.c
index d089284..b7dfa98 100644
--- a/auth1.c
+++ b/auth1.c
@@ -10,7 +10,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth1.c,v 1.59 2004/07/28 09:40:29 markus Exp $");
+RCSID("$OpenBSD: auth1.c,v 1.60 2005/05/20 12:57:01 djm Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -31,28 +31,181 @@
 extern ServerOptions options;
 extern Buffer loginmsg;
 
-/*
- * convert ssh auth msg type into description
- */
+static int auth1_process_password(Authctxt *, char *, size_t);
+static int auth1_process_rsa(Authctxt *, char *, size_t);
+static int auth1_process_rhosts_rsa(Authctxt *, char *, size_t);
+static int auth1_process_tis_challenge(Authctxt *, char *, size_t);
+static int auth1_process_tis_response(Authctxt *, char *, size_t);
+
+static char *client_user = NULL;    /* Used to fill in remote user for PAM */
+
+struct AuthMethod1 {
+	int type;
+	char *name;
+	int *enabled;
+	int (*method)(Authctxt *, char *, size_t);
+};
+
+const struct AuthMethod1 auth1_methods[] = {
+	{
+		SSH_CMSG_AUTH_PASSWORD, "password",
+		&options.password_authentication, auth1_process_password
+	},
+	{
+		SSH_CMSG_AUTH_RSA, "rsa",
+		&options.rsa_authentication, auth1_process_rsa
+	},
+	{
+		SSH_CMSG_AUTH_RHOSTS_RSA, "rhosts-rsa",
+		&options.rhosts_rsa_authentication, auth1_process_rhosts_rsa
+	},
+	{
+		SSH_CMSG_AUTH_TIS, "challenge-response",
+		&options.challenge_response_authentication,
+		auth1_process_tis_challenge
+	},
+	{
+		SSH_CMSG_AUTH_TIS_RESPONSE, "challenge-response",
+		&options.challenge_response_authentication,
+		auth1_process_tis_response
+	},
+	{ -1, NULL, NULL, NULL}
+};
+
+static const struct AuthMethod1
+*lookup_authmethod1(int type)
+{
+	int i;
+
+	for(i = 0; auth1_methods[i].name != NULL; i++)
+		if (auth1_methods[i].type == type)
+			return (&(auth1_methods[i]));
+
+	return (NULL);
+}
+
 static char *
 get_authname(int type)
 {
-	static char buf[1024];
-	switch (type) {
-	case SSH_CMSG_AUTH_PASSWORD:
-		return "password";
-	case SSH_CMSG_AUTH_RSA:
-		return "rsa";
-	case SSH_CMSG_AUTH_RHOSTS_RSA:
-		return "rhosts-rsa";
-	case SSH_CMSG_AUTH_RHOSTS:
-		return "rhosts";
-	case SSH_CMSG_AUTH_TIS:
-	case SSH_CMSG_AUTH_TIS_RESPONSE:
-		return "challenge-response";
+	const struct AuthMethod1 *a;
+	static char buf[64];
+
+	if ((a = lookup_authmethod1(type)) != NULL)
+		return (a->name);
+	snprintf(buf, sizeof(buf), "bad-auth-msg-%d", type);
+	return (buf);
+}
+
+static int
+auth1_process_password(Authctxt *authctxt, char *info, size_t infolen)
+{
+	int authenticated = 0;
+	char *password;
+	u_int dlen;
+
+	/*
+	 * 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_check_eom();
+
+	/* Try authentication with the password. */
+	authenticated = PRIVSEP(auth_password(authctxt, password));
+
+	memset(password, 0, dlen);
+	xfree(password);
+
+	return (authenticated);
+}
+
+static int
+auth1_process_rsa(Authctxt *authctxt, char *info, size_t infolen)
+{
+	int authenticated = 0;
+	BIGNUM *n;
+
+	/* RSA authentication requested. */
+	if ((n = BN_new()) == NULL)
+		fatal("do_authloop: BN_new failed");
+	packet_get_bignum(n);
+	packet_check_eom();
+	authenticated = auth_rsa(authctxt, n);
+	BN_clear_free(n);
+
+	return (authenticated);
+}
+
+static int
+auth1_process_rhosts_rsa(Authctxt *authctxt, char *info, size_t infolen)
+{
+	int authenticated = 0;
+	u_int bits;
+	Key *client_host_key;
+	u_int ulen;
+
+	/*
+	 * 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 = key_new(KEY_RSA1);
+	bits = packet_get_int();
+	packet_get_bignum(client_host_key->rsa->e);
+	packet_get_bignum(client_host_key->rsa->n);
+
+	if (bits != BN_num_bits(client_host_key->rsa->n)) {
+		verbose("Warning: keysize mismatch for client_host_key: "
+		    "actual %d, announced %d",
+		    BN_num_bits(client_host_key->rsa->n), bits);
 	}
-	snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
-	return buf;
+	packet_check_eom();
+
+	authenticated = auth_rhosts_rsa(authctxt, client_user,
+	    client_host_key);
+	key_free(client_host_key);
+
+	snprintf(info, infolen, " ruser %.100s", client_user);
+	
+	return (authenticated);
+}
+
+static int
+auth1_process_tis_challenge(Authctxt *authctxt, char *info, size_t infolen)
+{
+	char *challenge;
+	
+	if ((challenge = get_challenge(authctxt)) == NULL)
+		return (0);
+
+	debug("sending challenge '%s'", challenge);
+	packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
+	packet_put_cstring(challenge);
+	xfree(challenge);
+	packet_send();
+	packet_write_wait();
+
+	return (-1);
+}
+
+static int
+auth1_process_tis_response(Authctxt *authctxt, char *info, size_t infolen)
+{
+	int authenticated = 0;
+	char *response;
+	u_int dlen;
+
+	response = packet_get_string(&dlen);
+	packet_check_eom();
+	authenticated = verify_response(authctxt, response);
+	memset(response, 'r', dlen);
+	xfree(response);
+
+	return (authenticated);
 }
 
 /*
@@ -63,14 +216,9 @@
 do_authloop(Authctxt *authctxt)
 {
 	int authenticated = 0;
-	u_int bits;
-	Key *client_host_key;
-	BIGNUM *n;
-	char *client_user, *password;
 	char info[1024];
-	u_int dlen;
-	u_int ulen;
-	int prev, type = 0;
+	int prev = 0, type = 0;
+	const struct AuthMethod1 *meth;
 
 	debug("Attempting authentication for %s%.100s.",
 	    authctxt->valid ? "" : "invalid user ", authctxt->user);
@@ -95,8 +243,6 @@
 	packet_send();
 	packet_write_wait();
 
-	client_user = NULL;
-
 	for (;;) {
 		/* default to fail */
 		authenticated = 0;
@@ -118,107 +264,21 @@
 		    type != SSH_CMSG_AUTH_TIS_RESPONSE)
 			abandon_challenge_response(authctxt);
 
-		/* Process the packet. */
-		switch (type) {
-		case SSH_CMSG_AUTH_RHOSTS_RSA:
-			if (!options.rhosts_rsa_authentication) {
-				verbose("Rhosts with RSA authentication disabled.");
-				break;
-			}
-			/*
-			 * Get client user name.  Note that we just have to
-			 * trust the client; root on the client machine can
-			 * claim to be any user.
-			 */
-			client_user = packet_get_string(&ulen);
-
-			/* Get the client host key. */
-			client_host_key = key_new(KEY_RSA1);
-			bits = packet_get_int();
-			packet_get_bignum(client_host_key->rsa->e);
-			packet_get_bignum(client_host_key->rsa->n);
-
-			if (bits != BN_num_bits(client_host_key->rsa->n))
-				verbose("Warning: keysize mismatch for client_host_key: "
-				    "actual %d, announced %d",
-				    BN_num_bits(client_host_key->rsa->n), bits);
-			packet_check_eom();
-
-			authenticated = auth_rhosts_rsa(authctxt, client_user,
-			    client_host_key);
-			key_free(client_host_key);
-
-			snprintf(info, sizeof info, " ruser %.100s", client_user);
-			break;
-
-		case SSH_CMSG_AUTH_RSA:
-			if (!options.rsa_authentication) {
-				verbose("RSA authentication disabled.");
-				break;
-			}
-			/* RSA authentication requested. */
-			if ((n = BN_new()) == NULL)
-				fatal("do_authloop: BN_new failed");
-			packet_get_bignum(n);
-			packet_check_eom();
-			authenticated = auth_rsa(authctxt, n);
-			BN_clear_free(n);
-			break;
-
-		case SSH_CMSG_AUTH_PASSWORD:
-			if (!options.password_authentication) {
-				verbose("Password authentication disabled.");
-				break;
-			}
-			/*
-			 * Read user password.  It is in plain text, but was
-			 * transmitted over the encrypted channel so it is
-			 * not visible to an outside observer.
-			 */
-			password = packet_get_string(&dlen);
-			packet_check_eom();
-
-			/* Try authentication with the password. */
-			authenticated = PRIVSEP(auth_password(authctxt, password));
-
-			memset(password, 0, strlen(password));
-			xfree(password);
-			break;
-
-		case SSH_CMSG_AUTH_TIS:
-			debug("rcvd SSH_CMSG_AUTH_TIS");
-			if (options.challenge_response_authentication == 1) {
-				char *challenge = get_challenge(authctxt);
-				if (challenge != NULL) {
-					debug("sending challenge '%s'", challenge);
-					packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
-					packet_put_cstring(challenge);
-					xfree(challenge);
-					packet_send();
-					packet_write_wait();
-					continue;
-				}
-			}
-			break;
-		case SSH_CMSG_AUTH_TIS_RESPONSE:
-			debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
-			if (options.challenge_response_authentication == 1) {
-				char *response = packet_get_string(&dlen);
-				packet_check_eom();
-				authenticated = verify_response(authctxt, response);
-				memset(response, 'r', dlen);
-				xfree(response);
-			}
-			break;
-
-		default:
-			/*
-			 * Any unknown messages will be ignored (and failure
-			 * returned) during authentication.
-			 */
-			logit("Unknown message during authentication: type %d", type);
-			break;
+		if ((meth = lookup_authmethod1(type)) == NULL) {
+			logit("Unknown message during authentication: "
+			    "type %d", type);
+			goto skip;
 		}
+
+		if (!*(meth->enabled)) {
+			verbose("%s authentication disabled.", meth->name);
+			goto skip;
+		}
+
+		authenticated = meth->method(authctxt, info, sizeof(info));
+		if (authenticated == -1)
+			continue; /* "postponed" */
+
 #ifdef BSD_AUTH
 		if (authctxt->as) {
 			auth_close(authctxt->as);
@@ -247,8 +307,8 @@
 #else
 		/* Special handling for root */
 		if (authenticated && authctxt->pw->pw_uid == 0 &&
-		    !auth_root_allowed(get_authname(type))) {
-			authenticated = 0;
+		    !auth_root_allowed(meth->name)) {
+ 			authenticated = 0;
 # ifdef SSH_AUDIT_EVENTS
 			PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
 # endif
@@ -276,6 +336,7 @@
 		}
 #endif
 
+ skip:
 		/* Log before sending the reply */
 		auth_log(authctxt, authenticated, get_authname(type), info);
 
@@ -341,7 +402,7 @@
 
 	/*
 	 * If we are not running as root, the user must have the same uid as
-	 * the server. (Unless you are running Windows)
+	 * the server.
 	 */
 #ifndef HAVE_CYGWIN
 	if (!use_privsep && getuid() != 0 && authctxt->pw &&