Greetings,

  Attached please find a patch to change how the permissions checking
  for alter-owner is done.  With roles there can be more than one
  'owner' of an object and therefore it becomes sensible to allow
  specific cases of ownership change for non-superusers.

  The permission checks for change-owner follow the alter-rename
  precedent that the new owner must have permission to create the object
  in the schema.

  The roles patch previously applied did not require the role for 
  which a database is being created to have createdb privileges, or for
  the role for which a schema is being created to have create
  privileges on the database (the role doing the creation did have to
  have those privileges though, of course).

  For 'container' type objects this seems reasonable.  'container' type
  objects are unlike others in a few ways, but one of the more notable
  differences for this case is that an owner may be specified as part of
  the create command.

  To support cleaning up the various checks, I also went ahead and
  modified is_member_of_role() to always return true when asked if a
  superuser is in a given role.  This seems reasonable, won't affect
  what's actually seen in the various tables, and allows us to eliminate
  explicit superuser() checks in a number of places.

  I have also reviewed the other superuser() calls in
  src/backend/commands/ and feel pretty comfortable that they're all
  necessary, reasonable, and don't need to be replaced with 
  *_ownercheck or other calls.

  The specific changes which have been changed, by file:
  aggregatecmds.c, alter-owner:
    alter-owner checks:
      User is owner of the to-be-changed object
      User is a member of the new owner's role
      New owner is permitted to create objects in the schema
      Superuser() requirement removed

  conversioncmds.c, rename:
    rename-checks:
      Changed from superuser() or same-roleId to pg_conversion_ownercheck
    alter-owner checks:
      User is owner of the to-be-changed object
      User is a member of the new owner's role
      New owner is permitted to create objects in the schema
      Superuser() requirement removed
    
  dbcommands.c:
    Moved superuser() check to have_createdb_privilege
    Cleaned up permissions checking in createdb and rename
    alter-owner checks:
      User is owner of the database
      User is a member of the new owner's role
      User has createdb privilege

  functioncmds.c:
    alter-owner checks:
      User is owner of the function
      User is a member of the new owner's role
      New owner is permitted to create objects in the schema

  opclasscmds.c:
    alter-owner checks:
      User is owner of the object
      User is a member of the new owner's role
      New owner has permission to create objects in the schema

  operatorcmds.c:
    alter-owner checks:
      User is owner of the object
      User is a member of the new owner's role
      New owner has permission to create objects in the schema

  schemacmds.c:
    Cleaned up create schema identify changing/setting/checking
    (This code was quite different from all the other create functions,
     these changes make it much more closely match createdb)
    alter-owner checks:
      User is owner of the schema
      User is a member of the new owner's role
      User has create privilege on database

  tablecmds.c:
    alter-owner checks:
      User is owner of the object
      User is a member of the new owner's role
      New owner has permission to create objects in the schema

  tablespace.c:
    alter-owner checks:
      User is owner of the tablespace
      User is a member of the new owner's role
      (No create-tablespace permission to check, tablespaces must be
       created by superusers and so alter-owner here really only matters
       if the superuser changed the tablespace owner to a non-superuser
       and then that non-superuser wants to change the ownership to yet
       another user, the other option would be to continue to force
       superuser-only for tablespace owner changes but I'm not sure I
       see the point if the superuser trusts the non-superuser enough to
       give them a tablespace...)

  typecmds.c:
    alter-owner checks:
      User is owner of the object
      User is a member of the new owner's role
      New owner has permission to create objects in the schema

  Many thanks.  As always, comments, questions, concerns, please let me
  know.

        Thanks again,

                Stephen
