From aa1110624c08298393dfce996f7b21809d98d3fd Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 14 Jul 2005 21:46:30 +0000 Subject: [PATCH] Adjust permissions checking for ALTER OWNER commands: instead of requiring superuserness always, allow an owner to reassign ownership to any role he is a member of, if that role would have the right to create a similar object. These three requirements essentially state that the would-be alterer has enough privilege to DROP the existing object and then re-CREATE it as the new role; so we might as well let him do it in one step. The ALTER TABLESPACE case is a bit squirrely, but the whole concept of non-superuser tablespace owners is pretty dubious anyway. Stephen Frost, code review by Tom Lane. --- src/backend/commands/aggregatecmds.c | 22 ++++++-- src/backend/commands/conversioncmds.c | 25 ++++++--- src/backend/commands/dbcommands.c | 53 +++++++++++------- src/backend/commands/functioncmds.c | 22 ++++++-- src/backend/commands/opclasscmds.c | 22 ++++++-- src/backend/commands/operatorcmds.c | 22 ++++++-- src/backend/commands/schemacmds.c | 80 +++++++++++++++------------ src/backend/commands/tablecmds.c | 23 ++++++-- src/backend/commands/tablespace.c | 24 ++++++-- src/backend/commands/typecmds.c | 22 ++++++-- src/backend/utils/adt/acl.c | 20 ++++++- src/include/utils/acl.h | 3 +- 12 files changed, 229 insertions(+), 109 deletions(-) diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index 6335757981..e96f328d19 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.27 2005/06/28 05:08:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.28 2005/07/14 21:46:29 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -302,6 +302,7 @@ AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId) HeapTuple tup; Form_pg_proc procForm; Relation rel; + AclResult aclresult; /* * if a basetype is passed in, then attempt to find an aggregate for @@ -331,11 +332,20 @@ AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId) */ 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"))); + /* 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 diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c index 9cc72ec732..81e889aa4e 100644 --- a/src/backend/commands/conversioncmds.c +++ b/src/backend/commands/conversioncmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.20 2005/07/07 20:39:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.21 2005/07/14 21:46:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -152,8 +152,7 @@ RenameConversion(List *name, const char *newname) newname, get_namespace_name(namespaceOid)))); /* must be owner */ - if (!superuser() && - ((Form_pg_conversion) GETSTRUCT(tup))->conowner != GetUserId()) + if (!pg_conversion_ownercheck(conversionOid,GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, NameListToString(name)); @@ -182,6 +181,7 @@ AlterConversionOwner(List *name, Oid newOwnerId) HeapTuple tup; Relation rel; Form_pg_conversion convForm; + AclResult aclresult; rel = heap_open(ConversionRelationId, RowExclusiveLock); @@ -206,11 +206,20 @@ AlterConversionOwner(List *name, Oid newOwnerId) */ 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"))); + /* 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 diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 7f6791abfd..4e23def836 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.166 2005/07/08 04:12:24 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.167 2005/07/14 21:46:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -193,23 +193,19 @@ createdb(const CreatedbStmt *stmt) else datdba = GetUserId(); - if (is_member_of_role(GetUserId(), datdba)) - { - /* creating database for self: createdb is required */ - if (!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"))); - } + /* + * To create a database, must have createdb privilege and must be able + * to become the target role (this does not imply that the target role + * itself must have createdb privilege). The latter provision guards + * against "giveaway" attacks. Note that a superuser will always have + * both of these privileges a fortiori. + */ + if (!have_createdb_privilege()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to create database"))); + + check_is_member_of_role(GetUserId(), datdba); /* * Check for db name conflict. There is a race condition here, since @@ -930,11 +926,26 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId) bool isNull; HeapTuple newtuple; - /* must be superuser to change ownership */ - if (!superuser()) + /* Otherwise, must be owner of the existing object */ + if (!pg_database_ownercheck(HeapTupleGetOid(tuple),GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + dbname); + + /* Must be able to become new owner */ + check_is_member_of_role(GetUserId(), newOwnerId); + + /* + * 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 consistent + * with the CREATE case for databases. + */ + if (!have_createdb_privilege()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to change owner"))); + errmsg("permission denied to change owner of database"))); memset(repl_null, ' ', sizeof(repl_null)); memset(repl_repl, ' ', sizeof(repl_repl)); diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 8867538f8e..7e205890c9 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.63 2005/07/07 20:39:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.64 2005/07/14 21:46:29 tgl Exp $ * * DESCRIPTION * These routines take the parse tree and pick out the @@ -859,6 +859,7 @@ AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId) HeapTuple tup; Form_pg_proc procForm; Relation rel; + AclResult aclresult; rel = heap_open(ProcedureRelationId, RowExclusiveLock); @@ -892,11 +893,20 @@ AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId) 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"))); + /* 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)); diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index a0d0abd553..c9d11da70e 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.34 2005/07/07 20:39:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.35 2005/07/14 21:46:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -892,6 +892,7 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId) char *opcname; HeapTuple tup; Relation rel; + AclResult aclresult; Form_pg_opclass opcForm; amOid = GetSysCacheOid(AMNAME, @@ -950,11 +951,20 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId) */ 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"))); + /* 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 diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index ae93e9230e..d36ac6acd0 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.23 2005/07/07 20:39:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.24 2005/07/14 21:46:29 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -274,6 +274,7 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2, Oid operOid; HeapTuple tup; Relation rel; + AclResult aclresult; Form_pg_operator oprForm; rel = heap_open(OperatorRelationId, RowExclusiveLock); @@ -295,11 +296,20 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2, */ 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"))); + /* 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 diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index c4c20ddeb3..65a6edeabc 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.32 2005/07/07 20:39:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.33 2005/07/14 21:46:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,54 +49,45 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) saved_uid = GetUserId(); /* - * Figure out user identities. + * Who is supposed to own the new schema? */ - - if (!authId) - { - owner_uid = saved_uid; - } - else if (superuser()) - { + if (authId) 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. + * To create a schema, must have schema-create privilege on the current + * database and must be able to become the target role (this does not + * imply that the target role itself must have create-schema privilege). + * The latter provision guards against "giveaway" attacks. Note that + * a superuser will always have both of these privileges a fortiori. */ aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); + check_is_member_of_role(saved_uid, owner_uid); + + /* Additional check to protect reserved schema names */ if (!allowSystemTableMods && IsReservedName(schemaName)) ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("unacceptable schema name \"%s\"", schemaName), errdetail("The prefix \"pg_\" is reserved for system schemas."))); + /* + * If the requested authorization is different from the current user, + * temporarily set the current user so that the object(s) will be + * created with the correct ownership. + * + * (The setting will revert to session user on error or at the end of + * this routine.) + */ + if (saved_uid != owner_uid) + SetUserId(owner_uid); + /* Create the schema's namespace */ namespaceId = NamespaceCreate(schemaName, owner_uid); @@ -308,12 +299,29 @@ AlterSchemaOwner(const char *name, Oid newOwnerId) Datum aclDatum; bool isNull; HeapTuple newtuple; + AclResult aclresult; - /* Otherwise, must be superuser to change object ownership */ - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to change owner"))); + /* Otherwise, must be owner of the existing object */ + if (!pg_namespace_ownercheck(HeapTupleGetOid(tup),GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, + name); + + /* Must be able to become new owner */ + check_is_member_of_role(GetUserId(),newOwnerId); + + /* + * must have create-schema 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 consistent + * with the CREATE case for schemas. + */ + 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)); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 2b50a402fc..c06c272cbd 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.163 2005/07/07 20:39:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.164 2005/07/14 21:46:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -5286,12 +5286,23 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId) Datum aclDatum; bool isNull; HeapTuple newtuple; + Oid namespaceOid = tuple_class->relnamespace; + AclResult aclresult; - /* Otherwise, check that we are the superuser */ - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to change owner"))); + /* 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)); memset(repl_repl, ' ', sizeof(repl_repl)); diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index a2cce14335..06c939c2d5 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.25 2005/07/07 20:39:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.26 2005/07/14 21:46:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -788,11 +788,23 @@ AlterTableSpaceOwner(const char *name, Oid newOwnerId) 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"))); + /* Otherwise, must be owner of the existing object */ + if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, + name); + + /* Must be able to become new owner */ + check_is_member_of_role(GetUserId(), newOwnerId); + + /* + * Normally we would also check for create permissions here, + * but there are none for tablespaces so we follow 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)); diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 7406e15376..0979e8aeec 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.75 2005/07/10 21:13:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.76 2005/07/14 21:46:29 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -2025,6 +2025,7 @@ AlterTypeOwner(List *names, Oid newOwnerId) Relation rel; HeapTuple tup; Form_pg_type typTup; + AclResult aclresult; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeNode(TypeName); @@ -2067,11 +2068,20 @@ AlterTypeOwner(List *names, Oid newOwnerId) */ 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"))); + /* 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 diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index a416def815..3fedb33a8a 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.118 2005/07/07 20:39:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.119 2005/07/14 21:46:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2541,6 +2541,10 @@ is_member_of_role(Oid member, Oid role) if (member == role) return true; + /* Superusers have every privilege, so are part of every role */ + if (superuser_arg(member)) + return true; + /* If cache is already valid, just use the list */ if (OidIsValid(cached_role) && cached_role == member) return list_member_oid(cached_memberships, role); @@ -2604,6 +2608,20 @@ is_member_of_role(Oid member, Oid role) return list_member_oid(cached_memberships, role); } +/* + * check_is_member_of_role + * is_member_of_role with a standard permission-violation error if not + */ +void +check_is_member_of_role(Oid member, Oid role) +{ + if (!is_member_of_role(member, role)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be member of role \"%s\"", + GetUserNameFromId(role)))); +} + /* * Is member an admin of role (directly or indirectly)? That is, is it diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 7defb4e1e2..d3ef003198 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.81 2005/07/07 20:40:00 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.82 2005/07/14 21:46:30 tgl Exp $ * * NOTES * An ACL array is simply an array of AclItems, representing the union @@ -212,6 +212,7 @@ extern int aclmembers(const Acl *acl, Oid **roleids); extern bool is_member_of_role(Oid member, Oid role); extern bool is_admin_of_role(Oid member, Oid role); +extern void check_is_member_of_role(Oid member, Oid role); extern void initialize_acl(void);