Fix unwanted denial of ALTER OWNER rights to superusers. There was some
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 22 Aug 2005 17:38:20 +0000 (17:38 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 22 Aug 2005 17:38:20 +0000 (17:38 +0000)
discussion of getting around this by relaxing the checks made for regular
users, but I'm disinclined to toy with the security model right now,
so just special-case it for superusers where needed.

src/backend/commands/aggregatecmds.c
src/backend/commands/conversioncmds.c
src/backend/commands/dbcommands.c
src/backend/commands/functioncmds.c
src/backend/commands/opclasscmds.c
src/backend/commands/operatorcmds.c
src/backend/commands/schemacmds.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c

index e96f328d190a70c1e06fdae809667899cb6d747c..e3efde249d0dc2a51893ee5f65c9d34711722fd6 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.28 2005/07/14 21:46:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.29 2005/08/22 17:38:20 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -332,20 +332,25 @@ AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId)
         */
        if (procForm->proowner != newOwnerId)
        {
-               /* Otherwise, must be owner of the existing object */
-               if (!pg_proc_ownercheck(procOid, GetUserId()))
-                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
-                                                  NameListToString(name));
-
-               /* Must be able to become new owner */
-               check_is_member_of_role(GetUserId(), newOwnerId);
-
-               /* New owner must have CREATE privilege on namespace */
-               aclresult = pg_namespace_aclcheck(procForm->pronamespace, newOwnerId,
-                                                                                 ACL_CREATE);
-               if (aclresult != ACLCHECK_OK)
-                       aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-                                                  get_namespace_name(procForm->pronamespace));
+               /* Superusers can always do it */
+               if (!superuser())
+               {
+                       /* Otherwise, must be owner of the existing object */
+                       if (!pg_proc_ownercheck(procOid, GetUserId()))
+                               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+                                                          NameListToString(name));
+
+                       /* Must be able to become new owner */
+                       check_is_member_of_role(GetUserId(), newOwnerId);
+
+                       /* New owner must have CREATE privilege on namespace */
+                       aclresult = pg_namespace_aclcheck(procForm->pronamespace,
+                                                                                         newOwnerId,
+                                                                                         ACL_CREATE);
+                       if (aclresult != ACLCHECK_OK)
+                               aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+                                                          get_namespace_name(procForm->pronamespace));
+               }
 
                /*
                 * Modify the owner --- okay to scribble on tup because it's a
index 81e889aa4ee1d592cc2fbb0366bb30eca139c670..912f35ea20b08dd9930a574d508009947c4ad312 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.21 2005/07/14 21:46:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.22 2005/08/22 17:38:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -206,20 +206,25 @@ AlterConversionOwner(List *name, Oid newOwnerId)
         */
        if (convForm->conowner != newOwnerId)
        {
-               /* Otherwise, must be owner of the existing object */
-               if (!pg_conversion_ownercheck(HeapTupleGetOid(tup),GetUserId()))
-                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
-                                                  NameListToString(name));
-
-               /* Must be able to become new owner */
-               check_is_member_of_role(GetUserId(), newOwnerId);
-
-               /* New owner must have CREATE privilege on namespace */
-               aclresult = pg_namespace_aclcheck(convForm->connamespace, newOwnerId,
-                                                                                 ACL_CREATE);
-               if (aclresult != ACLCHECK_OK)
-                       aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-                                                  get_namespace_name(convForm->connamespace));
+               /* Superusers can always do it */
+               if (!superuser())
+               {
+                       /* Otherwise, must be owner of the existing object */
+                       if (!pg_conversion_ownercheck(HeapTupleGetOid(tup),GetUserId()))
+                               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
+                                                          NameListToString(name));
+
+                       /* Must be able to become new owner */
+                       check_is_member_of_role(GetUserId(), newOwnerId);
+
+                       /* New owner must have CREATE privilege on namespace */
+                       aclresult = pg_namespace_aclcheck(convForm->connamespace,
+                                                                                         newOwnerId,
+                                                                                         ACL_CREATE);
+                       if (aclresult != ACLCHECK_OK)
+                               aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+                                                          get_namespace_name(convForm->connamespace));
+               }
 
                /*
                 * Modify the owner --- okay to scribble on tup because it's a
index 40e28a0821c95076443e60919f9220a0c6939058..49d3e1d4f5da1bdc8e0a860dd5f3f57ba83c15a3 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.170 2005/08/12 01:35:57 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.171 2005/08/22 17:38:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1024,7 +1024,8 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
                 * NOTE: This is different from other alter-owner checks in 
                 * that the current user is checked for createdb privileges 
                 * instead of the destination owner.  This is consistent
-                * with the CREATE case for databases.
+                * with the CREATE case for databases.  Because superusers
+                * will always have this right, we need no special case for them.
                 */
                if (!have_createdb_privilege())
                        ereport(ERROR,
index 38912b777d94f21b54e12c3c30d9147cff6dd326..d6bb902274efc8a042a8a271d0ec3db4b6dd36e8 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.65 2005/08/01 04:03:55 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.66 2005/08/22 17:38:20 tgl Exp $
  *
  * DESCRIPTION
  *       These routines take the parse tree and pick out the
@@ -894,20 +894,25 @@ AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
                bool            isNull;
                HeapTuple       newtuple;
 
-               /* Otherwise, must be owner of the existing object */
-               if (!pg_proc_ownercheck(procOid,GetUserId()))
-                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
-                                                  NameListToString(name));
-
-               /* Must be able to become new owner */
-               check_is_member_of_role(GetUserId(), newOwnerId);
-
-               /* New owner must have CREATE privilege on namespace */
-               aclresult = pg_namespace_aclcheck(procForm->pronamespace, newOwnerId,
-                                                                                 ACL_CREATE);
-               if (aclresult != ACLCHECK_OK)
-                       aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-                                       get_namespace_name(procForm->pronamespace));
+               /* Superusers can always do it */
+               if (!superuser())
+               {
+                       /* Otherwise, must be owner of the existing object */
+                       if (!pg_proc_ownercheck(procOid,GetUserId()))
+                               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+                                                          NameListToString(name));
+
+                       /* Must be able to become new owner */
+                       check_is_member_of_role(GetUserId(), newOwnerId);
+
+                       /* New owner must have CREATE privilege on namespace */
+                       aclresult = pg_namespace_aclcheck(procForm->pronamespace,
+                                                                                         newOwnerId,
+                                                                                         ACL_CREATE);
+                       if (aclresult != ACLCHECK_OK)
+                               aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+                                                          get_namespace_name(procForm->pronamespace));
+               }
 
                memset(repl_null, ' ', sizeof(repl_null));
                memset(repl_repl, ' ', sizeof(repl_repl));
