1 /*-------------------------------------------------------------------------
4 * Routines to check access control permissions.
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
16 *-------------------------------------------------------------------------
20 #include "access/genam.h"
21 #include "access/heapam.h"
22 #include "access/sysattr.h"
23 #include "access/xact.h"
24 #include "catalog/catalog.h"
25 #include "catalog/dependency.h"
26 #include "catalog/indexing.h"
27 #include "catalog/pg_authid.h"
28 #include "catalog/pg_conversion.h"
29 #include "catalog/pg_database.h"
30 #include "catalog/pg_foreign_data_wrapper.h"
31 #include "catalog/pg_foreign_server.h"
32 #include "catalog/pg_language.h"
33 #include "catalog/pg_namespace.h"
34 #include "catalog/pg_opclass.h"
35 #include "catalog/pg_operator.h"
36 #include "catalog/pg_opfamily.h"
37 #include "catalog/pg_proc.h"
38 #include "catalog/pg_tablespace.h"
39 #include "catalog/pg_type.h"
40 #include "catalog/pg_ts_config.h"
41 #include "catalog/pg_ts_dict.h"
42 #include "commands/dbcommands.h"
43 #include "foreign/foreign.h"
44 #include "miscadmin.h"
45 #include "parser/parse_func.h"
46 #include "utils/acl.h"
47 #include "utils/fmgroids.h"
48 #include "utils/lsyscache.h"
49 #include "utils/rel.h"
50 #include "utils/syscache.h"
51 #include "utils/tqual.h"
54 static void ExecGrant_Relation(InternalGrant
*grantStmt
);
55 static void ExecGrant_Database(InternalGrant
*grantStmt
);
56 static void ExecGrant_Fdw(InternalGrant
*grantStmt
);
57 static void ExecGrant_ForeignServer(InternalGrant
*grantStmt
);
58 static void ExecGrant_Function(InternalGrant
*grantStmt
);
59 static void ExecGrant_Language(InternalGrant
*grantStmt
);
60 static void ExecGrant_Namespace(InternalGrant
*grantStmt
);
61 static void ExecGrant_Tablespace(InternalGrant
*grantStmt
);
63 static List
*objectNamesToOids(GrantObjectType objtype
, List
*objnames
);
64 static void expand_col_privileges(List
*colnames
, Oid table_oid
,
65 AclMode this_privileges
,
66 AclMode
*col_privileges
,
67 int num_col_privileges
);
68 static void expand_all_col_privileges(Oid table_oid
, Form_pg_class classForm
,
69 AclMode this_privileges
,
70 AclMode
*col_privileges
,
71 int num_col_privileges
);
72 static AclMode
string_to_privilege(const char *privname
);
73 static const char *privilege_to_string(AclMode privilege
);
74 static AclMode
restrict_and_check_grant(bool is_grant
, AclMode avail_goptions
,
75 bool all_privs
, AclMode privileges
,
76 Oid objectId
, Oid grantorId
,
77 AclObjectKind objkind
, const char *objname
,
78 AttrNumber att_number
, const char *colname
);
79 static AclMode
pg_aclmask(AclObjectKind objkind
, Oid table_oid
, AttrNumber attnum
,
80 Oid roleid
, AclMode mask
, AclMaskHow how
);
90 elog(DEBUG2
, "acl size = %d, # acls = %d",
91 ACL_SIZE(acl
), ACL_NUM(acl
));
93 for (i
= 0; i
< ACL_NUM(acl
); ++i
)
94 elog(DEBUG2
, " acl[%d]: %s", i
,
95 DatumGetCString(DirectFunctionCall1(aclitemout
,
96 PointerGetDatum(aip
+ i
))));
102 * If is_grant is true, adds the given privileges for the list of
103 * grantees to the existing old_acl. If is_grant is false, the
104 * privileges for the given grantees are removed from old_acl.
106 * NB: the original old_acl is pfree'd.
109 merge_acl_with_grant(Acl
*old_acl
, bool is_grant
,
110 bool grant_option
, DropBehavior behavior
,
111 List
*grantees
, AclMode privileges
,
112 Oid grantorId
, Oid ownerId
)
118 modechg
= is_grant
? ACL_MODECHG_ADD
: ACL_MODECHG_DEL
;
130 aclitem
. ai_grantee
= lfirst_oid(j
);
133 * Grant options can only be granted to individual roles, not PUBLIC.
134 * The reason is that if a user would re-grant a privilege that he
135 * held through PUBLIC, and later the user is removed, the situation
136 * is impossible to clean up.
138 if (is_grant
&& grant_option
&& aclitem
.ai_grantee
== ACL_ID_PUBLIC
)
140 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
141 errmsg("grant options can only be granted to roles")));
143 aclitem
. ai_grantor
= grantorId
;
146 * The asymmetry in the conditions here comes from the spec. In
147 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
148 * to grant both the basic privilege and its grant option. But in
149 * REVOKE, plain revoke revokes both the basic privilege and its grant
150 * option, while REVOKE GRANT OPTION revokes only the option.
152 ACLITEM_SET_PRIVS_GOPTIONS(aclitem
,
153 (is_grant
|| !grant_option
) ? privileges
: ACL_NO_RIGHTS
,
154 (!is_grant
|| grant_option
) ? privileges
: ACL_NO_RIGHTS
);
156 newer_acl
= aclupdate(new_acl
, &aclitem
, modechg
, ownerId
, behavior
);
158 /* avoid memory leak when there are many grantees */
171 * Restrict the privileges to what we can actually grant, and emit
172 * the standards-mandated warning and error messages.
175 restrict_and_check_grant(bool is_grant
, AclMode avail_goptions
, bool all_privs
,
176 AclMode privileges
, Oid objectId
, Oid grantorId
,
177 AclObjectKind objkind
, const char *objname
,
178 AttrNumber att_number
, const char *colname
)
180 AclMode this_privileges
;
185 case ACL_KIND_COLUMN
:
186 whole_mask
= ACL_ALL_RIGHTS_COLUMN
;
189 whole_mask
= ACL_ALL_RIGHTS_RELATION
;
191 case ACL_KIND_SEQUENCE
:
192 whole_mask
= ACL_ALL_RIGHTS_SEQUENCE
;
194 case ACL_KIND_DATABASE
:
195 whole_mask
= ACL_ALL_RIGHTS_DATABASE
;
198 whole_mask
= ACL_ALL_RIGHTS_FUNCTION
;
200 case ACL_KIND_LANGUAGE
:
201 whole_mask
= ACL_ALL_RIGHTS_LANGUAGE
;
203 case ACL_KIND_NAMESPACE
:
204 whole_mask
= ACL_ALL_RIGHTS_NAMESPACE
;
206 case ACL_KIND_TABLESPACE
:
207 whole_mask
= ACL_ALL_RIGHTS_TABLESPACE
;
210 whole_mask
= ACL_ALL_RIGHTS_FDW
;
212 case ACL_KIND_FOREIGN_SERVER
:
213 whole_mask
= ACL_ALL_RIGHTS_FOREIGN_SERVER
;
216 elog(ERROR
, "unrecognized object kind: %d", objkind
);
217 /* not reached, but keep compiler quiet */
218 return ACL_NO_RIGHTS
;
222 * If we found no grant options, consider whether to issue a hard error.
223 * Per spec, having any privilege at all on the object will get you by
226 if (avail_goptions
== ACL_NO_RIGHTS
)
228 if (pg_aclmask(objkind
, objectId
, att_number
, grantorId
,
229 whole_mask
| ACL_GRANT_OPTION_FOR(whole_mask
),
230 ACLMASK_ANY
) == ACL_NO_RIGHTS
)
232 if (objkind
== ACL_KIND_COLUMN
&& colname
)
233 aclcheck_error_col(ACLCHECK_NO_PRIV
, objkind
, objname
, colname
);
235 aclcheck_error(ACLCHECK_NO_PRIV
, objkind
, objname
);
240 * Restrict the operation to what we can actually grant or revoke, and
241 * issue a warning if appropriate. (For REVOKE this isn't quite what the
242 * spec says to do: the spec seems to want a warning only if no privilege
243 * bits actually change in the ACL. In practice that behavior seems much
244 * too noisy, as well as inconsistent with the GRANT case.)
246 this_privileges
= privileges
& ACL_OPTION_TO_PRIVS(avail_goptions
);
249 if (this_privileges
== 0)
251 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED
),
252 errmsg("no privileges were granted for \"%s\"", objname
)));
253 else if (!all_privs
&& this_privileges
!= privileges
)
255 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED
),
256 errmsg("not all privileges were granted for \"%s\"", objname
)));
260 if (this_privileges
== 0)
262 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED
),
263 errmsg("no privileges could be revoked for \"%s\"", objname
)));
264 else if (!all_privs
&& this_privileges
!= privileges
)
266 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED
),
267 errmsg("not all privileges could be revoked for \"%s\"", objname
)));
270 return this_privileges
;
274 * Called to execute the utility commands GRANT and REVOKE
277 ExecuteGrantStmt(GrantStmt
*stmt
)
281 const char *errormsg
;
282 AclMode all_privileges
;
285 * Turn the regular GrantStmt into the InternalGrant form.
287 istmt
.is_grant
= stmt
->is_grant
;
288 istmt
.objtype
= stmt
->objtype
;
289 istmt
.objects
= objectNamesToOids(stmt
->objtype
, stmt
->objects
);
290 /* all_privs to be filled below */
291 /* privileges to be filled below */
292 istmt
.col_privs
= NIL
; /* may get filled below */
293 istmt
.grantees
= NIL
; /* filled below */
294 istmt
.grant_option
= stmt
->grant_option
;
295 istmt
.behavior
= stmt
->behavior
;
298 * Convert the PrivGrantee list into an Oid list. Note that at this point
299 * we insert an ACL_ID_PUBLIC into the list if an empty role name is
300 * detected (which is what the grammar uses if PUBLIC is found), so
301 * downstream there shouldn't be any additional work needed to support
304 foreach(cell
, stmt
->grantees
)
306 PrivGrantee
*grantee
= (PrivGrantee
*) lfirst(cell
);
308 if (grantee
->rolname
== NULL
)
309 istmt
.grantees
= lappend_oid(istmt
.grantees
, ACL_ID_PUBLIC
);
312 lappend_oid(istmt
.grantees
,
313 get_roleid_checked(grantee
->rolname
));
317 * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
318 * bitmask. Note: objtype can't be ACL_OBJECT_COLUMN.
320 switch (stmt
->objtype
)
323 * Because this might be a sequence, we test both relation and
324 * sequence bits, and later do a more limited test when we know
327 case ACL_OBJECT_RELATION
:
328 all_privileges
= ACL_ALL_RIGHTS_RELATION
| ACL_ALL_RIGHTS_SEQUENCE
;
329 errormsg
= gettext_noop("invalid privilege type %s for relation");
331 case ACL_OBJECT_SEQUENCE
:
332 all_privileges
= ACL_ALL_RIGHTS_SEQUENCE
;
333 errormsg
= gettext_noop("invalid privilege type %s for sequence");
335 case ACL_OBJECT_DATABASE
:
336 all_privileges
= ACL_ALL_RIGHTS_DATABASE
;
337 errormsg
= gettext_noop("invalid privilege type %s for database");
339 case ACL_OBJECT_FUNCTION
:
340 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
341 errormsg
= gettext_noop("invalid privilege type %s for function");
343 case ACL_OBJECT_LANGUAGE
:
344 all_privileges
= ACL_ALL_RIGHTS_LANGUAGE
;
345 errormsg
= gettext_noop("invalid privilege type %s for language");
347 case ACL_OBJECT_NAMESPACE
:
348 all_privileges
= ACL_ALL_RIGHTS_NAMESPACE
;
349 errormsg
= gettext_noop("invalid privilege type %s for schema");
351 case ACL_OBJECT_TABLESPACE
:
352 all_privileges
= ACL_ALL_RIGHTS_TABLESPACE
;
353 errormsg
= gettext_noop("invalid privilege type %s for tablespace");
356 all_privileges
= ACL_ALL_RIGHTS_FDW
;
357 errormsg
= gettext_noop("invalid privilege type %s for foreign-data wrapper");
359 case ACL_OBJECT_FOREIGN_SERVER
:
360 all_privileges
= ACL_ALL_RIGHTS_FOREIGN_SERVER
;
361 errormsg
= gettext_noop("invalid privilege type %s for foreign server");
364 /* keep compiler quiet */
365 all_privileges
= ACL_NO_RIGHTS
;
367 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
368 (int) stmt
->objtype
);
371 if (stmt
->privileges
== NIL
)
373 istmt
.all_privs
= true;
376 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
377 * depending on the object type
379 istmt
.privileges
= ACL_NO_RIGHTS
;
383 istmt
.all_privs
= false;
384 istmt
.privileges
= ACL_NO_RIGHTS
;
386 foreach(cell
, stmt
->privileges
)
388 AccessPriv
*privnode
= (AccessPriv
*) lfirst(cell
);
392 * If it's a column-level specification, we just set it aside in
393 * col_privs for the moment; but insist it's for a relation.
397 if (stmt
->objtype
!= ACL_OBJECT_RELATION
)
399 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
400 errmsg("column privileges are only valid for relations")));
401 istmt
.col_privs
= lappend(istmt
.col_privs
, privnode
);
405 if (privnode
->priv_name
== NULL
) /* parser mistake? */
406 elog(ERROR
, "AccessPriv node must specify privilege or columns");
407 priv
= string_to_privilege(privnode
->priv_name
);
409 if (priv
& ~((AclMode
) all_privileges
))
411 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
412 errmsg(errormsg
, privilege_to_string(priv
))));
414 istmt
.privileges
|= priv
;
418 ExecGrantStmt_oids(&istmt
);
424 * "Internal" entrypoint for granting and revoking privileges. This is
425 * exported for pg_shdepend.c to use in revoking privileges when dropping
429 ExecGrantStmt_oids(InternalGrant
*istmt
)
431 switch (istmt
->objtype
)
433 case ACL_OBJECT_RELATION
:
434 case ACL_OBJECT_SEQUENCE
:
435 ExecGrant_Relation(istmt
);
437 case ACL_OBJECT_DATABASE
:
438 ExecGrant_Database(istmt
);
441 ExecGrant_Fdw(istmt
);
443 case ACL_OBJECT_FOREIGN_SERVER
:
444 ExecGrant_ForeignServer(istmt
);
446 case ACL_OBJECT_FUNCTION
:
447 ExecGrant_Function(istmt
);
449 case ACL_OBJECT_LANGUAGE
:
450 ExecGrant_Language(istmt
);
452 case ACL_OBJECT_NAMESPACE
:
453 ExecGrant_Namespace(istmt
);
455 case ACL_OBJECT_TABLESPACE
:
456 ExecGrant_Tablespace(istmt
);
459 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
460 (int) istmt
->objtype
);
467 * Turn a list of object names of a given type into an Oid list.
470 objectNamesToOids(GrantObjectType objtype
, List
*objnames
)
475 Assert(objnames
!= NIL
);
479 case ACL_OBJECT_RELATION
:
480 case ACL_OBJECT_SEQUENCE
:
481 foreach(cell
, objnames
)
483 RangeVar
*relvar
= (RangeVar
*) lfirst(cell
);
486 relOid
= RangeVarGetRelid(relvar
, false);
487 objects
= lappend_oid(objects
, relOid
);
490 case ACL_OBJECT_DATABASE
:
491 foreach(cell
, objnames
)
493 char *dbname
= strVal(lfirst(cell
));
496 dbid
= get_database_oid(dbname
);
497 if (!OidIsValid(dbid
))
499 (errcode(ERRCODE_UNDEFINED_DATABASE
),
500 errmsg("database \"%s\" does not exist",
502 objects
= lappend_oid(objects
, dbid
);
505 case ACL_OBJECT_FUNCTION
:
506 foreach(cell
, objnames
)
508 FuncWithArgs
*func
= (FuncWithArgs
*) lfirst(cell
);
511 funcid
= LookupFuncNameTypeNames(func
->funcname
,
512 func
->funcargs
, false);
513 objects
= lappend_oid(objects
, funcid
);
516 case ACL_OBJECT_LANGUAGE
:
517 foreach(cell
, objnames
)
519 char *langname
= strVal(lfirst(cell
));
522 tuple
= SearchSysCache(LANGNAME
,
523 PointerGetDatum(langname
),
525 if (!HeapTupleIsValid(tuple
))
527 (errcode(ERRCODE_UNDEFINED_OBJECT
),
528 errmsg("language \"%s\" does not exist",
531 objects
= lappend_oid(objects
, HeapTupleGetOid(tuple
));
533 ReleaseSysCache(tuple
);
536 case ACL_OBJECT_NAMESPACE
:
537 foreach(cell
, objnames
)
539 char *nspname
= strVal(lfirst(cell
));
542 tuple
= SearchSysCache(NAMESPACENAME
,
543 CStringGetDatum(nspname
),
545 if (!HeapTupleIsValid(tuple
))
547 (errcode(ERRCODE_UNDEFINED_SCHEMA
),
548 errmsg("schema \"%s\" does not exist",
551 objects
= lappend_oid(objects
, HeapTupleGetOid(tuple
));
553 ReleaseSysCache(tuple
);
556 case ACL_OBJECT_TABLESPACE
:
557 foreach(cell
, objnames
)
559 char *spcname
= strVal(lfirst(cell
));
560 ScanKeyData entry
[1];
565 relation
= heap_open(TableSpaceRelationId
, AccessShareLock
);
567 ScanKeyInit(&entry
[0],
568 Anum_pg_tablespace_spcname
,
569 BTEqualStrategyNumber
, F_NAMEEQ
,
570 CStringGetDatum(spcname
));
572 scan
= heap_beginscan(relation
, SnapshotNow
, 1, entry
);
573 tuple
= heap_getnext(scan
, ForwardScanDirection
);
574 if (!HeapTupleIsValid(tuple
))
576 (errcode(ERRCODE_UNDEFINED_OBJECT
),
577 errmsg("tablespace \"%s\" does not exist", spcname
)));
579 objects
= lappend_oid(objects
, HeapTupleGetOid(tuple
));
583 heap_close(relation
, AccessShareLock
);
587 foreach(cell
, objnames
)
589 char *fdwname
= strVal(lfirst(cell
));
590 Oid fdwid
= GetForeignDataWrapperOidByName(fdwname
, false);
592 objects
= lappend_oid(objects
, fdwid
);
595 case ACL_OBJECT_FOREIGN_SERVER
:
596 foreach(cell
, objnames
)
598 char *srvname
= strVal(lfirst(cell
));
599 Oid srvid
= GetForeignServerOidByName(srvname
, false);
601 objects
= lappend_oid(objects
, srvid
);
605 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
613 * expand_col_privileges
615 * OR the specified privilege(s) into per-column array entries for each
616 * specified attribute. The per-column array is indexed starting at
617 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
620 expand_col_privileges(List
*colnames
, Oid table_oid
,
621 AclMode this_privileges
,
622 AclMode
*col_privileges
,
623 int num_col_privileges
)
627 foreach(cell
, colnames
)
629 char *colname
= strVal(lfirst(cell
));
632 attnum
= get_attnum(table_oid
, colname
);
633 if (attnum
== InvalidAttrNumber
)
635 (errcode(ERRCODE_UNDEFINED_COLUMN
),
636 errmsg("column \"%s\" of relation \"%s\" does not exist",
637 colname
, get_rel_name(table_oid
))));
638 attnum
-= FirstLowInvalidHeapAttributeNumber
;
639 if (attnum
<= 0 || attnum
>= num_col_privileges
)
640 elog(ERROR
, "column number out of range"); /* safety check */
641 col_privileges
[attnum
] |= this_privileges
;
646 * expand_all_col_privileges
648 * OR the specified privilege(s) into per-column array entries for each valid
649 * attribute of a relation. The per-column array is indexed starting at
650 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
653 expand_all_col_privileges(Oid table_oid
, Form_pg_class classForm
,
654 AclMode this_privileges
,
655 AclMode
*col_privileges
,
656 int num_col_privileges
)
660 Assert(classForm
->relnatts
- FirstLowInvalidHeapAttributeNumber
< num_col_privileges
);
661 for (curr_att
= FirstLowInvalidHeapAttributeNumber
+ 1;
662 curr_att
<= classForm
->relnatts
;
668 if (curr_att
== InvalidAttrNumber
)
671 /* Skip OID column if it doesn't exist */
672 if (curr_att
== ObjectIdAttributeNumber
&& !classForm
->relhasoids
)
675 /* Views don't have any system columns at all */
676 if (classForm
->relkind
== RELKIND_VIEW
&& curr_att
< 0)
679 attTuple
= SearchSysCache(ATTNUM
,
680 ObjectIdGetDatum(table_oid
),
681 Int16GetDatum(curr_att
),
683 if (!HeapTupleIsValid(attTuple
))
684 elog(ERROR
, "cache lookup failed for attribute %d of relation %u",
685 curr_att
, table_oid
);
687 isdropped
= ((Form_pg_attribute
) GETSTRUCT(attTuple
))->attisdropped
;
689 ReleaseSysCache(attTuple
);
691 /* ignore dropped columns */
695 col_privileges
[curr_att
- FirstLowInvalidHeapAttributeNumber
] |= this_privileges
;
700 * This processes attributes, but expects to be called from
701 * ExecGrant_Relation, not directly from ExecGrantStmt.
704 ExecGrant_Attribute(InternalGrant
*istmt
, Oid relOid
, const char *relname
,
705 AttrNumber attnum
, Oid ownerId
, AclMode col_privileges
,
706 Relation attRelation
, const Acl
*old_rel_acl
)
708 HeapTuple attr_tuple
;
709 Form_pg_attribute pg_attribute_tuple
;
716 AclMode avail_goptions
;
719 Datum values
[Natts_pg_attribute
];
720 bool nulls
[Natts_pg_attribute
];
721 bool replaces
[Natts_pg_attribute
];
727 attr_tuple
= SearchSysCache(ATTNUM
,
728 ObjectIdGetDatum(relOid
),
729 Int16GetDatum(attnum
),
731 if (!HeapTupleIsValid(attr_tuple
))
732 elog(ERROR
, "cache lookup failed for attribute %d of relation %u",
734 pg_attribute_tuple
= (Form_pg_attribute
) GETSTRUCT(attr_tuple
);
737 * Get working copy of existing ACL. If there's no ACL, substitute the
740 aclDatum
= SysCacheGetAttr(ATTNUM
, attr_tuple
, Anum_pg_attribute_attacl
,
743 old_acl
= acldefault(ACL_OBJECT_COLUMN
, ownerId
);
745 old_acl
= DatumGetAclPCopy(aclDatum
);
748 * In select_best_grantor we should consider existing table-level ACL bits
749 * as well as the per-column ACL. Build a new ACL that is their
750 * concatenation. (This is a bit cheap and dirty compared to merging them
751 * properly with no duplications, but it's all we need here.)
753 merged_acl
= aclconcat(old_rel_acl
, old_acl
);
755 /* Determine ID to do the grant as, and available grant options */
756 select_best_grantor(GetUserId(), col_privileges
,
758 &grantorId
, &avail_goptions
);
763 * Restrict the privileges to what we can actually grant, and emit the
764 * standards-mandated warning and error messages. Note: we don't track
765 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
766 * each column; we just approximate it by whether all the possible
767 * privileges are specified now. Since the all_privs flag only determines
768 * whether a warning is issued, this seems close enough.
771 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
772 (col_privileges
== ACL_ALL_RIGHTS_COLUMN
),
774 relOid
, grantorId
, ACL_KIND_COLUMN
,
776 NameStr(pg_attribute_tuple
->attname
));
781 * We need the members of both old and new ACLs so we can correct the
782 * shared dependency information.
784 noldmembers
= aclmembers(old_acl
, &oldmembers
);
786 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
788 istmt
->behavior
, istmt
->grantees
,
789 col_privileges
, grantorId
,
792 nnewmembers
= aclmembers(new_acl
, &newmembers
);
794 /* finished building new ACL value, now insert it */
795 MemSet(values
, 0, sizeof(values
));
796 MemSet(nulls
, false, sizeof(nulls
));
797 MemSet(replaces
, false, sizeof(replaces
));
800 * If the updated ACL is empty, we can set attacl to null, and maybe even
801 * avoid an update of the pg_attribute row. This is worth testing because
802 * we'll come through here multiple times for any relation-level REVOKE,
803 * even if there were never any column GRANTs. Note we are assuming that
804 * the "default" ACL state for columns is empty.
806 if (ACL_NUM(new_acl
) > 0)
808 values
[Anum_pg_attribute_attacl
- 1] = PointerGetDatum(new_acl
);
813 nulls
[Anum_pg_attribute_attacl
- 1] = true;
814 need_update
= !isNull
;
816 replaces
[Anum_pg_attribute_attacl
- 1] = true;
820 newtuple
= heap_modify_tuple(attr_tuple
, RelationGetDescr(attRelation
),
821 values
, nulls
, replaces
);
823 simple_heap_update(attRelation
, &newtuple
->t_self
, newtuple
);
825 /* keep the catalog indexes up to date */
826 CatalogUpdateIndexes(attRelation
, newtuple
);
828 /* Update the shared dependency ACL info */
829 updateAclDependencies(RelationRelationId
, relOid
, attnum
,
830 ownerId
, istmt
->is_grant
,
831 noldmembers
, oldmembers
,
832 nnewmembers
, newmembers
);
837 ReleaseSysCache(attr_tuple
);
841 * This processes both sequences and non-sequences.
844 ExecGrant_Relation(InternalGrant
*istmt
)
847 Relation attRelation
;
850 relation
= heap_open(RelationRelationId
, RowExclusiveLock
);
851 attRelation
= heap_open(AttributeRelationId
, RowExclusiveLock
);
853 foreach(cell
, istmt
->objects
)
855 Oid relOid
= lfirst_oid(cell
);
857 Form_pg_class pg_class_tuple
;
859 AclMode this_privileges
;
860 AclMode
*col_privileges
;
861 int num_col_privileges
;
862 bool have_col_privileges
;
867 ListCell
*cell_colprivs
;
869 tuple
= SearchSysCache(RELOID
,
870 ObjectIdGetDatum(relOid
),
872 if (!HeapTupleIsValid(tuple
))
873 elog(ERROR
, "cache lookup failed for relation %u", relOid
);
874 pg_class_tuple
= (Form_pg_class
) GETSTRUCT(tuple
);
876 /* Not sensible to grant on an index */
877 if (pg_class_tuple
->relkind
== RELKIND_INDEX
)
879 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
880 errmsg("\"%s\" is an index",
881 NameStr(pg_class_tuple
->relname
))));
883 /* Composite types aren't tables either */
884 if (pg_class_tuple
->relkind
== RELKIND_COMPOSITE_TYPE
)
886 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
887 errmsg("\"%s\" is a composite type",
888 NameStr(pg_class_tuple
->relname
))));
890 /* Used GRANT SEQUENCE on a non-sequence? */
891 if (istmt
->objtype
== ACL_OBJECT_SEQUENCE
&&
892 pg_class_tuple
->relkind
!= RELKIND_SEQUENCE
)
894 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
895 errmsg("\"%s\" is not a sequence",
896 NameStr(pg_class_tuple
->relname
))));
898 /* Adjust the default permissions based on whether it is a sequence */
899 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
901 if (pg_class_tuple
->relkind
== RELKIND_SEQUENCE
)
902 this_privileges
= ACL_ALL_RIGHTS_SEQUENCE
;
904 this_privileges
= ACL_ALL_RIGHTS_RELATION
;
907 this_privileges
= istmt
->privileges
;
910 * The GRANT TABLE syntax can be used for sequences and non-sequences,
911 * so we have to look at the relkind to determine the supported
912 * permissions. The OR of table and sequence permissions were already
915 if (istmt
->objtype
== ACL_OBJECT_RELATION
)
917 if (pg_class_tuple
->relkind
== RELKIND_SEQUENCE
)
920 * For backward compatibility, just throw a warning for
921 * invalid sequence permissions when using the non-sequence
924 if (this_privileges
& ~((AclMode
) ACL_ALL_RIGHTS_SEQUENCE
))
927 * Mention the object name because the user needs to know
928 * which operations succeeded. This is required because
929 * WARNING allows the command to continue.
932 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
933 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
934 NameStr(pg_class_tuple
->relname
))));
935 this_privileges
&= (AclMode
) ACL_ALL_RIGHTS_SEQUENCE
;
940 if (this_privileges
& ~((AclMode
) ACL_ALL_RIGHTS_RELATION
))
943 * USAGE is the only permission supported by sequences but
944 * not by non-sequences. Don't mention the object name
945 * because we didn't in the combined TABLE | SEQUENCE
949 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
950 errmsg("invalid privilege type USAGE for table")));
956 * Set up array in which we'll accumulate any column privilege bits
957 * that need modification. The array is indexed such that entry [0]
958 * corresponds to FirstLowInvalidHeapAttributeNumber.
960 num_col_privileges
= pg_class_tuple
->relnatts
- FirstLowInvalidHeapAttributeNumber
+ 1;
961 col_privileges
= (AclMode
*) palloc0(num_col_privileges
* sizeof(AclMode
));
962 have_col_privileges
= false;
965 * If we are revoking relation privileges that are also column
966 * privileges, we must implicitly revoke them from each column too,
967 * per SQL spec. (We don't need to implicitly add column privileges
968 * during GRANT because the permissions-checking code always checks
969 * both relation and per-column privileges.)
971 if (!istmt
->is_grant
&&
972 (this_privileges
& ACL_ALL_RIGHTS_COLUMN
) != 0)
974 expand_all_col_privileges(relOid
, pg_class_tuple
,
975 this_privileges
& ACL_ALL_RIGHTS_COLUMN
,
978 have_col_privileges
= true;
982 * Get owner ID and working copy of existing ACL. If there's no ACL,
983 * substitute the proper default.
985 ownerId
= pg_class_tuple
->relowner
;
986 aclDatum
= SysCacheGetAttr(RELOID
, tuple
, Anum_pg_class_relacl
,
989 old_acl
= acldefault(pg_class_tuple
->relkind
== RELKIND_SEQUENCE
?
990 ACL_OBJECT_SEQUENCE
: ACL_OBJECT_RELATION
,
993 old_acl
= DatumGetAclPCopy(aclDatum
);
995 /* Need an extra copy of original rel ACL for column handling */
996 old_rel_acl
= aclcopy(old_acl
);
999 * Handle relation-level privileges, if any were specified
1001 if (this_privileges
!= ACL_NO_RIGHTS
)
1003 AclMode avail_goptions
;
1007 Datum values
[Natts_pg_class
];
1008 bool nulls
[Natts_pg_class
];
1009 bool replaces
[Natts_pg_class
];
1015 /* Determine ID to do the grant as, and available grant options */
1016 select_best_grantor(GetUserId(), this_privileges
,
1018 &grantorId
, &avail_goptions
);
1021 * Restrict the privileges to what we can actually grant, and emit
1022 * the standards-mandated warning and error messages.
1025 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1026 istmt
->all_privs
, this_privileges
,
1028 pg_class_tuple
->relkind
== RELKIND_SEQUENCE
1029 ? ACL_KIND_SEQUENCE
: ACL_KIND_CLASS
,
1030 NameStr(pg_class_tuple
->relname
),
1036 * We need the members of both old and new ACLs so we can correct
1037 * the shared dependency information.
1039 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1041 new_acl
= merge_acl_with_grant(old_acl
,
1043 istmt
->grant_option
,
1050 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1052 /* finished building new ACL value, now insert it */
1053 MemSet(values
, 0, sizeof(values
));
1054 MemSet(nulls
, false, sizeof(nulls
));
1055 MemSet(replaces
, false, sizeof(replaces
));
1057 replaces
[Anum_pg_class_relacl
- 1] = true;
1058 values
[Anum_pg_class_relacl
- 1] = PointerGetDatum(new_acl
);
1060 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
),
1061 values
, nulls
, replaces
);
1063 simple_heap_update(relation
, &newtuple
->t_self
, newtuple
);
1065 /* keep the catalog indexes up to date */
1066 CatalogUpdateIndexes(relation
, newtuple
);
1068 /* Update the shared dependency ACL info */
1069 updateAclDependencies(RelationRelationId
, relOid
, 0,
1070 ownerId
, istmt
->is_grant
,
1071 noldmembers
, oldmembers
,
1072 nnewmembers
, newmembers
);
1078 * Handle column-level privileges, if any were specified or implied.
1079 * We first expand the user-specified column privileges into the
1080 * array, and then iterate over all nonempty array entries.
1082 foreach(cell_colprivs
, istmt
->col_privs
)
1084 AccessPriv
*col_privs
= (AccessPriv
*) lfirst(cell_colprivs
);
1086 if (col_privs
->priv_name
== NULL
)
1087 this_privileges
= ACL_ALL_RIGHTS_COLUMN
;
1089 this_privileges
= string_to_privilege(col_privs
->priv_name
);
1091 if (this_privileges
& ~((AclMode
) ACL_ALL_RIGHTS_COLUMN
))
1093 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1094 errmsg("invalid privilege type %s for column",
1095 privilege_to_string(this_privileges
))));
1097 if (pg_class_tuple
->relkind
== RELKIND_SEQUENCE
&&
1098 this_privileges
& ~((AclMode
) ACL_SELECT
))
1101 * The only column privilege allowed on sequences is SELECT.
1102 * This is a warning not error because we do it that way for
1103 * relation-level privileges.
1106 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1107 errmsg("sequence \"%s\" only supports SELECT column privileges",
1108 NameStr(pg_class_tuple
->relname
))));
1110 this_privileges
&= (AclMode
) ACL_SELECT
;
1113 expand_col_privileges(col_privs
->cols
, relOid
,
1116 num_col_privileges
);
1117 have_col_privileges
= true;
1120 if (have_col_privileges
)
1124 for (i
= 0; i
< num_col_privileges
; i
++)
1126 if (col_privileges
[i
] == ACL_NO_RIGHTS
)
1128 ExecGrant_Attribute(istmt
,
1130 NameStr(pg_class_tuple
->relname
),
1131 i
+ FirstLowInvalidHeapAttributeNumber
,
1140 pfree(col_privileges
);
1142 ReleaseSysCache(tuple
);
1144 /* prevent error when processing duplicate objects */
1145 CommandCounterIncrement();
1148 heap_close(attRelation
, RowExclusiveLock
);
1149 heap_close(relation
, RowExclusiveLock
);
1153 ExecGrant_Database(InternalGrant
*istmt
)
1158 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
1159 istmt
->privileges
= ACL_ALL_RIGHTS_DATABASE
;
1161 relation
= heap_open(DatabaseRelationId
, RowExclusiveLock
);
1163 foreach(cell
, istmt
->objects
)
1165 Oid datId
= lfirst_oid(cell
);
1166 Form_pg_database pg_database_tuple
;
1169 AclMode avail_goptions
;
1170 AclMode this_privileges
;
1176 Datum values
[Natts_pg_database
];
1177 bool nulls
[Natts_pg_database
];
1178 bool replaces
[Natts_pg_database
];
1185 tuple
= SearchSysCache(DATABASEOID
,
1186 ObjectIdGetDatum(datId
),
1188 if (!HeapTupleIsValid(tuple
))
1189 elog(ERROR
, "cache lookup failed for database %u", datId
);
1191 pg_database_tuple
= (Form_pg_database
) GETSTRUCT(tuple
);
1194 * Get owner ID and working copy of existing ACL. If there's no ACL,
1195 * substitute the proper default.
1197 ownerId
= pg_database_tuple
->datdba
;
1198 aclDatum
= heap_getattr(tuple
, Anum_pg_database_datacl
,
1199 RelationGetDescr(relation
), &isNull
);
1201 old_acl
= acldefault(ACL_OBJECT_DATABASE
, ownerId
);
1203 old_acl
= DatumGetAclPCopy(aclDatum
);
1205 /* Determine ID to do the grant as, and available grant options */
1206 select_best_grantor(GetUserId(), istmt
->privileges
,
1208 &grantorId
, &avail_goptions
);
1211 * Restrict the privileges to what we can actually grant, and emit the
1212 * standards-mandated warning and error messages.
1215 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1216 istmt
->all_privs
, istmt
->privileges
,
1217 datId
, grantorId
, ACL_KIND_DATABASE
,
1218 NameStr(pg_database_tuple
->datname
),
1224 * We need the members of both old and new ACLs so we can correct the
1225 * shared dependency information.
1227 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1229 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
1230 istmt
->grant_option
, istmt
->behavior
,
1231 istmt
->grantees
, this_privileges
,
1232 grantorId
, ownerId
);
1234 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1236 /* finished building new ACL value, now insert it */
1237 MemSet(values
, 0, sizeof(values
));
1238 MemSet(nulls
, false, sizeof(nulls
));
1239 MemSet(replaces
, false, sizeof(replaces
));
1241 replaces
[Anum_pg_database_datacl
- 1] = true;
1242 values
[Anum_pg_database_datacl
- 1] = PointerGetDatum(new_acl
);
1244 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
1247 simple_heap_update(relation
, &newtuple
->t_self
, newtuple
);
1249 /* keep the catalog indexes up to date */
1250 CatalogUpdateIndexes(relation
, newtuple
);
1252 /* Update the shared dependency ACL info */
1253 updateAclDependencies(DatabaseRelationId
, HeapTupleGetOid(tuple
), 0,
1254 ownerId
, istmt
->is_grant
,
1255 noldmembers
, oldmembers
,
1256 nnewmembers
, newmembers
);
1258 ReleaseSysCache(tuple
);
1262 /* prevent error when processing duplicate objects */
1263 CommandCounterIncrement();
1266 heap_close(relation
, RowExclusiveLock
);
1270 ExecGrant_Fdw(InternalGrant
*istmt
)
1275 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
1276 istmt
->privileges
= ACL_ALL_RIGHTS_FDW
;
1278 relation
= heap_open(ForeignDataWrapperRelationId
, RowExclusiveLock
);
1280 foreach(cell
, istmt
->objects
)
1282 Oid fdwid
= lfirst_oid(cell
);
1283 Form_pg_foreign_data_wrapper pg_fdw_tuple
;
1286 AclMode avail_goptions
;
1287 AclMode this_privileges
;
1294 Datum values
[Natts_pg_foreign_data_wrapper
];
1295 bool nulls
[Natts_pg_foreign_data_wrapper
];
1296 bool replaces
[Natts_pg_foreign_data_wrapper
];
1302 tuple
= SearchSysCache(FOREIGNDATAWRAPPEROID
,
1303 ObjectIdGetDatum(fdwid
),
1305 if (!HeapTupleIsValid(tuple
))
1306 elog(ERROR
, "cache lookup failed for foreign-data wrapper %u", fdwid
);
1308 pg_fdw_tuple
= (Form_pg_foreign_data_wrapper
) GETSTRUCT(tuple
);
1311 * Get owner ID and working copy of existing ACL. If there's no ACL,
1312 * substitute the proper default.
1314 ownerId
= pg_fdw_tuple
->fdwowner
;
1315 aclDatum
= SysCacheGetAttr(FOREIGNDATAWRAPPEROID
, tuple
,
1316 Anum_pg_foreign_data_wrapper_fdwacl
,
1319 old_acl
= acldefault(ACL_OBJECT_FDW
, ownerId
);
1321 old_acl
= DatumGetAclPCopy(aclDatum
);
1323 /* Determine ID to do the grant as, and available grant options */
1324 select_best_grantor(GetUserId(), istmt
->privileges
,
1326 &grantorId
, &avail_goptions
);
1329 * Restrict the privileges to what we can actually grant, and emit the
1330 * standards-mandated warning and error messages.
1333 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1334 istmt
->all_privs
, istmt
->privileges
,
1335 fdwid
, grantorId
, ACL_KIND_FDW
,
1336 NameStr(pg_fdw_tuple
->fdwname
),
1342 * We need the members of both old and new ACLs so we can correct the
1343 * shared dependency information.
1345 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1347 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
1348 istmt
->grant_option
, istmt
->behavior
,
1349 istmt
->grantees
, this_privileges
,
1350 grantorId
, ownerId
);
1352 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1354 /* finished building new ACL value, now insert it */
1355 MemSet(values
, 0, sizeof(values
));
1356 MemSet(nulls
, false, sizeof(nulls
));
1357 MemSet(replaces
, false, sizeof(replaces
));
1359 replaces
[Anum_pg_foreign_data_wrapper_fdwacl
- 1] = true;
1360 values
[Anum_pg_foreign_data_wrapper_fdwacl
- 1] = PointerGetDatum(new_acl
);
1362 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
1365 simple_heap_update(relation
, &newtuple
->t_self
, newtuple
);
1367 /* keep the catalog indexes up to date */
1368 CatalogUpdateIndexes(relation
, newtuple
);
1370 /* Update the shared dependency ACL info */
1371 updateAclDependencies(ForeignDataWrapperRelationId
,
1372 HeapTupleGetOid(tuple
), 0,
1373 ownerId
, istmt
->is_grant
,
1374 noldmembers
, oldmembers
,
1375 nnewmembers
, newmembers
);
1377 ReleaseSysCache(tuple
);
1381 /* prevent error when processing duplicate objects */
1382 CommandCounterIncrement();
1385 heap_close(relation
, RowExclusiveLock
);
1389 ExecGrant_ForeignServer(InternalGrant
*istmt
)
1394 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
1395 istmt
->privileges
= ACL_ALL_RIGHTS_FOREIGN_SERVER
;
1397 relation
= heap_open(ForeignServerRelationId
, RowExclusiveLock
);
1399 foreach(cell
, istmt
->objects
)
1401 Oid srvid
= lfirst_oid(cell
);
1402 Form_pg_foreign_server pg_server_tuple
;
1405 AclMode avail_goptions
;
1406 AclMode this_privileges
;
1413 Datum values
[Natts_pg_foreign_server
];
1414 bool nulls
[Natts_pg_foreign_server
];
1415 bool replaces
[Natts_pg_foreign_server
];
1421 tuple
= SearchSysCache(FOREIGNSERVEROID
,
1422 ObjectIdGetDatum(srvid
),
1424 if (!HeapTupleIsValid(tuple
))
1425 elog(ERROR
, "cache lookup failed for foreign server %u", srvid
);
1427 pg_server_tuple
= (Form_pg_foreign_server
) GETSTRUCT(tuple
);
1430 * Get owner ID and working copy of existing ACL. If there's no ACL,
1431 * substitute the proper default.
1433 ownerId
= pg_server_tuple
->srvowner
;
1434 aclDatum
= SysCacheGetAttr(FOREIGNSERVEROID
, tuple
,
1435 Anum_pg_foreign_server_srvacl
,
1438 old_acl
= acldefault(ACL_OBJECT_FOREIGN_SERVER
, ownerId
);
1440 old_acl
= DatumGetAclPCopy(aclDatum
);
1442 /* Determine ID to do the grant as, and available grant options */
1443 select_best_grantor(GetUserId(), istmt
->privileges
,
1445 &grantorId
, &avail_goptions
);
1448 * Restrict the privileges to what we can actually grant, and emit the
1449 * standards-mandated warning and error messages.
1452 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1453 istmt
->all_privs
, istmt
->privileges
,
1454 srvid
, grantorId
, ACL_KIND_FOREIGN_SERVER
,
1455 NameStr(pg_server_tuple
->srvname
),
1461 * We need the members of both old and new ACLs so we can correct the
1462 * shared dependency information.
1464 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1466 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
1467 istmt
->grant_option
, istmt
->behavior
,
1468 istmt
->grantees
, this_privileges
,
1469 grantorId
, ownerId
);
1471 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1473 /* finished building new ACL value, now insert it */
1474 MemSet(values
, 0, sizeof(values
));
1475 MemSet(nulls
, false, sizeof(nulls
));
1476 MemSet(replaces
, false, sizeof(replaces
));
1478 replaces
[Anum_pg_foreign_server_srvacl
- 1] = true;
1479 values
[Anum_pg_foreign_server_srvacl
- 1] = PointerGetDatum(new_acl
);
1481 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
1484 simple_heap_update(relation
, &newtuple
->t_self
, newtuple
);
1486 /* keep the catalog indexes up to date */
1487 CatalogUpdateIndexes(relation
, newtuple
);
1489 /* Update the shared dependency ACL info */
1490 updateAclDependencies(ForeignServerRelationId
,
1491 HeapTupleGetOid(tuple
), 0,
1492 ownerId
, istmt
->is_grant
,
1493 noldmembers
, oldmembers
,
1494 nnewmembers
, newmembers
);
1496 ReleaseSysCache(tuple
);
1500 /* prevent error when processing duplicate objects */
1501 CommandCounterIncrement();
1504 heap_close(relation
, RowExclusiveLock
);
1508 ExecGrant_Function(InternalGrant
*istmt
)
1513 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
1514 istmt
->privileges
= ACL_ALL_RIGHTS_FUNCTION
;
1516 relation
= heap_open(ProcedureRelationId
, RowExclusiveLock
);
1518 foreach(cell
, istmt
->objects
)
1520 Oid funcId
= lfirst_oid(cell
);
1521 Form_pg_proc pg_proc_tuple
;
1524 AclMode avail_goptions
;
1525 AclMode this_privileges
;
1532 Datum values
[Natts_pg_proc
];
1533 bool nulls
[Natts_pg_proc
];
1534 bool replaces
[Natts_pg_proc
];
1540 tuple
= SearchSysCache(PROCOID
,
1541 ObjectIdGetDatum(funcId
),
1543 if (!HeapTupleIsValid(tuple
))
1544 elog(ERROR
, "cache lookup failed for function %u", funcId
);
1546 pg_proc_tuple
= (Form_pg_proc
) GETSTRUCT(tuple
);
1549 * Get owner ID and working copy of existing ACL. If there's no ACL,
1550 * substitute the proper default.
1552 ownerId
= pg_proc_tuple
->proowner
;
1553 aclDatum
= SysCacheGetAttr(PROCOID
, tuple
, Anum_pg_proc_proacl
,
1556 old_acl
= acldefault(ACL_OBJECT_FUNCTION
, ownerId
);
1558 old_acl
= DatumGetAclPCopy(aclDatum
);
1560 /* Determine ID to do the grant as, and available grant options */
1561 select_best_grantor(GetUserId(), istmt
->privileges
,
1563 &grantorId
, &avail_goptions
);
1566 * Restrict the privileges to what we can actually grant, and emit the
1567 * standards-mandated warning and error messages.
1570 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1571 istmt
->all_privs
, istmt
->privileges
,
1572 funcId
, grantorId
, ACL_KIND_PROC
,
1573 NameStr(pg_proc_tuple
->proname
),
1579 * We need the members of both old and new ACLs so we can correct the
1580 * shared dependency information.
1582 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1584 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
1585 istmt
->grant_option
, istmt
->behavior
,
1586 istmt
->grantees
, this_privileges
,
1587 grantorId
, ownerId
);
1589 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1591 /* finished building new ACL value, now insert it */
1592 MemSet(values
, 0, sizeof(values
));
1593 MemSet(nulls
, false, sizeof(nulls
));
1594 MemSet(replaces
, false, sizeof(replaces
));
1596 replaces
[Anum_pg_proc_proacl
- 1] = true;
1597 values
[Anum_pg_proc_proacl
- 1] = PointerGetDatum(new_acl
);
1599 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
1602 simple_heap_update(relation
, &newtuple
->t_self
, newtuple
);
1604 /* keep the catalog indexes up to date */
1605 CatalogUpdateIndexes(relation
, newtuple
);
1607 /* Update the shared dependency ACL info */
1608 updateAclDependencies(ProcedureRelationId
, funcId
, 0,
1609 ownerId
, istmt
->is_grant
,
1610 noldmembers
, oldmembers
,
1611 nnewmembers
, newmembers
);
1613 ReleaseSysCache(tuple
);
1617 /* prevent error when processing duplicate objects */
1618 CommandCounterIncrement();
1621 heap_close(relation
, RowExclusiveLock
);
1625 ExecGrant_Language(InternalGrant
*istmt
)
1630 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
1631 istmt
->privileges
= ACL_ALL_RIGHTS_LANGUAGE
;
1633 relation
= heap_open(LanguageRelationId
, RowExclusiveLock
);
1635 foreach(cell
, istmt
->objects
)
1637 Oid langId
= lfirst_oid(cell
);
1638 Form_pg_language pg_language_tuple
;
1641 AclMode avail_goptions
;
1642 AclMode this_privileges
;
1649 Datum values
[Natts_pg_language
];
1650 bool nulls
[Natts_pg_language
];
1651 bool replaces
[Natts_pg_language
];
1657 tuple
= SearchSysCache(LANGOID
,
1658 ObjectIdGetDatum(langId
),
1660 if (!HeapTupleIsValid(tuple
))
1661 elog(ERROR
, "cache lookup failed for language %u", langId
);
1663 pg_language_tuple
= (Form_pg_language
) GETSTRUCT(tuple
);
1665 if (!pg_language_tuple
->lanpltrusted
)
1667 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1668 errmsg("language \"%s\" is not trusted",
1669 NameStr(pg_language_tuple
->lanname
)),
1670 errhint("Only superusers can use untrusted languages.")));
1673 * Get owner ID and working copy of existing ACL. If there's no ACL,
1674 * substitute the proper default.
1676 ownerId
= pg_language_tuple
->lanowner
;
1677 aclDatum
= SysCacheGetAttr(LANGNAME
, tuple
, Anum_pg_language_lanacl
,
1680 old_acl
= acldefault(ACL_OBJECT_LANGUAGE
, ownerId
);
1682 old_acl
= DatumGetAclPCopy(aclDatum
);
1684 /* Determine ID to do the grant as, and available grant options */
1685 select_best_grantor(GetUserId(), istmt
->privileges
,
1687 &grantorId
, &avail_goptions
);
1690 * Restrict the privileges to what we can actually grant, and emit the
1691 * standards-mandated warning and error messages.
1694 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1695 istmt
->all_privs
, istmt
->privileges
,
1696 langId
, grantorId
, ACL_KIND_LANGUAGE
,
1697 NameStr(pg_language_tuple
->lanname
),
1703 * We need the members of both old and new ACLs so we can correct the
1704 * shared dependency information.
1706 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1708 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
1709 istmt
->grant_option
, istmt
->behavior
,
1710 istmt
->grantees
, this_privileges
,
1711 grantorId
, ownerId
);
1713 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1715 /* finished building new ACL value, now insert it */
1716 MemSet(values
, 0, sizeof(values
));
1717 MemSet(nulls
, false, sizeof(nulls
));
1718 MemSet(replaces
, false, sizeof(replaces
));
1720 replaces
[Anum_pg_language_lanacl
- 1] = true;
1721 values
[Anum_pg_language_lanacl
- 1] = PointerGetDatum(new_acl
);
1723 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
1726 simple_heap_update(relation
, &newtuple
->t_self
, newtuple
);
1728 /* keep the catalog indexes up to date */
1729 CatalogUpdateIndexes(relation
, newtuple
);
1731 /* Update the shared dependency ACL info */
1732 updateAclDependencies(LanguageRelationId
, HeapTupleGetOid(tuple
), 0,
1733 ownerId
, istmt
->is_grant
,
1734 noldmembers
, oldmembers
,
1735 nnewmembers
, newmembers
);
1737 ReleaseSysCache(tuple
);
1741 /* prevent error when processing duplicate objects */
1742 CommandCounterIncrement();
1745 heap_close(relation
, RowExclusiveLock
);
1749 ExecGrant_Namespace(InternalGrant
*istmt
)
1754 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
1755 istmt
->privileges
= ACL_ALL_RIGHTS_NAMESPACE
;
1757 relation
= heap_open(NamespaceRelationId
, RowExclusiveLock
);
1759 foreach(cell
, istmt
->objects
)
1761 Oid nspid
= lfirst_oid(cell
);
1762 Form_pg_namespace pg_namespace_tuple
;
1765 AclMode avail_goptions
;
1766 AclMode this_privileges
;
1773 Datum values
[Natts_pg_namespace
];
1774 bool nulls
[Natts_pg_namespace
];
1775 bool replaces
[Natts_pg_namespace
];
1781 tuple
= SearchSysCache(NAMESPACEOID
,
1782 ObjectIdGetDatum(nspid
),
1784 if (!HeapTupleIsValid(tuple
))
1785 elog(ERROR
, "cache lookup failed for namespace %u", nspid
);
1787 pg_namespace_tuple
= (Form_pg_namespace
) GETSTRUCT(tuple
);
1790 * Get owner ID and working copy of existing ACL. If there's no ACL,
1791 * substitute the proper default.
1793 ownerId
= pg_namespace_tuple
->nspowner
;
1794 aclDatum
= SysCacheGetAttr(NAMESPACENAME
, tuple
,
1795 Anum_pg_namespace_nspacl
,
1798 old_acl
= acldefault(ACL_OBJECT_NAMESPACE
, ownerId
);
1800 old_acl
= DatumGetAclPCopy(aclDatum
);
1802 /* Determine ID to do the grant as, and available grant options */
1803 select_best_grantor(GetUserId(), istmt
->privileges
,
1805 &grantorId
, &avail_goptions
);
1808 * Restrict the privileges to what we can actually grant, and emit the
1809 * standards-mandated warning and error messages.
1812 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1813 istmt
->all_privs
, istmt
->privileges
,
1814 nspid
, grantorId
, ACL_KIND_NAMESPACE
,
1815 NameStr(pg_namespace_tuple
->nspname
),
1821 * We need the members of both old and new ACLs so we can correct the
1822 * shared dependency information.
1824 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1826 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
1827 istmt
->grant_option
, istmt
->behavior
,
1828 istmt
->grantees
, this_privileges
,
1829 grantorId
, ownerId
);
1831 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1833 /* finished building new ACL value, now insert it */
1834 MemSet(values
, 0, sizeof(values
));
1835 MemSet(nulls
, false, sizeof(nulls
));
1836 MemSet(replaces
, false, sizeof(replaces
));
1838 replaces
[Anum_pg_namespace_nspacl
- 1] = true;
1839 values
[Anum_pg_namespace_nspacl
- 1] = PointerGetDatum(new_acl
);
1841 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
1844 simple_heap_update(relation
, &newtuple
->t_self
, newtuple
);
1846 /* keep the catalog indexes up to date */
1847 CatalogUpdateIndexes(relation
, newtuple
);
1849 /* Update the shared dependency ACL info */
1850 updateAclDependencies(NamespaceRelationId
, HeapTupleGetOid(tuple
), 0,
1851 ownerId
, istmt
->is_grant
,
1852 noldmembers
, oldmembers
,
1853 nnewmembers
, newmembers
);
1855 ReleaseSysCache(tuple
);
1859 /* prevent error when processing duplicate objects */
1860 CommandCounterIncrement();
1863 heap_close(relation
, RowExclusiveLock
);
1867 ExecGrant_Tablespace(InternalGrant
*istmt
)
1872 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
1873 istmt
->privileges
= ACL_ALL_RIGHTS_TABLESPACE
;
1875 relation
= heap_open(TableSpaceRelationId
, RowExclusiveLock
);
1877 foreach(cell
, istmt
->objects
)
1879 Oid tblId
= lfirst_oid(cell
);
1880 Form_pg_tablespace pg_tablespace_tuple
;
1883 AclMode avail_goptions
;
1884 AclMode this_privileges
;
1890 Datum values
[Natts_pg_tablespace
];
1891 bool nulls
[Natts_pg_tablespace
];
1892 bool replaces
[Natts_pg_tablespace
];
1897 ScanKeyData entry
[1];
1901 /* There's no syscache for pg_tablespace, so must look the hard way */
1902 ScanKeyInit(&entry
[0],
1903 ObjectIdAttributeNumber
,
1904 BTEqualStrategyNumber
, F_OIDEQ
,
1905 ObjectIdGetDatum(tblId
));
1906 scan
= systable_beginscan(relation
, TablespaceOidIndexId
, true,
1907 SnapshotNow
, 1, entry
);
1908 tuple
= systable_getnext(scan
);
1909 if (!HeapTupleIsValid(tuple
))
1910 elog(ERROR
, "cache lookup failed for tablespace %u", tblId
);
1912 pg_tablespace_tuple
= (Form_pg_tablespace
) GETSTRUCT(tuple
);
1915 * Get owner ID and working copy of existing ACL. If there's no ACL,
1916 * substitute the proper default.
1918 ownerId
= pg_tablespace_tuple
->spcowner
;
1919 aclDatum
= heap_getattr(tuple
, Anum_pg_tablespace_spcacl
,
1920 RelationGetDescr(relation
), &isNull
);
1922 old_acl
= acldefault(ACL_OBJECT_TABLESPACE
, ownerId
);
1924 old_acl
= DatumGetAclPCopy(aclDatum
);
1926 /* Determine ID to do the grant as, and available grant options */
1927 select_best_grantor(GetUserId(), istmt
->privileges
,
1929 &grantorId
, &avail_goptions
);
1932 * Restrict the privileges to what we can actually grant, and emit the
1933 * standards-mandated warning and error messages.
1936 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1937 istmt
->all_privs
, istmt
->privileges
,
1938 tblId
, grantorId
, ACL_KIND_TABLESPACE
,
1939 NameStr(pg_tablespace_tuple
->spcname
),
1945 * We need the members of both old and new ACLs so we can correct the
1946 * shared dependency information.
1948 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1950 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
1951 istmt
->grant_option
, istmt
->behavior
,
1952 istmt
->grantees
, this_privileges
,
1953 grantorId
, ownerId
);
1955 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1957 /* finished building new ACL value, now insert it */
1958 MemSet(values
, 0, sizeof(values
));
1959 MemSet(nulls
, false, sizeof(nulls
));
1960 MemSet(replaces
, false, sizeof(replaces
));
1962 replaces
[Anum_pg_tablespace_spcacl
- 1] = true;
1963 values
[Anum_pg_tablespace_spcacl
- 1] = PointerGetDatum(new_acl
);
1965 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
1968 simple_heap_update(relation
, &newtuple
->t_self
, newtuple
);
1970 /* keep the catalog indexes up to date */
1971 CatalogUpdateIndexes(relation
, newtuple
);
1973 /* Update the shared dependency ACL info */
1974 updateAclDependencies(TableSpaceRelationId
, tblId
, 0,
1975 ownerId
, istmt
->is_grant
,
1976 noldmembers
, oldmembers
,
1977 nnewmembers
, newmembers
);
1979 systable_endscan(scan
);
1983 /* prevent error when processing duplicate objects */
1984 CommandCounterIncrement();
1987 heap_close(relation
, RowExclusiveLock
);
1992 string_to_privilege(const char *privname
)
1994 if (strcmp(privname
, "insert") == 0)
1996 if (strcmp(privname
, "select") == 0)
1998 if (strcmp(privname
, "update") == 0)
2000 if (strcmp(privname
, "delete") == 0)
2002 if (strcmp(privname
, "truncate") == 0)
2003 return ACL_TRUNCATE
;
2004 if (strcmp(privname
, "references") == 0)
2005 return ACL_REFERENCES
;
2006 if (strcmp(privname
, "trigger") == 0)
2008 if (strcmp(privname
, "execute") == 0)
2010 if (strcmp(privname
, "usage") == 0)
2012 if (strcmp(privname
, "create") == 0)
2014 if (strcmp(privname
, "temporary") == 0)
2015 return ACL_CREATE_TEMP
;
2016 if (strcmp(privname
, "temp") == 0)
2017 return ACL_CREATE_TEMP
;
2018 if (strcmp(privname
, "connect") == 0)
2020 if (strcmp(privname
, "rule") == 0)
2021 return 0; /* ignore old RULE privileges */
2023 (errcode(ERRCODE_SYNTAX_ERROR
),
2024 errmsg("unrecognized privilege type \"%s\"", privname
)));
2025 return 0; /* appease compiler */
2029 privilege_to_string(AclMode privilege
)
2043 case ACL_REFERENCES
:
2044 return "REFERENCES";
2053 case ACL_CREATE_TEMP
:
2058 elog(ERROR
, "unrecognized privilege: %d", (int) privilege
);
2060 return NULL
; /* appease compiler */
2064 * Standardized reporting of aclcheck permissions failures.
2066 * Note: we do not double-quote the %s's below, because many callers
2067 * supply strings that might be already quoted.
2070 static const char *const no_priv_msg
[MAX_ACL_KIND
] =
2072 /* ACL_KIND_COLUMN */
2073 gettext_noop("permission denied for column %s"),
2074 /* ACL_KIND_CLASS */
2075 gettext_noop("permission denied for relation %s"),
2076 /* ACL_KIND_SEQUENCE */
2077 gettext_noop("permission denied for sequence %s"),
2078 /* ACL_KIND_DATABASE */
2079 gettext_noop("permission denied for database %s"),
2081 gettext_noop("permission denied for function %s"),
2083 gettext_noop("permission denied for operator %s"),
2085 gettext_noop("permission denied for type %s"),
2086 /* ACL_KIND_LANGUAGE */
2087 gettext_noop("permission denied for language %s"),
2088 /* ACL_KIND_NAMESPACE */
2089 gettext_noop("permission denied for schema %s"),
2090 /* ACL_KIND_OPCLASS */
2091 gettext_noop("permission denied for operator class %s"),
2092 /* ACL_KIND_OPFAMILY */
2093 gettext_noop("permission denied for operator family %s"),
2094 /* ACL_KIND_CONVERSION */
2095 gettext_noop("permission denied for conversion %s"),
2096 /* ACL_KIND_TABLESPACE */
2097 gettext_noop("permission denied for tablespace %s"),
2098 /* ACL_KIND_TSDICTIONARY */
2099 gettext_noop("permission denied for text search dictionary %s"),
2100 /* ACL_KIND_TSCONFIGURATION */
2101 gettext_noop("permission denied for text search configuration %s"),
2103 gettext_noop("permission denied for foreign-data wrapper %s"),
2104 /* ACL_KIND_FOREIGN_SERVER */
2105 gettext_noop("permission denied for foreign server %s")
2108 static const char *const not_owner_msg
[MAX_ACL_KIND
] =
2110 /* ACL_KIND_COLUMN */
2111 gettext_noop("must be owner of relation %s"),
2112 /* ACL_KIND_CLASS */
2113 gettext_noop("must be owner of relation %s"),
2114 /* ACL_KIND_SEQUENCE */
2115 gettext_noop("must be owner of sequence %s"),
2116 /* ACL_KIND_DATABASE */
2117 gettext_noop("must be owner of database %s"),
2119 gettext_noop("must be owner of function %s"),
2121 gettext_noop("must be owner of operator %s"),
2123 gettext_noop("must be owner of type %s"),
2124 /* ACL_KIND_LANGUAGE */
2125 gettext_noop("must be owner of language %s"),
2126 /* ACL_KIND_NAMESPACE */
2127 gettext_noop("must be owner of schema %s"),
2128 /* ACL_KIND_OPCLASS */
2129 gettext_noop("must be owner of operator class %s"),
2130 /* ACL_KIND_OPFAMILY */
2131 gettext_noop("must be owner of operator family %s"),
2132 /* ACL_KIND_CONVERSION */
2133 gettext_noop("must be owner of conversion %s"),
2134 /* ACL_KIND_TABLESPACE */
2135 gettext_noop("must be owner of tablespace %s"),
2136 /* ACL_KIND_TSDICTIONARY */
2137 gettext_noop("must be owner of text search dictionary %s"),
2138 /* ACL_KIND_TSCONFIGURATION */
2139 gettext_noop("must be owner of text search configuration %s"),
2141 gettext_noop("must be owner of foreign-data wrapper %s"),
2142 /* ACL_KIND_FOREIGN_SERVER */
2143 gettext_noop("must be owner of foreign server %s")
2148 aclcheck_error(AclResult aclerr
, AclObjectKind objectkind
,
2149 const char *objectname
)
2154 /* no error, so return to caller */
2156 case ACLCHECK_NO_PRIV
:
2158 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
2159 errmsg(no_priv_msg
[objectkind
], objectname
)));
2161 case ACLCHECK_NOT_OWNER
:
2163 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
2164 errmsg(not_owner_msg
[objectkind
], objectname
)));
2167 elog(ERROR
, "unrecognized AclResult: %d", (int) aclerr
);
2174 aclcheck_error_col(AclResult aclerr
, AclObjectKind objectkind
,
2175 const char *objectname
, const char *colname
)
2180 /* no error, so return to caller */
2182 case ACLCHECK_NO_PRIV
:
2184 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
2185 errmsg("permission denied for column %s of relation %s",
2186 colname
, objectname
)));
2188 case ACLCHECK_NOT_OWNER
:
2189 /* relation msg is OK since columns don't have separate owners */
2191 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
2192 errmsg(not_owner_msg
[objectkind
], objectname
)));
2195 elog(ERROR
, "unrecognized AclResult: %d", (int) aclerr
);
2201 /* Check if given user has rolcatupdate privilege according to pg_authid */
2203 has_rolcatupdate(Oid roleid
)
2208 tuple
= SearchSysCache(AUTHOID
,
2209 ObjectIdGetDatum(roleid
),
2211 if (!HeapTupleIsValid(tuple
))
2213 (errcode(ERRCODE_UNDEFINED_OBJECT
),
2214 errmsg("role with OID %u does not exist", roleid
)));
2216 rolcatupdate
= ((Form_pg_authid
) GETSTRUCT(tuple
))->rolcatupdate
;
2218 ReleaseSysCache(tuple
);
2220 return rolcatupdate
;
2224 * Relay for the various pg_*_mask routines depending on object kind
2227 pg_aclmask(AclObjectKind objkind
, Oid table_oid
, AttrNumber attnum
, Oid roleid
,
2228 AclMode mask
, AclMaskHow how
)
2232 case ACL_KIND_COLUMN
:
2234 pg_class_aclmask(table_oid
, roleid
, mask
, how
) |
2235 pg_attribute_aclmask(table_oid
, attnum
, roleid
, mask
, how
);
2236 case ACL_KIND_CLASS
:
2237 case ACL_KIND_SEQUENCE
:
2238 return pg_class_aclmask(table_oid
, roleid
, mask
, how
);
2239 case ACL_KIND_DATABASE
:
2240 return pg_database_aclmask(table_oid
, roleid
, mask
, how
);
2242 return pg_proc_aclmask(table_oid
, roleid
, mask
, how
);
2243 case ACL_KIND_LANGUAGE
:
2244 return pg_language_aclmask(table_oid
, roleid
, mask
, how
);
2245 case ACL_KIND_NAMESPACE
:
2246 return pg_namespace_aclmask(table_oid
, roleid
, mask
, how
);
2247 case ACL_KIND_TABLESPACE
:
2248 return pg_tablespace_aclmask(table_oid
, roleid
, mask
, how
);
2250 return pg_foreign_data_wrapper_aclmask(table_oid
, roleid
, mask
, how
);
2251 case ACL_KIND_FOREIGN_SERVER
:
2252 return pg_foreign_server_aclmask(table_oid
, roleid
, mask
, how
);
2254 elog(ERROR
, "unrecognized objkind: %d",
2256 /* not reached, but keep compiler quiet */
2257 return ACL_NO_RIGHTS
;
2262 /* ****************************************************************
2263 * Exported routines for examining a user's privileges for various objects
2265 * See aclmask() for a description of the common API for these functions.
2267 * Note: we give lookup failure the full ereport treatment because the
2268 * has_xxx_privilege() family of functions allow users to pass any random
2269 * OID to these functions.
2270 * ****************************************************************
2274 * Exported routine for examining a user's privileges for a column
2276 * Note: this considers only privileges granted specifically on the column.
2277 * It is caller's responsibility to take relation-level privileges into account
2278 * as appropriate. (For the same reason, we have no special case for
2279 * superuser-ness here.)
2282 pg_attribute_aclmask(Oid table_oid
, AttrNumber attnum
, Oid roleid
,
2283 AclMode mask
, AclMaskHow how
)
2286 HeapTuple classTuple
;
2288 Form_pg_class classForm
;
2289 Form_pg_attribute attributeForm
;
2296 * First, get the column's ACL from its pg_attribute entry
2298 attTuple
= SearchSysCache(ATTNUM
,
2299 ObjectIdGetDatum(table_oid
),
2300 Int16GetDatum(attnum
),
2302 if (!HeapTupleIsValid(attTuple
))
2304 (errcode(ERRCODE_UNDEFINED_COLUMN
),
2305 errmsg("attribute %d of relation with OID %u does not exist",
2306 attnum
, table_oid
)));
2307 attributeForm
= (Form_pg_attribute
) GETSTRUCT(attTuple
);
2309 /* Throw error on dropped columns, too */
2310 if (attributeForm
->attisdropped
)
2312 (errcode(ERRCODE_UNDEFINED_COLUMN
),
2313 errmsg("attribute %d of relation with OID %u does not exist",
2314 attnum
, table_oid
)));
2316 aclDatum
= SysCacheGetAttr(ATTNUM
, attTuple
, Anum_pg_attribute_attacl
,
2320 * Here we hard-wire knowledge that the default ACL for a column grants no
2321 * privileges, so that we can fall out quickly in the very common case
2322 * where attacl is null.
2326 ReleaseSysCache(attTuple
);
2331 * Must get the relation's ownerId from pg_class. Since we already found
2332 * a pg_attribute entry, the only likely reason for this to fail is that a
2333 * concurrent DROP of the relation committed since then (which could only
2334 * happen if we don't have lock on the relation). We prefer to report "no
2335 * privileges" rather than failing in such a case, so as to avoid unwanted
2336 * failures in has_column_privilege() tests.
2338 classTuple
= SearchSysCache(RELOID
,
2339 ObjectIdGetDatum(table_oid
),
2341 if (!HeapTupleIsValid(classTuple
))
2343 ReleaseSysCache(attTuple
);
2346 classForm
= (Form_pg_class
) GETSTRUCT(classTuple
);
2348 ownerId
= classForm
->relowner
;
2350 ReleaseSysCache(classTuple
);
2352 /* detoast column's ACL if necessary */
2353 acl
= DatumGetAclP(aclDatum
);
2355 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
2357 /* if we have a detoasted copy, free it */
2358 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
2361 ReleaseSysCache(attTuple
);
2367 * Exported routine for examining a user's privileges for a table
2370 pg_class_aclmask(Oid table_oid
, Oid roleid
,
2371 AclMode mask
, AclMaskHow how
)
2375 Form_pg_class classForm
;
2382 * Must get the relation's tuple from pg_class
2384 tuple
= SearchSysCache(RELOID
,
2385 ObjectIdGetDatum(table_oid
),
2387 if (!HeapTupleIsValid(tuple
))
2389 (errcode(ERRCODE_UNDEFINED_TABLE
),
2390 errmsg("relation with OID %u does not exist",
2392 classForm
= (Form_pg_class
) GETSTRUCT(tuple
);
2395 * Deny anyone permission to update a system catalog unless
2396 * pg_authid.rolcatupdate is set. (This is to let superusers protect
2397 * themselves from themselves.) Also allow it if allowSystemTableMods.
2399 * As of 7.4 we have some updatable system views; those shouldn't be
2400 * protected in this way. Assume the view rules can take care of
2401 * themselves. ACL_USAGE is if we ever have system sequences.
2403 if ((mask
& (ACL_INSERT
| ACL_UPDATE
| ACL_DELETE
| ACL_TRUNCATE
| ACL_USAGE
)) &&
2404 IsSystemClass(classForm
) &&
2405 classForm
->relkind
!= RELKIND_VIEW
&&
2406 !has_rolcatupdate(roleid
) &&
2407 !allowSystemTableMods
)
2410 elog(DEBUG2
, "permission denied for system catalog update");
2412 mask
&= ~(ACL_INSERT
| ACL_UPDATE
| ACL_DELETE
| ACL_TRUNCATE
| ACL_USAGE
);
2416 * Otherwise, superusers bypass all permission-checking.
2418 if (superuser_arg(roleid
))
2421 elog(DEBUG2
, "OID %u is superuser, home free", roleid
);
2423 ReleaseSysCache(tuple
);
2428 * Normal case: get the relation's ACL from pg_class
2430 ownerId
= classForm
->relowner
;
2432 aclDatum
= SysCacheGetAttr(RELOID
, tuple
, Anum_pg_class_relacl
,
2436 /* No ACL, so build default ACL */
2437 acl
= acldefault(classForm
->relkind
== RELKIND_SEQUENCE
?
2438 ACL_OBJECT_SEQUENCE
: ACL_OBJECT_RELATION
,
2440 aclDatum
= (Datum
) 0;
2444 /* detoast rel's ACL if necessary */
2445 acl
= DatumGetAclP(aclDatum
);
2448 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
2450 /* if we have a detoasted copy, free it */
2451 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
2454 ReleaseSysCache(tuple
);
2460 * Exported routine for examining a user's privileges for a database
2463 pg_database_aclmask(Oid db_oid
, Oid roleid
,
2464 AclMode mask
, AclMaskHow how
)
2473 /* Superusers bypass all permission checking. */
2474 if (superuser_arg(roleid
))
2478 * Get the database's ACL from pg_database
2480 tuple
= SearchSysCache(DATABASEOID
,
2481 ObjectIdGetDatum(db_oid
),
2483 if (!HeapTupleIsValid(tuple
))
2485 (errcode(ERRCODE_UNDEFINED_DATABASE
),
2486 errmsg("database with OID %u does not exist", db_oid
)));
2488 ownerId
= ((Form_pg_database
) GETSTRUCT(tuple
))->datdba
;
2490 aclDatum
= SysCacheGetAttr(DATABASEOID
, tuple
, Anum_pg_database_datacl
,
2494 /* No ACL, so build default ACL */
2495 acl
= acldefault(ACL_OBJECT_DATABASE
, ownerId
);
2496 aclDatum
= (Datum
) 0;
2500 /* detoast ACL if necessary */
2501 acl
= DatumGetAclP(aclDatum
);
2504 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
2506 /* if we have a detoasted copy, free it */
2507 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
2510 ReleaseSysCache(tuple
);
2516 * Exported routine for examining a user's privileges for a function
2519 pg_proc_aclmask(Oid proc_oid
, Oid roleid
,
2520 AclMode mask
, AclMaskHow how
)
2529 /* Superusers bypass all permission checking. */
2530 if (superuser_arg(roleid
))
2534 * Get the function's ACL from pg_proc
2536 tuple
= SearchSysCache(PROCOID
,
2537 ObjectIdGetDatum(proc_oid
),
2539 if (!HeapTupleIsValid(tuple
))
2541 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
2542 errmsg("function with OID %u does not exist", proc_oid
)));
2544 ownerId
= ((Form_pg_proc
) GETSTRUCT(tuple
))->proowner
;
2546 aclDatum
= SysCacheGetAttr(PROCOID
, tuple
, Anum_pg_proc_proacl
,
2550 /* No ACL, so build default ACL */
2551 acl
= acldefault(ACL_OBJECT_FUNCTION
, ownerId
);
2552 aclDatum
= (Datum
) 0;
2556 /* detoast ACL if necessary */
2557 acl
= DatumGetAclP(aclDatum
);
2560 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
2562 /* if we have a detoasted copy, free it */
2563 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
2566 ReleaseSysCache(tuple
);
2572 * Exported routine for examining a user's privileges for a language
2575 pg_language_aclmask(Oid lang_oid
, Oid roleid
,
2576 AclMode mask
, AclMaskHow how
)
2585 /* Superusers bypass all permission checking. */
2586 if (superuser_arg(roleid
))
2590 * Get the language's ACL from pg_language
2592 tuple
= SearchSysCache(LANGOID
,
2593 ObjectIdGetDatum(lang_oid
),
2595 if (!HeapTupleIsValid(tuple
))
2597 (errcode(ERRCODE_UNDEFINED_OBJECT
),
2598 errmsg("language with OID %u does not exist", lang_oid
)));
2600 ownerId
= ((Form_pg_language
) GETSTRUCT(tuple
))->lanowner
;
2602 aclDatum
= SysCacheGetAttr(LANGOID
, tuple
, Anum_pg_language_lanacl
,
2606 /* No ACL, so build default ACL */
2607 acl
= acldefault(ACL_OBJECT_LANGUAGE
, ownerId
);
2608 aclDatum
= (Datum
) 0;
2612 /* detoast ACL if necessary */
2613 acl
= DatumGetAclP(aclDatum
);
2616 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
2618 /* if we have a detoasted copy, free it */
2619 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
2622 ReleaseSysCache(tuple
);
2628 * Exported routine for examining a user's privileges for a namespace
2631 pg_namespace_aclmask(Oid nsp_oid
, Oid roleid
,
2632 AclMode mask
, AclMaskHow how
)
2641 /* Superusers bypass all permission checking. */
2642 if (superuser_arg(roleid
))
2646 * If we have been assigned this namespace as a temp namespace, check to
2647 * make sure we have CREATE TEMP permission on the database, and if so act
2648 * as though we have all standard (but not GRANT OPTION) permissions on
2649 * the namespace. If we don't have CREATE TEMP, act as though we have
2650 * only USAGE (and not CREATE) rights.
2652 * This may seem redundant given the check in InitTempTableNamespace, but
2653 * it really isn't since current user ID may have changed since then. The
2654 * upshot of this behavior is that a SECURITY DEFINER function can create
2655 * temp tables that can then be accessed (if permission is granted) by
2656 * code in the same session that doesn't have permissions to create temp
2659 * XXX Would it be safe to ereport a special error message as
2660 * InitTempTableNamespace does? Returning zero here means we'll get a
2661 * generic "permission denied for schema pg_temp_N" message, which is not
2662 * remarkably user-friendly.
2664 if (isTempNamespace(nsp_oid
))
2666 if (pg_database_aclcheck(MyDatabaseId
, roleid
,
2667 ACL_CREATE_TEMP
) == ACLCHECK_OK
)
2668 return mask
& ACL_ALL_RIGHTS_NAMESPACE
;
2670 return mask
& ACL_USAGE
;
2674 * Get the schema's ACL from pg_namespace
2676 tuple
= SearchSysCache(NAMESPACEOID
,
2677 ObjectIdGetDatum(nsp_oid
),
2679 if (!HeapTupleIsValid(tuple
))
2681 (errcode(ERRCODE_UNDEFINED_SCHEMA
),
2682 errmsg("schema with OID %u does not exist", nsp_oid
)));
2684 ownerId
= ((Form_pg_namespace
) GETSTRUCT(tuple
))->nspowner
;
2686 aclDatum
= SysCacheGetAttr(NAMESPACEOID
, tuple
, Anum_pg_namespace_nspacl
,
2690 /* No ACL, so build default ACL */
2691 acl
= acldefault(ACL_OBJECT_NAMESPACE
, ownerId
);
2692 aclDatum
= (Datum
) 0;
2696 /* detoast ACL if necessary */
2697 acl
= DatumGetAclP(aclDatum
);
2700 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
2702 /* if we have a detoasted copy, free it */
2703 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
2706 ReleaseSysCache(tuple
);
2712 * Exported routine for examining a user's privileges for a tablespace
2715 pg_tablespace_aclmask(Oid spc_oid
, Oid roleid
,
2716 AclMode mask
, AclMaskHow how
)
2719 Relation pg_tablespace
;
2720 ScanKeyData entry
[1];
2728 /* Superusers bypass all permission checking. */
2729 if (superuser_arg(roleid
))
2733 * Get the tablespace's ACL from pg_tablespace
2735 * There's no syscache for pg_tablespace, so must look the hard way
2737 pg_tablespace
= heap_open(TableSpaceRelationId
, AccessShareLock
);
2738 ScanKeyInit(&entry
[0],
2739 ObjectIdAttributeNumber
,
2740 BTEqualStrategyNumber
, F_OIDEQ
,
2741 ObjectIdGetDatum(spc_oid
));
2742 scan
= systable_beginscan(pg_tablespace
, TablespaceOidIndexId
, true,
2743 SnapshotNow
, 1, entry
);
2744 tuple
= systable_getnext(scan
);
2745 if (!HeapTupleIsValid(tuple
))
2747 (errcode(ERRCODE_UNDEFINED_OBJECT
),
2748 errmsg("tablespace with OID %u does not exist", spc_oid
)));
2750 ownerId
= ((Form_pg_tablespace
) GETSTRUCT(tuple
))->spcowner
;
2752 aclDatum
= heap_getattr(tuple
, Anum_pg_tablespace_spcacl
,
2753 RelationGetDescr(pg_tablespace
), &isNull
);
2757 /* No ACL, so build default ACL */
2758 acl
= acldefault(ACL_OBJECT_TABLESPACE
, ownerId
);
2759 aclDatum
= (Datum
) 0;
2763 /* detoast ACL if necessary */
2764 acl
= DatumGetAclP(aclDatum
);
2767 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
2769 /* if we have a detoasted copy, free it */
2770 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
2773 systable_endscan(scan
);
2774 heap_close(pg_tablespace
, AccessShareLock
);
2780 * Exported routine for examining a user's privileges for a foreign
2784 pg_foreign_data_wrapper_aclmask(Oid fdw_oid
, Oid roleid
,
2785 AclMode mask
, AclMaskHow how
)
2794 Form_pg_foreign_data_wrapper fdwForm
;
2796 /* Bypass permission checks for superusers */
2797 if (superuser_arg(roleid
))
2801 * Must get the FDW's tuple from pg_foreign_data_wrapper
2803 tuple
= SearchSysCache(FOREIGNDATAWRAPPEROID
,
2804 ObjectIdGetDatum(fdw_oid
),
2806 if (!HeapTupleIsValid(tuple
))
2808 (errmsg("foreign-data wrapper with OID %u does not exist",
2810 fdwForm
= (Form_pg_foreign_data_wrapper
) GETSTRUCT(tuple
);
2813 * Normal case: get the FDW's ACL from pg_foreign_data_wrapper
2815 ownerId
= fdwForm
->fdwowner
;
2817 aclDatum
= SysCacheGetAttr(FOREIGNDATAWRAPPEROID
, tuple
,
2818 Anum_pg_foreign_data_wrapper_fdwacl
, &isNull
);
2821 /* No ACL, so build default ACL */
2822 acl
= acldefault(ACL_OBJECT_FDW
, ownerId
);
2823 aclDatum
= (Datum
) 0;
2827 /* detoast rel's ACL if necessary */
2828 acl
= DatumGetAclP(aclDatum
);
2831 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
2833 /* if we have a detoasted copy, free it */
2834 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
2837 ReleaseSysCache(tuple
);
2843 * Exported routine for examining a user's privileges for a foreign
2847 pg_foreign_server_aclmask(Oid srv_oid
, Oid roleid
,
2848 AclMode mask
, AclMaskHow how
)
2857 Form_pg_foreign_server srvForm
;
2859 /* Bypass permission checks for superusers */
2860 if (superuser_arg(roleid
))
2864 * Must get the FDW's tuple from pg_foreign_data_wrapper
2866 tuple
= SearchSysCache(FOREIGNSERVEROID
,
2867 ObjectIdGetDatum(srv_oid
),
2869 if (!HeapTupleIsValid(tuple
))
2871 (errmsg("foreign server with OID %u does not exist",
2873 srvForm
= (Form_pg_foreign_server
) GETSTRUCT(tuple
);
2876 * Normal case: get the foreign server's ACL from pg_foreign_server
2878 ownerId
= srvForm
->srvowner
;
2880 aclDatum
= SysCacheGetAttr(FOREIGNSERVEROID
, tuple
,
2881 Anum_pg_foreign_server_srvacl
, &isNull
);
2884 /* No ACL, so build default ACL */
2885 acl
= acldefault(ACL_OBJECT_FOREIGN_SERVER
, ownerId
);
2886 aclDatum
= (Datum
) 0;
2890 /* detoast rel's ACL if necessary */
2891 acl
= DatumGetAclP(aclDatum
);
2894 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
2896 /* if we have a detoasted copy, free it */
2897 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
2900 ReleaseSysCache(tuple
);
2906 * Exported routine for checking a user's access privileges to a column
2908 * Returns ACLCHECK_OK if the user has any of the privileges identified by
2909 * 'mode'; otherwise returns a suitable error code (in practice, always
2910 * ACLCHECK_NO_PRIV).
2912 * As with pg_attribute_aclmask, only privileges granted directly on the
2913 * column are considered here.
2916 pg_attribute_aclcheck(Oid table_oid
, AttrNumber attnum
,
2917 Oid roleid
, AclMode mode
)
2919 if (pg_attribute_aclmask(table_oid
, attnum
, roleid
, mode
, ACLMASK_ANY
) != 0)
2922 return ACLCHECK_NO_PRIV
;
2926 * Exported routine for checking a user's access privileges to any/all columns
2928 * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
2929 * privileges identified by 'mode' on any non-dropped column in the relation;
2930 * otherwise returns a suitable error code (in practice, always
2931 * ACLCHECK_NO_PRIV).
2933 * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
2934 * privileges identified by 'mode' on each non-dropped column in the relation
2935 * (and there must be at least one such column); otherwise returns a suitable
2936 * error code (in practice, always ACLCHECK_NO_PRIV).
2938 * As with pg_attribute_aclmask, only privileges granted directly on the
2939 * column(s) are considered here.
2941 * Note: system columns are not considered here; there are cases where that
2942 * might be appropriate but there are also cases where it wouldn't.
2945 pg_attribute_aclcheck_all(Oid table_oid
, Oid roleid
, AclMode mode
,
2949 HeapTuple classTuple
;
2950 Form_pg_class classForm
;
2952 AttrNumber curr_att
;
2955 * Must fetch pg_class row to check number of attributes. As in
2956 * pg_attribute_aclmask, we prefer to return "no privileges" instead of
2957 * throwing an error if we get any unexpected lookup errors.
2959 classTuple
= SearchSysCache(RELOID
,
2960 ObjectIdGetDatum(table_oid
),
2962 if (!HeapTupleIsValid(classTuple
))
2963 return ACLCHECK_NO_PRIV
;
2964 classForm
= (Form_pg_class
) GETSTRUCT(classTuple
);
2966 nattrs
= classForm
->relnatts
;
2968 ReleaseSysCache(classTuple
);
2971 * Initialize result in case there are no non-dropped columns. We want to
2972 * report failure in such cases for either value of 'how'.
2974 result
= ACLCHECK_NO_PRIV
;
2976 for (curr_att
= 1; curr_att
<= nattrs
; curr_att
++)
2981 attTuple
= SearchSysCache(ATTNUM
,
2982 ObjectIdGetDatum(table_oid
),
2983 Int16GetDatum(curr_att
),
2985 if (!HeapTupleIsValid(attTuple
))
2988 /* ignore dropped columns */
2989 if (((Form_pg_attribute
) GETSTRUCT(attTuple
))->attisdropped
)
2991 ReleaseSysCache(attTuple
);
2996 * Here we hard-wire knowledge that the default ACL for a column
2997 * grants no privileges, so that we can fall out quickly in the very
2998 * common case where attacl is null.
3000 if (heap_attisnull(attTuple
, Anum_pg_attribute_attacl
))
3003 attmask
= pg_attribute_aclmask(table_oid
, curr_att
, roleid
,
3006 ReleaseSysCache(attTuple
);
3010 result
= ACLCHECK_OK
;
3011 if (how
== ACLMASK_ANY
)
3012 break; /* succeed on any success */
3016 result
= ACLCHECK_NO_PRIV
;
3017 if (how
== ACLMASK_ALL
)
3018 break; /* fail on any failure */
3026 * Exported routine for checking a user's access privileges to a table
3028 * Returns ACLCHECK_OK if the user has any of the privileges identified by
3029 * 'mode'; otherwise returns a suitable error code (in practice, always
3030 * ACLCHECK_NO_PRIV).
3033 pg_class_aclcheck(Oid table_oid
, Oid roleid
, AclMode mode
)
3035 if (pg_class_aclmask(table_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
3038 return ACLCHECK_NO_PRIV
;
3042 * Exported routine for checking a user's access privileges to a database
3045 pg_database_aclcheck(Oid db_oid
, Oid roleid
, AclMode mode
)
3047 if (pg_database_aclmask(db_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
3050 return ACLCHECK_NO_PRIV
;
3054 * Exported routine for checking a user's access privileges to a function
3057 pg_proc_aclcheck(Oid proc_oid
, Oid roleid
, AclMode mode
)
3059 if (pg_proc_aclmask(proc_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
3062 return ACLCHECK_NO_PRIV
;
3066 * Exported routine for checking a user's access privileges to a language
3069 pg_language_aclcheck(Oid lang_oid
, Oid roleid
, AclMode mode
)
3071 if (pg_language_aclmask(lang_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
3074 return ACLCHECK_NO_PRIV
;
3078 * Exported routine for checking a user's access privileges to a namespace
3081 pg_namespace_aclcheck(Oid nsp_oid
, Oid roleid
, AclMode mode
)
3083 if (pg_namespace_aclmask(nsp_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
3086 return ACLCHECK_NO_PRIV
;
3090 * Exported routine for checking a user's access privileges to a tablespace
3093 pg_tablespace_aclcheck(Oid spc_oid
, Oid roleid
, AclMode mode
)
3095 if (pg_tablespace_aclmask(spc_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
3098 return ACLCHECK_NO_PRIV
;
3102 * Exported routine for checking a user's access privileges to a foreign
3106 pg_foreign_data_wrapper_aclcheck(Oid fdw_oid
, Oid roleid
, AclMode mode
)
3108 if (pg_foreign_data_wrapper_aclmask(fdw_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
3111 return ACLCHECK_NO_PRIV
;
3115 * Exported routine for checking a user's access privileges to a foreign
3119 pg_foreign_server_aclcheck(Oid srv_oid
, Oid roleid
, AclMode mode
)
3121 if (pg_foreign_server_aclmask(srv_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
3124 return ACLCHECK_NO_PRIV
;
3128 * Ownership check for a relation (specified by OID).
3131 pg_class_ownercheck(Oid class_oid
, Oid roleid
)
3136 /* Superusers bypass all permission checking. */
3137 if (superuser_arg(roleid
))
3140 tuple
= SearchSysCache(RELOID
,
3141 ObjectIdGetDatum(class_oid
),
3143 if (!HeapTupleIsValid(tuple
))
3145 (errcode(ERRCODE_UNDEFINED_TABLE
),
3146 errmsg("relation with OID %u does not exist", class_oid
)));
3148 ownerId
= ((Form_pg_class
) GETSTRUCT(tuple
))->relowner
;
3150 ReleaseSysCache(tuple
);
3152 return has_privs_of_role(roleid
, ownerId
);
3156 * Ownership check for a type (specified by OID).
3159 pg_type_ownercheck(Oid type_oid
, Oid roleid
)
3164 /* Superusers bypass all permission checking. */
3165 if (superuser_arg(roleid
))
3168 tuple
= SearchSysCache(TYPEOID
,
3169 ObjectIdGetDatum(type_oid
),
3171 if (!HeapTupleIsValid(tuple
))
3173 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3174 errmsg("type with OID %u does not exist", type_oid
)));
3176 ownerId
= ((Form_pg_type
) GETSTRUCT(tuple
))->typowner
;
3178 ReleaseSysCache(tuple
);
3180 return has_privs_of_role(roleid
, ownerId
);
3184 * Ownership check for an operator (specified by OID).
3187 pg_oper_ownercheck(Oid oper_oid
, Oid roleid
)
3192 /* Superusers bypass all permission checking. */
3193 if (superuser_arg(roleid
))
3196 tuple
= SearchSysCache(OPEROID
,
3197 ObjectIdGetDatum(oper_oid
),
3199 if (!HeapTupleIsValid(tuple
))
3201 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
3202 errmsg("operator with OID %u does not exist", oper_oid
)));
3204 ownerId
= ((Form_pg_operator
) GETSTRUCT(tuple
))->oprowner
;
3206 ReleaseSysCache(tuple
);
3208 return has_privs_of_role(roleid
, ownerId
);
3212 * Ownership check for a function (specified by OID).
3215 pg_proc_ownercheck(Oid proc_oid
, Oid roleid
)
3220 /* Superusers bypass all permission checking. */
3221 if (superuser_arg(roleid
))
3224 tuple
= SearchSysCache(PROCOID
,
3225 ObjectIdGetDatum(proc_oid
),
3227 if (!HeapTupleIsValid(tuple
))
3229 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
3230 errmsg("function with OID %u does not exist", proc_oid
)));
3232 ownerId
= ((Form_pg_proc
) GETSTRUCT(tuple
))->proowner
;
3234 ReleaseSysCache(tuple
);
3236 return has_privs_of_role(roleid
, ownerId
);
3240 * Ownership check for a procedural language (specified by OID)
3243 pg_language_ownercheck(Oid lan_oid
, Oid roleid
)
3248 /* Superusers bypass all permission checking. */
3249 if (superuser_arg(roleid
))
3252 tuple
= SearchSysCache(LANGOID
,
3253 ObjectIdGetDatum(lan_oid
),
3255 if (!HeapTupleIsValid(tuple
))
3257 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
3258 errmsg("language with OID %u does not exist", lan_oid
)));
3260 ownerId
= ((Form_pg_language
) GETSTRUCT(tuple
))->lanowner
;
3262 ReleaseSysCache(tuple
);
3264 return has_privs_of_role(roleid
, ownerId
);
3268 * Ownership check for a namespace (specified by OID).
3271 pg_namespace_ownercheck(Oid nsp_oid
, Oid roleid
)
3276 /* Superusers bypass all permission checking. */
3277 if (superuser_arg(roleid
))
3280 tuple
= SearchSysCache(NAMESPACEOID
,
3281 ObjectIdGetDatum(nsp_oid
),
3283 if (!HeapTupleIsValid(tuple
))
3285 (errcode(ERRCODE_UNDEFINED_SCHEMA
),
3286 errmsg("schema with OID %u does not exist", nsp_oid
)));
3288 ownerId
= ((Form_pg_namespace
) GETSTRUCT(tuple
))->nspowner
;
3290 ReleaseSysCache(tuple
);
3292 return has_privs_of_role(roleid
, ownerId
);
3296 * Ownership check for a tablespace (specified by OID).
3299 pg_tablespace_ownercheck(Oid spc_oid
, Oid roleid
)
3301 Relation pg_tablespace
;
3302 ScanKeyData entry
[1];
3307 /* Superusers bypass all permission checking. */
3308 if (superuser_arg(roleid
))
3311 /* There's no syscache for pg_tablespace, so must look the hard way */
3312 pg_tablespace
= heap_open(TableSpaceRelationId
, AccessShareLock
);
3313 ScanKeyInit(&entry
[0],
3314 ObjectIdAttributeNumber
,
3315 BTEqualStrategyNumber
, F_OIDEQ
,
3316 ObjectIdGetDatum(spc_oid
));
3317 scan
= systable_beginscan(pg_tablespace
, TablespaceOidIndexId
, true,
3318 SnapshotNow
, 1, entry
);
3320 spctuple
= systable_getnext(scan
);
3322 if (!HeapTupleIsValid(spctuple
))
3324 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3325 errmsg("tablespace with OID %u does not exist", spc_oid
)));
3327 spcowner
= ((Form_pg_tablespace
) GETSTRUCT(spctuple
))->spcowner
;
3329 systable_endscan(scan
);
3330 heap_close(pg_tablespace
, AccessShareLock
);
3332 return has_privs_of_role(roleid
, spcowner
);
3336 * Ownership check for an operator class (specified by OID).
3339 pg_opclass_ownercheck(Oid opc_oid
, Oid roleid
)
3344 /* Superusers bypass all permission checking. */
3345 if (superuser_arg(roleid
))
3348 tuple
= SearchSysCache(CLAOID
,
3349 ObjectIdGetDatum(opc_oid
),
3351 if (!HeapTupleIsValid(tuple
))
3353 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3354 errmsg("operator class with OID %u does not exist",
3357 ownerId
= ((Form_pg_opclass
) GETSTRUCT(tuple
))->opcowner
;
3359 ReleaseSysCache(tuple
);
3361 return has_privs_of_role(roleid
, ownerId
);
3365 * Ownership check for an operator family (specified by OID).
3368 pg_opfamily_ownercheck(Oid opf_oid
, Oid roleid
)
3373 /* Superusers bypass all permission checking. */
3374 if (superuser_arg(roleid
))
3377 tuple
= SearchSysCache(OPFAMILYOID
,
3378 ObjectIdGetDatum(opf_oid
),
3380 if (!HeapTupleIsValid(tuple
))
3382 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3383 errmsg("operator family with OID %u does not exist",
3386 ownerId
= ((Form_pg_opfamily
) GETSTRUCT(tuple
))->opfowner
;
3388 ReleaseSysCache(tuple
);
3390 return has_privs_of_role(roleid
, ownerId
);
3394 * Ownership check for a text search dictionary (specified by OID).
3397 pg_ts_dict_ownercheck(Oid dict_oid
, Oid roleid
)
3402 /* Superusers bypass all permission checking. */
3403 if (superuser_arg(roleid
))
3406 tuple
= SearchSysCache(TSDICTOID
,
3407 ObjectIdGetDatum(dict_oid
),
3409 if (!HeapTupleIsValid(tuple
))
3411 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3412 errmsg("text search dictionary with OID %u does not exist",
3415 ownerId
= ((Form_pg_ts_dict
) GETSTRUCT(tuple
))->dictowner
;
3417 ReleaseSysCache(tuple
);
3419 return has_privs_of_role(roleid
, ownerId
);
3423 * Ownership check for a text search configuration (specified by OID).
3426 pg_ts_config_ownercheck(Oid cfg_oid
, Oid roleid
)
3431 /* Superusers bypass all permission checking. */
3432 if (superuser_arg(roleid
))
3435 tuple
= SearchSysCache(TSCONFIGOID
,
3436 ObjectIdGetDatum(cfg_oid
),
3438 if (!HeapTupleIsValid(tuple
))
3440 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3441 errmsg("text search configuration with OID %u does not exist",
3444 ownerId
= ((Form_pg_ts_config
) GETSTRUCT(tuple
))->cfgowner
;
3446 ReleaseSysCache(tuple
);
3448 return has_privs_of_role(roleid
, ownerId
);
3452 * Ownership check for a foreign server (specified by OID).
3455 pg_foreign_server_ownercheck(Oid srv_oid
, Oid roleid
)
3460 /* Superusers bypass all permission checking. */
3461 if (superuser_arg(roleid
))
3464 tuple
= SearchSysCache(FOREIGNSERVEROID
,
3465 ObjectIdGetDatum(srv_oid
),
3467 if (!HeapTupleIsValid(tuple
))
3469 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3470 errmsg("foreign server with OID %u does not exist",
3473 ownerId
= ((Form_pg_foreign_server
) GETSTRUCT(tuple
))->srvowner
;
3475 ReleaseSysCache(tuple
);
3477 return has_privs_of_role(roleid
, ownerId
);
3481 * Ownership check for a database (specified by OID).
3484 pg_database_ownercheck(Oid db_oid
, Oid roleid
)
3489 /* Superusers bypass all permission checking. */
3490 if (superuser_arg(roleid
))
3493 tuple
= SearchSysCache(DATABASEOID
,
3494 ObjectIdGetDatum(db_oid
),
3496 if (!HeapTupleIsValid(tuple
))
3498 (errcode(ERRCODE_UNDEFINED_DATABASE
),
3499 errmsg("database with OID %u does not exist", db_oid
)));
3501 dba
= ((Form_pg_database
) GETSTRUCT(tuple
))->datdba
;
3503 ReleaseSysCache(tuple
);
3505 return has_privs_of_role(roleid
, dba
);
3509 * Ownership check for a conversion (specified by OID).
3512 pg_conversion_ownercheck(Oid conv_oid
, Oid roleid
)
3517 /* Superusers bypass all permission checking. */
3518 if (superuser_arg(roleid
))
3521 tuple
= SearchSysCache(CONVOID
,
3522 ObjectIdGetDatum(conv_oid
),
3524 if (!HeapTupleIsValid(tuple
))
3526 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3527 errmsg("conversion with OID %u does not exist", conv_oid
)));
3529 ownerId
= ((Form_pg_conversion
) GETSTRUCT(tuple
))->conowner
;
3531 ReleaseSysCache(tuple
);
3533 return has_privs_of_role(roleid
, ownerId
);