--- options.h	cc4daa6019aab0ada058027a96817de43ce44fdc
+++ options.h	aa73a7020edf3744ad1f16619515939168c3999d
@@ -158,10 +158,11 @@ much traffic. */
 /* Authentication Types - at least one required.
    RFC Draft requires pubkey auth, and recommends password */
 
-/* Note: PAM auth is quite simple, and only works for PAM modules which just do
+/* Note: PAM auth is quite simple and only works for PAM modules which just do
  * a simple "Login: " "Password: " (you can edit the strings in svr-authpam.c).
- * It's useful for systems like OS X where standard password crypts don't work,
- * but there's an interface via a PAM module - don't bother using it otherwise.
+ * It's useful for systems like OS X where standard password crypts don't work
+ * but there's an interface via a PAM module. It won't work for more complex
+ * PAM challenge/response.
  * You can't enable both PASSWORD and PAM. */
 
 #define ENABLE_SVR_PASSWORD_AUTH
@@ -175,6 +176,12 @@ much traffic. */
 #define ENABLE_SVR_PUBKEY_OPTIONS
 #endif
 
+/* Define this to allow logging in to accounts that have no password specified.
+ * Public key logins are allowed for blank-password accounts regardless of this
+ * setting.  PAM is not affected by this setting, it uses the normal pam.d
+ * settings ('nullok' option) */
+/* #define ALLOW_BLANK_PASSWORD */
+
 #define ENABLE_CLI_PASSWORD_AUTH
 #define ENABLE_CLI_PUBKEY_AUTH
 #define ENABLE_CLI_INTERACT_AUTH
============================================================
--- svr-auth.c	87ba6602f2f7bcbe1a4ef6d351fa3263287cbd24
+++ svr-auth.c	f85b12a830f621d2abc22d2ec205f4833cdd1dcc
@@ -249,15 +249,6 @@ static int checkusername(unsigned char *
 		return DROPBEAR_FAILURE;
 	}
 
-	/* check for an empty password */
-	if (ses.authstate.pw_passwd[0] == '\0') {
-		TRACE(("leave checkusername: empty pword"))
-		dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
-				ses.authstate.pw_name);
-		send_msg_userauth_failure(0, 1);
-		return DROPBEAR_FAILURE;
-	}
-
 	TRACE(("shell is %s", ses.authstate.pw_shell))
 
 	/* check that the shell is set */
============================================================
--- svr-authpasswd.c	93639d92d64e6f2455174a9841290bc09f5fcf98
+++ svr-authpasswd.c	03a2ed6543ebcab3d1c1c42ad6dafea87dbbce77
@@ -42,6 +42,7 @@ void svr_auth_password() {
 	char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
 	char * testcrypt = NULL; /* crypt generated from the user's password sent */
 	unsigned char * password;
+	int success_blank = 0;
 	unsigned int passwordlen;
 
 	unsigned int changepw;
@@ -60,16 +61,6 @@ void svr_auth_password() {
 	passwdcrypt = DEBUG_HACKCRYPT;
 #endif
 
-	/* check for empty password - need to do this again here
-	 * since the shadow password may differ to that tested
-	 * in auth.c */
-	if (passwdcrypt[0] == '\0') {
-		dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
-				ses.authstate.pw_name);
-		send_msg_userauth_failure(0, 1);
-		return;
-	}
-
 	/* check if client wants to change password */
 	changepw = buf_getbool(ses.payload);
 	if (changepw) {
@@ -85,7 +76,21 @@ void svr_auth_password() {
 	m_burn(password, passwordlen);
 	m_free(password);
 
-	if (strcmp(testcrypt, passwdcrypt) == 0) {
+	/* check for empty password */
+	if (passwdcrypt[0] == '\0') {
+#ifdef ALLOW_BLANK_PASSWORD
+		if (passwordlen == 0) {
+			success_blank = 1;
+		}
+#else
+		dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
+				ses.authstate.pw_name);
+		send_msg_userauth_failure(0, 1);
+		return;
+#endif
+	}
+
+	if (success_blank || strcmp(testcrypt, passwdcrypt) == 0) {
 		/* successful authentication */
 		dropbear_log(LOG_NOTICE, 
 				"Password auth succeeded for '%s' from %s",
@@ -99,7 +104,6 @@ void svr_auth_password() {
 				svr_ses.addrstring);
 		send_msg_userauth_failure(0, 1);
 	}
-
 }
 
 #endif