? src/backend/commands/.typecmds.c.swp
Index: src/backend/commands/aggregatecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v
retrieving revision 1.27
diff -c -r1.27 aggregatecmds.c
*** src/backend/commands/aggregatecmds.c        28 Jun 2005 05:08:53 -0000      
1.27
--- src/backend/commands/aggregatecmds.c        29 Jun 2005 15:29:57 -0000
***************
*** 299,307 ****
--- 299,309 ----
  {
        Oid                     basetypeOid;
        Oid                     procOid;
+       Oid                     namespaceOid;
        HeapTuple       tup;
        Form_pg_proc procForm;
        Relation        rel;
+       AclResult       aclresult;
  
        /*
         * if a basetype is passed in, then attempt to find an aggregate for
***************
*** 325,341 ****
                elog(ERROR, "cache lookup failed for function %u", procOid);
        procForm = (Form_pg_proc) GETSTRUCT(tup);
  
        /*
         * If the new owner is the same as the existing owner, consider the
         * command to have succeeded.  This is for dump restoration purposes.
         */
        if (procForm->proowner != newOwnerId)
        {
!               /* Otherwise, must be superuser to change object ownership */
!               if (!superuser())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to change 
owner")));
  
                /*
                 * Modify the owner --- okay to scribble on tup because it's a
--- 327,356 ----
                elog(ERROR, "cache lookup failed for function %u", procOid);
        procForm = (Form_pg_proc) GETSTRUCT(tup);
  
+       namespaceOid = procForm->pronamespace;
+ 
        /*
         * If the new owner is the same as the existing owner, consider the
         * command to have succeeded.  This is for dump restoration purposes.
         */
        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 */
!               if (!is_member_of_role(GetUserId(),newOwnerId))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
!                                                  NameListToString(name));
! 
!               /* 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: src/backend/commands/conversioncmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/conversioncmds.c,v
retrieving revision 1.19
diff -c -r1.19 conversioncmds.c
*** src/backend/commands/conversioncmds.c       28 Jun 2005 05:08:53 -0000      
1.19
--- src/backend/commands/conversioncmds.c       29 Jun 2005 15:29:57 -0000
***************
*** 151,158 ****
                                         newname, 
get_namespace_name(namespaceOid))));
  
        /* must be owner */
!       if (!superuser() &&
!               ((Form_pg_conversion) GETSTRUCT(tup))->conowner != GetUserId())
                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
                                           NameListToString(name));
  
--- 151,157 ----
                                         newname, 
get_namespace_name(namespaceOid))));
  
        /* must be owner */
!       if (!pg_conversion_ownercheck(conversionOid,GetUserId()))
                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
                                           NameListToString(name));
  
