When a superuser does GRANT or REVOKE on an object he doesn't own,
process the command as though it were issued by the object owner. This prevents creating weird scenarios in which the same privileges may appear to flow from different sources, and ensures that a superuser can in fact revoke all privileges if he wants to. In particular this means that the regression tests work when run by a superuser other than the original bootstrap userid. Per report from Larry Rosenman.
This commit is contained in:
parent
19554ed487
commit
8545482947
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.36 2003/09/20 20:12:05 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.37 2003/10/31 20:00:48 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -66,19 +66,21 @@ GRANT { { CREATE | USAGE } [,...] | ALL [ PRIVILEGES ] }
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There is no need to grant privileges to the owner of an object (usually the user that created it),
|
If <literal>WITH GRANT OPTION</literal> is specified, the recipient
|
||||||
as the owner has all privileges by default. (The owner could,
|
of the privilege may in turn grant it to others. By default this
|
||||||
however, choose to revoke some of his own privileges for safety.)
|
is not allowed. Grant options can only be granted to individual
|
||||||
The right to drop an object, or to alter it in any way is
|
users, not to groups or <literal>PUBLIC</literal>.
|
||||||
not described by a grantable right; it is inherent in the owner,
|
|
||||||
and cannot be granted or revoked.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If <literal>WITH GRANT OPTION</literal> is specified, the recipient
|
There is no need to grant privileges to the owner of an object
|
||||||
of the privilege may in turn grant it to others. By default this
|
(usually the user that created it),
|
||||||
is not possible. Grant options can only be granted to individual
|
as the owner has all privileges by default. (The owner could,
|
||||||
users, not groups or <literal>PUBLIC</literal>.
|
however, choose to revoke some of his own privileges for safety.)
|
||||||
|
The right to drop an object, or to alter its definition in any way is
|
||||||
|
not described by a grantable privilege; it is inherent in the owner,
|
||||||
|
and cannot be granted or revoked. It is not possible for the owner's
|
||||||
|
grant options to be revoked, either.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -263,6 +265,13 @@ GRANT { { CREATE | USAGE } [,...] | ALL [ PRIVILEGES ] }
|
|||||||
except when absolutely necessary.
|
except when absolutely necessary.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If a superuser chooses to issue a <command>GRANT</> or <command>REVOKE</>
|
||||||
|
command, the command is performed as though it were issued by the
|
||||||
|
owner of the affected object. In particular, privileges granted via
|
||||||
|
such a command will appear to have been granted by the object owner.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Currently, to grant privileges in <productname>PostgreSQL</productname>
|
Currently, to grant privileges in <productname>PostgreSQL</productname>
|
||||||
to only a few columns, you must
|
to only a few columns, you must
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v 1.27 2003/08/31 17:32:24 petere Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v 1.28 2003/10/31 20:00:48 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -63,6 +63,11 @@ REVOKE [ GRANT OPTION FOR ]
|
|||||||
all users.
|
all users.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
See the description of the <xref linkend="sql-grant" endterm="sql-grant-title"> command for
|
||||||
|
the meaning of the privilege types.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Note that any particular user will have the sum
|
Note that any particular user will have the sum
|
||||||
of privileges granted directly to him, privileges granted to any group he
|
of privileges granted directly to him, privileges granted to any group he
|
||||||
@ -73,11 +78,6 @@ REVOKE [ GRANT OPTION FOR ]
|
|||||||
directly or via a group will still have it.
|
directly or via a group will still have it.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
See the description of the <xref linkend="sql-grant" endterm="sql-grant-title"> command for
|
|
||||||
the meaning of the privilege types.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If <literal>GRANT OPTION FOR</literal> is specified, only the grant
|
If <literal>GRANT OPTION FOR</literal> is specified, only the grant
|
||||||
option for the privilege is revoked, not the privilege itself.
|
option for the privilege is revoked, not the privilege itself.
|
||||||
@ -116,6 +116,15 @@ REVOKE [ GRANT OPTION FOR ]
|
|||||||
the <literal>CASCADE</literal> option so that the privilege is
|
the <literal>CASCADE</literal> option so that the privilege is
|
||||||
automatically revoked from user C.
|
automatically revoked from user C.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If a superuser chooses to issue a <command>GRANT</> or <command>REVOKE</>
|
||||||
|
command, the command is performed as though it were issued by the
|
||||||
|
owner of the affected object. Since all privileges ultimately come
|
||||||
|
from the object owner (possibly indirectly via chains of grant options),
|
||||||
|
it is possible for a superuser to revoke all privileges, but this may
|
||||||
|
require use of <literal>CASCADE</literal> as stated above.
|
||||||
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1 id="SQL-REVOKE-examples">
|
<refsect1 id="SQL-REVOKE-examples">
|
||||||
@ -153,7 +162,8 @@ REVOKE [ GRANT OPTION FOR ] <replaceable class="PARAMETER">privileges</replaceab
|
|||||||
{ RESTRICT | CASCADE }
|
{ RESTRICT | CASCADE }
|
||||||
</synopsis>
|
</synopsis>
|
||||||
One of <literal>RESTRICT</literal> or <literal>CASCADE</literal>
|
One of <literal>RESTRICT</literal> or <literal>CASCADE</literal>
|
||||||
is required.
|
is required according to the standard, but <productname>PostgreSQL</>
|
||||||
|
assumes <literal>RESTRICT</literal> by default.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.90 2003/10/29 22:20:54 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.91 2003/10/31 20:00:49 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* See acl.h.
|
* See acl.h.
|
||||||
@ -68,6 +68,32 @@ dumpacl(Acl *acl)
|
|||||||
#endif /* ACLDEBUG */
|
#endif /* ACLDEBUG */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the effective grantor ID for a GRANT or REVOKE operation.
|
||||||
|
*
|
||||||
|
* Ordinarily this is just the current user, but when a superuser does
|
||||||
|
* GRANT or REVOKE, we pretend he is the object owner. This ensures that
|
||||||
|
* all granted privileges appear to flow from the object owner, and there
|
||||||
|
* are never multiple "original sources" of a privilege.
|
||||||
|
*/
|
||||||
|
static AclId
|
||||||
|
select_grantor(AclId ownerId)
|
||||||
|
{
|
||||||
|
AclId grantorId;
|
||||||
|
|
||||||
|
grantorId = GetUserId();
|
||||||
|
|
||||||
|
/* fast path if no difference */
|
||||||
|
if (grantorId == ownerId)
|
||||||
|
return grantorId;
|
||||||
|
|
||||||
|
if (superuser())
|
||||||
|
grantorId = ownerId;
|
||||||
|
|
||||||
|
return grantorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If is_grant is true, adds the given privileges for the list of
|
* If is_grant is true, adds the given privileges for the list of
|
||||||
* grantees to the existing old_acl. If is_grant is false, the
|
* grantees to the existing old_acl. If is_grant is false, the
|
||||||
@ -77,9 +103,9 @@ dumpacl(Acl *acl)
|
|||||||
*/
|
*/
|
||||||
static Acl *
|
static Acl *
|
||||||
merge_acl_with_grant(Acl *old_acl, bool is_grant,
|
merge_acl_with_grant(Acl *old_acl, bool is_grant,
|
||||||
List *grantees, AclMode privileges,
|
|
||||||
bool grant_option, DropBehavior behavior,
|
bool grant_option, DropBehavior behavior,
|
||||||
AclId owner_uid)
|
List *grantees, AclMode privileges,
|
||||||
|
AclId grantor_uid, AclId owner_uid)
|
||||||
{
|
{
|
||||||
unsigned modechg;
|
unsigned modechg;
|
||||||
List *j;
|
List *j;
|
||||||
@ -128,7 +154,7 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
|
|||||||
* and later the user is removed from the group, the situation is
|
* and later the user is removed from the group, the situation is
|
||||||
* impossible to clean up.
|
* impossible to clean up.
|
||||||
*/
|
*/
|
||||||
if (is_grant && idtype != ACL_IDTYPE_UID && grant_option)
|
if (is_grant && grant_option && idtype != ACL_IDTYPE_UID)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
||||||
errmsg("grant options can only be granted to individual users")));
|
errmsg("grant options can only be granted to individual users")));
|
||||||
@ -138,7 +164,7 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
|
|||||||
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
||||||
errmsg("cannot revoke grant options from owner")));
|
errmsg("cannot revoke grant options from owner")));
|
||||||
|
|
||||||
aclitem.ai_grantor = GetUserId();
|
aclitem.ai_grantor = grantor_uid;
|
||||||
|
|
||||||
ACLITEM_SET_PRIVS_IDTYPE(aclitem,
|
ACLITEM_SET_PRIVS_IDTYPE(aclitem,
|
||||||
(is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
|
(is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
|
||||||
@ -224,6 +250,8 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
|
|||||||
bool isNull;
|
bool isNull;
|
||||||
Acl *old_acl;
|
Acl *old_acl;
|
||||||
Acl *new_acl;
|
Acl *new_acl;
|
||||||
|
AclId grantorId;
|
||||||
|
AclId ownerId;
|
||||||
HeapTuple newtuple;
|
HeapTuple newtuple;
|
||||||
Datum values[Natts_pg_class];
|
Datum values[Natts_pg_class];
|
||||||
char nulls[Natts_pg_class];
|
char nulls[Natts_pg_class];
|
||||||
@ -239,9 +267,13 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
|
|||||||
elog(ERROR, "cache lookup failed for relation %u", relOid);
|
elog(ERROR, "cache lookup failed for relation %u", relOid);
|
||||||
pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
|
pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
ownerId = pg_class_tuple->relowner;
|
||||||
|
grantorId = select_grantor(ownerId);
|
||||||
|
|
||||||
if (stmt->is_grant
|
if (stmt->is_grant
|
||||||
&& !pg_class_ownercheck(relOid, GetUserId())
|
&& !pg_class_ownercheck(relOid, GetUserId())
|
||||||
&& pg_class_aclcheck(relOid, GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
|
&& pg_class_aclcheck(relOid, GetUserId(),
|
||||||
|
ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
|
||||||
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, relvar->relname);
|
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, relvar->relname);
|
||||||
|
|
||||||
/* Not sensible to grant on an index */
|
/* Not sensible to grant on an index */
|
||||||
@ -252,22 +284,20 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
|
|||||||
relvar->relname)));
|
relvar->relname)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's no ACL, create a default using the pg_class.relowner
|
* If there's no ACL, substitute the proper default.
|
||||||
* field.
|
|
||||||
*/
|
*/
|
||||||
aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
|
aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
|
||||||
&isNull);
|
&isNull);
|
||||||
if (isNull)
|
if (isNull)
|
||||||
old_acl = acldefault(ACL_OBJECT_RELATION,
|
old_acl = acldefault(ACL_OBJECT_RELATION, ownerId);
|
||||||
pg_class_tuple->relowner);
|
|
||||||
else
|
else
|
||||||
/* get a detoasted copy of the ACL */
|
/* get a detoasted copy of the ACL */
|
||||||
old_acl = DatumGetAclPCopy(aclDatum);
|
old_acl = DatumGetAclPCopy(aclDatum);
|
||||||
|
|
||||||
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
||||||
stmt->grantees, privileges,
|
|
||||||
stmt->grant_option, stmt->behavior,
|
stmt->grant_option, stmt->behavior,
|
||||||
pg_class_tuple->relowner);
|
stmt->grantees, privileges,
|
||||||
|
grantorId, ownerId);
|
||||||
|
|
||||||
/* finished building new ACL value, now insert it */
|
/* finished building new ACL value, now insert it */
|
||||||
MemSet(values, 0, sizeof(values));
|
MemSet(values, 0, sizeof(values));
|
||||||
@ -328,6 +358,8 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
|
|||||||
bool isNull;
|
bool isNull;
|
||||||
Acl *old_acl;
|
Acl *old_acl;
|
||||||
Acl *new_acl;
|
Acl *new_acl;
|
||||||
|
AclId grantorId;
|
||||||
|
AclId ownerId;
|
||||||
HeapTuple newtuple;
|
HeapTuple newtuple;
|
||||||
Datum values[Natts_pg_database];
|
Datum values[Natts_pg_database];
|
||||||
char nulls[Natts_pg_database];
|
char nulls[Natts_pg_database];
|
||||||
@ -345,28 +377,31 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
|
|||||||
errmsg("database \"%s\" does not exist", dbname)));
|
errmsg("database \"%s\" does not exist", dbname)));
|
||||||
pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
|
pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
ownerId = pg_database_tuple->datdba;
|
||||||
|
grantorId = select_grantor(ownerId);
|
||||||
|
|
||||||
if (stmt->is_grant
|
if (stmt->is_grant
|
||||||
&& pg_database_tuple->datdba != GetUserId()
|
&& !pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId())
|
||||||
&& pg_database_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
|
&& pg_database_aclcheck(HeapTupleGetOid(tuple), GetUserId(),
|
||||||
|
ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
|
||||||
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
|
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
|
||||||
NameStr(pg_database_tuple->datname));
|
NameStr(pg_database_tuple->datname));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's no ACL, create a default.
|
* If there's no ACL, substitute the proper default.
|
||||||
*/
|
*/
|
||||||
aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
|
aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
|
||||||
RelationGetDescr(relation), &isNull);
|
RelationGetDescr(relation), &isNull);
|
||||||
if (isNull)
|
if (isNull)
|
||||||
old_acl = acldefault(ACL_OBJECT_DATABASE,
|
old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
|
||||||
pg_database_tuple->datdba);
|
|
||||||
else
|
else
|
||||||
/* get a detoasted copy of the ACL */
|
/* get a detoasted copy of the ACL */
|
||||||
old_acl = DatumGetAclPCopy(aclDatum);
|
old_acl = DatumGetAclPCopy(aclDatum);
|
||||||
|
|
||||||
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
||||||
stmt->grantees, privileges,
|
|
||||||
stmt->grant_option, stmt->behavior,
|
stmt->grant_option, stmt->behavior,
|
||||||
pg_database_tuple->datdba);
|
stmt->grantees, privileges,
|
||||||
|
grantorId, ownerId);
|
||||||
|
|
||||||
/* finished building new ACL value, now insert it */
|
/* finished building new ACL value, now insert it */
|
||||||
MemSet(values, 0, sizeof(values));
|
MemSet(values, 0, sizeof(values));
|
||||||
@ -426,6 +461,8 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
|
|||||||
bool isNull;
|
bool isNull;
|
||||||
Acl *old_acl;
|
Acl *old_acl;
|
||||||
Acl *new_acl;
|
Acl *new_acl;
|
||||||
|
AclId grantorId;
|
||||||
|
AclId ownerId;
|
||||||
HeapTuple newtuple;
|
HeapTuple newtuple;
|
||||||
Datum values[Natts_pg_proc];
|
Datum values[Natts_pg_proc];
|
||||||
char nulls[Natts_pg_proc];
|
char nulls[Natts_pg_proc];
|
||||||
@ -441,29 +478,31 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
|
|||||||
elog(ERROR, "cache lookup failed for function %u", oid);
|
elog(ERROR, "cache lookup failed for function %u", oid);
|
||||||
pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
|
pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
ownerId = pg_proc_tuple->proowner;
|
||||||
|
grantorId = select_grantor(ownerId);
|
||||||
|
|
||||||
if (stmt->is_grant
|
if (stmt->is_grant
|
||||||
&& !pg_proc_ownercheck(oid, GetUserId())
|
&& !pg_proc_ownercheck(oid, GetUserId())
|
||||||
&& pg_proc_aclcheck(oid, GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
|
&& pg_proc_aclcheck(oid, GetUserId(),
|
||||||
|
ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
|
||||||
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
|
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
|
||||||
NameStr(pg_proc_tuple->proname));
|
NameStr(pg_proc_tuple->proname));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's no ACL, create a default using the pg_proc.proowner
|
* If there's no ACL, substitute the proper default.
|
||||||
* field.
|
|
||||||
*/
|
*/
|
||||||
aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
|
aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
|
||||||
&isNull);
|
&isNull);
|
||||||
if (isNull)
|
if (isNull)
|
||||||
old_acl = acldefault(ACL_OBJECT_FUNCTION,
|
old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
|
||||||
pg_proc_tuple->proowner);
|
|
||||||
else
|
else
|
||||||
/* get a detoasted copy of the ACL */
|
/* get a detoasted copy of the ACL */
|
||||||
old_acl = DatumGetAclPCopy(aclDatum);
|
old_acl = DatumGetAclPCopy(aclDatum);
|
||||||
|
|
||||||
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
||||||
stmt->grantees, privileges,
|
|
||||||
stmt->grant_option, stmt->behavior,
|
stmt->grant_option, stmt->behavior,
|
||||||
pg_proc_tuple->proowner);
|
stmt->grantees, privileges,
|
||||||
|
grantorId, ownerId);
|
||||||
|
|
||||||
/* finished building new ACL value, now insert it */
|
/* finished building new ACL value, now insert it */
|
||||||
MemSet(values, 0, sizeof(values));
|
MemSet(values, 0, sizeof(values));
|
||||||
@ -522,6 +561,8 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
|
|||||||
bool isNull;
|
bool isNull;
|
||||||
Acl *old_acl;
|
Acl *old_acl;
|
||||||
Acl *new_acl;
|
Acl *new_acl;
|
||||||
|
AclId grantorId;
|
||||||
|
AclId ownerId;
|
||||||
HeapTuple newtuple;
|
HeapTuple newtuple;
|
||||||
Datum values[Natts_pg_language];
|
Datum values[Natts_pg_language];
|
||||||
char nulls[Natts_pg_language];
|
char nulls[Natts_pg_language];
|
||||||
@ -537,36 +578,40 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
|
|||||||
errmsg("language \"%s\" does not exist", langname)));
|
errmsg("language \"%s\" does not exist", langname)));
|
||||||
pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
|
pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: for now, languages are treated as owned by the bootstrap
|
||||||
|
* user. We should add an owner column to pg_language instead.
|
||||||
|
*/
|
||||||
|
ownerId = BOOTSTRAP_USESYSID;
|
||||||
|
grantorId = select_grantor(ownerId);
|
||||||
|
|
||||||
|
if (stmt->is_grant
|
||||||
|
&& !superuser() /* XXX no ownercheck() available */
|
||||||
|
&& pg_language_aclcheck(HeapTupleGetOid(tuple), GetUserId(),
|
||||||
|
ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
|
||||||
|
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
|
||||||
|
NameStr(pg_language_tuple->lanname));
|
||||||
|
|
||||||
if (!pg_language_tuple->lanpltrusted && stmt->is_grant)
|
if (!pg_language_tuple->lanpltrusted && stmt->is_grant)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("language \"%s\" is not trusted", langname)));
|
errmsg("language \"%s\" is not trusted", langname)));
|
||||||
|
|
||||||
if (stmt->is_grant
|
|
||||||
&& !superuser()
|
|
||||||
&& pg_language_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
|
|
||||||
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
|
|
||||||
NameStr(pg_language_tuple->lanname));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's no ACL, create a default.
|
* If there's no ACL, substitute the proper default.
|
||||||
*
|
|
||||||
* Note: for now, languages are treated as owned by the bootstrap
|
|
||||||
* user. We should add an owner column to pg_language instead.
|
|
||||||
*/
|
*/
|
||||||
aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
|
aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
|
||||||
&isNull);
|
&isNull);
|
||||||
if (isNull)
|
if (isNull)
|
||||||
old_acl = acldefault(ACL_OBJECT_LANGUAGE,
|
old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
|
||||||
BOOTSTRAP_USESYSID);
|
|
||||||
else
|
else
|
||||||
/* get a detoasted copy of the ACL */
|
/* get a detoasted copy of the ACL */
|
||||||
old_acl = DatumGetAclPCopy(aclDatum);
|
old_acl = DatumGetAclPCopy(aclDatum);
|
||||||
|
|
||||||
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
||||||
stmt->grantees, privileges,
|
|
||||||
stmt->grant_option, stmt->behavior,
|
stmt->grant_option, stmt->behavior,
|
||||||
BOOTSTRAP_USESYSID);
|
stmt->grantees, privileges,
|
||||||
|
grantorId, ownerId);
|
||||||
|
|
||||||
/* finished building new ACL value, now insert it */
|
/* finished building new ACL value, now insert it */
|
||||||
MemSet(values, 0, sizeof(values));
|
MemSet(values, 0, sizeof(values));
|
||||||
@ -625,6 +670,8 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
|
|||||||
bool isNull;
|
bool isNull;
|
||||||
Acl *old_acl;
|
Acl *old_acl;
|
||||||
Acl *new_acl;
|
Acl *new_acl;
|
||||||
|
AclId grantorId;
|
||||||
|
AclId ownerId;
|
||||||
HeapTuple newtuple;
|
HeapTuple newtuple;
|
||||||
Datum values[Natts_pg_namespace];
|
Datum values[Natts_pg_namespace];
|
||||||
char nulls[Natts_pg_namespace];
|
char nulls[Natts_pg_namespace];
|
||||||
@ -640,30 +687,32 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
|
|||||||
errmsg("schema \"%s\" does not exist", nspname)));
|
errmsg("schema \"%s\" does not exist", nspname)));
|
||||||
pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
|
pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
ownerId = pg_namespace_tuple->nspowner;
|
||||||
|
grantorId = select_grantor(ownerId);
|
||||||
|
|
||||||
if (stmt->is_grant
|
if (stmt->is_grant
|
||||||
&& !pg_namespace_ownercheck(HeapTupleGetOid(tuple), GetUserId())
|
&& !pg_namespace_ownercheck(HeapTupleGetOid(tuple), GetUserId())
|
||||||
&& pg_namespace_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
|
&& pg_namespace_aclcheck(HeapTupleGetOid(tuple), GetUserId(),
|
||||||
|
ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
|
||||||
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,
|
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,
|
||||||
nspname);
|
nspname);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's no ACL, create a default using the
|
* If there's no ACL, substitute the proper default.
|
||||||
* pg_namespace.nspowner field.
|
|
||||||
*/
|
*/
|
||||||
aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
|
aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
|
||||||
Anum_pg_namespace_nspacl,
|
Anum_pg_namespace_nspacl,
|
||||||
&isNull);
|
&isNull);
|
||||||
if (isNull)
|
if (isNull)
|
||||||
old_acl = acldefault(ACL_OBJECT_NAMESPACE,
|
old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
|
||||||
pg_namespace_tuple->nspowner);
|
|
||||||
else
|
else
|
||||||
/* get a detoasted copy of the ACL */
|
/* get a detoasted copy of the ACL */
|
||||||
old_acl = DatumGetAclPCopy(aclDatum);
|
old_acl = DatumGetAclPCopy(aclDatum);
|
||||||
|
|
||||||
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
||||||
stmt->grantees, privileges,
|
|
||||||
stmt->grant_option, stmt->behavior,
|
stmt->grant_option, stmt->behavior,
|
||||||
pg_namespace_tuple->nspowner);
|
stmt->grantees, privileges,
|
||||||
|
grantorId, ownerId);
|
||||||
|
|
||||||
/* finished building new ACL value, now insert it */
|
/* finished building new ACL value, now insert it */
|
||||||
MemSet(values, 0, sizeof(values));
|
MemSet(values, 0, sizeof(values));
|
||||||
@ -1032,7 +1081,7 @@ pg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode)
|
|||||||
&isNull);
|
&isNull);
|
||||||
if (isNull)
|
if (isNull)
|
||||||
{
|
{
|
||||||
/* No ACL, so build default ACL for rel */
|
/* No ACL, so build default ACL */
|
||||||
AclId ownerId;
|
AclId ownerId;
|
||||||
|
|
||||||
ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
|
ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user