From 7c326e7b0ae7a4e614d4f21703e0987d235d42aa Mon Sep 17 00:00:00 2001
From: Vaishnavi Prabakaran <Vaishnavi.Prabakaran@au.fujitsu.com>
Date: Wed, 10 May 2017 11:39:50 +1000
Subject: [PATCH] Removal of plaintext password reference

---
 src/backend/commands/user.c    |  6 +++---
 src/backend/libpq/auth-scram.c |  2 +-
 src/backend/libpq/auth.c       |  2 +-
 src/backend/libpq/crypt.c      | 35 +++++++++++++++++++----------------
 src/include/commands/user.h    |  2 +-
 src/include/libpq/crypt.h      |  9 +++++++--
 6 files changed, 32 insertions(+), 24 deletions(-)

diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 36d5f40..841fc98 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -362,7 +362,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
 	if (check_password_hook && password)
 		(*check_password_hook) (stmt->role,
 								password,
-								get_password_type(password),
+								isPasswordEncrypted(password),
 								validUntil_datum,
 								validUntil_null);
 
@@ -724,7 +724,7 @@ AlterRole(AlterRoleStmt *stmt)
 	if (check_password_hook && password)
 		(*check_password_hook) (rolename,
 								password,
-								get_password_type(password),
+								isPasswordEncrypted(password),
 								validUntil_datum,
 								validUntil_null);
 
@@ -1204,7 +1204,7 @@ RenameRole(const char *oldname, const char *newname)
 
 	datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
 
-	if (!isnull && get_password_type(TextDatumGetCString(datum)) == PASSWORD_TYPE_MD5)
+	if (!isnull && get_password_encryption_type(TextDatumGetCString(datum)) == PASSWORD_TYPE_MD5)
 	{
 		/* MD5 uses the username as salt, so just clear it on a rename */
 		repl_repl[Anum_pg_authid_rolpassword - 1] = true;
diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c
index 99feb0c..8aebaeb 100644
--- a/src/backend/libpq/auth-scram.c
+++ b/src/backend/libpq/auth-scram.c
@@ -182,7 +182,7 @@ pg_be_scram_init(const char *username, const char *shadow_pass)
 	 */
 	if (shadow_pass)
 	{
-		int			password_type = get_password_type(shadow_pass);
+		int			password_type = get_password_encryption_type(shadow_pass);
 
 		if (password_type == PASSWORD_TYPE_SCRAM_SHA_256)
 		{
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 6d3ff68..dadfdd4 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -765,7 +765,7 @@ CheckPWChallengeAuth(Port *port, char **logdetail)
 	if (!shadow_pass)
 		pwtype = Password_encryption;
 	else
-		pwtype = get_password_type(shadow_pass);
+		pwtype = get_password_encryption_type(shadow_pass);
 
 	/*
 	 * If 'md5' authentication is allowed, decide whether to perform 'md5' or
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index e7a6b04..1d7c73f 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -96,13 +96,24 @@ get_role_password(const char *role, char **logdetail)
  * What kind of a password verifier is 'shadow_pass'?
  */
 PasswordType
-get_password_type(const char *shadow_pass)
+get_password_encryption_type(const char *shadow_pass)
 {
-	if (strncmp(shadow_pass, "md5", 3) == 0 && strlen(shadow_pass) == MD5_PASSWD_LEN)
+	/* Currently only 2 encryption mechanism are supported, so we can skip verifying password against SCRAM */
+	if(isMD5(shadow_pass))
 		return PASSWORD_TYPE_MD5;
-	if (strncmp(shadow_pass, "SCRAM-SHA-256$", strlen("SCRAM-SHA-256$")) == 0)
+	else
 		return PASSWORD_TYPE_SCRAM_SHA_256;
-	return PASSWORD_TYPE_PLAINTEXT;
+}
+
+/*
+ * Verify whether the given password is already encrypted or not
+ */
+bool
+isPasswordEncrypted(const char *password)
+{
+	if(isMD5(password) || isSCRAM(password))
+		return true;
+	return false;
 }
 
 /*
@@ -116,10 +127,10 @@ char *
 encrypt_password(PasswordType target_type, const char *role,
 				 const char *password)
 {
-	PasswordType guessed_type = get_password_type(password);
+	bool		password_encrypted = isPasswordEncrypted(password);
 	char	   *encrypted_password;
 
-	if (guessed_type != PASSWORD_TYPE_PLAINTEXT)
+	if (password_encrypted)
 	{
 		/*
 		 * Cannot convert an already-encrypted password from one
@@ -141,8 +152,6 @@ encrypt_password(PasswordType target_type, const char *role,
 		case PASSWORD_TYPE_SCRAM_SHA_256:
 			return pg_be_scram_build_verifier(password);
 
-		case PASSWORD_TYPE_PLAINTEXT:
-			elog(ERROR, "cannot encrypt password with 'plaintext'");
 	}
 
 	/*
@@ -175,7 +184,7 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
 
 	Assert(md5_salt_len > 0);
 
-	if (get_password_type(shadow_pass) != PASSWORD_TYPE_MD5)
+	if (get_password_encryption_type(shadow_pass) != PASSWORD_TYPE_MD5)
 	{
 		/* incompatible password hash format. */
 		*logdetail = psprintf(_("User \"%s\" has a password that cannot be used with MD5 authentication."),
@@ -232,7 +241,7 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
 	 * the password the client sent, and compare the hashes.  Otherwise
 	 * compare the plaintext passwords directly.
 	 */
-	switch (get_password_type(shadow_pass))
+	switch (get_password_encryption_type(shadow_pass))
 	{
 		case PASSWORD_TYPE_SCRAM_SHA_256:
 			if (scram_verify_plain_password(role,
@@ -273,12 +282,6 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
 			}
 			break;
 
-		case PASSWORD_TYPE_PLAINTEXT:
-			/*
-			 * We never store passwords in plaintext, so this shouldn't
-			 * happen.
-			 */
-			break;
 	}
 
 	/*
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index 08037e0..4984faa 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -20,7 +20,7 @@
 extern int	Password_encryption;
 
 /* Hook to check passwords in CreateRole() and AlterRole() */
-typedef void (*check_password_hook_type) (const char *username, const char *shadow_pass, PasswordType password_type, Datum validuntil_time, bool validuntil_null);
+typedef void (*check_password_hook_type) (const char *username, const char *shadow_pass, bool password_encrypted, Datum validuntil_time, bool validuntil_null);
 
 extern PGDLLIMPORT check_password_hook_type check_password_hook;
 
diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h
index 9bad67c..5516dba 100644
--- a/src/include/libpq/crypt.h
+++ b/src/include/libpq/crypt.h
@@ -26,12 +26,17 @@
  */
 typedef enum PasswordType
 {
-	PASSWORD_TYPE_PLAINTEXT = 0,
 	PASSWORD_TYPE_MD5,
 	PASSWORD_TYPE_SCRAM_SHA_256
 } PasswordType;
 
-extern PasswordType get_password_type(const char *shadow_pass);
+#define isMD5(password) \
+	((strncmp(password, "md5", 3) == 0 && strlen(password) == MD5_PASSWD_LEN)? 1:0)
+
+#define isSCRAM(password) \
+	( (strncmp(password, "SCRAM-SHA-256$", 14) == 0)? 1 :0)
+
+extern PasswordType get_password_encryption_type(const char *shadow_pass);
 extern char *encrypt_password(PasswordType target_type, const char *role,
 				 const char *password);
 
-- 
2.7.4.windows.1