***************
*** 178,185 ****
--- 177,186 ----
  AlterConversionOwner(List *name, Oid newOwnerId)
  {
        Oid                     conversionOid;
+       Oid                     namespaceOid;
        HeapTuple       tup;
        Relation        rel;
+       AclResult       aclresult;
        Form_pg_conversion convForm;
  
        rel = heap_open(ConversionRelationId, RowExclusiveLock);
***************
*** 198,203 ****
--- 199,205 ----
                elog(ERROR, "cache lookup failed for conversion %u", 
conversionOid);
  
        convForm = (Form_pg_conversion) GETSTRUCT(tup);
+       namespaceOid = convForm->connamespace;
  
        /*
         * If the new owner is the same as the existing owner, consider the
***************
*** 205,215 ****
         */
        if (convForm->conowner != newOwnerId)
        {
!               /* Otherwise, must be superuser to change object ownership */
!               if (!superuser())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to change 
owner")));
  
                /*
                 * Modify the owner --- okay to scribble on tup because it's a
--- 207,227 ----
         */
        if (convForm->conowner != newOwnerId)
        {
!               /* must be owner to change object ownership */
!               if (!pg_conversion_ownercheck(HeapTupleGetOid(tup),GetUserId()))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
!                                                  NameListToString(name));
! 
!               /* Must be able to become new owner */
!               if (!is_member_of_role(GetUserId(),newOwnerId))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
!                                       NameListToString(name));
! 
!               /* 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: src/backend/commands/dbcommands.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/dbcommands.c,v
retrieving revision 1.162
diff -c -r1.162 dbcommands.c
*** src/backend/commands/dbcommands.c   28 Jun 2005 05:08:53 -0000      1.162
--- src/backend/commands/dbcommands.c   29 Jun 2005 15:29:57 -0000
***************
*** 192,214 ****
        else
                datdba = GetUserId();
  
!       if (is_member_of_role(GetUserId(), datdba))
!       {
!               /* creating database for self: can be superuser or createdb */
!               if (!superuser() && !have_createdb_privilege())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("permission denied to create 
database")));
!       }
!       else
!       {
!               /* creating database for someone else: must be superuser */
!               /* note that the someone else need not have any permissions */
!               if (!superuser())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to create 
database for another user")));
!       }
  
        /*
         * Check for db name conflict.  There is a race condition here, since
--- 192,209 ----
        else
                datdba = GetUserId();
  
!       /* creating database, must have createdb
!        * must be creating database for role user can become
!        *
!        * NOTE: This does not require the role for which the database
!        * is being created to have createdb privileges.  For 'container'
!        * type objects where specifying a different owner during
!        * creation is allowed this seems reasonable.
!        */
!       if (!have_createdb_privilege() || !is_member_of_role(GetUserId(), 
datdba))
!               ereport(ERROR,
!                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                errmsg("permission denied to create 
database")));
  
        /*
         * Check for db name conflict.  There is a race condition here, since
***************
*** 759,765 ****
                                           oldname);
  
        /* must have createdb rights */
!       if (!superuser() && !have_createdb_privilege())
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 errmsg("permission denied to rename 
database")));
--- 754,760 ----
                                           oldname);
  
        /* must have createdb rights */
!       if (!have_createdb_privilege())
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 errmsg("permission denied to rename 
database")));
***************
*** 918,928 ****
                bool            isNull;
                HeapTuple       newtuple;
  
!               /* must be superuser to change ownership */
!               if (!superuser())
                        ereport(ERROR,
                                        
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to change 
owner")));
  
                memset(repl_null, ' ', sizeof(repl_null));
                memset(repl_repl, ' ', sizeof(repl_repl));
--- 913,941 ----
                bool            isNull;
                HeapTuple       newtuple;
  
!               /* must be owner of the database */
!               if (!pg_database_ownercheck(HeapTupleGetOid(tuple),GetUserId()))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
!                                                  dbname);
! 
!               /* Must be able to become new owner */
!               if (!is_member_of_role(GetUserId(),newOwnerId))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
!                                                  dbname);
! 
!               /* must have createdb rights 
!                *
!                * 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 because this 
!                * is a 'container' type object and the owner can be 
!                * specified during creation.
!                * This matches the current createdb checks.
!                */
!               if (!have_createdb_privilege())
                        ereport(ERROR,
                                        
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("permission denied to change 
owner of database")));
  
                memset(repl_null, ' ', sizeof(repl_null));
                memset(repl_repl, ' ', sizeof(repl_repl));
***************
*** 1044,1049 ****
--- 1057,1066 ----
        bool            result = false;
        HeapTuple       utup;
  
+       /* superuser bybasses privilege checks */
+       if (superuser())
+               return true;
+ 
        utup = SearchSysCache(AUTHOID,
                                                  ObjectIdGetDatum(GetUserId()),
                                                  0, 0, 0);
Index: src/backend/commands/functioncmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/functioncmds.c,v
retrieving revision 1.62
diff -c -r1.62 functioncmds.c
*** src/backend/commands/functioncmds.c 28 Jun 2005 05:08:53 -0000      1.62
--- src/backend/commands/functioncmds.c 29 Jun 2005 15:29:58 -0000
***************
*** 856,864 ****
--- 856,866 ----
  AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
  {
        Oid                     procOid;
+       Oid                     namespaceOid;
        HeapTuple       tup;
        Form_pg_proc procForm;
        Relation        rel;
+       AclResult       aclresult;
  
        rel = heap_open(ProcedureRelationId, RowExclusiveLock);
  
***************
*** 878,883 ****
--- 880,887 ----
                                                NameListToString(name)),
                                 errhint("Use ALTER AGGREGATE to change owner 
of aggregate functions.")));
  
+       namespaceOid = procForm->pronamespace;
+ 
        /*
         * If the new owner is the same as the existing owner, consider the
         * command to have succeeded.  This is for dump restoration purposes.
***************
*** 892,902 ****
                bool            isNull;
                HeapTuple       newtuple;
  
!               /* Otherwise, must be superuser to change object ownership */
!               if (!superuser())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to change 
owner")));
  
                memset(repl_null, ' ', sizeof(repl_null));
                memset(repl_repl, ' ', sizeof(repl_repl));
--- 896,916 ----
                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 */
!               if (!is_member_of_role(GetUserId(),newOwnerId))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
!                                                  NameListToString(name));
! 
!               /* new role 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));
                memset(repl_repl, ' ', sizeof(repl_repl));
Index: src/backend/commands/opclasscmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/opclasscmds.c,v
retrieving revision 1.33
diff -c -r1.33 opclasscmds.c
*** src/backend/commands/opclasscmds.c  28 Jun 2005 05:08:53 -0000      1.33
--- src/backend/commands/opclasscmds.c  29 Jun 2005 15:29:58 -0000
***************
*** 889,894 ****
--- 889,895 ----
        char       *opcname;
        HeapTuple       tup;
        Relation        rel;
+       AclResult       aclresult;
        Form_pg_opclass opcForm;
  
        amOid = GetSysCacheOid(AMNAME,
***************
*** 947,957 ****
         */
        if (opcForm->opcowner != newOwnerId)
        {
!               /* Otherwise, must be superuser to change object ownership */
!               if (!superuser())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to change 
owner")));
  
                /*
                 * Modify the owner --- okay to scribble on tup because it's a
--- 948,968 ----
         */
        if (opcForm->opcowner != newOwnerId)
        {
!               /* Otherwise, must be owner of the existing object */
!               if (!pg_type_ownercheck(HeapTupleGetOid(tup),GetUserId()))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
!                                                  
format_type_be(HeapTupleGetOid(tup)));
! 
!               /* Must be able to become the new owner */
!               if (!is_member_of_role(GetUserId(),newOwnerId))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
!                                       NameListToString(name));
! 
!               /* new role 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: src/backend/commands/operatorcmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/operatorcmds.c,v
retrieving revision 1.22
diff -c -r1.22 operatorcmds.c
*** src/backend/commands/operatorcmds.c 28 Jun 2005 05:08:54 -0000      1.22
--- src/backend/commands/operatorcmds.c 29 Jun 2005 15:29:58 -0000
***************
*** 274,279 ****
--- 274,280 ----
        Oid                     operOid;
        HeapTuple       tup;
        Relation        rel;
+       AclResult       aclresult;
        Form_pg_operator oprForm;
  
        rel = heap_open(OperatorRelationId, RowExclusiveLock);
***************
*** 295,305 ****
         */
        if (oprForm->oprowner != newOwnerId)
        {
!               /* Otherwise, must be superuser to change object ownership */
!               if (!superuser())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to change 
owner")));
  
                /*
                 * Modify the owner --- okay to scribble on tup because it's a
--- 296,316 ----
         */
        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 */
!               if (!is_member_of_role(GetUserId(),newOwnerId))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
!                                       NameListToString(name));
! 
!               /* new role 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: src/backend/commands/schemacmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/schemacmds.c,v
retrieving revision 1.31
diff -c -r1.31 schemacmds.c
*** src/backend/commands/schemacmds.c   28 Jun 2005 05:08:54 -0000      1.31
--- src/backend/commands/schemacmds.c   29 Jun 2005 15:29:58 -0000
***************
*** 52,96 ****
         * Figure out user identities.
         */
  
!       if (!authId)
!       {
!               owner_uid = saved_uid;
!       }
!       else if (superuser())
!       {
                owner_uid = get_roleid_checked(authId);
- 
-               /*
-                * Set the current user to the requested authorization so that
-                * objects created in the statement have the requested owner.
-                * (This will revert to session user on error or at the end of
-                * this routine.)
-                */
-               SetUserId(owner_uid);
-       }
        else
-       {
-               const char *owner_name;
- 
-               /* not superuser */
                owner_uid = saved_uid;
-               owner_name = GetUserNameFromId(owner_uid);
-               if (strcmp(authId, owner_name) != 0)
-                       ereport(ERROR,
-                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                                        errmsg("permission denied"),
-                                        errdetail("\"%s\" is not a superuser, 
so cannot create a schema for \"%s\"",
-                                                          owner_name, 
authId)));
-       }
  
        /*
         * Permissions checks.
         */
        aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE);
        if (aclresult != ACLCHECK_OK)
                aclcheck_error(aclresult, ACL_KIND_DATABASE,
                                           get_database_name(MyDatabaseId));
  
        if (!allowSystemTableMods && IsReservedName(schemaName))
                ereport(ERROR,
                                (errcode(ERRCODE_RESERVED_NAME),
--- 52,95 ----
         * Figure out user identities.
         */
  
!       if (authId)
                owner_uid = get_roleid_checked(authId);
        else
                owner_uid = saved_uid;
  
        /*
         * Permissions checks.
         */
+ 
+       /* must be creating schema for role which user is a member of */
+       if (!is_member_of_role(saved_uid, owner_uid))
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                errmsg("permission denied to create schema")));
+ 
+       /* creating schema, must have create privs on db
+        *
+        * NOTE: This does not require the role for which the schema
+        * is being created to have create privileges.  For 'container'
+        * type objects where specifying a different owner during
+        * creation is allowed this seems reasonable.
+        */
        aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE);
        if (aclresult != ACLCHECK_OK)
                aclcheck_error(aclresult, ACL_KIND_DATABASE,
                                           get_database_name(MyDatabaseId));
  
+       /*
+        * If the requested authorization is different from the current
+        * user then set the current user to the requested authorization 
+        * so that objects created in the statement have the requested 
+        * owner.
+        * (This will revert to session user on error or at the end of
+        * this routine.)
+        */
+       if (saved_uid != owner_uid)
+               SetUserId(owner_uid);
+ 
        if (!allowSystemTableMods && IsReservedName(schemaName))
                ereport(ERROR,
                                (errcode(ERRCODE_RESERVED_NAME),
***************
*** 308,319 ****
                Datum           aclDatum;
                bool            isNull;
                HeapTuple       newtuple;
  
!               /* Otherwise, must be superuser to change object ownership */
!               if (!superuser())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to change 
owner")));
  
                memset(repl_null, ' ', sizeof(repl_null));
                memset(repl_repl, ' ', sizeof(repl_repl));
--- 307,337 ----
                Datum           aclDatum;
                bool            isNull;
                HeapTuple       newtuple;
+               AclResult       aclresult;
  
!               /* Otherwise, must be owner of the existing object */
!               if (!pg_proc_ownercheck(HeapTupleGetOid(tup),GetUserId()))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
!                                       name);
! 
!               /* Must be able to become new owner */
!               if (!is_member_of_role(GetUserId(),newOwnerId))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
!                                       name);
! 
!               /* must have create rights
!                *
!                * 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 because this 
!                * is a 'container' type object and the owner can be 
!                * specified during creation.
!                * This matches the create schema checks.
!                */
!               aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(), 
ACL_CREATE);
!               if (aclresult != ACLCHECK_OK)
!                       aclcheck_error(aclresult, ACL_KIND_DATABASE,
!                                                  
get_database_name(MyDatabaseId));
  
                memset(repl_null, ' ', sizeof(repl_null));
                memset(repl_repl, ' ', sizeof(repl_repl));
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.162
diff -c -r1.162 tablecmds.c
*** src/backend/commands/tablecmds.c    28 Jun 2005 05:08:54 -0000      1.162
--- src/backend/commands/tablecmds.c    29 Jun 2005 15:29:58 -0000
***************
*** 5286,5297 ****
                Datum           aclDatum;
                bool            isNull;
                HeapTuple       newtuple;
  
!               /* Otherwise, check that we are the superuser */
!               if (!superuser())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to change 
owner")));
  
                memset(repl_null, ' ', sizeof(repl_null));
                memset(repl_repl, ' ', sizeof(repl_repl));
--- 5286,5309 ----
                Datum           aclDatum;
                bool            isNull;
                HeapTuple       newtuple;
+               Oid                 namespaceOid = 
get_rel_namespace(relationOid);
+               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 */
!               if (!is_member_of_role(GetUserId(),newOwnerId))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
!                                       RelationGetRelationName(target_rel));
! 
!               /* new role 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));
                memset(repl_repl, ' ', sizeof(repl_repl));
Index: src/backend/commands/tablespace.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/tablespace.c,v
retrieving revision 1.23
diff -c -r1.23 tablespace.c
*** src/backend/commands/tablespace.c   28 Jun 2005 05:08:54 -0000      1.23
--- src/backend/commands/tablespace.c   29 Jun 2005 15:29:58 -0000
***************
*** 784,794 ****
                bool            isNull;
                HeapTuple       newtuple;
  
!               /* Otherwise, must be superuser to change object ownership */
!               if (!superuser())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to change 
owner")));
  
                memset(repl_null, ' ', sizeof(repl_null));
                memset(repl_repl, ' ', sizeof(repl_repl));
