1 /*-------------------------------------------------------------------------
4 * Routines to check access control permissions.
6 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.133 2006/11/16 14:41:49 petere Exp $
16 *-------------------------------------------------------------------------
20 #include "access/genam.h"
21 #include "access/heapam.h"
22 #include "access/xact.h"
23 #include "catalog/catalog.h"
24 #include "catalog/dependency.h"
25 #include "catalog/indexing.h"
26 #include "catalog/pg_authid.h"
27 #include "catalog/pg_conversion.h"
28 #include "catalog/pg_database.h"
29 #include "catalog/pg_language.h"
30 #include "catalog/pg_namespace.h"
31 #include "catalog/pg_opclass.h"
32 #include "catalog/pg_operator.h"
33 #include "catalog/pg_proc.h"
34 #include "catalog/pg_tablespace.h"
35 #include "catalog/pg_type.h"
36 #include "commands/dbcommands.h"
37 #include "miscadmin.h"
38 #include "parser/parse_func.h"
39 #include "utils/acl.h"
40 #include "utils/fmgroids.h"
41 #include "utils/lsyscache.h"
42 #include "utils/syscache.h"
45 static void ExecGrant_Relation(InternalGrant *grantStmt);
46 static void ExecGrant_Database(InternalGrant *grantStmt);
47 static void ExecGrant_Function(InternalGrant *grantStmt);
48 static void ExecGrant_Language(InternalGrant *grantStmt);
49 static void ExecGrant_Namespace(InternalGrant *grantStmt);
50 static void ExecGrant_Tablespace(InternalGrant *grantStmt);
52 static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
53 static AclMode string_to_privilege(const char *privname);
54 static const char *privilege_to_string(AclMode privilege);
55 static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
56 bool all_privs, AclMode privileges,
57 Oid objectId, Oid grantorId,
58 AclObjectKind objkind, char *objname);
59 static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid,
60 AclMode mask, AclMaskHow how);
70 elog(DEBUG2, "acl size = %d, # acls = %d",
71 ACL_SIZE(acl), ACL_NUM(acl));
73 for (i = 0; i < ACL_NUM(acl); ++i)
74 elog(DEBUG2, " acl[%d]: %s", i,
75 DatumGetCString(DirectFunctionCall1(aclitemout,
76 PointerGetDatum(aip + i))));
82 * If is_grant is true, adds the given privileges for the list of
83 * grantees to the existing old_acl. If is_grant is false, the
84 * privileges for the given grantees are removed from old_acl.
86 * NB: the original old_acl is pfree'd.
89 merge_acl_with_grant(Acl *old_acl, bool is_grant,
90 bool grant_option, DropBehavior behavior,
91 List *grantees, AclMode privileges,
92 Oid grantorId, Oid ownerId)
98 modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
110 aclitem. ai_grantee = lfirst_oid(j);
113 * Grant options can only be granted to individual roles, not PUBLIC.
114 * The reason is that if a user would re-grant a privilege that he
115 * held through PUBLIC, and later the user is removed, the situation
116 * is impossible to clean up.
118 if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
120 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
121 errmsg("grant options can only be granted to roles")));
123 aclitem. ai_grantor = grantorId;
126 * The asymmetry in the conditions here comes from the spec. In
127 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
128 * to grant both the basic privilege and its grant option. But in
129 * REVOKE, plain revoke revokes both the basic privilege and its grant
130 * option, while REVOKE GRANT OPTION revokes only the option.
132 ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
133 (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
134 (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
136 newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
138 /* avoid memory leak when there are many grantees */
151 * Restrict the privileges to what we can actually grant, and emit
152 * the standards-mandated warning and error messages.
155 restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
156 AclMode privileges, Oid objectId, Oid grantorId,
157 AclObjectKind objkind, char *objname)
159 AclMode this_privileges;
165 whole_mask = ACL_ALL_RIGHTS_RELATION;
167 case ACL_KIND_SEQUENCE:
168 whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
170 case ACL_KIND_DATABASE:
171 whole_mask = ACL_ALL_RIGHTS_DATABASE;
174 whole_mask = ACL_ALL_RIGHTS_FUNCTION;
176 case ACL_KIND_LANGUAGE:
177 whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
179 case ACL_KIND_NAMESPACE:
180 whole_mask = ACL_ALL_RIGHTS_NAMESPACE;
182 case ACL_KIND_TABLESPACE:
183 whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
186 elog(ERROR, "unrecognized object kind: %d", objkind);
187 /* not reached, but keep compiler quiet */
188 return ACL_NO_RIGHTS;
192 * If we found no grant options, consider whether to issue a hard error.
193 * Per spec, having any privilege at all on the object will get you by
196 if (avail_goptions == ACL_NO_RIGHTS)
198 if (pg_aclmask(objkind, objectId, grantorId,
199 whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
200 ACLMASK_ANY) == ACL_NO_RIGHTS)
201 aclcheck_error(ACLCHECK_NO_PRIV, objkind, objname);
205 * Restrict the operation to what we can actually grant or revoke, and
206 * issue a warning if appropriate. (For REVOKE this isn't quite what the
207 * spec says to do: the spec seems to want a warning only if no privilege
208 * bits actually change in the ACL. In practice that behavior seems much
209 * too noisy, as well as inconsistent with the GRANT case.)
211 this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
214 if (this_privileges == 0)
216 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
217 errmsg("no privileges were granted for \"%s\"", objname)));
218 else if (!all_privs && this_privileges != privileges)
220 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
221 errmsg("not all privileges were granted for \"%s\"", objname)));
225 if (this_privileges == 0)
227 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
228 errmsg("no privileges could be revoked for \"%s\"", objname)));
229 else if (!all_privs && this_privileges != privileges)
231 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
232 errmsg("not all privileges could be revoked for \"%s\"", objname)));
235 return this_privileges;
239 * Called to execute the utility commands GRANT and REVOKE
242 ExecuteGrantStmt(GrantStmt *stmt)
247 AclMode all_privileges;
250 * Turn the regular GrantStmt into the InternalGrant form.
252 istmt.is_grant = stmt->is_grant;
253 istmt.objtype = stmt->objtype;
254 istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
255 /* all_privs to be filled below */
256 /* privileges to be filled below */
257 istmt.grantees = NIL;
259 istmt.grant_option = stmt->grant_option;
260 istmt.behavior = stmt->behavior;
264 * Convert the PrivGrantee list into an Oid list. Note that at this point
265 * we insert an ACL_ID_PUBLIC into the list if an empty role name is
266 * detected (which is what the grammar uses if PUBLIC is found), so
267 * downstream there shouldn't be any additional work needed to support
270 foreach(cell, stmt->grantees)
272 PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
274 if (grantee->rolname == NULL)
275 istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
278 lappend_oid(istmt.grantees,
279 get_roleid_checked(grantee->rolname));
283 * Convert stmt->privileges, a textual list, into an AclMode bitmask.
285 switch (stmt->objtype)
288 * Because this might be a sequence, we test both relation and
289 * sequence bits, and later do a more limited test when we know
292 case ACL_OBJECT_RELATION:
293 all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
294 errormsg = _("invalid privilege type %s for relation");
296 case ACL_OBJECT_SEQUENCE:
297 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
298 errormsg = _("invalid privilege type %s for sequence");
300 case ACL_OBJECT_DATABASE:
301 all_privileges = ACL_ALL_RIGHTS_DATABASE;
302 errormsg = _("invalid privilege type %s for database");
304 case ACL_OBJECT_FUNCTION:
305 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
306 errormsg = _("invalid privilege type %s for function");
308 case ACL_OBJECT_LANGUAGE:
309 all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
310 errormsg = _("invalid privilege type %s for language");
312 case ACL_OBJECT_NAMESPACE:
313 all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
314 errormsg = _("invalid privilege type %s for schema");
316 case ACL_OBJECT_TABLESPACE:
317 all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
318 errormsg = _("invalid privilege type %s for tablespace");
321 /* keep compiler quiet */
322 all_privileges = ACL_NO_RIGHTS;
324 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
325 (int) stmt->objtype);
328 if (stmt->privileges == NIL)
330 istmt.all_privs = true;
333 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
334 * depending on the object type
336 istmt.privileges = ACL_NO_RIGHTS;
340 istmt.all_privs = false;
341 istmt.privileges = ACL_NO_RIGHTS;
343 foreach(cell, stmt->privileges)
345 char *privname = strVal(lfirst(cell));
346 AclMode priv = string_to_privilege(privname);
348 if (priv & ~((AclMode) all_privileges))
350 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
352 privilege_to_string(priv))));
354 istmt.privileges |= priv;
358 ExecGrantStmt_oids(&istmt);
364 * "Internal" entrypoint for granting and revoking privileges.
367 ExecGrantStmt_oids(InternalGrant *istmt)
369 switch (istmt->objtype)
371 case ACL_OBJECT_RELATION:
372 case ACL_OBJECT_SEQUENCE:
373 ExecGrant_Relation(istmt);
375 case ACL_OBJECT_DATABASE:
376 ExecGrant_Database(istmt);
378 case ACL_OBJECT_FUNCTION:
379 ExecGrant_Function(istmt);
381 case ACL_OBJECT_LANGUAGE:
382 ExecGrant_Language(istmt);
384 case ACL_OBJECT_NAMESPACE:
385 ExecGrant_Namespace(istmt);
387 case ACL_OBJECT_TABLESPACE:
388 ExecGrant_Tablespace(istmt);
391 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
392 (int) istmt->objtype);
399 * Turn a list of object names of a given type into an Oid list.
402 objectNamesToOids(GrantObjectType objtype, List *objnames)
407 Assert(objnames != NIL);
411 case ACL_OBJECT_RELATION:
412 case ACL_OBJECT_SEQUENCE:
413 foreach(cell, objnames)
415 RangeVar *relvar = (RangeVar *) lfirst(cell);
418 relOid = RangeVarGetRelid(relvar, false);
419 objects = lappend_oid(objects, relOid);
422 case ACL_OBJECT_DATABASE:
423 foreach(cell, objnames)
425 char *dbname = strVal(lfirst(cell));
428 dbid = get_database_oid(dbname);
429 if (!OidIsValid(dbid))
431 (errcode(ERRCODE_UNDEFINED_DATABASE),
432 errmsg("database \"%s\" does not exist",
434 objects = lappend_oid(objects, dbid);
437 case ACL_OBJECT_FUNCTION:
438 foreach(cell, objnames)
440 FuncWithArgs *func = (FuncWithArgs *) lfirst(cell);
443 funcid = LookupFuncNameTypeNames(func->funcname,
444 func->funcargs, false);
445 objects = lappend_oid(objects, funcid);
448 case ACL_OBJECT_LANGUAGE:
449 foreach(cell, objnames)
451 char *langname = strVal(lfirst(cell));
454 tuple = SearchSysCache(LANGNAME,
455 PointerGetDatum(langname),
457 if (!HeapTupleIsValid(tuple))
459 (errcode(ERRCODE_UNDEFINED_OBJECT),
460 errmsg("language \"%s\" does not exist",
463 objects = lappend_oid(objects, HeapTupleGetOid(tuple));
465 ReleaseSysCache(tuple);
468 case ACL_OBJECT_NAMESPACE:
469 foreach(cell, objnames)
471 char *nspname = strVal(lfirst(cell));
474 tuple = SearchSysCache(NAMESPACENAME,
475 CStringGetDatum(nspname),
477 if (!HeapTupleIsValid(tuple))
479 (errcode(ERRCODE_UNDEFINED_SCHEMA),
480 errmsg("schema \"%s\" does not exist",
483 objects = lappend_oid(objects, HeapTupleGetOid(tuple));
485 ReleaseSysCache(tuple);
488 case ACL_OBJECT_TABLESPACE:
489 foreach(cell, objnames)
491 char *spcname = strVal(lfirst(cell));
492 ScanKeyData entry[1];
497 relation = heap_open(TableSpaceRelationId, AccessShareLock);
499 ScanKeyInit(&entry[0],
500 Anum_pg_tablespace_spcname,
501 BTEqualStrategyNumber, F_NAMEEQ,
502 CStringGetDatum(spcname));
504 scan = heap_beginscan(relation, SnapshotNow, 1, entry);
505 tuple = heap_getnext(scan, ForwardScanDirection);
506 if (!HeapTupleIsValid(tuple))
508 (errcode(ERRCODE_UNDEFINED_OBJECT),
509 errmsg("tablespace \"%s\" does not exist", spcname)));
511 objects = lappend_oid(objects, HeapTupleGetOid(tuple));
515 heap_close(relation, AccessShareLock);
519 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
527 * This processes both sequences and non-sequences.
530 ExecGrant_Relation(InternalGrant *istmt)
535 relation = heap_open(RelationRelationId, RowExclusiveLock);
537 foreach(cell, istmt->objects)
539 Oid relOid = lfirst_oid(cell);
541 Form_pg_class pg_class_tuple;
543 AclMode avail_goptions;
544 AclMode this_privileges;
551 Datum values[Natts_pg_class];
552 char nulls[Natts_pg_class];
553 char replaces[Natts_pg_class];
559 tuple = SearchSysCache(RELOID,
560 ObjectIdGetDatum(relOid),
562 if (!HeapTupleIsValid(tuple))
563 elog(ERROR, "cache lookup failed for relation %u", relOid);
564 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
566 /* Not sensible to grant on an index */
567 if (pg_class_tuple->relkind == RELKIND_INDEX)
569 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
570 errmsg("\"%s\" is an index",
571 NameStr(pg_class_tuple->relname))));
573 /* Composite types aren't tables either */
574 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
576 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
577 errmsg("\"%s\" is a composite type",
578 NameStr(pg_class_tuple->relname))));
580 /* Used GRANT SEQUENCE on a non-sequence? */
581 if (istmt->objtype == ACL_OBJECT_SEQUENCE &&
582 pg_class_tuple->relkind != RELKIND_SEQUENCE)
584 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
585 errmsg("\"%s\" is not a sequence",
586 NameStr(pg_class_tuple->relname))));
588 /* Adjust the default permissions based on whether it is a sequence */
589 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
591 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
592 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
594 this_privileges = ACL_ALL_RIGHTS_RELATION;
597 this_privileges = istmt->privileges;
600 * The GRANT TABLE syntax can be used for sequences and non-sequences,
601 * so we have to look at the relkind to determine the supported
602 * permissions. The OR of table and sequence permissions were already
605 if (istmt->objtype == ACL_OBJECT_RELATION)
607 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
610 * For backward compatibility, throw just a warning for
611 * invalid sequence permissions when using the non-sequence
612 * GRANT syntax is used.
614 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
617 * Mention the object name because the user needs to know
618 * which operations succeeded. This is required because
619 * WARNING allows the command to continue.
622 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
623 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE",
624 NameStr(pg_class_tuple->relname))));
625 this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
630 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
633 * USAGE is the only permission supported by sequences but
634 * not by non-sequences. Don't mention the object name
635 * because we didn't in the combined TABLE | SEQUENCE
639 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
640 errmsg("invalid privilege type USAGE for table")));
645 * Get owner ID and working copy of existing ACL. If there's no ACL,
646 * substitute the proper default.
648 ownerId = pg_class_tuple->relowner;
649 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
652 old_acl = acldefault(pg_class_tuple->relkind == RELKIND_SEQUENCE ?
653 ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION,
656 old_acl = DatumGetAclPCopy(aclDatum);
658 /* Determine ID to do the grant as, and available grant options */
659 select_best_grantor(GetUserId(), this_privileges,
661 &grantorId, &avail_goptions);
664 * Restrict the privileges to what we can actually grant, and emit the
665 * standards-mandated warning and error messages.
668 restrict_and_check_grant(istmt->is_grant, avail_goptions,
669 istmt->all_privs, this_privileges,
671 pg_class_tuple->relkind == RELKIND_SEQUENCE
672 ? ACL_KIND_SEQUENCE : ACL_KIND_CLASS,
673 NameStr(pg_class_tuple->relname));
678 * We need the members of both old and new ACLs so we can correct the
679 * shared dependency information.
681 noldmembers = aclmembers(old_acl, &oldmembers);
683 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
684 istmt->grant_option, istmt->behavior,
685 istmt->grantees, this_privileges,
688 nnewmembers = aclmembers(new_acl, &newmembers);
690 /* finished building new ACL value, now insert it */
691 MemSet(values, 0, sizeof(values));
692 MemSet(nulls, ' ', sizeof(nulls));
693 MemSet(replaces, ' ', sizeof(replaces));
695 replaces[Anum_pg_class_relacl - 1] = 'r';
696 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
698 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
700 simple_heap_update(relation, &newtuple->t_self, newtuple);
702 /* keep the catalog indexes up to date */
703 CatalogUpdateIndexes(relation, newtuple);
705 /* Update the shared dependency ACL info */
706 updateAclDependencies(RelationRelationId, relOid,
707 ownerId, istmt->is_grant,
708 noldmembers, oldmembers,
709 nnewmembers, newmembers);
711 ReleaseSysCache(tuple);
715 /* prevent error when processing duplicate objects */
716 CommandCounterIncrement();
719 heap_close(relation, RowExclusiveLock);
723 ExecGrant_Database(InternalGrant *istmt)
728 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
729 istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
731 relation = heap_open(DatabaseRelationId, RowExclusiveLock);
733 foreach(cell, istmt->objects)
735 Oid datId = lfirst_oid(cell);
736 Form_pg_database pg_database_tuple;
739 AclMode avail_goptions;
740 AclMode this_privileges;
746 Datum values[Natts_pg_database];
747 char nulls[Natts_pg_database];
748 char replaces[Natts_pg_database];
755 tuple = SearchSysCache(DATABASEOID,
756 ObjectIdGetDatum(datId),
758 if (!HeapTupleIsValid(tuple))
759 elog(ERROR, "cache lookup failed for database %u", datId);
761 pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
764 * Get owner ID and working copy of existing ACL. If there's no ACL,
765 * substitute the proper default.
767 ownerId = pg_database_tuple->datdba;
768 aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
769 RelationGetDescr(relation), &isNull);
771 old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
773 old_acl = DatumGetAclPCopy(aclDatum);
775 /* Determine ID to do the grant as, and available grant options */
776 select_best_grantor(GetUserId(), istmt->privileges,
778 &grantorId, &avail_goptions);
781 * Restrict the privileges to what we can actually grant, and emit the
782 * standards-mandated warning and error messages.
785 restrict_and_check_grant(istmt->is_grant, avail_goptions,
786 istmt->all_privs, istmt->privileges,
787 datId, grantorId, ACL_KIND_DATABASE,
788 NameStr(pg_database_tuple->datname));
793 * We need the members of both old and new ACLs so we can correct the
794 * shared dependency information.
796 noldmembers = aclmembers(old_acl, &oldmembers);
798 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
799 istmt->grant_option, istmt->behavior,
800 istmt->grantees, this_privileges,
803 nnewmembers = aclmembers(new_acl, &newmembers);
805 /* finished building new ACL value, now insert it */
806 MemSet(values, 0, sizeof(values));
807 MemSet(nulls, ' ', sizeof(nulls));
808 MemSet(replaces, ' ', sizeof(replaces));
810 replaces[Anum_pg_database_datacl - 1] = 'r';
811 values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
813 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
816 simple_heap_update(relation, &newtuple->t_self, newtuple);
818 /* keep the catalog indexes up to date */
819 CatalogUpdateIndexes(relation, newtuple);
821 /* Update the shared dependency ACL info */
822 updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
823 ownerId, istmt->is_grant,
824 noldmembers, oldmembers,
825 nnewmembers, newmembers);
827 ReleaseSysCache(tuple);
831 /* prevent error when processing duplicate objects */
832 CommandCounterIncrement();
835 heap_close(relation, RowExclusiveLock);
839 ExecGrant_Function(InternalGrant *istmt)
844 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
845 istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
847 relation = heap_open(ProcedureRelationId, RowExclusiveLock);
849 foreach(cell, istmt->objects)
851 Oid funcId = lfirst_oid(cell);
852 Form_pg_proc pg_proc_tuple;
855 AclMode avail_goptions;
856 AclMode this_privileges;
863 Datum values[Natts_pg_proc];
864 char nulls[Natts_pg_proc];
865 char replaces[Natts_pg_proc];
871 tuple = SearchSysCache(PROCOID,
872 ObjectIdGetDatum(funcId),
874 if (!HeapTupleIsValid(tuple))
875 elog(ERROR, "cache lookup failed for function %u", funcId);
877 pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
880 * Get owner ID and working copy of existing ACL. If there's no ACL,
881 * substitute the proper default.
883 ownerId = pg_proc_tuple->proowner;
884 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
887 old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
889 old_acl = DatumGetAclPCopy(aclDatum);
891 /* Determine ID to do the grant as, and available grant options */
892 select_best_grantor(GetUserId(), istmt->privileges,
894 &grantorId, &avail_goptions);
897 * Restrict the privileges to what we can actually grant, and emit the
898 * standards-mandated warning and error messages.
901 restrict_and_check_grant(istmt->is_grant, avail_goptions,
902 istmt->all_privs, istmt->privileges,
903 funcId, grantorId, ACL_KIND_PROC,
904 NameStr(pg_proc_tuple->proname));
909 * We need the members of both old and new ACLs so we can correct the
910 * shared dependency information.
912 noldmembers = aclmembers(old_acl, &oldmembers);
914 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
915 istmt->grant_option, istmt->behavior,
916 istmt->grantees, this_privileges,
919 nnewmembers = aclmembers(new_acl, &newmembers);
921 /* finished building new ACL value, now insert it */
922 MemSet(values, 0, sizeof(values));
923 MemSet(nulls, ' ', sizeof(nulls));
924 MemSet(replaces, ' ', sizeof(replaces));
926 replaces[Anum_pg_proc_proacl - 1] = 'r';
927 values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
929 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
932 simple_heap_update(relation, &newtuple->t_self, newtuple);
934 /* keep the catalog indexes up to date */
935 CatalogUpdateIndexes(relation, newtuple);
937 /* Update the shared dependency ACL info */
938 updateAclDependencies(ProcedureRelationId, funcId,
939 ownerId, istmt->is_grant,
940 noldmembers, oldmembers,
941 nnewmembers, newmembers);
943 ReleaseSysCache(tuple);
947 /* prevent error when processing duplicate objects */
948 CommandCounterIncrement();
951 heap_close(relation, RowExclusiveLock);
955 ExecGrant_Language(InternalGrant *istmt)
960 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
961 istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
963 relation = heap_open(LanguageRelationId, RowExclusiveLock);
965 foreach(cell, istmt->objects)
967 Oid langId = lfirst_oid(cell);
968 Form_pg_language pg_language_tuple;
971 AclMode avail_goptions;
972 AclMode this_privileges;
979 Datum values[Natts_pg_language];
980 char nulls[Natts_pg_language];
981 char replaces[Natts_pg_language];
987 tuple = SearchSysCache(LANGOID,
988 ObjectIdGetDatum(langId),
990 if (!HeapTupleIsValid(tuple))
991 elog(ERROR, "cache lookup failed for language %u", langId);
993 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
995 if (!pg_language_tuple->lanpltrusted)
997 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
998 errmsg("language \"%s\" is not trusted",
999 NameStr(pg_language_tuple->lanname)),
1000 errhint("Only superusers may use untrusted languages.")));
1003 * Get owner ID and working copy of existing ACL. If there's no ACL,
1004 * substitute the proper default.
1006 * Note: for now, languages are treated as owned by the bootstrap
1007 * user. We should add an owner column to pg_language instead.
1009 ownerId = BOOTSTRAP_SUPERUSERID;
1010 aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
1013 old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
1015 old_acl = DatumGetAclPCopy(aclDatum);
1017 /* Determine ID to do the grant as, and available grant options */
1018 select_best_grantor(GetUserId(), istmt->privileges,
1020 &grantorId, &avail_goptions);
1023 * Restrict the privileges to what we can actually grant, and emit the
1024 * standards-mandated warning and error messages.
1027 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1028 istmt->all_privs, istmt->privileges,
1029 langId, grantorId, ACL_KIND_LANGUAGE,
1030 NameStr(pg_language_tuple->lanname));
1035 * We need the members of both old and new ACLs so we can correct the
1036 * shared dependency information.
1038 noldmembers = aclmembers(old_acl, &oldmembers);
1040 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1041 istmt->grant_option, istmt->behavior,
1042 istmt->grantees, this_privileges,
1043 grantorId, ownerId);
1045 nnewmembers = aclmembers(new_acl, &newmembers);
1047 /* finished building new ACL value, now insert it */
1048 MemSet(values, 0, sizeof(values));
1049 MemSet(nulls, ' ', sizeof(nulls));
1050 MemSet(replaces, ' ', sizeof(replaces));
1052 replaces[Anum_pg_language_lanacl - 1] = 'r';
1053 values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
1055 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
1058 simple_heap_update(relation, &newtuple->t_self, newtuple);
1060 /* keep the catalog indexes up to date */
1061 CatalogUpdateIndexes(relation, newtuple);
1063 /* Update the shared dependency ACL info */
1064 updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
1065 ownerId, istmt->is_grant,
1066 noldmembers, oldmembers,
1067 nnewmembers, newmembers);
1069 ReleaseSysCache(tuple);
1073 /* prevent error when processing duplicate objects */
1074 CommandCounterIncrement();
1077 heap_close(relation, RowExclusiveLock);
1081 ExecGrant_Namespace(InternalGrant *istmt)
1086 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1087 istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE;
1089 relation = heap_open(NamespaceRelationId, RowExclusiveLock);
1091 foreach(cell, istmt->objects)
1093 Oid nspid = lfirst_oid(cell);
1094 Form_pg_namespace pg_namespace_tuple;
1097 AclMode avail_goptions;
1098 AclMode this_privileges;
1105 Datum values[Natts_pg_namespace];
1106 char nulls[Natts_pg_namespace];
1107 char replaces[Natts_pg_namespace];
1113 tuple = SearchSysCache(NAMESPACEOID,
1114 ObjectIdGetDatum(nspid),
1116 if (!HeapTupleIsValid(tuple))
1117 elog(ERROR, "cache lookup failed for namespace %u", nspid);
1119 pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
1122 * Get owner ID and working copy of existing ACL. If there's no ACL,
1123 * substitute the proper default.
1125 ownerId = pg_namespace_tuple->nspowner;
1126 aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
1127 Anum_pg_namespace_nspacl,
1130 old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
1132 old_acl = DatumGetAclPCopy(aclDatum);
1134 /* Determine ID to do the grant as, and available grant options */
1135 select_best_grantor(GetUserId(), istmt->privileges,
1137 &grantorId, &avail_goptions);
1140 * Restrict the privileges to what we can actually grant, and emit the
1141 * standards-mandated warning and error messages.
1144 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1145 istmt->all_privs, istmt->privileges,
1146 nspid, grantorId, ACL_KIND_NAMESPACE,
1147 NameStr(pg_namespace_tuple->nspname));
1152 * We need the members of both old and new ACLs so we can correct the
1153 * shared dependency information.
1155 noldmembers = aclmembers(old_acl, &oldmembers);
1157 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1158 istmt->grant_option, istmt->behavior,
1159 istmt->grantees, this_privileges,
1160 grantorId, ownerId);
1162 nnewmembers = aclmembers(new_acl, &newmembers);
1164 /* finished building new ACL value, now insert it */
1165 MemSet(values, 0, sizeof(values));
1166 MemSet(nulls, ' ', sizeof(nulls));
1167 MemSet(replaces, ' ', sizeof(replaces));
1169 replaces[Anum_pg_namespace_nspacl - 1] = 'r';
1170 values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
1172 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
1175 simple_heap_update(relation, &newtuple->t_self, newtuple);
1177 /* keep the catalog indexes up to date */
1178 CatalogUpdateIndexes(relation, newtuple);
1180 /* Update the shared dependency ACL info */
1181 updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
1182 ownerId, istmt->is_grant,
1183 noldmembers, oldmembers,
1184 nnewmembers, newmembers);
1186 ReleaseSysCache(tuple);
1190 /* prevent error when processing duplicate objects */
1191 CommandCounterIncrement();
1194 heap_close(relation, RowExclusiveLock);
1198 ExecGrant_Tablespace(InternalGrant *istmt)
1203 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1204 istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
1206 relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
1208 foreach(cell, istmt->objects)
1210 Oid tblId = lfirst_oid(cell);
1211 Form_pg_tablespace pg_tablespace_tuple;
1214 AclMode avail_goptions;
1215 AclMode this_privileges;
1221 Datum values[Natts_pg_tablespace];
1222 char nulls[Natts_pg_tablespace];
1223 char replaces[Natts_pg_tablespace];
1228 ScanKeyData entry[1];
1232 /* There's no syscache for pg_tablespace, so must look the hard way */
1233 ScanKeyInit(&entry[0],
1234 ObjectIdAttributeNumber,
1235 BTEqualStrategyNumber, F_OIDEQ,
1236 ObjectIdGetDatum(tblId));
1237 scan = systable_beginscan(relation, TablespaceOidIndexId, true,
1238 SnapshotNow, 1, entry);
1239 tuple = systable_getnext(scan);
1240 if (!HeapTupleIsValid(tuple))
1241 elog(ERROR, "cache lookup failed for tablespace %u", tblId);
1243 pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
1246 * Get owner ID and working copy of existing ACL. If there's no ACL,
1247 * substitute the proper default.
1249 ownerId = pg_tablespace_tuple->spcowner;
1250 aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
1251 RelationGetDescr(relation), &isNull);
1253 old_acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
1255 old_acl = DatumGetAclPCopy(aclDatum);
1257 /* Determine ID to do the grant as, and available grant options */
1258 select_best_grantor(GetUserId(), istmt->privileges,
1260 &grantorId, &avail_goptions);
1263 * Restrict the privileges to what we can actually grant, and emit the
1264 * standards-mandated warning and error messages.
1267 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1268 istmt->all_privs, istmt->privileges,
1269 tblId, grantorId, ACL_KIND_TABLESPACE,
1270 NameStr(pg_tablespace_tuple->spcname));
1275 * We need the members of both old and new ACLs so we can correct the
1276 * shared dependency information.
1278 noldmembers = aclmembers(old_acl, &oldmembers);
1280 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1281 istmt->grant_option, istmt->behavior,
1282 istmt->grantees, this_privileges,
1283 grantorId, ownerId);
1285 nnewmembers = aclmembers(new_acl, &newmembers);
1287 /* finished building new ACL value, now insert it */
1288 MemSet(values, 0, sizeof(values));
1289 MemSet(nulls, ' ', sizeof(nulls));
1290 MemSet(replaces, ' ', sizeof(replaces));
1292 replaces[Anum_pg_tablespace_spcacl - 1] = 'r';
1293 values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
1295 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
1298 simple_heap_update(relation, &newtuple->t_self, newtuple);
1300 /* keep the catalog indexes up to date */
1301 CatalogUpdateIndexes(relation, newtuple);
1303 /* Update the shared dependency ACL info */
1304 updateAclDependencies(TableSpaceRelationId, tblId,
1305 ownerId, istmt->is_grant,
1306 noldmembers, oldmembers,
1307 nnewmembers, newmembers);
1309 systable_endscan(scan);
1313 /* prevent error when processing duplicate objects */
1314 CommandCounterIncrement();
1317 heap_close(relation, RowExclusiveLock);
1322 string_to_privilege(const char *privname)
1324 if (strcmp(privname, "insert") == 0)
1326 if (strcmp(privname, "select") == 0)
1328 if (strcmp(privname, "update") == 0)
1330 if (strcmp(privname, "delete") == 0)
1332 if (strcmp(privname, "references") == 0)
1333 return ACL_REFERENCES;
1334 if (strcmp(privname, "trigger") == 0)
1336 if (strcmp(privname, "execute") == 0)
1338 if (strcmp(privname, "usage") == 0)
1340 if (strcmp(privname, "create") == 0)
1342 if (strcmp(privname, "temporary") == 0)
1343 return ACL_CREATE_TEMP;
1344 if (strcmp(privname, "temp") == 0)
1345 return ACL_CREATE_TEMP;
1346 if (strcmp(privname, "connect") == 0)
1348 if (strcmp(privname, "rule") == 0)
1349 return 0; /* ignore old RULE privileges */
1351 (errcode(ERRCODE_SYNTAX_ERROR),
1352 errmsg("unrecognized privilege type \"%s\"", privname)));
1353 return 0; /* appease compiler */
1357 privilege_to_string(AclMode privilege)
1369 case ACL_REFERENCES:
1370 return "REFERENCES";
1379 case ACL_CREATE_TEMP:
1384 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
1386 return NULL; /* appease compiler */
1390 * Standardized reporting of aclcheck permissions failures.
1392 * Note: we do not double-quote the %s's below, because many callers
1393 * supply strings that might be already quoted.
1396 static const char *const no_priv_msg[MAX_ACL_KIND] =
1398 /* ACL_KIND_CLASS */
1399 gettext_noop("permission denied for relation %s"),
1400 /* ACL_KIND_SEQUENCE */
1401 gettext_noop("permission denied for sequence %s"),
1402 /* ACL_KIND_DATABASE */
1403 gettext_noop("permission denied for database %s"),
1405 gettext_noop("permission denied for function %s"),
1407 gettext_noop("permission denied for operator %s"),
1409 gettext_noop("permission denied for type %s"),
1410 /* ACL_KIND_LANGUAGE */
1411 gettext_noop("permission denied for language %s"),
1412 /* ACL_KIND_NAMESPACE */
1413 gettext_noop("permission denied for schema %s"),
1414 /* ACL_KIND_OPCLASS */
1415 gettext_noop("permission denied for operator class %s"),
1416 /* ACL_KIND_CONVERSION */
1417 gettext_noop("permission denied for conversion %s"),
1418 /* ACL_KIND_TABLESPACE */
1419 gettext_noop("permission denied for tablespace %s")
1422 static const char *const not_owner_msg[MAX_ACL_KIND] =
1424 /* ACL_KIND_CLASS */
1425 gettext_noop("must be owner of relation %s"),
1426 /* ACL_KIND_SEQUENCE */
1427 gettext_noop("must be owner of sequence %s"),
1428 /* ACL_KIND_DATABASE */
1429 gettext_noop("must be owner of database %s"),
1431 gettext_noop("must be owner of function %s"),
1433 gettext_noop("must be owner of operator %s"),
1435 gettext_noop("must be owner of type %s"),
1436 /* ACL_KIND_LANGUAGE */
1437 gettext_noop("must be owner of language %s"),
1438 /* ACL_KIND_NAMESPACE */
1439 gettext_noop("must be owner of schema %s"),
1440 /* ACL_KIND_OPCLASS */
1441 gettext_noop("must be owner of operator class %s"),
1442 /* ACL_KIND_CONVERSION */
1443 gettext_noop("must be owner of conversion %s"),
1444 /* ACL_KIND_TABLESPACE */
1445 gettext_noop("must be owner of tablespace %s")
1450 aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
1451 const char *objectname)
1456 /* no error, so return to caller */
1458 case ACLCHECK_NO_PRIV:
1460 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1461 errmsg(no_priv_msg[objectkind], objectname)));
1463 case ACLCHECK_NOT_OWNER:
1465 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1466 errmsg(not_owner_msg[objectkind], objectname)));
1469 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
1475 /* Check if given user has rolcatupdate privilege according to pg_authid */
1477 has_rolcatupdate(Oid roleid)
1482 tuple = SearchSysCache(AUTHOID,
1483 ObjectIdGetDatum(roleid),
1485 if (!HeapTupleIsValid(tuple))
1487 (errcode(ERRCODE_UNDEFINED_OBJECT),
1488 errmsg("role with OID %u does not exist", roleid)));
1490 rolcatupdate = ((Form_pg_authid) GETSTRUCT(tuple))->rolcatupdate;
1492 ReleaseSysCache(tuple);
1494 return rolcatupdate;
1498 * Relay for the various pg_*_mask routines depending on object kind
1501 pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid,
1502 AclMode mask, AclMaskHow how)
1506 case ACL_KIND_CLASS:
1507 case ACL_KIND_SEQUENCE:
1508 return pg_class_aclmask(table_oid, roleid, mask, how);
1509 case ACL_KIND_DATABASE:
1510 return pg_database_aclmask(table_oid, roleid, mask, how);
1512 return pg_proc_aclmask(table_oid, roleid, mask, how);
1513 case ACL_KIND_LANGUAGE:
1514 return pg_language_aclmask(table_oid, roleid, mask, how);
1515 case ACL_KIND_NAMESPACE:
1516 return pg_namespace_aclmask(table_oid, roleid, mask, how);
1517 case ACL_KIND_TABLESPACE:
1518 return pg_tablespace_aclmask(table_oid, roleid, mask, how);
1520 elog(ERROR, "unrecognized objkind: %d",
1522 /* not reached, but keep compiler quiet */
1523 return ACL_NO_RIGHTS;
1528 * Exported routine for examining a user's privileges for a table
1530 * See aclmask() for a description of the API.
1532 * Note: we give lookup failure the full ereport treatment because the
1533 * has_table_privilege() family of functions allow users to pass
1534 * any random OID to this function. Likewise for the sibling functions
1538 pg_class_aclmask(Oid table_oid, Oid roleid,
1539 AclMode mask, AclMaskHow how)
1543 Form_pg_class classForm;
1550 * Must get the relation's tuple from pg_class
1552 tuple = SearchSysCache(RELOID,
1553 ObjectIdGetDatum(table_oid),
1555 if (!HeapTupleIsValid(tuple))
1557 (errcode(ERRCODE_UNDEFINED_TABLE),
1558 errmsg("relation with OID %u does not exist",
1560 classForm = (Form_pg_class) GETSTRUCT(tuple);
1563 * Deny anyone permission to update a system catalog unless
1564 * pg_authid.rolcatupdate is set. (This is to let superusers protect
1565 * themselves from themselves.) Also allow it if allowSystemTableMods.
1567 * As of 7.4 we have some updatable system views; those shouldn't be
1568 * protected in this way. Assume the view rules can take care of
1569 * themselves. ACL_USAGE is if we ever have system sequences.
1571 if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_USAGE)) &&
1572 IsSystemClass(classForm) &&
1573 classForm->relkind != RELKIND_VIEW &&
1574 !has_rolcatupdate(roleid) &&
1575 !allowSystemTableMods)
1578 elog(DEBUG2, "permission denied for system catalog update");
1580 mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_USAGE);
1584 * Otherwise, superusers bypass all permission-checking.
1586 if (superuser_arg(roleid))
1589 elog(DEBUG2, "OID %u is superuser, home free", roleid);
1591 ReleaseSysCache(tuple);
1596 * Normal case: get the relation's ACL from pg_class
1598 ownerId = classForm->relowner;
1600 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1604 /* No ACL, so build default ACL */
1605 acl = acldefault(classForm->relkind == RELKIND_SEQUENCE ?
1606 ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION,
1608 aclDatum = (Datum) 0;
1612 /* detoast rel's ACL if necessary */
1613 acl = DatumGetAclP(aclDatum);
1616 result = aclmask(acl, roleid, ownerId, mask, how);
1618 /* if we have a detoasted copy, free it */
1619 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1622 ReleaseSysCache(tuple);
1628 * Exported routine for examining a user's privileges for a database
1631 pg_database_aclmask(Oid db_oid, Oid roleid,
1632 AclMode mask, AclMaskHow how)
1641 /* Superusers bypass all permission checking. */
1642 if (superuser_arg(roleid))
1646 * Get the database's ACL from pg_database
1648 tuple = SearchSysCache(DATABASEOID,
1649 ObjectIdGetDatum(db_oid),
1651 if (!HeapTupleIsValid(tuple))
1653 (errcode(ERRCODE_UNDEFINED_DATABASE),
1654 errmsg("database with OID %u does not exist", db_oid)));
1656 ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
1658 aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl,
1662 /* No ACL, so build default ACL */
1663 acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
1664 aclDatum = (Datum) 0;
1668 /* detoast ACL if necessary */
1669 acl = DatumGetAclP(aclDatum);
1672 result = aclmask(acl, roleid, ownerId, mask, how);
1674 /* if we have a detoasted copy, free it */
1675 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1678 ReleaseSysCache(tuple);
1684 * Exported routine for examining a user's privileges for a function
1687 pg_proc_aclmask(Oid proc_oid, Oid roleid,
1688 AclMode mask, AclMaskHow how)
1697 /* Superusers bypass all permission checking. */
1698 if (superuser_arg(roleid))
1702 * Get the function's ACL from pg_proc
1704 tuple = SearchSysCache(PROCOID,
1705 ObjectIdGetDatum(proc_oid),
1707 if (!HeapTupleIsValid(tuple))
1709 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1710 errmsg("function with OID %u does not exist", proc_oid)));
1712 ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
1714 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
1718 /* No ACL, so build default ACL */
1719 acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
1720 aclDatum = (Datum) 0;
1724 /* detoast ACL if necessary */
1725 acl = DatumGetAclP(aclDatum);
1728 result = aclmask(acl, roleid, ownerId, mask, how);
1730 /* if we have a detoasted copy, free it */
1731 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1734 ReleaseSysCache(tuple);
1740 * Exported routine for examining a user's privileges for a language
1743 pg_language_aclmask(Oid lang_oid, Oid roleid,
1744 AclMode mask, AclMaskHow how)
1753 /* Superusers bypass all permission checking. */
1754 if (superuser_arg(roleid))
1758 * Get the language's ACL from pg_language
1760 tuple = SearchSysCache(LANGOID,
1761 ObjectIdGetDatum(lang_oid),
1763 if (!HeapTupleIsValid(tuple))
1765 (errcode(ERRCODE_UNDEFINED_OBJECT),
1766 errmsg("language with OID %u does not exist", lang_oid)));
1768 /* XXX pg_language should have an owner column, but doesn't */
1769 ownerId = BOOTSTRAP_SUPERUSERID;
1771 aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
1775 /* No ACL, so build default ACL */
1776 acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
1777 aclDatum = (Datum) 0;
1781 /* detoast ACL if necessary */
1782 acl = DatumGetAclP(aclDatum);
1785 result = aclmask(acl, roleid, ownerId, mask, how);
1787 /* if we have a detoasted copy, free it */
1788 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1791 ReleaseSysCache(tuple);
1797 * Exported routine for examining a user's privileges for a namespace
1800 pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
1801 AclMode mask, AclMaskHow how)
1810 /* Superusers bypass all permission checking. */
1811 if (superuser_arg(roleid))
1815 * If we have been assigned this namespace as a temp namespace, check to
1816 * make sure we have CREATE TEMP permission on the database, and if so act
1817 * as though we have all standard (but not GRANT OPTION) permissions on
1818 * the namespace. If we don't have CREATE TEMP, act as though we have
1819 * only USAGE (and not CREATE) rights.
1821 * This may seem redundant given the check in InitTempTableNamespace, but
1822 * it really isn't since current user ID may have changed since then. The
1823 * upshot of this behavior is that a SECURITY DEFINER function can create
1824 * temp tables that can then be accessed (if permission is granted) by
1825 * code in the same session that doesn't have permissions to create temp
1828 * XXX Would it be safe to ereport a special error message as
1829 * InitTempTableNamespace does? Returning zero here means we'll get a
1830 * generic "permission denied for schema pg_temp_N" message, which is not
1831 * remarkably user-friendly.
1833 if (isTempNamespace(nsp_oid))
1835 if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
1836 ACL_CREATE_TEMP) == ACLCHECK_OK)
1837 return mask & ACL_ALL_RIGHTS_NAMESPACE;
1839 return mask & ACL_USAGE;
1843 * Get the schema's ACL from pg_namespace
1845 tuple = SearchSysCache(NAMESPACEOID,
1846 ObjectIdGetDatum(nsp_oid),
1848 if (!HeapTupleIsValid(tuple))
1850 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1851 errmsg("schema with OID %u does not exist", nsp_oid)));
1853 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
1855 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
1859 /* No ACL, so build default ACL */
1860 acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
1861 aclDatum = (Datum) 0;
1865 /* detoast ACL if necessary */
1866 acl = DatumGetAclP(aclDatum);
1869 result = aclmask(acl, roleid, ownerId, mask, how);
1871 /* if we have a detoasted copy, free it */
1872 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1875 ReleaseSysCache(tuple);
1881 * Exported routine for examining a user's privileges for a tablespace
1884 pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
1885 AclMode mask, AclMaskHow how)
1888 Relation pg_tablespace;
1889 ScanKeyData entry[1];
1898 * Only shared relations can be stored in global space; don't let even
1899 * superusers override this
1901 if (spc_oid == GLOBALTABLESPACE_OID && !IsBootstrapProcessingMode())
1904 /* Otherwise, superusers bypass all permission checking. */
1905 if (superuser_arg(roleid))
1909 * Get the tablespace's ACL from pg_tablespace
1911 * There's no syscache for pg_tablespace, so must look the hard way
1913 pg_tablespace = heap_open(TableSpaceRelationId, AccessShareLock);
1914 ScanKeyInit(&entry[0],
1915 ObjectIdAttributeNumber,
1916 BTEqualStrategyNumber, F_OIDEQ,
1917 ObjectIdGetDatum(spc_oid));
1918 scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
1919 SnapshotNow, 1, entry);
1920 tuple = systable_getnext(scan);
1921 if (!HeapTupleIsValid(tuple))
1923 (errcode(ERRCODE_UNDEFINED_OBJECT),
1924 errmsg("tablespace with OID %u does not exist", spc_oid)));
1926 ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
1928 aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
1929 RelationGetDescr(pg_tablespace), &isNull);
1933 /* No ACL, so build default ACL */
1934 acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
1935 aclDatum = (Datum) 0;
1939 /* detoast ACL if necessary */
1940 acl = DatumGetAclP(aclDatum);
1943 result = aclmask(acl, roleid, ownerId, mask, how);
1945 /* if we have a detoasted copy, free it */
1946 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1949 systable_endscan(scan);
1950 heap_close(pg_tablespace, AccessShareLock);
1957 * Exported routine for checking a user's access privileges to a table
1959 * Returns ACLCHECK_OK if the user has any of the privileges identified by
1960 * 'mode'; otherwise returns a suitable error code (in practice, always
1961 * ACLCHECK_NO_PRIV).
1964 pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
1966 if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY) != 0)
1969 return ACLCHECK_NO_PRIV;
1973 * Exported routine for checking a user's access privileges to a database
1976 pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
1978 if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
1981 return ACLCHECK_NO_PRIV;
1985 * Exported routine for checking a user's access privileges to a function
1988 pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
1990 if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
1993 return ACLCHECK_NO_PRIV;
1997 * Exported routine for checking a user's access privileges to a language
2000 pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode)
2002 if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0)
2005 return ACLCHECK_NO_PRIV;
2009 * Exported routine for checking a user's access privileges to a namespace
2012 pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
2014 if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
2017 return ACLCHECK_NO_PRIV;
2021 * Exported routine for checking a user's access privileges to a tablespace
2024 pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
2026 if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0)
2029 return ACLCHECK_NO_PRIV;
2034 * Ownership check for a relation (specified by OID).
2037 pg_class_ownercheck(Oid class_oid, Oid roleid)
2042 /* Superusers bypass all permission checking. */
2043 if (superuser_arg(roleid))
2046 tuple = SearchSysCache(RELOID,
2047 ObjectIdGetDatum(class_oid),
2049 if (!HeapTupleIsValid(tuple))
2051 (errcode(ERRCODE_UNDEFINED_TABLE),
2052 errmsg("relation with OID %u does not exist", class_oid)));
2054 ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
2056 ReleaseSysCache(tuple);
2058 return has_privs_of_role(roleid, ownerId);
2062 * Ownership check for a type (specified by OID).
2065 pg_type_ownercheck(Oid type_oid, Oid roleid)
2070 /* Superusers bypass all permission checking. */
2071 if (superuser_arg(roleid))
2074 tuple = SearchSysCache(TYPEOID,
2075 ObjectIdGetDatum(type_oid),
2077 if (!HeapTupleIsValid(tuple))
2079 (errcode(ERRCODE_UNDEFINED_OBJECT),
2080 errmsg("type with OID %u does not exist", type_oid)));
2082 ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
2084 ReleaseSysCache(tuple);
2086 return has_privs_of_role(roleid, ownerId);
2090 * Ownership check for an operator (specified by OID).
2093 pg_oper_ownercheck(Oid oper_oid, Oid roleid)
2098 /* Superusers bypass all permission checking. */
2099 if (superuser_arg(roleid))
2102 tuple = SearchSysCache(OPEROID,
2103 ObjectIdGetDatum(oper_oid),
2105 if (!HeapTupleIsValid(tuple))
2107 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2108 errmsg("operator with OID %u does not exist", oper_oid)));
2110 ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
2112 ReleaseSysCache(tuple);
2114 return has_privs_of_role(roleid, ownerId);
2118 * Ownership check for a function (specified by OID).
2121 pg_proc_ownercheck(Oid proc_oid, Oid roleid)
2126 /* Superusers bypass all permission checking. */
2127 if (superuser_arg(roleid))
2130 tuple = SearchSysCache(PROCOID,
2131 ObjectIdGetDatum(proc_oid),
2133 if (!HeapTupleIsValid(tuple))
2135 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2136 errmsg("function with OID %u does not exist", proc_oid)));
2138 ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
2140 ReleaseSysCache(tuple);
2142 return has_privs_of_role(roleid, ownerId);
2146 * Ownership check for a namespace (specified by OID).
2149 pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
2154 /* Superusers bypass all permission checking. */
2155 if (superuser_arg(roleid))
2158 tuple = SearchSysCache(NAMESPACEOID,
2159 ObjectIdGetDatum(nsp_oid),
2161 if (!HeapTupleIsValid(tuple))
2163 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2164 errmsg("schema with OID %u does not exist", nsp_oid)));
2166 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
2168 ReleaseSysCache(tuple);
2170 return has_privs_of_role(roleid, ownerId);
2174 * Ownership check for a tablespace (specified by OID).
2177 pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
2179 Relation pg_tablespace;
2180 ScanKeyData entry[1];
2185 /* Superusers bypass all permission checking. */
2186 if (superuser_arg(roleid))
2189 /* There's no syscache for pg_tablespace, so must look the hard way */
2190 pg_tablespace = heap_open(TableSpaceRelationId, AccessShareLock);
2191 ScanKeyInit(&entry[0],
2192 ObjectIdAttributeNumber,
2193 BTEqualStrategyNumber, F_OIDEQ,
2194 ObjectIdGetDatum(spc_oid));
2195 scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
2196 SnapshotNow, 1, entry);
2198 spctuple = systable_getnext(scan);
2200 if (!HeapTupleIsValid(spctuple))
2202 (errcode(ERRCODE_UNDEFINED_OBJECT),
2203 errmsg("tablespace with OID %u does not exist", spc_oid)));
2205 spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
2207 systable_endscan(scan);
2208 heap_close(pg_tablespace, AccessShareLock);
2210 return has_privs_of_role(roleid, spcowner);
2214 * Ownership check for an operator class (specified by OID).
2217 pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
2222 /* Superusers bypass all permission checking. */
2223 if (superuser_arg(roleid))
2226 tuple = SearchSysCache(CLAOID,
2227 ObjectIdGetDatum(opc_oid),
2229 if (!HeapTupleIsValid(tuple))
2231 (errcode(ERRCODE_UNDEFINED_OBJECT),
2232 errmsg("operator class with OID %u does not exist",
2235 ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
2237 ReleaseSysCache(tuple);
2239 return has_privs_of_role(roleid, ownerId);
2243 * Ownership check for a database (specified by OID).
2246 pg_database_ownercheck(Oid db_oid, Oid roleid)
2251 /* Superusers bypass all permission checking. */
2252 if (superuser_arg(roleid))
2255 tuple = SearchSysCache(DATABASEOID,
2256 ObjectIdGetDatum(db_oid),
2258 if (!HeapTupleIsValid(tuple))
2260 (errcode(ERRCODE_UNDEFINED_DATABASE),
2261 errmsg("database with OID %u does not exist", db_oid)));
2263 dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
2265 ReleaseSysCache(tuple);
2267 return has_privs_of_role(roleid, dba);
2271 * Ownership check for a conversion (specified by OID).
2274 pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
2279 /* Superusers bypass all permission checking. */
2280 if (superuser_arg(roleid))
2283 tuple = SearchSysCache(CONOID,
2284 ObjectIdGetDatum(conv_oid),
2286 if (!HeapTupleIsValid(tuple))
2288 (errcode(ERRCODE_UNDEFINED_OBJECT),
2289 errmsg("conversion with OID %u does not exist", conv_oid)));
2291 ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
2293 ReleaseSysCache(tuple);
2295 return has_privs_of_role(roleid, ownerId);