From e4f06dc12efaf14878288a175efcf50ce2318813 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Tue, 30 Apr 2002 01:26:26 +0000
Subject: [PATCH] Clean up loose ends remaining from schema privileges
 discussion. I concluded that RENAME should require CREATE privilege on the
 namespace as well as ownership of the table.

---
 doc/src/sgml/ref/grant.sgml         |  4 +-
 src/backend/catalog/namespace.c     |  9 +++-
 src/backend/tcop/utility.c          | 68 ++++++++++++++++++++---------
 src/backend/utils/cache/lsyscache.c | 28 +++++++++++-
 src/include/utils/lsyscache.h       |  3 +-
 5 files changed, 86 insertions(+), 26 deletions(-)

diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index 1697f91929a..226db71d683 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.24 2002/04/29 22:28:19 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.25 2002/04/30 01:26:25 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -161,6 +161,8 @@ GRANT { { CREATE | USAGE } [,...] | ALL [ PRIVILEGES ] }
       </para>
       <para>
        For schemas, allows new objects to be created within the schema.
+       To rename an existing object, you must own the object <emphasis>and</>
+       have this privilege for the containing schema.
       </para>
      </listitem>
     </varlistentry>
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 51ef7c3f8d9..80ce60f8ab2 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.15 2002/04/29 22:15:07 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.16 2002/04/30 01:26:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1161,7 +1161,12 @@ GetTempTableNamespace(void)
 	{
 		/*
 		 * First use of this temp namespace in this database; create it.
-		 * The temp namespaces are always owned by the superuser.
+		 * The temp namespaces are always owned by the superuser.  We
+		 * leave their permissions at default --- i.e., no access except to
+		 * superuser --- to ensure that unprivileged users can't peek
+		 * at other backends' temp tables.  This works because the places
+		 * that access the temp namespace for my own backend skip permissions
+		 * checks on it.
 		 */
 		namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID);
 		/* Advance command counter to make namespace visible */
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 771f3d30cc8..9a9c062559e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.152 2002/04/27 03:45:03 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.153 2002/04/30 01:26:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -374,25 +374,49 @@ ProcessUtility(Node *parsetree,
 		case T_RenameStmt:
 			{
 				RenameStmt *stmt = (RenameStmt *) parsetree;
+				Oid		relid;
 
 				CheckOwnership(stmt->relation, true);
 
+				relid = RangeVarGetRelid(stmt->relation, false);
+
 				switch (stmt->renameType)
 				{
 					case RENAME_TABLE:
-						renamerel(RangeVarGetRelid(stmt->relation, false),
-								  stmt->newname);
+					{
+						/*
+						 * RENAME TABLE requires that we (still) hold CREATE
+						 * rights on the containing namespace, as well as
+						 * ownership of the table.  But skip check for
+						 * temp tables.
+						 */
+						Oid			namespaceId = get_rel_namespace(relid);
+
+						if (!isTempNamespace(namespaceId))
+						{
+							AclResult	aclresult;
+
+							aclresult = pg_namespace_aclcheck(namespaceId,
+															  GetUserId(),
+															  ACL_CREATE);
+							if (aclresult != ACLCHECK_OK)
+								aclcheck_error(aclresult,
+											get_namespace_name(namespaceId));
+						}
+
+						renamerel(relid, stmt->newname);
 						break;
+					}
 					case RENAME_COLUMN:
-						renameatt(RangeVarGetRelid(stmt->relation, false),
-							  stmt->oldname,	/* old att name */
-							  stmt->newname,	/* new att name */
-							  interpretInhOption(stmt->relation->inhOpt));	/* recursive? */
+						renameatt(relid,
+								  stmt->oldname,	/* old att name */
+								  stmt->newname,	/* new att name */
+								  interpretInhOption(stmt->relation->inhOpt));	/* recursive? */
 						break;
 					case RENAME_TRIGGER:
-						renametrig(RangeVarGetRelid(stmt->relation, false),
-							  stmt->oldname,	/* old att name */
-							  stmt->newname);	/* new att name */
+						renametrig(relid,
+								   stmt->oldname,	/* old att name */
+								   stmt->newname);	/* new att name */
 						break;
 					case RENAME_RULE:
 						elog(ERROR, "ProcessUtility: Invalid target for RENAME: %d",
@@ -410,6 +434,9 @@ ProcessUtility(Node *parsetree,
 		case T_AlterTableStmt:
 			{
 				AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
+				Oid		relid;
+
+				relid = RangeVarGetRelid(stmt->relation, false);
 
 				/*
 				 * Some or all of these functions are recursive to cover
@@ -422,7 +449,7 @@ ProcessUtility(Node *parsetree,
 						 * Recursively add column to table and,
 						 * if requested, to descendants
 						 */
-						AlterTableAddColumn(RangeVarGetRelid(stmt->relation, false),
+						AlterTableAddColumn(relid,
 											interpretInhOption(stmt->relation->inhOpt),
 											(ColumnDef *) stmt->def);
 						break;
@@ -431,18 +458,18 @@ ProcessUtility(Node *parsetree,
 						 * Recursively alter column default for table and,
 						 * if requested, for descendants
 						 */
-						AlterTableAlterColumnDefault(RangeVarGetRelid(stmt->relation, false),
+						AlterTableAlterColumnDefault(relid,
 													 interpretInhOption(stmt->relation->inhOpt),
 													 stmt->name,
 													 stmt->def);
 						break;
 					case 'N':	/* ALTER COLUMN DROP NOT NULL */
-						AlterTableAlterColumnDropNotNull(RangeVarGetRelid(stmt->relation, false),
+						AlterTableAlterColumnDropNotNull(relid,
 										interpretInhOption(stmt->relation->inhOpt),
 													stmt->name);
 						break;
 					case 'O':	/* ALTER COLUMN SET NOT NULL */
-						AlterTableAlterColumnSetNotNull(RangeVarGetRelid(stmt->relation, false),
+						AlterTableAlterColumnSetNotNull(relid,
 										interpretInhOption(stmt->relation->inhOpt),
 													stmt->name);
 						break;
@@ -452,7 +479,7 @@ ProcessUtility(Node *parsetree,
 						 * Recursively alter column statistics for table and,
 						 * if requested, for descendants
 						 */
-						AlterTableAlterColumnFlags(RangeVarGetRelid(stmt->relation, false),
+						AlterTableAlterColumnFlags(relid,
 												   interpretInhOption(stmt->relation->inhOpt),
 												   stmt->name,
 												   stmt->def,
@@ -464,7 +491,7 @@ ProcessUtility(Node *parsetree,
 						 * Recursively drop column from table and,
 						 * if requested, from descendants
 						 */
-						AlterTableDropColumn(RangeVarGetRelid(stmt->relation, false),
+						AlterTableDropColumn(relid,
 											 interpretInhOption(stmt->relation->inhOpt),
 											 stmt->name,
 											 stmt->behavior);
@@ -474,7 +501,7 @@ ProcessUtility(Node *parsetree,
 						 * Recursively add constraint to table and,
 						 * if requested, to descendants
 						 */
-						AlterTableAddConstraint(RangeVarGetRelid(stmt->relation, false),
+						AlterTableAddConstraint(relid,
 												interpretInhOption(stmt->relation->inhOpt),
 												(List *) stmt->def);
 						break;
@@ -483,21 +510,20 @@ ProcessUtility(Node *parsetree,
 						 * Recursively drop constraint from table and,
 						 * if requested, from descendants
 						 */
-						AlterTableDropConstraint(RangeVarGetRelid(stmt->relation, false),
+						AlterTableDropConstraint(relid,
 												 interpretInhOption(stmt->relation->inhOpt),
 												 stmt->name,
 												 stmt->behavior);
 						break;
 					case 'E':	/* CREATE TOAST TABLE */
-						AlterTableCreateToastTable(RangeVarGetRelid(stmt->relation, false),
-												   false);
+						AlterTableCreateToastTable(relid, false);
 						break;
 					case 'U':	/* ALTER OWNER */
 						/* check that we are the superuser */
 						if (!superuser())
 							elog(ERROR, "ALTER TABLE: permission denied");
 						/* get_usesysid raises an error if no such user */
-						AlterTableOwner(RangeVarGetRelid(stmt->relation, false),
+						AlterTableOwner(relid,
 										get_usesysid(stmt->name));
 						break;
 					default:	/* oops */
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index f6b98c5bee6..ca3bd80e8a7 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.71 2002/04/27 03:45:03 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.72 2002/04/30 01:26:26 tgl Exp $
  *
  * NOTES
  *	  Eventually, the index information should go through here, too.
@@ -708,6 +708,32 @@ get_rel_name(Oid relid)
 		return NULL;
 }
 
+/*
+ * get_rel_namespace
+ *
+ *		Returns the pg_namespace OID associated with a given relation.
+ */
+Oid
+get_rel_namespace(Oid relid)
+{
+	HeapTuple	tp;
+
+	tp = SearchSysCache(RELOID,
+						ObjectIdGetDatum(relid),
+						0, 0, 0);
+	if (HeapTupleIsValid(tp))
+	{
+		Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+		Oid		result;
+
+		result = reltup->relnamespace;
+		ReleaseSysCache(tp);
+		return result;
+	}
+	else
+		return InvalidOid;
+}
+
 /*
  * get_rel_type_id
  *
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index f57219df119..9f812256737 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lsyscache.h,v 1.50 2002/04/27 03:45:03 tgl Exp $
+ * $Id: lsyscache.h,v 1.51 2002/04/30 01:26:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,6 +42,7 @@ extern Oid	get_func_rettype(Oid funcid);
 extern char func_volatile(Oid funcid);
 extern Oid	get_relname_relid(const char *relname, Oid relnamespace);
 extern char *get_rel_name(Oid relid);
+extern Oid	get_rel_namespace(Oid relid);
 extern Oid	get_rel_type_id(Oid relid);
 extern bool get_typisdefined(Oid typid);
 extern int16 get_typlen(Oid typid);
-- 
GitLab