--- 784,806 ----
                bool            isNull;
                HeapTuple       newtuple;
  
!               /* Must be owner */
!               if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), 
GetUserId()))
!                       aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, 
name);
! 
!               /* Must be able to become new owner */
!               if (!is_member_of_role(GetUserId(),newOwnerId))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, 
name);
! 
!               /*
!                * Normally we would also check for create permissions here,
!                * but there are none for tablespaces so we follow the what 
rename
!                * tablespace does and omit the create permissions check.   
!                *
!                * NOTE: Only superusers may create tablespaces to begin with 
and
!                * so initially only a superuser would be able to change its
!                * ownership anyway.
!                */
  
                memset(repl_null, ' ', sizeof(repl_null));
                memset(repl_repl, ' ', sizeof(repl_repl));
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.73
diff -c -r1.73 typecmds.c
*** src/backend/commands/typecmds.c     28 Jun 2005 05:08:54 -0000      1.73
--- src/backend/commands/typecmds.c     29 Jun 2005 15:29:58 -0000
***************
*** 2023,2028 ****
--- 2023,2030 ----
        Relation        rel;
        HeapTuple       tup;
        Form_pg_type typTup;
+       Oid                     typeNamespace;
+       AclResult       aclresult;
  
        /* Make a TypeName so we can use standard type lookup machinery */
        typename = makeNode(TypeName);
