Fix unwanted denial of ALTER OWNER rights to superusers. There was some
authorTom Lane
Mon, 22 Aug 2005 17:38:20 +0000 (17:38 +0000)
committerTom Lane
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