1 /*-------------------------------------------------------------------------
4 * Routines to check access control permissions.
6 * Portions Copyright (c) 1996-2005, 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.112 2005/05/29 23:38:05 tgl Exp $
16 *-------------------------------------------------------------------------
20 #include "access/heapam.h"
21 #include "catalog/catalog.h"
22 #include "catalog/indexing.h"
23 #include "catalog/namespace.h"
24 #include "catalog/pg_conversion.h"
25 #include "catalog/pg_database.h"
26 #include "catalog/pg_group.h"
27 #include "catalog/pg_language.h"
28 #include "catalog/pg_namespace.h"
29 #include "catalog/pg_opclass.h"
30 #include "catalog/pg_operator.h"
31 #include "catalog/pg_proc.h"
32 #include "catalog/pg_shadow.h"
33 #include "catalog/pg_tablespace.h"
34 #include "catalog/pg_type.h"
35 #include "miscadmin.h"
36 #include "parser/parse_func.h"
37 #include "utils/acl.h"
38 #include "utils/fmgroids.h"
39 #include "utils/lsyscache.h"
40 #include "utils/syscache.h"
43 static void ExecuteGrantStmt_Relation(GrantStmt *stmt);
44 static void ExecuteGrantStmt_Database(GrantStmt *stmt);
45 static void ExecuteGrantStmt_Function(GrantStmt *stmt);
46 static void ExecuteGrantStmt_Language(GrantStmt *stmt);
47 static void ExecuteGrantStmt_Namespace(GrantStmt *stmt);
48 static void ExecuteGrantStmt_Tablespace(GrantStmt *stmt);
50 static const char *privilege_to_string(AclMode privilege);
60 elog(DEBUG2, "acl size = %d, # acls = %d",
61 ACL_SIZE(acl), ACL_NUM(acl));
63 for (i = 0; i < ACL_NUM(acl); ++i)
64 elog(DEBUG2, " acl[%d]: %s", i,
65 DatumGetCString(DirectFunctionCall1(aclitemout,
66 PointerGetDatum(aip + i))));
72 * Determine the effective grantor ID for a GRANT or REVOKE operation.
74 * Ordinarily this is just the current user, but when a superuser does
75 * GRANT or REVOKE, we pretend he is the object owner. This ensures that
76 * all granted privileges appear to flow from the object owner, and there
77 * are never multiple "original sources" of a privilege.
80 select_grantor(AclId ownerId)
84 grantorId = GetUserId();
86 /* fast path if no difference */
87 if (grantorId == ownerId)
98 * If is_grant is true, adds the given privileges for the list of
99 * grantees to the existing old_acl. If is_grant is false, the
100 * privileges for the given grantees are removed from old_acl.
102 * NB: the original old_acl is pfree'd.
105 merge_acl_with_grant(Acl *old_acl, bool is_grant,
106 bool grant_option, DropBehavior behavior,
107 List *grantees, AclMode privileges,
108 AclId grantor_uid, AclId owner_uid)
114 modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
123 PrivGrantee *grantee = (PrivGrantee *) lfirst(j);
128 if (grantee->username)
130 aclitem. ai_grantee = get_usesysid(grantee->username);
132 idtype = ACL_IDTYPE_UID;
134 else if (grantee->groupname)
136 aclitem. ai_grantee = get_grosysid(grantee->groupname);
138 idtype = ACL_IDTYPE_GID;
142 aclitem. ai_grantee = ACL_ID_WORLD;
144 idtype = ACL_IDTYPE_WORLD;
148 * Grant options can only be granted to individual users, not
149 * groups or public. The reason is that if a user would re-grant
150 * a privilege that he held through a group having a grant option,
151 * and later the user is removed from the group, the situation is
152 * impossible to clean up.
154 if (is_grant && grant_option && idtype != ACL_IDTYPE_UID)
156 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
157 errmsg("grant options can only be granted to individual users")));
159 aclitem. ai_grantor = grantor_uid;
162 * The asymmetry in the conditions here comes from the spec. In
163 * GRANT, the grant_option flag signals WITH GRANT OPTION, which
164 * means to grant both the basic privilege and its grant option.
165 * But in REVOKE, plain revoke revokes both the basic privilege
166 * and its grant option, while REVOKE GRANT OPTION revokes only
169 ACLITEM_SET_PRIVS_IDTYPE(aclitem,
170 (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
171 (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS,
174 newer_acl = aclupdate(new_acl, &aclitem, modechg, owner_uid, behavior);
176 /* avoid memory leak when there are many grantees */
190 * Called to execute the utility commands GRANT and REVOKE
193 ExecuteGrantStmt(GrantStmt *stmt)
195 switch (stmt->objtype)
197 case ACL_OBJECT_RELATION:
198 ExecuteGrantStmt_Relation(stmt);
200 case ACL_OBJECT_DATABASE:
201 ExecuteGrantStmt_Database(stmt);
203 case ACL_OBJECT_FUNCTION:
204 ExecuteGrantStmt_Function(stmt);
206 case ACL_OBJECT_LANGUAGE:
207 ExecuteGrantStmt_Language(stmt);
209 case ACL_OBJECT_NAMESPACE:
210 ExecuteGrantStmt_Namespace(stmt);
212 case ACL_OBJECT_TABLESPACE:
213 ExecuteGrantStmt_Tablespace(stmt);
216 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
217 (int) stmt->objtype);
223 ExecuteGrantStmt_Relation(GrantStmt *stmt)
229 if (linitial_int(stmt->privileges) == ACL_ALL_RIGHTS)
232 privileges = ACL_ALL_RIGHTS_RELATION;
237 privileges = ACL_NO_RIGHTS;
238 foreach(i, stmt->privileges)
240 AclMode priv = lfirst_int(i);
242 if (priv & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
244 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
245 errmsg("invalid privilege type %s for table",
246 privilege_to_string(priv))));
251 foreach(i, stmt->objects)
253 RangeVar *relvar = (RangeVar *) lfirst(i);
257 Form_pg_class pg_class_tuple;
261 AclMode this_privileges;
267 Datum values[Natts_pg_class];
268 char nulls[Natts_pg_class];
269 char replaces[Natts_pg_class];
272 relation = heap_open(RelationRelationId, RowExclusiveLock);
273 relOid = RangeVarGetRelid(relvar, false);
274 tuple = SearchSysCache(RELOID,
275 ObjectIdGetDatum(relOid),
277 if (!HeapTupleIsValid(tuple))
278 elog(ERROR, "cache lookup failed for relation %u", relOid);
279 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
281 /* Not sensible to grant on an index */
282 if (pg_class_tuple->relkind == RELKIND_INDEX)
284 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
285 errmsg("\"%s\" is an index",
288 /* Composite types aren't tables either */
289 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
291 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
292 errmsg("\"%s\" is a composite type",
295 ownerId = pg_class_tuple->relowner;
296 grantorId = select_grantor(ownerId);
299 * Must be owner or have some privilege on the object (per spec,
300 * any privilege will get you by here). The owner is always
301 * treated as having all grant options.
303 if (pg_class_ownercheck(relOid, GetUserId()))
304 my_goptions = ACL_ALL_RIGHTS_RELATION;
309 my_rights = pg_class_aclmask(relOid,
311 ACL_ALL_RIGHTS_RELATION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_RELATION),
313 if (my_rights == ACL_NO_RIGHTS)
314 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
316 my_goptions = ACL_OPTION_TO_PRIVS(my_rights);
320 * Restrict the operation to what we can actually grant or revoke,
321 * and issue a warning if appropriate. (For REVOKE this isn't
322 * quite what the spec says to do: the spec seems to want a
323 * warning only if no privilege bits actually change in the ACL.
324 * In practice that behavior seems much too noisy, as well as
325 * inconsistent with the GRANT case.)
327 this_privileges = privileges & my_goptions;
330 if (this_privileges == 0)
332 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
333 errmsg("no privileges were granted")));
334 else if (!all_privs && this_privileges != privileges)
336 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
337 errmsg("not all privileges were granted")));
341 if (this_privileges == 0)
343 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
344 errmsg("no privileges could be revoked")));
345 else if (!all_privs && this_privileges != privileges)
347 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
348 errmsg("not all privileges could be revoked")));
352 * If there's no ACL, substitute the proper default.
354 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
357 old_acl = acldefault(ACL_OBJECT_RELATION, ownerId);
359 /* get a detoasted copy of the ACL */
360 old_acl = DatumGetAclPCopy(aclDatum);
362 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
363 stmt->grant_option, stmt->behavior,
364 stmt->grantees, this_privileges,
367 /* finished building new ACL value, now insert it */
368 MemSet(values, 0, sizeof(values));
369 MemSet(nulls, ' ', sizeof(nulls));
370 MemSet(replaces, ' ', sizeof(replaces));
372 replaces[Anum_pg_class_relacl - 1] = 'r';
373 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
375 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
377 ReleaseSysCache(tuple);
379 simple_heap_update(relation, &newtuple->t_self, newtuple);
381 /* keep the catalog indexes up to date */
382 CatalogUpdateIndexes(relation, newtuple);
386 heap_close(relation, RowExclusiveLock);
391 ExecuteGrantStmt_Database(GrantStmt *stmt)
397 if (linitial_int(stmt->privileges) == ACL_ALL_RIGHTS)
400 privileges = ACL_ALL_RIGHTS_DATABASE;
405 privileges = ACL_NO_RIGHTS;
406 foreach(i, stmt->privileges)
408 AclMode priv = lfirst_int(i);
410 if (priv & ~((AclMode) ACL_ALL_RIGHTS_DATABASE))
412 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
413 errmsg("invalid privilege type %s for database",
414 privilege_to_string(priv))));
419 foreach(i, stmt->objects)
421 char *dbname = strVal(lfirst(i));
423 ScanKeyData entry[1];
426 Form_pg_database pg_database_tuple;
430 AclMode this_privileges;
436 Datum values[Natts_pg_database];
437 char nulls[Natts_pg_database];
438 char replaces[Natts_pg_database];
440 relation = heap_open(DatabaseRelationId, RowExclusiveLock);
441 ScanKeyInit(&entry[0],
442 Anum_pg_database_datname,
443 BTEqualStrategyNumber, F_NAMEEQ,
444 CStringGetDatum(dbname));
445 scan = heap_beginscan(relation, SnapshotNow, 1, entry);
446 tuple = heap_getnext(scan, ForwardScanDirection);
447 if (!HeapTupleIsValid(tuple))
449 (errcode(ERRCODE_UNDEFINED_DATABASE),
450 errmsg("database \"%s\" does not exist", dbname)));
451 pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
453 ownerId = pg_database_tuple->datdba;
454 grantorId = select_grantor(ownerId);
457 * Must be owner or have some privilege on the object (per spec,
458 * any privilege will get you by here). The owner is always
459 * treated as having all grant options.
461 if (pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
462 my_goptions = ACL_ALL_RIGHTS_DATABASE;
467 my_rights = pg_database_aclmask(HeapTupleGetOid(tuple),
469 ACL_ALL_RIGHTS_DATABASE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_DATABASE),
471 if (my_rights == ACL_NO_RIGHTS)
472 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
473 NameStr(pg_database_tuple->datname));
474 my_goptions = ACL_OPTION_TO_PRIVS(my_rights);
478 * Restrict the operation to what we can actually grant or revoke,
479 * and issue a warning if appropriate. (For REVOKE this isn't
480 * quite what the spec says to do: the spec seems to want a
481 * warning only if no privilege bits actually change in the ACL.
482 * In practice that behavior seems much too noisy, as well as
483 * inconsistent with the GRANT case.)
485 this_privileges = privileges & my_goptions;
488 if (this_privileges == 0)
490 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
491 errmsg("no privileges were granted")));
492 else if (!all_privs && this_privileges != privileges)
494 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
495 errmsg("not all privileges were granted")));
499 if (this_privileges == 0)
501 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
502 errmsg("no privileges could be revoked")));
503 else if (!all_privs && this_privileges != privileges)
505 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
506 errmsg("not all privileges could be revoked")));
510 * If there's no ACL, substitute the proper default.
512 aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
513 RelationGetDescr(relation), &isNull);
515 old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
517 /* get a detoasted copy of the ACL */
518 old_acl = DatumGetAclPCopy(aclDatum);
520 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
521 stmt->grant_option, stmt->behavior,
522 stmt->grantees, this_privileges,
525 /* finished building new ACL value, now insert it */
526 MemSet(values, 0, sizeof(values));
527 MemSet(nulls, ' ', sizeof(nulls));
528 MemSet(replaces, ' ', sizeof(replaces));
530 replaces[Anum_pg_database_datacl - 1] = 'r';
531 values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
533 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
535 simple_heap_update(relation, &newtuple->t_self, newtuple);
537 /* keep the catalog indexes up to date */
538 CatalogUpdateIndexes(relation, newtuple);
544 heap_close(relation, RowExclusiveLock);
549 ExecuteGrantStmt_Function(GrantStmt *stmt)
555 if (linitial_int(stmt->privileges) == ACL_ALL_RIGHTS)
558 privileges = ACL_ALL_RIGHTS_FUNCTION;
563 privileges = ACL_NO_RIGHTS;
564 foreach(i, stmt->privileges)
566 AclMode priv = lfirst_int(i);
568 if (priv & ~((AclMode) ACL_ALL_RIGHTS_FUNCTION))
570 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
571 errmsg("invalid privilege type %s for function",
572 privilege_to_string(priv))));
577 foreach(i, stmt->objects)
579 FuncWithArgs *func = (FuncWithArgs *) lfirst(i);
583 Form_pg_proc pg_proc_tuple;
587 AclMode this_privileges;
593 Datum values[Natts_pg_proc];
594 char nulls[Natts_pg_proc];
595 char replaces[Natts_pg_proc];
597 oid = LookupFuncNameTypeNames(func->funcname, func->funcargs, false);
599 relation = heap_open(ProcedureRelationId, RowExclusiveLock);
600 tuple = SearchSysCache(PROCOID,
601 ObjectIdGetDatum(oid),
603 if (!HeapTupleIsValid(tuple))
604 elog(ERROR, "cache lookup failed for function %u", oid);
605 pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
607 ownerId = pg_proc_tuple->proowner;
608 grantorId = select_grantor(ownerId);
611 * Must be owner or have some privilege on the object (per spec,
612 * any privilege will get you by here). The owner is always
613 * treated as having all grant options.
615 if (pg_proc_ownercheck(oid, GetUserId()))
616 my_goptions = ACL_ALL_RIGHTS_FUNCTION;
621 my_rights = pg_proc_aclmask(oid,
623 ACL_ALL_RIGHTS_FUNCTION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_FUNCTION),
625 if (my_rights == ACL_NO_RIGHTS)
626 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
627 NameStr(pg_proc_tuple->proname));
628 my_goptions = ACL_OPTION_TO_PRIVS(my_rights);
632 * Restrict the operation to what we can actually grant or revoke,
633 * and issue a warning if appropriate. (For REVOKE this isn't
634 * quite what the spec says to do: the spec seems to want a
635 * warning only if no privilege bits actually change in the ACL.
636 * In practice that behavior seems much too noisy, as well as
637 * inconsistent with the GRANT case.)
639 this_privileges = privileges & my_goptions;
642 if (this_privileges == 0)
644 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
645 errmsg("no privileges were granted")));
646 else if (!all_privs && this_privileges != privileges)
648 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
649 errmsg("not all privileges were granted")));
653 if (this_privileges == 0)
655 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
656 errmsg("no privileges could be revoked")));
657 else if (!all_privs && this_privileges != privileges)
659 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
660 errmsg("not all privileges could be revoked")));
664 * If there's no ACL, substitute the proper default.
666 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
669 old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
671 /* get a detoasted copy of the ACL */
672 old_acl = DatumGetAclPCopy(aclDatum);
674 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
675 stmt->grant_option, stmt->behavior,
676 stmt->grantees, this_privileges,
679 /* finished building new ACL value, now insert it */
680 MemSet(values, 0, sizeof(values));
681 MemSet(nulls, ' ', sizeof(nulls));
682 MemSet(replaces, ' ', sizeof(replaces));
684 replaces[Anum_pg_proc_proacl - 1] = 'r';
685 values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
687 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
689 ReleaseSysCache(tuple);
691 simple_heap_update(relation, &newtuple->t_self, newtuple);
693 /* keep the catalog indexes up to date */
694 CatalogUpdateIndexes(relation, newtuple);
698 heap_close(relation, RowExclusiveLock);
703 ExecuteGrantStmt_Language(GrantStmt *stmt)
709 if (linitial_int(stmt->privileges) == ACL_ALL_RIGHTS)
712 privileges = ACL_ALL_RIGHTS_LANGUAGE;
717 privileges = ACL_NO_RIGHTS;
718 foreach(i, stmt->privileges)
720 AclMode priv = lfirst_int(i);
722 if (priv & ~((AclMode) ACL_ALL_RIGHTS_LANGUAGE))
724 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
725 errmsg("invalid privilege type %s for language",
726 privilege_to_string(priv))));
731 foreach(i, stmt->objects)
733 char *langname = strVal(lfirst(i));
736 Form_pg_language pg_language_tuple;
740 AclMode this_privileges;
746 Datum values[Natts_pg_language];
747 char nulls[Natts_pg_language];
748 char replaces[Natts_pg_language];
750 relation = heap_open(LanguageRelationId, RowExclusiveLock);
751 tuple = SearchSysCache(LANGNAME,
752 PointerGetDatum(langname),
754 if (!HeapTupleIsValid(tuple))
756 (errcode(ERRCODE_UNDEFINED_OBJECT),
757 errmsg("language \"%s\" does not exist", langname)));
758 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
760 if (!pg_language_tuple->lanpltrusted)
762 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
763 errmsg("language \"%s\" is not trusted", langname),
764 errhint("Only superusers may use untrusted languages.")));
767 * Note: for now, languages are treated as owned by the bootstrap
768 * user. We should add an owner column to pg_language instead.
770 ownerId = BOOTSTRAP_USESYSID;
771 grantorId = select_grantor(ownerId);
774 * Must be owner or have some privilege on the object (per spec,
775 * any privilege will get you by here). The owner is always
776 * treated as having all grant options.
778 if (superuser()) /* XXX no ownercheck() available */
779 my_goptions = ACL_ALL_RIGHTS_LANGUAGE;
784 my_rights = pg_language_aclmask(HeapTupleGetOid(tuple),
786 ACL_ALL_RIGHTS_LANGUAGE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_LANGUAGE),
788 if (my_rights == ACL_NO_RIGHTS)
789 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
790 NameStr(pg_language_tuple->lanname));
791 my_goptions = ACL_OPTION_TO_PRIVS(my_rights);
795 * Restrict the operation to what we can actually grant or revoke,
796 * and issue a warning if appropriate. (For REVOKE this isn't
797 * quite what the spec says to do: the spec seems to want a
798 * warning only if no privilege bits actually change in the ACL.
799 * In practice that behavior seems much too noisy, as well as
800 * inconsistent with the GRANT case.)
802 this_privileges = privileges & my_goptions;
805 if (this_privileges == 0)
807 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
808 errmsg("no privileges were granted")));
809 else if (!all_privs && this_privileges != privileges)
811 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
812 errmsg("not all privileges were granted")));
816 if (this_privileges == 0)
818 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
819 errmsg("no privileges could be revoked")));
820 else if (!all_privs && this_privileges != privileges)
822 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
823 errmsg("not all privileges could be revoked")));
827 * If there's no ACL, substitute the proper default.
829 aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
832 old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
834 /* get a detoasted copy of the ACL */
835 old_acl = DatumGetAclPCopy(aclDatum);
837 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
838 stmt->grant_option, stmt->behavior,
839 stmt->grantees, this_privileges,
842 /* finished building new ACL value, now insert it */
843 MemSet(values, 0, sizeof(values));
844 MemSet(nulls, ' ', sizeof(nulls));
845 MemSet(replaces, ' ', sizeof(replaces));
847 replaces[Anum_pg_language_lanacl - 1] = 'r';
848 values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
850 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
852 ReleaseSysCache(tuple);
854 simple_heap_update(relation, &newtuple->t_self, newtuple);
856 /* keep the catalog indexes up to date */
857 CatalogUpdateIndexes(relation, newtuple);
861 heap_close(relation, RowExclusiveLock);
866 ExecuteGrantStmt_Namespace(GrantStmt *stmt)
872 if (linitial_int(stmt->privileges) == ACL_ALL_RIGHTS)
875 privileges = ACL_ALL_RIGHTS_NAMESPACE;
880 privileges = ACL_NO_RIGHTS;
881 foreach(i, stmt->privileges)
883 AclMode priv = lfirst_int(i);
885 if (priv & ~((AclMode) ACL_ALL_RIGHTS_NAMESPACE))
887 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
888 errmsg("invalid privilege type %s for schema",
889 privilege_to_string(priv))));
894 foreach(i, stmt->objects)
896 char *nspname = strVal(lfirst(i));
899 Form_pg_namespace pg_namespace_tuple;
903 AclMode this_privileges;
909 Datum values[Natts_pg_namespace];
910 char nulls[Natts_pg_namespace];
911 char replaces[Natts_pg_namespace];
913 relation = heap_open(NamespaceRelationId, RowExclusiveLock);
914 tuple = SearchSysCache(NAMESPACENAME,
915 CStringGetDatum(nspname),
917 if (!HeapTupleIsValid(tuple))
919 (errcode(ERRCODE_UNDEFINED_SCHEMA),
920 errmsg("schema \"%s\" does not exist", nspname)));
921 pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
923 ownerId = pg_namespace_tuple->nspowner;
924 grantorId = select_grantor(ownerId);
927 * Must be owner or have some privilege on the object (per spec,
928 * any privilege will get you by here). The owner is always
929 * treated as having all grant options.
931 if (pg_namespace_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
932 my_goptions = ACL_ALL_RIGHTS_NAMESPACE;
937 my_rights = pg_namespace_aclmask(HeapTupleGetOid(tuple),
939 ACL_ALL_RIGHTS_NAMESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_NAMESPACE),
941 if (my_rights == ACL_NO_RIGHTS)
942 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,
944 my_goptions = ACL_OPTION_TO_PRIVS(my_rights);
948 * Restrict the operation to what we can actually grant or revoke,
949 * and issue a warning if appropriate. (For REVOKE this isn't
950 * quite what the spec says to do: the spec seems to want a
951 * warning only if no privilege bits actually change in the ACL.
952 * In practice that behavior seems much too noisy, as well as
953 * inconsistent with the GRANT case.)
955 this_privileges = privileges & my_goptions;
958 if (this_privileges == 0)
960 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
961 errmsg("no privileges were granted")));
962 else if (!all_privs && this_privileges != privileges)
964 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
965 errmsg("not all privileges were granted")));
969 if (this_privileges == 0)
971 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
972 errmsg("no privileges could be revoked")));
973 else if (!all_privs && this_privileges != privileges)
975 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
976 errmsg("not all privileges could be revoked")));
980 * If there's no ACL, substitute the proper default.
982 aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
983 Anum_pg_namespace_nspacl,
986 old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
988 /* get a detoasted copy of the ACL */
989 old_acl = DatumGetAclPCopy(aclDatum);
991 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
992 stmt->grant_option, stmt->behavior,
993 stmt->grantees, this_privileges,
996 /* finished building new ACL value, now insert it */
997 MemSet(values, 0, sizeof(values));
998 MemSet(nulls, ' ', sizeof(nulls));
999 MemSet(replaces, ' ', sizeof(replaces));
1001 replaces[Anum_pg_namespace_nspacl - 1] = 'r';
1002 values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
1004 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
1006 ReleaseSysCache(tuple);
1008 simple_heap_update(relation, &newtuple->t_self, newtuple);
1010 /* keep the catalog indexes up to date */
1011 CatalogUpdateIndexes(relation, newtuple);
1015 heap_close(relation, RowExclusiveLock);
1020 ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
1026 if (linitial_int(stmt->privileges) == ACL_ALL_RIGHTS)
1029 privileges = ACL_ALL_RIGHTS_TABLESPACE;
1034 privileges = ACL_NO_RIGHTS;
1035 foreach(i, stmt->privileges)
1037 AclMode priv = lfirst_int(i);
1039 if (priv & ~((AclMode) ACL_ALL_RIGHTS_TABLESPACE))
1041 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1042 errmsg("invalid privilege type %s for tablespace",
1043 privilege_to_string(priv))));
1048 foreach(i, stmt->objects)
1050 char *spcname = strVal(lfirst(i));
1052 ScanKeyData entry[1];
1055 Form_pg_tablespace pg_tablespace_tuple;
1058 AclMode my_goptions;
1059 AclMode this_privileges;
1065 Datum values[Natts_pg_tablespace];
1066 char nulls[Natts_pg_tablespace];
1067 char replaces[Natts_pg_tablespace];
1069 relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
1070 ScanKeyInit(&entry[0],
1071 Anum_pg_tablespace_spcname,
1072 BTEqualStrategyNumber, F_NAMEEQ,
1073 CStringGetDatum(spcname));
1074 scan = heap_beginscan(relation, SnapshotNow, 1, entry);
1075 tuple = heap_getnext(scan, ForwardScanDirection);
1076 if (!HeapTupleIsValid(tuple))
1078 (errcode(ERRCODE_UNDEFINED_OBJECT),
1079 errmsg("tablespace \"%s\" does not exist", spcname)));
1080 pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
1082 ownerId = pg_tablespace_tuple->spcowner;
1083 grantorId = select_grantor(ownerId);
1086 * Must be owner or have some privilege on the object (per spec,
1087 * any privilege will get you by here). The owner is always
1088 * treated as having all grant options.
1090 if (pg_tablespace_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
1091 my_goptions = ACL_ALL_RIGHTS_TABLESPACE;
1096 my_rights = pg_tablespace_aclmask(HeapTupleGetOid(tuple),
1098 ACL_ALL_RIGHTS_TABLESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_TABLESPACE),
1100 if (my_rights == ACL_NO_RIGHTS)
1101 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
1103 my_goptions = ACL_OPTION_TO_PRIVS(my_rights);
1107 * Restrict the operation to what we can actually grant or revoke,
1108 * and issue a warning if appropriate. (For REVOKE this isn't
1109 * quite what the spec says to do: the spec seems to want a
1110 * warning only if no privilege bits actually change in the ACL.
1111 * In practice that behavior seems much too noisy, as well as
1112 * inconsistent with the GRANT case.)
1114 this_privileges = privileges & my_goptions;
1117 if (this_privileges == 0)
1119 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
1120 errmsg("no privileges were granted")));
1121 else if (!all_privs && this_privileges != privileges)
1123 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
1124 errmsg("not all privileges were granted")));
1128 if (this_privileges == 0)
1130 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
1131 errmsg("no privileges could be revoked")));
1132 else if (!all_privs && this_privileges != privileges)
1134 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
1135 errmsg("not all privileges could be revoked")));
1139 * If there's no ACL, substitute the proper default.
1141 aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
1142 RelationGetDescr(relation), &isNull);
1144 old_acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
1146 /* get a detoasted copy of the ACL */
1147 old_acl = DatumGetAclPCopy(aclDatum);
1149 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
1150 stmt->grant_option, stmt->behavior,
1151 stmt->grantees, this_privileges,
1152 grantorId, ownerId);
1154 /* finished building new ACL value, now insert it */
1155 MemSet(values, 0, sizeof(values));
1156 MemSet(nulls, ' ', sizeof(nulls));
1157 MemSet(replaces, ' ', sizeof(replaces));
1159 replaces[Anum_pg_tablespace_spcacl - 1] = 'r';
1160 values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
1162 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
1164 simple_heap_update(relation, &newtuple->t_self, newtuple);
1166 /* keep the catalog indexes up to date */
1167 CatalogUpdateIndexes(relation, newtuple);
1172 heap_close(relation, RowExclusiveLock);
1178 privilege_to_string(AclMode privilege)
1192 case ACL_REFERENCES:
1193 return "REFERENCES";
1202 case ACL_CREATE_TEMP:
1205 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
1207 return NULL; /* appease compiler */
1211 * Convert group ID to name, or return NULL if group can't be found
1214 get_groname(AclId grosysid)
1219 tuple = SearchSysCache(GROSYSID,
1220 ObjectIdGetDatum(grosysid),
1222 if (HeapTupleIsValid(tuple))
1224 name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname));
1225 ReleaseSysCache(tuple);
1232 * Standardized reporting of aclcheck permissions failures.
1234 * Note: we do not double-quote the %s's below, because many callers
1235 * supply strings that might be already quoted.
1238 static const char *const no_priv_msg[MAX_ACL_KIND] =
1240 /* ACL_KIND_CLASS */
1241 gettext_noop("permission denied for relation %s"),
1242 /* ACL_KIND_DATABASE */
1243 gettext_noop("permission denied for database %s"),
1245 gettext_noop("permission denied for function %s"),
1247 gettext_noop("permission denied for operator %s"),
1249 gettext_noop("permission denied for type %s"),
1250 /* ACL_KIND_LANGUAGE */
1251 gettext_noop("permission denied for language %s"),
1252 /* ACL_KIND_NAMESPACE */
1253 gettext_noop("permission denied for schema %s"),
1254 /* ACL_KIND_OPCLASS */
1255 gettext_noop("permission denied for operator class %s"),
1256 /* ACL_KIND_CONVERSION */
1257 gettext_noop("permission denied for conversion %s"),
1258 /* ACL_KIND_TABLESPACE */
1259 gettext_noop("permission denied for tablespace %s")
1262 static const char *const not_owner_msg[MAX_ACL_KIND] =
1264 /* ACL_KIND_CLASS */
1265 gettext_noop("must be owner of relation %s"),
1266 /* ACL_KIND_DATABASE */
1267 gettext_noop("must be owner of database %s"),
1269 gettext_noop("must be owner of function %s"),
1271 gettext_noop("must be owner of operator %s"),
1273 gettext_noop("must be owner of type %s"),
1274 /* ACL_KIND_LANGUAGE */
1275 gettext_noop("must be owner of language %s"),
1276 /* ACL_KIND_NAMESPACE */
1277 gettext_noop("must be owner of schema %s"),
1278 /* ACL_KIND_OPCLASS */
1279 gettext_noop("must be owner of operator class %s"),
1280 /* ACL_KIND_CONVERSION */
1281 gettext_noop("must be owner of conversion %s"),
1282 /* ACL_KIND_TABLESPACE */
1283 gettext_noop("must be owner of tablespace %s")
1288 aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
1289 const char *objectname)
1294 /* no error, so return to caller */
1296 case ACLCHECK_NO_PRIV:
1298 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1299 errmsg(no_priv_msg[objectkind], objectname)));
1301 case ACLCHECK_NOT_OWNER:
1303 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1304 errmsg(not_owner_msg[objectkind], objectname)));
1307 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
1313 /* Check if given userid has usecatupd privilege according to pg_shadow */
1315 has_usecatupd(AclId userid)
1320 tuple = SearchSysCache(SHADOWSYSID,
1321 ObjectIdGetDatum(userid),
1323 if (!HeapTupleIsValid(tuple))
1325 (errcode(ERRCODE_UNDEFINED_OBJECT),
1326 errmsg("user with ID %u does not exist", userid)));
1328 usecatupd = ((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd;
1330 ReleaseSysCache(tuple);
1337 * Exported routine for examining a user's privileges for a table
1339 * See aclmask() for a description of the API.
1341 * Note: we give lookup failure the full ereport treatment because the
1342 * has_table_privilege() family of functions allow users to pass
1343 * any random OID to this function. Likewise for the sibling functions
1347 pg_class_aclmask(Oid table_oid, AclId userid,
1348 AclMode mask, AclMaskHow how)
1352 Form_pg_class classForm;
1359 * Must get the relation's tuple from pg_class
1361 tuple = SearchSysCache(RELOID,
1362 ObjectIdGetDatum(table_oid),
1364 if (!HeapTupleIsValid(tuple))
1366 (errcode(ERRCODE_UNDEFINED_TABLE),
1367 errmsg("relation with OID %u does not exist",
1369 classForm = (Form_pg_class) GETSTRUCT(tuple);
1372 * Deny anyone permission to update a system catalog unless
1373 * pg_shadow.usecatupd is set. (This is to let superusers protect
1374 * themselves from themselves.) Also allow it if
1375 * allowSystemTableMods.
1377 * As of 7.4 we have some updatable system views; those shouldn't be
1378 * protected in this way. Assume the view rules can take care of
1381 if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
1382 IsSystemClass(classForm) &&
1383 classForm->relkind != RELKIND_VIEW &&
1384 !has_usecatupd(userid) &&
1385 !allowSystemTableMods)
1388 elog(DEBUG2, "permission denied for system catalog update");
1390 mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE);
1394 * Otherwise, superusers bypass all permission-checking.
1396 if (superuser_arg(userid))
1399 elog(DEBUG2, "%u is superuser, home free", userid);
1401 ReleaseSysCache(tuple);
1406 * Normal case: get the relation's ACL from pg_class
1408 ownerId = classForm->relowner;
1410 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1414 /* No ACL, so build default ACL */
1415 acl = acldefault(ACL_OBJECT_RELATION, ownerId);
1416 aclDatum = (Datum) 0;
1420 /* detoast rel's ACL if necessary */
1421 acl = DatumGetAclP(aclDatum);
1424 result = aclmask(acl, userid, ownerId, mask, how);
1426 /* if we have a detoasted copy, free it */
1427 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1430 ReleaseSysCache(tuple);
1436 * Exported routine for examining a user's privileges for a database
1439 pg_database_aclmask(Oid db_oid, AclId userid,
1440 AclMode mask, AclMaskHow how)
1443 Relation pg_database;
1444 ScanKeyData entry[1];
1452 /* Superusers bypass all permission checking. */
1453 if (superuser_arg(userid))
1457 * Get the database's ACL from pg_database
1459 * There's no syscache for pg_database, so must look the hard way
1461 pg_database = heap_open(DatabaseRelationId, AccessShareLock);
1462 ScanKeyInit(&entry[0],
1463 ObjectIdAttributeNumber,
1464 BTEqualStrategyNumber, F_OIDEQ,
1465 ObjectIdGetDatum(db_oid));
1466 scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
1467 tuple = heap_getnext(scan, ForwardScanDirection);
1468 if (!HeapTupleIsValid(tuple))
1470 (errcode(ERRCODE_UNDEFINED_DATABASE),
1471 errmsg("database with OID %u does not exist", db_oid)));
1473 ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
1475 aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
1476 RelationGetDescr(pg_database), &isNull);
1480 /* No ACL, so build default ACL */
1481 acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
1482 aclDatum = (Datum) 0;
1486 /* detoast ACL if necessary */
1487 acl = DatumGetAclP(aclDatum);
1490 result = aclmask(acl, userid, ownerId, mask, how);
1492 /* if we have a detoasted copy, free it */
1493 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1497 heap_close(pg_database, AccessShareLock);
1503 * Exported routine for examining a user's privileges for a function
1506 pg_proc_aclmask(Oid proc_oid, AclId userid,
1507 AclMode mask, AclMaskHow how)
1516 /* Superusers bypass all permission checking. */
1517 if (superuser_arg(userid))
1521 * Get the function's ACL from pg_proc
1523 tuple = SearchSysCache(PROCOID,
1524 ObjectIdGetDatum(proc_oid),
1526 if (!HeapTupleIsValid(tuple))
1528 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1529 errmsg("function with OID %u does not exist", proc_oid)));
1531 ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
1533 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
1537 /* No ACL, so build default ACL */
1538 acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
1539 aclDatum = (Datum) 0;
1543 /* detoast ACL if necessary */
1544 acl = DatumGetAclP(aclDatum);
1547 result = aclmask(acl, userid, ownerId, mask, how);
1549 /* if we have a detoasted copy, free it */
1550 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1553 ReleaseSysCache(tuple);
1559 * Exported routine for examining a user's privileges for a language
1562 pg_language_aclmask(Oid lang_oid, AclId userid,
1563 AclMode mask, AclMaskHow how)
1572 /* Superusers bypass all permission checking. */
1573 if (superuser_arg(userid))
1577 * Get the language's ACL from pg_language
1579 tuple = SearchSysCache(LANGOID,
1580 ObjectIdGetDatum(lang_oid),
1582 if (!HeapTupleIsValid(tuple))
1584 (errcode(ERRCODE_UNDEFINED_OBJECT),
1585 errmsg("language with OID %u does not exist", lang_oid)));
1587 /* XXX pg_language should have an owner column, but doesn't */
1588 ownerId = BOOTSTRAP_USESYSID;
1590 aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
1594 /* No ACL, so build default ACL */
1595 acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
1596 aclDatum = (Datum) 0;
1600 /* detoast ACL if necessary */
1601 acl = DatumGetAclP(aclDatum);
1604 result = aclmask(acl, userid, ownerId, mask, how);
1606 /* if we have a detoasted copy, free it */
1607 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1610 ReleaseSysCache(tuple);
1616 * Exported routine for examining a user's privileges for a namespace
1619 pg_namespace_aclmask(Oid nsp_oid, AclId userid,
1620 AclMode mask, AclMaskHow how)
1629 /* Superusers bypass all permission checking. */
1630 if (superuser_arg(userid))
1634 * If we have been assigned this namespace as a temp namespace, check
1635 * to make sure we have CREATE TEMP permission on the database, and if
1636 * so act as though we have all standard (but not GRANT OPTION)
1637 * permissions on the namespace. If we don't have CREATE TEMP, act as
1638 * though we have only USAGE (and not CREATE) rights.
1640 * This may seem redundant given the check in InitTempTableNamespace, but
1641 * it really isn't since current user ID may have changed since then.
1642 * The upshot of this behavior is that a SECURITY DEFINER function can
1643 * create temp tables that can then be accessed (if permission is
1644 * granted) by code in the same session that doesn't have permissions
1645 * to create temp tables.
1647 * XXX Would it be safe to ereport a special error message as
1648 * InitTempTableNamespace does? Returning zero here means we'll get a
1649 * generic "permission denied for schema pg_temp_N" message, which is
1650 * not remarkably user-friendly.
1652 if (isTempNamespace(nsp_oid))
1654 if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
1655 ACL_CREATE_TEMP) == ACLCHECK_OK)
1656 return mask & ACL_ALL_RIGHTS_NAMESPACE;
1658 return mask & ACL_USAGE;
1662 * Get the schema's ACL from pg_namespace
1664 tuple = SearchSysCache(NAMESPACEOID,
1665 ObjectIdGetDatum(nsp_oid),
1667 if (!HeapTupleIsValid(tuple))
1669 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1670 errmsg("schema with OID %u does not exist", nsp_oid)));
1672 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
1674 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
1678 /* No ACL, so build default ACL */
1679 acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
1680 aclDatum = (Datum) 0;
1684 /* detoast ACL if necessary */
1685 acl = DatumGetAclP(aclDatum);
1688 result = aclmask(acl, userid, ownerId, mask, how);
1690 /* if we have a detoasted copy, free it */
1691 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1694 ReleaseSysCache(tuple);
1700 * Exported routine for examining a user's privileges for a tablespace
1703 pg_tablespace_aclmask(Oid spc_oid, AclId userid,
1704 AclMode mask, AclMaskHow how)
1707 Relation pg_tablespace;
1708 ScanKeyData entry[1];
1717 * Only shared relations can be stored in global space; don't let even
1718 * superusers override this
1720 if (spc_oid == GLOBALTABLESPACE_OID && !IsBootstrapProcessingMode())
1723 /* Otherwise, superusers bypass all permission checking. */
1724 if (superuser_arg(userid))
1728 * Get the tablespace's ACL from pg_tablespace
1730 * There's no syscache for pg_tablespace, so must look the hard way
1732 pg_tablespace = heap_open(TableSpaceRelationId, AccessShareLock);
1733 ScanKeyInit(&entry[0],
1734 ObjectIdAttributeNumber,
1735 BTEqualStrategyNumber, F_OIDEQ,
1736 ObjectIdGetDatum(spc_oid));
1737 scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry);
1738 tuple = heap_getnext(scan, ForwardScanDirection);
1739 if (!HeapTupleIsValid(tuple))
1741 (errcode(ERRCODE_UNDEFINED_OBJECT),
1742 errmsg("tablespace with OID %u does not exist", spc_oid)));
1744 ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
1746 aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
1747 RelationGetDescr(pg_tablespace), &isNull);
1751 /* No ACL, so build default ACL */
1752 acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
1753 aclDatum = (Datum) 0;
1757 /* detoast ACL if necessary */
1758 acl = DatumGetAclP(aclDatum);
1761 result = aclmask(acl, userid, ownerId, mask, how);
1763 /* if we have a detoasted copy, free it */
1764 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1768 heap_close(pg_tablespace, AccessShareLock);
1775 * Exported routine for checking a user's access privileges to a table
1777 * Returns ACLCHECK_OK if the user has any of the privileges identified by
1778 * 'mode'; otherwise returns a suitable error code (in practice, always
1779 * ACLCHECK_NO_PRIV).
1782 pg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode)
1784 if (pg_class_aclmask(table_oid, userid, mode, ACLMASK_ANY) != 0)
1787 return ACLCHECK_NO_PRIV;
1791 * Exported routine for checking a user's access privileges to a database
1794 pg_database_aclcheck(Oid db_oid, AclId userid, AclMode mode)
1796 if (pg_database_aclmask(db_oid, userid, mode, ACLMASK_ANY) != 0)
1799 return ACLCHECK_NO_PRIV;
1803 * Exported routine for checking a user's access privileges to a function
1806 pg_proc_aclcheck(Oid proc_oid, AclId userid, AclMode mode)
1808 if (pg_proc_aclmask(proc_oid, userid, mode, ACLMASK_ANY) != 0)
1811 return ACLCHECK_NO_PRIV;
1815 * Exported routine for checking a user's access privileges to a language
1818 pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode)
1820 if (pg_language_aclmask(lang_oid, userid, mode, ACLMASK_ANY) != 0)
1823 return ACLCHECK_NO_PRIV;
1827 * Exported routine for checking a user's access privileges to a namespace
1830 pg_namespace_aclcheck(Oid nsp_oid, AclId userid, AclMode mode)
1832 if (pg_namespace_aclmask(nsp_oid, userid, mode, ACLMASK_ANY) != 0)
1835 return ACLCHECK_NO_PRIV;
1839 * Exported routine for checking a user's access privileges to a tablespace
1842 pg_tablespace_aclcheck(Oid spc_oid, AclId userid, AclMode mode)
1844 if (pg_tablespace_aclmask(spc_oid, userid, mode, ACLMASK_ANY) != 0)
1847 return ACLCHECK_NO_PRIV;
1852 * Ownership check for a relation (specified by OID).
1855 pg_class_ownercheck(Oid class_oid, AclId userid)
1860 /* Superusers bypass all permission checking. */
1861 if (superuser_arg(userid))
1864 tuple = SearchSysCache(RELOID,
1865 ObjectIdGetDatum(class_oid),
1867 if (!HeapTupleIsValid(tuple))
1869 (errcode(ERRCODE_UNDEFINED_TABLE),
1870 errmsg("relation with OID %u does not exist", class_oid)));
1872 owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
1874 ReleaseSysCache(tuple);
1876 return userid == owner_id;
1880 * Ownership check for a type (specified by OID).
1883 pg_type_ownercheck(Oid type_oid, AclId userid)
1888 /* Superusers bypass all permission checking. */
1889 if (superuser_arg(userid))
1892 tuple = SearchSysCache(TYPEOID,
1893 ObjectIdGetDatum(type_oid),
1895 if (!HeapTupleIsValid(tuple))
1897 (errcode(ERRCODE_UNDEFINED_OBJECT),
1898 errmsg("type with OID %u does not exist", type_oid)));
1900 owner_id = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
1902 ReleaseSysCache(tuple);
1904 return userid == owner_id;
1908 * Ownership check for an operator (specified by OID).
1911 pg_oper_ownercheck(Oid oper_oid, AclId userid)
1916 /* Superusers bypass all permission checking. */
1917 if (superuser_arg(userid))
1920 tuple = SearchSysCache(OPEROID,
1921 ObjectIdGetDatum(oper_oid),
1923 if (!HeapTupleIsValid(tuple))
1925 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1926 errmsg("operator with OID %u does not exist", oper_oid)));
1928 owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
1930 ReleaseSysCache(tuple);
1932 return userid == owner_id;
1936 * Ownership check for a function (specified by OID).
1939 pg_proc_ownercheck(Oid proc_oid, AclId userid)
1944 /* Superusers bypass all permission checking. */
1945 if (superuser_arg(userid))
1948 tuple = SearchSysCache(PROCOID,
1949 ObjectIdGetDatum(proc_oid),
1951 if (!HeapTupleIsValid(tuple))
1953 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1954 errmsg("function with OID %u does not exist", proc_oid)));
1956 owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
1958 ReleaseSysCache(tuple);
1960 return userid == owner_id;
1964 * Ownership check for a namespace (specified by OID).
1967 pg_namespace_ownercheck(Oid nsp_oid, AclId userid)
1972 /* Superusers bypass all permission checking. */
1973 if (superuser_arg(userid))
1976 tuple = SearchSysCache(NAMESPACEOID,
1977 ObjectIdGetDatum(nsp_oid),
1979 if (!HeapTupleIsValid(tuple))
1981 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1982 errmsg("schema with OID %u does not exist", nsp_oid)));
1984 owner_id = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
1986 ReleaseSysCache(tuple);
1988 return userid == owner_id;
1992 * Ownership check for a tablespace (specified by OID).
1995 pg_tablespace_ownercheck(Oid spc_oid, AclId userid)
1997 Relation pg_tablespace;
1998 ScanKeyData entry[1];
2003 /* Superusers bypass all permission checking. */
2004 if (superuser_arg(userid))
2007 /* There's no syscache for pg_tablespace, so must look the hard way */
2008 pg_tablespace = heap_open(TableSpaceRelationId, AccessShareLock);
2009 ScanKeyInit(&entry[0],
2010 ObjectIdAttributeNumber,
2011 BTEqualStrategyNumber, F_OIDEQ,
2012 ObjectIdGetDatum(spc_oid));
2013 scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry);
2015 spctuple = heap_getnext(scan, ForwardScanDirection);
2017 if (!HeapTupleIsValid(spctuple))
2019 (errcode(ERRCODE_UNDEFINED_OBJECT),
2020 errmsg("tablespace with OID %u does not exist", spc_oid)));
2022 spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
2025 heap_close(pg_tablespace, AccessShareLock);
2027 return userid == spcowner;
2031 * Ownership check for an operator class (specified by OID).
2034 pg_opclass_ownercheck(Oid opc_oid, AclId userid)
2039 /* Superusers bypass all permission checking. */
2040 if (superuser_arg(userid))
2043 tuple = SearchSysCache(CLAOID,
2044 ObjectIdGetDatum(opc_oid),
2046 if (!HeapTupleIsValid(tuple))
2048 (errcode(ERRCODE_UNDEFINED_OBJECT),
2049 errmsg("operator class with OID %u does not exist",
2052 owner_id = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
2054 ReleaseSysCache(tuple);
2056 return userid == owner_id;
2060 * Ownership check for a database (specified by OID).
2063 pg_database_ownercheck(Oid db_oid, AclId userid)
2065 Relation pg_database;
2066 ScanKeyData entry[1];
2071 /* Superusers bypass all permission checking. */
2072 if (superuser_arg(userid))
2075 /* There's no syscache for pg_database, so must look the hard way */
2076 pg_database = heap_open(DatabaseRelationId, AccessShareLock);
2077 ScanKeyInit(&entry[0],
2078 ObjectIdAttributeNumber,
2079 BTEqualStrategyNumber, F_OIDEQ,
2080 ObjectIdGetDatum(db_oid));
2081 scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
2083 dbtuple = heap_getnext(scan, ForwardScanDirection);
2085 if (!HeapTupleIsValid(dbtuple))
2087 (errcode(ERRCODE_UNDEFINED_DATABASE),
2088 errmsg("database with OID %u does not exist", db_oid)));
2090 dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
2093 heap_close(pg_database, AccessShareLock);
2095 return userid == dba;
2099 * Ownership check for a conversion (specified by OID).
2102 pg_conversion_ownercheck(Oid conv_oid, AclId userid)
2107 /* Superusers bypass all permission checking. */
2108 if (superuser_arg(userid))
2111 tuple = SearchSysCache(CONOID,
2112 ObjectIdGetDatum(conv_oid),
2114 if (!HeapTupleIsValid(tuple))
2116 (errcode(ERRCODE_UNDEFINED_OBJECT),
2117 errmsg("conversion with OID %u does not exist", conv_oid)));
2119 owner_id = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
2121 ReleaseSysCache(tuple);
2123 return userid == owner_id;