mirror of
https://github.com/postgres/postgres.git
synced 2025-07-18 17:42:25 +03:00
Add support for privileges on types
This adds support for the more or less SQL-conforming USAGE privilege on types and domains. The intent is to be able restrict which users can create dependencies on types, which restricts the way in which owners can alter types. reviewed by Yeb Havinga
This commit is contained in:
@ -20,7 +20,9 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include "catalog/pg_type.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/resowner.h"
|
||||
#include "utils/syscache.h"
|
||||
@ -557,6 +559,7 @@ BuildDescForRelation(List *schema)
|
||||
foreach(l, schema)
|
||||
{
|
||||
ColumnDef *entry = lfirst(l);
|
||||
AclResult aclresult;
|
||||
|
||||
/*
|
||||
* for each entry in the list, get the name and type information from
|
||||
@ -567,6 +570,12 @@ BuildDescForRelation(List *schema)
|
||||
|
||||
attname = entry->colname;
|
||||
typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
|
||||
|
||||
aclresult = pg_type_aclcheck(atttypid, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(atttypid));
|
||||
|
||||
attcollation = GetColumnDefCollation(NULL, entry, atttypid);
|
||||
attdim = list_length(entry->typeName->arrayBounds);
|
||||
|
||||
|
@ -49,7 +49,9 @@
|
||||
#include "commands/tablespace.h"
|
||||
#include "foreign/foreign.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
@ -113,6 +115,7 @@ static void ExecGrant_Language(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Largeobject(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Namespace(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Tablespace(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Type(InternalGrant *grantStmt);
|
||||
|
||||
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
|
||||
static void SetDefaultACL(InternalDefaultACL *iacls);
|
||||
@ -274,6 +277,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
|
||||
case ACL_KIND_FOREIGN_SERVER:
|
||||
whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
|
||||
break;
|
||||
case ACL_KIND_TYPE:
|
||||
whole_mask = ACL_ALL_RIGHTS_TYPE;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized object kind: %d", objkind);
|
||||
/* not reached, but keep compiler quiet */
|
||||
@ -449,6 +455,10 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
||||
all_privileges = ACL_ALL_RIGHTS_DATABASE;
|
||||
errormsg = gettext_noop("invalid privilege type %s for database");
|
||||
break;
|
||||
case ACL_OBJECT_DOMAIN:
|
||||
all_privileges = ACL_ALL_RIGHTS_TYPE;
|
||||
errormsg = gettext_noop("invalid privilege type %s for domain");
|
||||
break;
|
||||
case ACL_OBJECT_FUNCTION:
|
||||
all_privileges = ACL_ALL_RIGHTS_FUNCTION;
|
||||
errormsg = gettext_noop("invalid privilege type %s for function");
|
||||
@ -469,6 +479,10 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
||||
all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
|
||||
errormsg = gettext_noop("invalid privilege type %s for tablespace");
|
||||
break;
|
||||
case ACL_OBJECT_TYPE:
|
||||
all_privileges = ACL_ALL_RIGHTS_TYPE;
|
||||
errormsg = gettext_noop("invalid privilege type %s for type");
|
||||
break;
|
||||
case ACL_OBJECT_FDW:
|
||||
all_privileges = ACL_ALL_RIGHTS_FDW;
|
||||
errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
|
||||
@ -552,6 +566,10 @@ ExecGrantStmt_oids(InternalGrant *istmt)
|
||||
case ACL_OBJECT_DATABASE:
|
||||
ExecGrant_Database(istmt);
|
||||
break;
|
||||
case ACL_OBJECT_DOMAIN:
|
||||
case ACL_OBJECT_TYPE:
|
||||
ExecGrant_Type(istmt);
|
||||
break;
|
||||
case ACL_OBJECT_FDW:
|
||||
ExecGrant_Fdw(istmt);
|
||||
break;
|
||||
@ -620,6 +638,17 @@ objectNamesToOids(GrantObjectType objtype, List *objnames)
|
||||
objects = lappend_oid(objects, dbid);
|
||||
}
|
||||
break;
|
||||
case ACL_OBJECT_DOMAIN:
|
||||
case ACL_OBJECT_TYPE:
|
||||
foreach(cell, objnames)
|
||||
{
|
||||
List *typname = (List *) lfirst(cell);
|
||||
Oid oid;
|
||||
|
||||
oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
|
||||
objects = lappend_oid(objects, oid);
|
||||
}
|
||||
break;
|
||||
case ACL_OBJECT_FUNCTION:
|
||||
foreach(cell, objnames)
|
||||
{
|
||||
@ -903,6 +932,10 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
|
||||
all_privileges = ACL_ALL_RIGHTS_FUNCTION;
|
||||
errormsg = gettext_noop("invalid privilege type %s for function");
|
||||
break;
|
||||
case ACL_OBJECT_TYPE:
|
||||
all_privileges = ACL_ALL_RIGHTS_TYPE;
|
||||
errormsg = gettext_noop("invalid privilege type %s for type");
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
|
||||
(int) action->objtype);
|
||||
@ -1085,6 +1118,12 @@ SetDefaultACL(InternalDefaultACL *iacls)
|
||||
this_privileges = ACL_ALL_RIGHTS_FUNCTION;
|
||||
break;
|
||||
|
||||
case ACL_OBJECT_TYPE:
|
||||
objtype = DEFACLOBJ_TYPE;
|
||||
if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
|
||||
this_privileges = ACL_ALL_RIGHTS_TYPE;
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized objtype: %d",
|
||||
(int) iacls->objtype);
|
||||
@ -1334,6 +1373,9 @@ RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
|
||||
case DatabaseRelationId:
|
||||
istmt.objtype = ACL_OBJECT_DATABASE;
|
||||
break;
|
||||
case TypeRelationId:
|
||||
istmt.objtype = ACL_OBJECT_TYPE;
|
||||
break;
|
||||
case ProcedureRelationId:
|
||||
istmt.objtype = ACL_OBJECT_FUNCTION;
|
||||
break;
|
||||
@ -2987,6 +3029,143 @@ ExecGrant_Tablespace(InternalGrant *istmt)
|
||||
heap_close(relation, RowExclusiveLock);
|
||||
}
|
||||
|
||||
static void
|
||||
ExecGrant_Type(InternalGrant *istmt)
|
||||
{
|
||||
Relation relation;
|
||||
ListCell *cell;
|
||||
|
||||
if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
|
||||
istmt->privileges = ACL_ALL_RIGHTS_TYPE;
|
||||
|
||||
relation = heap_open(TypeRelationId, RowExclusiveLock);
|
||||
|
||||
foreach(cell, istmt->objects)
|
||||
{
|
||||
Oid typId = lfirst_oid(cell);
|
||||
Form_pg_type pg_type_tuple;
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
AclMode avail_goptions;
|
||||
AclMode this_privileges;
|
||||
Acl *old_acl;
|
||||
Acl *new_acl;
|
||||
Oid grantorId;
|
||||
Oid ownerId;
|
||||
HeapTuple newtuple;
|
||||
Datum values[Natts_pg_type];
|
||||
bool nulls[Natts_pg_type];
|
||||
bool replaces[Natts_pg_type];
|
||||
int noldmembers;
|
||||
int nnewmembers;
|
||||
Oid *oldmembers;
|
||||
Oid *newmembers;
|
||||
HeapTuple tuple;
|
||||
|
||||
/* Search syscache for pg_type */
|
||||
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typId));
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "cache lookup failed for type %u", typId);
|
||||
|
||||
pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
|
||||
|
||||
if (pg_type_tuple->typelem != 0 && pg_type_tuple->typlen == -1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
||||
errmsg("cannot set privileges of array types"),
|
||||
errhint("Set the privileges of the element type instead.")));
|
||||
|
||||
/* Used GRANT DOMAIN on a non-domain? */
|
||||
if (istmt->objtype == ACL_OBJECT_DOMAIN &&
|
||||
pg_type_tuple->typtype != TYPTYPE_DOMAIN)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is not a domain",
|
||||
NameStr(pg_type_tuple->typname))));
|
||||
|
||||
/*
|
||||
* Get owner ID and working copy of existing ACL. If there's no ACL,
|
||||
* substitute the proper default.
|
||||
*/
|
||||
ownerId = pg_type_tuple->typowner;
|
||||
aclDatum = heap_getattr(tuple, Anum_pg_type_typacl,
|
||||
RelationGetDescr(relation), &isNull);
|
||||
if (isNull)
|
||||
{
|
||||
old_acl = acldefault(istmt->objtype, ownerId);
|
||||
/* There are no old member roles according to the catalogs */
|
||||
noldmembers = 0;
|
||||
oldmembers = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
old_acl = DatumGetAclPCopy(aclDatum);
|
||||
/* Get the roles mentioned in the existing ACL */
|
||||
noldmembers = aclmembers(old_acl, &oldmembers);
|
||||
}
|
||||
|
||||
/* Determine ID to do the grant as, and available grant options */
|
||||
select_best_grantor(GetUserId(), istmt->privileges,
|
||||
old_acl, ownerId,
|
||||
&grantorId, &avail_goptions);
|
||||
|
||||
/*
|
||||
* Restrict the privileges to what we can actually grant, and emit the
|
||||
* standards-mandated warning and error messages.
|
||||
*/
|
||||
this_privileges =
|
||||
restrict_and_check_grant(istmt->is_grant, avail_goptions,
|
||||
istmt->all_privs, istmt->privileges,
|
||||
typId, grantorId, ACL_KIND_TYPE,
|
||||
NameStr(pg_type_tuple->typname),
|
||||
0, NULL);
|
||||
|
||||
/*
|
||||
* Generate new ACL.
|
||||
*/
|
||||
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
|
||||
istmt->grant_option, istmt->behavior,
|
||||
istmt->grantees, this_privileges,
|
||||
grantorId, ownerId);
|
||||
|
||||
/*
|
||||
* We need the members of both old and new ACLs so we can correct the
|
||||
* shared dependency information.
|
||||
*/
|
||||
nnewmembers = aclmembers(new_acl, &newmembers);
|
||||
|
||||
/* finished building new ACL value, now insert it */
|
||||
MemSet(values, 0, sizeof(values));
|
||||
MemSet(nulls, false, sizeof(nulls));
|
||||
MemSet(replaces, false, sizeof(replaces));
|
||||
|
||||
replaces[Anum_pg_type_typacl - 1] = true;
|
||||
values[Anum_pg_type_typacl - 1] = PointerGetDatum(new_acl);
|
||||
|
||||
newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
|
||||
nulls, replaces);
|
||||
|
||||
simple_heap_update(relation, &newtuple->t_self, newtuple);
|
||||
|
||||
/* keep the catalog indexes up to date */
|
||||
CatalogUpdateIndexes(relation, newtuple);
|
||||
|
||||
/* Update the shared dependency ACL info */
|
||||
updateAclDependencies(TypeRelationId, typId, 0,
|
||||
ownerId,
|
||||
noldmembers, oldmembers,
|
||||
nnewmembers, newmembers);
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
pfree(new_acl);
|
||||
|
||||
/* prevent error when processing duplicate objects */
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
|
||||
heap_close(relation, RowExclusiveLock);
|
||||
}
|
||||
|
||||
|
||||
static AclMode
|
||||
string_to_privilege(const char *privname)
|
||||
@ -3263,6 +3442,8 @@ pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum, Oid roleid,
|
||||
return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
|
||||
case ACL_KIND_FOREIGN_SERVER:
|
||||
return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
|
||||
case ACL_KIND_TYPE:
|
||||
return pg_type_aclmask(table_oid, roleid, mask, how);
|
||||
default:
|
||||
elog(ERROR, "unrecognized objkind: %d",
|
||||
(int) objkind);
|
||||
@ -3971,6 +4152,80 @@ pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported routine for examining a user's privileges for a type.
|
||||
*/
|
||||
AclMode
|
||||
pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
|
||||
{
|
||||
AclMode result;
|
||||
HeapTuple tuple;
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
Acl *acl;
|
||||
Oid ownerId;
|
||||
|
||||
Form_pg_type typeForm;
|
||||
|
||||
/* Bypass permission checks for superusers */
|
||||
if (superuser_arg(roleid))
|
||||
return mask;
|
||||
|
||||
/*
|
||||
* Must get the type's tuple from pg_type
|
||||
*/
|
||||
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
(errmsg("type with OID %u does not exist",
|
||||
type_oid)));
|
||||
typeForm = (Form_pg_type) GETSTRUCT(tuple);
|
||||
|
||||
/* "True" array types don't manage permissions of their own */
|
||||
if (typeForm->typelem != 0 && typeForm->typlen == -1)
|
||||
{
|
||||
Oid elttype_oid = typeForm->typelem;
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
(errmsg("type with OID %u does not exist",
|
||||
type_oid)));
|
||||
typeForm = (Form_pg_type) GETSTRUCT(tuple);
|
||||
}
|
||||
|
||||
/*
|
||||
* Normal case: get the type's ACL from pg_type
|
||||
*/
|
||||
ownerId = typeForm->typowner;
|
||||
|
||||
aclDatum = SysCacheGetAttr(TYPEOID, tuple,
|
||||
Anum_pg_type_typacl, &isNull);
|
||||
if (isNull)
|
||||
{
|
||||
/* No ACL, so build default ACL */
|
||||
acl = acldefault(ACL_OBJECT_TYPE, ownerId);
|
||||
aclDatum = (Datum) 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* detoast rel's ACL if necessary */
|
||||
acl = DatumGetAclP(aclDatum);
|
||||
}
|
||||
|
||||
result = aclmask(acl, roleid, ownerId, mask, how);
|
||||
|
||||
/* if we have a detoasted copy, free it */
|
||||
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
|
||||
pfree(acl);
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported routine for checking a user's access privileges to a column
|
||||
*
|
||||
@ -4204,6 +4459,18 @@ pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode)
|
||||
return ACLCHECK_NO_PRIV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported routine for checking a user's access privileges to a type
|
||||
*/
|
||||
AclResult
|
||||
pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
|
||||
{
|
||||
if (pg_type_aclmask(type_oid, roleid, mode, ACLMASK_ANY) != 0)
|
||||
return ACLCHECK_OK;
|
||||
else
|
||||
return ACLCHECK_NO_PRIV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ownership check for a relation (specified by OID).
|
||||
*/
|
||||
@ -4813,6 +5080,10 @@ get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
|
||||
defaclobjtype = DEFACLOBJ_FUNCTION;
|
||||
break;
|
||||
|
||||
case ACL_OBJECT_TYPE:
|
||||
defaclobjtype = DEFACLOBJ_TYPE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -357,7 +357,9 @@ CREATE VIEW attributes AS
|
||||
ON a.attcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default')
|
||||
|
||||
WHERE a.attnum > 0 AND NOT a.attisdropped
|
||||
AND c.relkind in ('c');
|
||||
AND c.relkind in ('c')
|
||||
AND (pg_has_role(c.relowner, 'USAGE')
|
||||
OR has_type_privilege(c.reltype, 'USAGE'));
|
||||
|
||||
GRANT SELECT ON attributes TO PUBLIC;
|
||||
|
||||
@ -868,7 +870,9 @@ CREATE VIEW domain_constraints AS
|
||||
FROM pg_namespace rs, pg_namespace n, pg_constraint con, pg_type t
|
||||
WHERE rs.oid = con.connamespace
|
||||
AND n.oid = t.typnamespace
|
||||
AND t.oid = con.contypid;
|
||||
AND t.oid = con.contypid
|
||||
AND (pg_has_role(t.typowner, 'USAGE')
|
||||
OR has_type_privilege(t.oid, 'USAGE'));
|
||||
|
||||
GRANT SELECT ON domain_constraints TO PUBLIC;
|
||||
|
||||
@ -978,7 +982,8 @@ CREATE VIEW domains AS
|
||||
LEFT JOIN (pg_collation co JOIN pg_namespace nco ON (co.collnamespace = nco.oid))
|
||||
ON t.typcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default')
|
||||
|
||||
;
|
||||
WHERE (pg_has_role(t.typowner, 'USAGE')
|
||||
OR has_type_privilege(t.oid, 'USAGE'));
|
||||
|
||||
GRANT SELECT ON domains TO PUBLIC;
|
||||
|
||||
@ -2024,20 +2029,38 @@ GRANT SELECT ON triggers TO PUBLIC;
|
||||
*/
|
||||
|
||||
CREATE VIEW udt_privileges AS
|
||||
SELECT CAST(null AS sql_identifier) AS grantor,
|
||||
CAST('PUBLIC' AS sql_identifier) AS grantee,
|
||||
SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
|
||||
CAST(grantee.rolname AS sql_identifier) AS grantee,
|
||||
CAST(current_database() AS sql_identifier) AS udt_catalog,
|
||||
CAST(n.nspname AS sql_identifier) AS udt_schema,
|
||||
CAST(t.typname AS sql_identifier) AS udt_name,
|
||||
CAST('TYPE USAGE' AS character_data) AS privilege_type, -- sic
|
||||
CAST('NO' AS yes_or_no) AS is_grantable
|
||||
CAST(
|
||||
CASE WHEN
|
||||
-- object owner always has grant options
|
||||
pg_has_role(grantee.oid, t.typowner, 'USAGE')
|
||||
OR t.grantable
|
||||
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
|
||||
|
||||
FROM pg_authid u, pg_namespace n, pg_type t
|
||||
FROM (
|
||||
SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(typacl)).* FROM pg_type
|
||||
) AS t (oid, typname, typnamespace, typtype, typowner, grantor, grantee, prtype, grantable),
|
||||
pg_namespace n,
|
||||
pg_authid u_grantor,
|
||||
(
|
||||
SELECT oid, rolname FROM pg_authid
|
||||
UNION ALL
|
||||
SELECT 0::oid, 'PUBLIC'
|
||||
) AS grantee (oid, rolname)
|
||||
|
||||
WHERE u.oid = t.typowner
|
||||
AND n.oid = t.typnamespace
|
||||
AND t.typtype <> 'd'
|
||||
AND NOT (t.typelem <> 0 AND t.typlen = -1);
|
||||
WHERE t.typnamespace = n.oid
|
||||
AND t.typtype = 'c'
|
||||
AND t.grantee = grantee.oid
|
||||
AND t.grantor = u_grantor.oid
|
||||
AND t.prtype IN ('USAGE')
|
||||
AND (pg_has_role(u_grantor.oid, 'USAGE')
|
||||
OR pg_has_role(grantee.oid, 'USAGE')
|
||||
OR grantee.rolname = 'PUBLIC');
|
||||
|
||||
GRANT SELECT ON udt_privileges TO PUBLIC;
|
||||
|
||||
@ -2091,23 +2114,39 @@ CREATE VIEW usage_privileges AS
|
||||
UNION ALL
|
||||
|
||||
/* domains */
|
||||
-- Domains have no real privileges, so we represent all domains with implicit usage privilege here.
|
||||
SELECT CAST(u.rolname AS sql_identifier) AS grantor,
|
||||
CAST('PUBLIC' AS sql_identifier) AS grantee,
|
||||
SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
|
||||
CAST(grantee.rolname AS sql_identifier) AS grantee,
|
||||
CAST(current_database() AS sql_identifier) AS object_catalog,
|
||||
CAST(n.nspname AS sql_identifier) AS object_schema,
|
||||
CAST(t.typname AS sql_identifier) AS object_name,
|
||||
CAST('DOMAIN' AS character_data) AS object_type,
|
||||
CAST('USAGE' AS character_data) AS privilege_type,
|
||||
CAST('NO' AS yes_or_no) AS is_grantable
|
||||
CAST(
|
||||
CASE WHEN
|
||||
-- object owner always has grant options
|
||||
pg_has_role(grantee.oid, t.typowner, 'USAGE')
|
||||
OR t.grantable
|
||||
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
|
||||
|
||||
FROM pg_authid u,
|
||||
FROM (
|
||||
SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(typacl)).* FROM pg_type
|
||||
) AS t (oid, typname, typnamespace, typtype, typowner, grantor, grantee, prtype, grantable),
|
||||
pg_namespace n,
|
||||
pg_type t
|
||||
pg_authid u_grantor,
|
||||
(
|
||||
SELECT oid, rolname FROM pg_authid
|
||||
UNION ALL
|
||||
SELECT 0::oid, 'PUBLIC'
|
||||
) AS grantee (oid, rolname)
|
||||
|
||||
WHERE u.oid = t.typowner
|
||||
AND t.typnamespace = n.oid
|
||||
WHERE t.typnamespace = n.oid
|
||||
AND t.typtype = 'd'
|
||||
AND t.grantee = grantee.oid
|
||||
AND t.grantor = u_grantor.oid
|
||||
AND t.prtype IN ('USAGE')
|
||||
AND (pg_has_role(u_grantor.oid, 'USAGE')
|
||||
OR pg_has_role(grantee.oid, 'USAGE')
|
||||
OR grantee.rolname = 'PUBLIC')
|
||||
|
||||
UNION ALL
|
||||
|
||||
@ -2237,10 +2276,13 @@ CREATE VIEW user_defined_types AS
|
||||
CAST(null AS sql_identifier) AS source_dtd_identifier,
|
||||
CAST(null AS sql_identifier) AS ref_dtd_identifier
|
||||
|
||||
FROM pg_namespace n, pg_class c
|
||||
FROM pg_namespace n, pg_class c, pg_type t
|
||||
|
||||
WHERE n.oid = c.relnamespace
|
||||
AND c.relkind = 'c';
|
||||
AND t.typrelid = c.oid
|
||||
AND c.relkind = 'c'
|
||||
AND (pg_has_role(t.typowner, 'USAGE')
|
||||
OR has_type_privilege(t.oid, 'USAGE'));
|
||||
|
||||
GRANT SELECT ON user_defined_types TO PUBLIC;
|
||||
|
||||
|
@ -71,6 +71,7 @@ AggregateCreate(const char *aggName,
|
||||
int i;
|
||||
ObjectAddress myself,
|
||||
referenced;
|
||||
AclResult aclresult;
|
||||
|
||||
/* sanity checks (caller should have caught these) */
|
||||
if (!aggName)
|
||||
@ -200,6 +201,28 @@ AggregateCreate(const char *aggName,
|
||||
false, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* permission checks on used types
|
||||
*/
|
||||
for (i = 0; i < numArgs; i++)
|
||||
{
|
||||
aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(aggArgTypes[i]));
|
||||
}
|
||||
|
||||
aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(aggTransType));
|
||||
|
||||
aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(finaltype));
|
||||
|
||||
|
||||
/*
|
||||
* Everything looks okay. Try to create the pg_proc entry for the
|
||||
* aggregate. (This could fail if there's already a conflicting entry.)
|
||||
|
@ -117,6 +117,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
|
||||
values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
|
||||
nulls[Anum_pg_type_typdefaultbin - 1] = true;
|
||||
nulls[Anum_pg_type_typdefault - 1] = true;
|
||||
nulls[Anum_pg_type_typacl - 1] = true;
|
||||
|
||||
/*
|
||||
* create a new type tuple
|
||||
@ -224,6 +225,7 @@ TypeCreate(Oid newTypeOid,
|
||||
Datum values[Natts_pg_type];
|
||||
NameData name;
|
||||
int i;
|
||||
Acl *typacl = NULL;
|
||||
|
||||
/*
|
||||
* We assume that the caller validated the arguments individually, but did
|
||||
@ -369,6 +371,13 @@ TypeCreate(Oid newTypeOid,
|
||||
else
|
||||
nulls[Anum_pg_type_typdefault - 1] = true;
|
||||
|
||||
typacl = get_user_default_acl(ACL_OBJECT_TYPE, ownerId,
|
||||
typeNamespace);
|
||||
if (typacl != NULL)
|
||||
values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
|
||||
else
|
||||
nulls[Anum_pg_type_typacl - 1] = true;
|
||||
|
||||
/*
|
||||
* open pg_type and prepare to insert or update a row.
|
||||
*
|
||||
|
@ -87,9 +87,11 @@ compute_return_type(TypeName *returnType, Oid languageOid,
|
||||
{
|
||||
Oid rettype;
|
||||
Type typtup;
|
||||
AclResult aclresult;
|
||||
|
||||
typtup = LookupTypeName(NULL, returnType, NULL);
|
||||
|
||||
|
||||
if (typtup)
|
||||
{
|
||||
if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
|
||||
@ -150,6 +152,11 @@ compute_return_type(TypeName *returnType, Oid languageOid,
|
||||
Assert(OidIsValid(rettype));
|
||||
}
|
||||
|
||||
aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(rettype));
|
||||
|
||||
*prorettype_p = rettype;
|
||||
*returnsSet_p = returnType->setof;
|
||||
}
|
||||
@ -207,6 +214,7 @@ examine_parameter_list(List *parameters, Oid languageOid,
|
||||
bool isinput = false;
|
||||
Oid toid;
|
||||
Type typtup;
|
||||
AclResult aclresult;
|
||||
|
||||
typtup = LookupTypeName(NULL, t, NULL);
|
||||
if (typtup)
|
||||
@ -237,6 +245,11 @@ examine_parameter_list(List *parameters, Oid languageOid,
|
||||
toid = InvalidOid; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(toid));
|
||||
|
||||
if (t->setof)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
@ -1429,6 +1442,7 @@ CreateCast(CreateCastStmt *stmt)
|
||||
bool nulls[Natts_pg_cast];
|
||||
ObjectAddress myself,
|
||||
referenced;
|
||||
AclResult aclresult;
|
||||
|
||||
sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
|
||||
targettypeid = typenameTypeId(NULL, stmt->targettype);
|
||||
@ -1457,6 +1471,16 @@ CreateCast(CreateCastStmt *stmt)
|
||||
format_type_be(sourcetypeid),
|
||||
format_type_be(targettypeid))));
|
||||
|
||||
aclresult = pg_type_aclcheck(sourcetypeid, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(sourcetypeid));
|
||||
|
||||
aclresult = pg_type_aclcheck(targettypeid, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(targettypeid));
|
||||
|
||||
/* Detemine the cast method */
|
||||
if (stmt->func != NULL)
|
||||
castmethod = COERCION_METHOD_FUNCTION;
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_oper.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/syscache.h"
|
||||
@ -73,6 +74,7 @@ DefineOperator(List *names, List *parameters)
|
||||
TypeName *typeName2 = NULL; /* second type name */
|
||||
Oid typeId1 = InvalidOid; /* types converted to OID */
|
||||
Oid typeId2 = InvalidOid;
|
||||
Oid rettype;
|
||||
List *commutatorName = NIL; /* optional commutator operator name */
|
||||
List *negatorName = NIL; /* optional negator operator name */
|
||||
List *restrictionName = NIL; /* optional restrict. sel. procedure */
|
||||
@ -175,6 +177,22 @@ DefineOperator(List *names, List *parameters)
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("at least one of leftarg or rightarg must be specified")));
|
||||
|
||||
if (typeName1)
|
||||
{
|
||||
aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(typeId1));
|
||||
}
|
||||
|
||||
if (typeName2)
|
||||
{
|
||||
aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(typeId2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the operator's underlying function.
|
||||
*/
|
||||
@ -206,6 +224,12 @@ DefineOperator(List *names, List *parameters)
|
||||
aclcheck_error(aclresult, ACL_KIND_PROC,
|
||||
NameListToString(functionName));
|
||||
|
||||
rettype = get_func_rettype(functionOid);
|
||||
aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(rettype));
|
||||
|
||||
/*
|
||||
* Look up restriction estimator if specified
|
||||
*/
|
||||
|
@ -506,7 +506,16 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
|
||||
(void) heap_reloptions(relkind, reloptions, true);
|
||||
|
||||
if (stmt->ofTypename)
|
||||
{
|
||||
AclResult aclresult;
|
||||
|
||||
ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
|
||||
|
||||
aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(ofTypeId));
|
||||
}
|
||||
else
|
||||
ofTypeId = InvalidOid;
|
||||
|
||||
@ -4326,6 +4335,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
Expr *defval;
|
||||
List *children;
|
||||
ListCell *child;
|
||||
AclResult aclresult;
|
||||
|
||||
/* At top level, permission check was done in ATPrepCmd, else do it */
|
||||
if (recursing)
|
||||
@ -4429,6 +4439,12 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
typeTuple = typenameType(NULL, colDef->typeName, &typmod);
|
||||
tform = (Form_pg_type) GETSTRUCT(typeTuple);
|
||||
typeOid = HeapTupleGetOid(typeTuple);
|
||||
|
||||
aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(typeOid));
|
||||
|
||||
collOid = GetColumnDefCollation(NULL, colDef, typeOid);
|
||||
|
||||
/* make sure datatype is legal for a column */
|
||||
@ -6973,6 +6989,7 @@ ATPrepAlterColumnType(List **wqueue,
|
||||
Oid targetcollid;
|
||||
NewColumnValue *newval;
|
||||
ParseState *pstate = make_parsestate(NULL);
|
||||
AclResult aclresult;
|
||||
|
||||
if (rel->rd_rel->reloftype && !recursing)
|
||||
ereport(ERROR,
|
||||
@ -7006,6 +7023,11 @@ ATPrepAlterColumnType(List **wqueue,
|
||||
/* Look up the target type */
|
||||
typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
|
||||
|
||||
aclresult = pg_type_aclcheck(targettype, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(targettype));
|
||||
|
||||
/* And the collation */
|
||||
targetcollid = GetColumnDefCollation(NULL, def, targettype);
|
||||
|
||||
|
@ -756,6 +756,11 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
errmsg("\"%s\" is not a valid base type for a domain",
|
||||
TypeNameToString(stmt->typeName))));
|
||||
|
||||
aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(basetypeoid));
|
||||
|
||||
/*
|
||||
* Identify the collation if any
|
||||
*/
|
||||
|
@ -2490,6 +2490,21 @@ OpenIntoRel(QueryDesc *queryDesc)
|
||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||
errmsg("ON COMMIT can only be used on temporary tables")));
|
||||
|
||||
{
|
||||
AclResult aclresult;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < intoTupDesc->natts; i++)
|
||||
{
|
||||
Oid atttypid = intoTupDesc->attrs[i]->atttypid;
|
||||
|
||||
aclresult = pg_type_aclcheck(atttypid, GetUserId(), ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_TYPE,
|
||||
format_type_be(atttypid));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If a column name list was specified in CREATE TABLE AS, override the
|
||||
* column names derived from the query. (Too few column names are OK, too
|
||||
|
@ -558,7 +558,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
|
||||
|
||||
TABLE TABLES TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP
|
||||
TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
|
||||
TRUNCATE TRUSTED TYPE_P
|
||||
TRUNCATE TRUSTED TYPE_P TYPES_P
|
||||
|
||||
UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNLOGGED
|
||||
UNTIL UPDATE USER USING
|
||||
@ -5434,6 +5434,14 @@ privilege_target:
|
||||
n->objs = $2;
|
||||
$$ = n;
|
||||
}
|
||||
| DOMAIN_P any_name_list
|
||||
{
|
||||
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
|
||||
n->targtype = ACL_TARGET_OBJECT;
|
||||
n->objtype = ACL_OBJECT_DOMAIN;
|
||||
n->objs = $2;
|
||||
$$ = n;
|
||||
}
|
||||
| LANGUAGE name_list
|
||||
{
|
||||
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
|
||||
@ -5466,6 +5474,14 @@ privilege_target:
|
||||
n->objs = $2;
|
||||
$$ = n;
|
||||
}
|
||||
| TYPE_P any_name_list
|
||||
{
|
||||
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
|
||||
n->targtype = ACL_TARGET_OBJECT;
|
||||
n->objtype = ACL_OBJECT_TYPE;
|
||||
n->objs = $2;
|
||||
$$ = n;
|
||||
}
|
||||
| ALL TABLES IN_P SCHEMA name_list
|
||||
{
|
||||
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
|
||||
@ -5680,6 +5696,7 @@ defacl_privilege_target:
|
||||
TABLES { $$ = ACL_OBJECT_RELATION; }
|
||||
| FUNCTIONS { $$ = ACL_OBJECT_FUNCTION; }
|
||||
| SEQUENCES { $$ = ACL_OBJECT_SEQUENCE; }
|
||||
| TYPES_P { $$ = ACL_OBJECT_TYPE; }
|
||||
;
|
||||
|
||||
|
||||
|
@ -109,6 +109,8 @@ static Oid convert_server_name(text *servername);
|
||||
static AclMode convert_server_priv_string(text *priv_type_text);
|
||||
static Oid convert_tablespace_name(text *tablespacename);
|
||||
static AclMode convert_tablespace_priv_string(text *priv_type_text);
|
||||
static Oid convert_type_name(text *typename);
|
||||
static AclMode convert_type_priv_string(text *priv_type_text);
|
||||
static AclMode convert_role_priv_string(text *priv_type_text);
|
||||
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
|
||||
|
||||
@ -782,6 +784,11 @@ acldefault(GrantObjectType objtype, Oid ownerId)
|
||||
world_default = ACL_NO_RIGHTS;
|
||||
owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
|
||||
break;
|
||||
case ACL_OBJECT_DOMAIN:
|
||||
case ACL_OBJECT_TYPE:
|
||||
world_default = ACL_USAGE;
|
||||
owner_default = ACL_ALL_RIGHTS_TYPE;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
|
||||
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
|
||||
@ -4126,6 +4133,206 @@ convert_tablespace_priv_string(text *priv_type_text)
|
||||
return convert_any_priv_string(priv_type_text, tablespace_priv_map);
|
||||
}
|
||||
|
||||
/*
|
||||
* has_type_privilege variants
|
||||
* These are all named "has_type_privilege" at the SQL level.
|
||||
* They take various combinations of type name, type OID,
|
||||
* user name, user OID, or implicit user = current_user.
|
||||
*
|
||||
* The result is a boolean value: true if user has the indicated
|
||||
* privilege, false if not, or NULL if object doesn't exist.
|
||||
*/
|
||||
|
||||
/*
|
||||
* has_type_privilege_name_name
|
||||
* Check user privileges on a type given
|
||||
* name username, text typename, and text priv name.
|
||||
*/
|
||||
Datum
|
||||
has_type_privilege_name_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Name username = PG_GETARG_NAME(0);
|
||||
text *typename = PG_GETARG_TEXT_P(1);
|
||||
text *priv_type_text = PG_GETARG_TEXT_P(2);
|
||||
Oid roleid;
|
||||
Oid typeoid;
|
||||
AclMode mode;
|
||||
AclResult aclresult;
|
||||
|
||||
roleid = get_role_oid_or_public(NameStr(*username));
|
||||
typeoid = convert_type_name(typename);
|
||||
mode = convert_type_priv_string(priv_type_text);
|
||||
|
||||
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
|
||||
|
||||
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* has_type_privilege_name
|
||||
* Check user privileges on a type given
|
||||
* text typename and text priv name.
|
||||
* current_user is assumed
|
||||
*/
|
||||
Datum
|
||||
has_type_privilege_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *typename = PG_GETARG_TEXT_P(0);
|
||||
text *priv_type_text = PG_GETARG_TEXT_P(1);
|
||||
Oid roleid;
|
||||
Oid typeoid;
|
||||
AclMode mode;
|
||||
AclResult aclresult;
|
||||
|
||||
roleid = GetUserId();
|
||||
typeoid = convert_type_name(typename);
|
||||
mode = convert_type_priv_string(priv_type_text);
|
||||
|
||||
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
|
||||
|
||||
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* has_type_privilege_name_id
|
||||
* Check user privileges on a type given
|
||||
* name usename, type oid, and text priv name.
|
||||
*/
|
||||
Datum
|
||||
has_type_privilege_name_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Name username = PG_GETARG_NAME(0);
|
||||
Oid typeoid = PG_GETARG_OID(1);
|
||||
text *priv_type_text = PG_GETARG_TEXT_P(2);
|
||||
Oid roleid;
|
||||
AclMode mode;
|
||||
AclResult aclresult;
|
||||
|
||||
roleid = get_role_oid_or_public(NameStr(*username));
|
||||
mode = convert_type_priv_string(priv_type_text);
|
||||
|
||||
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
|
||||
|
||||
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* has_type_privilege_id
|
||||
* Check user privileges on a type given
|
||||
* type oid, and text priv name.
|
||||
* current_user is assumed
|
||||
*/
|
||||
Datum
|
||||
has_type_privilege_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid typeoid = PG_GETARG_OID(0);
|
||||
text *priv_type_text = PG_GETARG_TEXT_P(1);
|
||||
Oid roleid;
|
||||
AclMode mode;
|
||||
AclResult aclresult;
|
||||
|
||||
roleid = GetUserId();
|
||||
mode = convert_type_priv_string(priv_type_text);
|
||||
|
||||
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
|
||||
|
||||
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* has_type_privilege_id_name
|
||||
* Check user privileges on a type given
|
||||
* roleid, text typename, and text priv name.
|
||||
*/
|
||||
Datum
|
||||
has_type_privilege_id_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid roleid = PG_GETARG_OID(0);
|
||||
text *typename = PG_GETARG_TEXT_P(1);
|
||||
text *priv_type_text = PG_GETARG_TEXT_P(2);
|
||||
Oid typeoid;
|
||||
AclMode mode;
|
||||
AclResult aclresult;
|
||||
|
||||
typeoid = convert_type_name(typename);
|
||||
mode = convert_type_priv_string(priv_type_text);
|
||||
|
||||
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
|
||||
|
||||
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* has_type_privilege_id_id
|
||||
* Check user privileges on a type given
|
||||
* roleid, type oid, and text priv name.
|
||||
*/
|
||||
Datum
|
||||
has_type_privilege_id_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid roleid = PG_GETARG_OID(0);
|
||||
Oid typeoid = PG_GETARG_OID(1);
|
||||
text *priv_type_text = PG_GETARG_TEXT_P(2);
|
||||
AclMode mode;
|
||||
AclResult aclresult;
|
||||
|
||||
mode = convert_type_priv_string(priv_type_text);
|
||||
|
||||
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
|
||||
|
||||
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support routines for has_type_privilege family.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Given a type name expressed as a string, look it up and return Oid
|
||||
*/
|
||||
static Oid
|
||||
convert_type_name(text *typename)
|
||||
{
|
||||
char *typname = text_to_cstring(typename);
|
||||
Oid oid;
|
||||
|
||||
oid = DatumGetObjectId(DirectFunctionCall1(regtypein,
|
||||
CStringGetDatum(typname)));
|
||||
|
||||
if (!OidIsValid(oid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("type \"%s\" does not exist", typname)));
|
||||
|
||||
return oid;
|
||||
}
|
||||
|
||||
/*
|
||||
* convert_type_priv_string
|
||||
* Convert text string to AclMode value.
|
||||
*/
|
||||
static AclMode
|
||||
convert_type_priv_string(text *priv_type_text)
|
||||
{
|
||||
static const priv_map type_priv_map[] = {
|
||||
{"USAGE", ACL_USAGE},
|
||||
{"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
return convert_any_priv_string(priv_type_text, type_priv_map);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* pg_has_role variants
|
||||
* These are all named "pg_has_role" at the SQL level.
|
||||
|
Reference in New Issue
Block a user