index c9d11da70eb92405f10f6f1525901d026e4607bf..1884c25f1732643b3b4f24873e44f722b227ed2d 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.35 2005/07/14 21:46:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.36 2005/08/22 17:38:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -951,20 +951,24 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
         */
        if (opcForm->opcowner != newOwnerId)
        {
-               /* Otherwise, must be owner of the existing object */
-               if (!pg_opclass_ownercheck(HeapTupleGetOid(tup),GetUserId()))
-                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
-                                                  NameListToString(name));
-
-               /* Must be able to become new owner */
-               check_is_member_of_role(GetUserId(), newOwnerId);
-
-               /* New owner must have CREATE privilege on namespace */
-               aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
-                                                                                 ACL_CREATE);
-               if (aclresult != ACLCHECK_OK)
-                       aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-                                       get_namespace_name(namespaceOid));
+               /* Superusers can always do it */
+               if (!superuser())
+               {
+                       /* Otherwise, must be owner of the existing object */
+                       if (!pg_opclass_ownercheck(HeapTupleGetOid(tup),GetUserId()))
+                               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
+                                                          NameListToString(name));
+
+                       /* Must be able to become new owner */
+                       check_is_member_of_role(GetUserId(), newOwnerId);
+
+                       /* New owner must have CREATE privilege on namespace */
+                       aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
+                                                                                         ACL_CREATE);
+                       if (aclresult != ACLCHECK_OK)
+                               aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+                                                          get_namespace_name(namespaceOid));
+               }
 
                /*
                 * Modify the owner --- okay to scribble on tup because it's a
index d36ac6acd0bc0b5ed0709c22c34040d7da1bd341..f9db742e84405978784018f207053d81232de6da 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.24 2005/07/14 21:46:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.25 2005/08/22 17:38:20 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -296,20 +296,25 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
         */
        if (oprForm->oprowner != newOwnerId)
        {
-               /* Otherwise, must be owner of the existing object */
-               if (!pg_oper_ownercheck(operOid,GetUserId()))
-                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
-                                                  NameListToString(name));
-
-               /* Must be able to become new owner */
-               check_is_member_of_role(GetUserId(), newOwnerId);
-
-               /* New owner must have CREATE privilege on namespace */
-               aclresult = pg_namespace_aclcheck(oprForm->oprnamespace, newOwnerId,
-                                                                                 ACL_CREATE);
-               if (aclresult != ACLCHECK_OK)
-                       aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-                                       get_namespace_name(oprForm->oprnamespace));
+               /* Superusers can always do it */
+               if (!superuser())
+               {
+                       /* Otherwise, must be owner of the existing object */
+                       if (!pg_oper_ownercheck(operOid,GetUserId()))
+                               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
+                                                          NameListToString(name));
+
+                       /* Must be able to become new owner */
+                       check_is_member_of_role(GetUserId(), newOwnerId);
+
+                       /* New owner must have CREATE privilege on namespace */
+                       aclresult = pg_namespace_aclcheck(oprForm->oprnamespace,
+                                                                                         newOwnerId,
+                                                                                         ACL_CREATE);
+                       if (aclresult != ACLCHECK_OK)
+                               aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+                                                          get_namespace_name(oprForm->oprnamespace));
+               }
 
                /*
                 * Modify the owner --- okay to scribble on tup because it's a
index 65a6edeabc79a1fc6198987b663f299e702f0921..f0ae06f15c627b9cba6a55206b7cc2a35a12ab5a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.33 2005/07/14 21:46:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.34 2005/08/22 17:38:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -315,7 +315,8 @@ AlterSchemaOwner(const char *name, Oid newOwnerId)
                 * NOTE: This is different from other alter-owner checks in 
                 * that the current user is checked for create privileges 
                 * instead of the destination owner.  This is consistent
-                * with the CREATE case for schemas.
+                * with the CREATE case for schemas.  Because superusers
+                * will always have this right, we need no special case for them.
                 */
                aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(),
                                                                                 ACL_CREATE);
