From 22a2c4b576fe1423382e68b418d954208555ba34 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Thu, 6 May 2004 16:59:16 +0000
Subject: [PATCH] Erase MD5 user passwords when a user is renamed because the
 username is used as salt for the MD5 password.

---
 doc/src/sgml/ref/alter_user.sgml |  5 ++-
 src/backend/commands/user.c      | 55 ++++++++++++++++++++++++--------
 2 files changed, 46 insertions(+), 14 deletions(-)

diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml
index 4af08885094..e74da13c877 100644
--- a/doc/src/sgml/ref/alter_user.sgml
+++ b/doc/src/sgml/ref/alter_user.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.32 2003/11/29 19:51:38 pgsql Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.33 2004/05/06 16:59:16 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -57,6 +57,9 @@ ALTER USER <replaceable class="PARAMETER">name</replaceable> RESET <replaceable>
    The second variant changes the name of the user.  Only a database
    superuser can rename user accounts.  The session user cannot be
    renamed.  (Connect as a different user if you need to do that.)
+   Because <literal>MD5</>-encrypted passwords use the username as
+   cryptographic salt, renaming a user clears their <literal>MD5</>
+   password.
   </para>
 
   <para>
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index d646c8e14b3..476e7e1865e 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.139 2004/03/16 05:05:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.140 2004/05/06 16:59:16 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -959,8 +959,8 @@ AlterUserSet(AlterUserSetStmt *stmt)
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("user \"%s\" does not exist", stmt->user)));
 
-	if (!(superuser()
-	 || ((Form_pg_shadow) GETSTRUCT(oldtuple))->usesysid == GetUserId()))
+	if (!(superuser() ||
+	    ((Form_pg_shadow) GETSTRUCT(oldtuple))->usesysid == GetUserId()))
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("permission denied")));
@@ -1157,16 +1157,25 @@ DropUser(DropUserStmt *stmt)
 void
 RenameUser(const char *oldname, const char *newname)
 {
-	HeapTuple	tup;
+	HeapTuple	oldtuple,
+				newtuple;
+	TupleDesc	dsc;
 	Relation	rel;
-
+	Datum		datum;
+	bool		isnull;
+	Datum		repl_val[Natts_pg_shadow];
+	char		repl_null[Natts_pg_shadow];
+	char		repl_repl[Natts_pg_shadow];
+	int			i;
+	
 	/* ExclusiveLock because we need to update the password file */
 	rel = heap_openr(ShadowRelationName, ExclusiveLock);
+	dsc = RelationGetDescr(rel);
 
-	tup = SearchSysCacheCopy(SHADOWNAME,
+	oldtuple = SearchSysCache(SHADOWNAME,
 							 CStringGetDatum(oldname),
 							 0, 0, 0);
-	if (!HeapTupleIsValid(tup))
+	if (!HeapTupleIsValid(oldtuple))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("user \"%s\" does not exist", oldname)));
@@ -1177,7 +1186,7 @@ RenameUser(const char *oldname, const char *newname)
 	 * not be an actual problem besides a little confusion, so think about
 	 * this and decide.
 	 */
-	if (((Form_pg_shadow) GETSTRUCT(tup))->usesysid == GetSessionUserId())
+	if (((Form_pg_shadow) GETSTRUCT(oldtuple))->usesysid == GetSessionUserId())
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("session user may not be renamed")));
@@ -1196,13 +1205,33 @@ RenameUser(const char *oldname, const char *newname)
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("must be superuser to rename users")));
 
-	/* rename */
-	namestrcpy(&(((Form_pg_shadow) GETSTRUCT(tup))->usename), newname);
-	simple_heap_update(rel, &tup->t_self, tup);
-	CatalogUpdateIndexes(rel, tup);
+	for (i = 0; i < Natts_pg_shadow; i++)
+		repl_repl[i] = ' ';
+
+	repl_repl[Anum_pg_shadow_usename - 1] = 'r';
+	repl_val[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein,
+											CStringGetDatum(newname));
+	repl_null[Anum_pg_shadow_usename - 1] = ' ';
 
+	datum = heap_getattr(oldtuple, Anum_pg_shadow_passwd, dsc, &isnull);
+
+	if (!isnull && isMD5(DatumGetCString(DirectFunctionCall1(textout, datum))))
+	{
+		/* MD5 uses the username as salt, so just clear it on a rename */
+		repl_repl[Anum_pg_shadow_passwd - 1] = 'r';
+		repl_null[Anum_pg_shadow_passwd - 1] = 'n';
+	
+		ereport(NOTICE,
+			(errmsg("MD5 password cleared because of user rename")));
+	}
+			 
+	newtuple = heap_modifytuple(oldtuple, rel, repl_val, repl_null, repl_repl);
+	simple_heap_update(rel, &oldtuple->t_self, newtuple);
+	
+	CatalogUpdateIndexes(rel, newtuple);
+
+	ReleaseSysCache(oldtuple);
 	heap_close(rel, NoLock);
-	heap_freetuple(tup);
 
 	user_file_update_needed = true;
 }
-- 
GitLab