***************
*** 2065,2075 ****
         */
        if (typTup->typowner != newOwnerId)
        {
!               /* Otherwise, must be superuser to change object ownership */
!               if (!superuser())
!                       ereport(ERROR,
!                                       
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
!                                        errmsg("must be superuser to change 
owner")));
  
                /*
                 * Modify the owner --- okay to scribble on typTup because it's 
a
--- 2067,2089 ----
         */
        if (typTup->typowner != newOwnerId)
        {
!               char *name = TypeNameToString(typename);
! 
!               /* Otherwise, must be owner of the existing object */
!               if (!pg_type_ownercheck(HeapTupleGetOid(tup),GetUserId()))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, name);
! 
!               /* Must be able to become new owner */
!               if (!is_member_of_role(GetUserId(),newOwnerId))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, name);
! 
!               typeNamespace = QualifiedNameGetCreationNamespace(names, &name);
! 
!               /* new role must have CREATE privilege on namespace */
!               aclresult = pg_namespace_aclcheck(typeNamespace, newOwnerId, 
ACL_CREATE);
!               if (aclresult != ACLCHECK_OK)
!                       aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
!                                                  
get_namespace_name(typeNamespace));
  
                /*
                 * Modify the owner --- okay to scribble on typTup because it's 
a
Index: src/backend/utils/adt/acl.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/acl.c,v
retrieving revision 1.116
diff -c -r1.116 acl.c
*** src/backend/utils/adt/acl.c 28 Jun 2005 19:51:23 -0000      1.116
--- src/backend/utils/adt/acl.c 29 Jun 2005 15:29:58 -0000
***************
*** 1031,1036 ****
--- 1031,1040 ----
  bool
  is_member_of_role(Oid member, Oid role)
  {
+       /* superuser considered part of every role */
+       if (superuser_arg(member))
+               return true;
+ 
        /* Fast path for simple case */
        if (member == role)
                return true;
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

               http://archives.postgresql.org

Reply via email to