index aaf9a2ce7435d18240af257109ed7d1c82352eee..95e3ef68bb050d0de1da97a1a948b5edc0513a3f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.166 2005/08/04 01:09:28 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.167 2005/08/22 17:38:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -5307,23 +5307,27 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
                /* skip permission checks when recursing to index or toast table */
                if (!recursing)
                {
-                       Oid                 namespaceOid = tuple_class->relnamespace;
-                       AclResult       aclresult;
-
-                       /* Otherwise, must be owner of the existing object */
-                       if (!pg_class_ownercheck(relationOid,GetUserId()))
-                               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
-                                                          RelationGetRelationName(target_rel));
-
-                       /* Must be able to become new owner */
-                       check_is_member_of_role(GetUserId(), newOwnerId);
-
-                       /* New owner must have CREATE privilege on namespace */
-                       aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
-                                                                                         ACL_CREATE);
-                       if (aclresult != ACLCHECK_OK)
-                               aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-                                                          get_namespace_name(namespaceOid));
+                       /* Superusers can always do it */
+                       if (!superuser())
+                       {
+                               Oid                 namespaceOid = tuple_class->relnamespace;
+                               AclResult       aclresult;
+
+                               /* Otherwise, must be owner of the existing object */
+                               if (!pg_class_ownercheck(relationOid,GetUserId()))
+                                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+                                                                  RelationGetRelationName(target_rel));
+
+                               /* Must be able to become new owner */
+                               check_is_member_of_role(GetUserId(), newOwnerId);
+
+                               /* New owner must have CREATE privilege on namespace */
+                               aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
+                                                                                                 ACL_CREATE);
+                               if (aclresult != ACLCHECK_OK)
+                                       aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+                                                                  get_namespace_name(namespaceOid));
+                       }
                }
 
                memset(repl_null, ' ', sizeof(repl_null));
index e0c3a311eac32755637d4373b4e293974f09d5c9..ee69821bcfbe68bed52acda258b2e7a8b78d07be 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.79 2005/08/12 01:35:58 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.80 2005/08/22 17:38:20 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -2067,20 +2067,25 @@ AlterTypeOwner(List *names, Oid newOwnerId)
         */
        if (typTup->typowner != newOwnerId)
        {
-               /* Otherwise, must be owner of the existing object */
-               if (!pg_type_ownercheck(HeapTupleGetOid(tup),GetUserId()))
-                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
-                                                  TypeNameToString(typename));
-
-               /* Must be able to become new owner */
-               check_is_member_of_role(GetUserId(), newOwnerId);
-
-               /* New owner must have CREATE privilege on namespace */
-               aclresult = pg_namespace_aclcheck(typTup->typnamespace, newOwnerId,
-                                                                                 ACL_CREATE);
-               if (aclresult != ACLCHECK_OK)
-                       aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-                                                  get_namespace_name(typTup->typnamespace));
+               /* Superusers can always do it */
+               if (!superuser())
+               {
+                       /* Otherwise, must be owner of the existing object */
+                       if (!pg_type_ownercheck(HeapTupleGetOid(tup),GetUserId()))
+                               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
+                                                          TypeNameToString(typename));
+
+                       /* Must be able to become new owner */
+                       check_is_member_of_role(GetUserId(), newOwnerId);
+
+                       /* New owner must have CREATE privilege on namespace */
+                       aclresult = pg_namespace_aclcheck(typTup->typnamespace,
+                                                                                         newOwnerId,
+                                                                                         ACL_CREATE);
+                       if (aclresult != ACLCHECK_OK)
+                               aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+                                                          get_namespace_name(typTup->typnamespace));
+               }
 
                /*
                 * Modify the owner --- okay to scribble on typTup because it's a