1 /*-------------------------------------------------------------------------
4 * Routines to check access control permissions.
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.86 2003/08/04 00:43:16 momjian Exp $
16 *-------------------------------------------------------------------------
20 #include "access/heapam.h"
21 #include "catalog/catalog.h"
22 #include "catalog/catname.h"
23 #include "catalog/indexing.h"
24 #include "catalog/namespace.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_type.h"
34 #include "miscadmin.h"
35 #include "parser/parse_func.h"
36 #include "utils/acl.h"
37 #include "utils/fmgroids.h"
38 #include "utils/lsyscache.h"
39 #include "utils/syscache.h"
42 static void ExecuteGrantStmt_Relation(GrantStmt *stmt);
43 static void ExecuteGrantStmt_Database(GrantStmt *stmt);
44 static void ExecuteGrantStmt_Function(GrantStmt *stmt);
45 static void ExecuteGrantStmt_Language(GrantStmt *stmt);
46 static void ExecuteGrantStmt_Namespace(GrantStmt *stmt);
48 static const char *privilege_to_string(AclMode privilege);
50 static AclResult aclcheck(Acl *acl, AclId userid, AclMode mode);
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 * If is_grant is true, adds the given privileges for the list of
73 * grantees to the existing old_acl. If is_grant is false, the
74 * privileges for the given grantees are removed from old_acl.
77 merge_acl_with_grant(Acl *old_acl, bool is_grant,
78 List *grantees, AclMode privileges,
79 bool grant_option, DropBehavior behavior)
85 modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
94 PrivGrantee *grantee = (PrivGrantee *) lfirst(j);
98 if (grantee->username)
100 aclitem. ai_grantee = get_usesysid(grantee->username);
102 idtype = ACL_IDTYPE_UID;
104 else if (grantee->groupname)
106 aclitem. ai_grantee = get_grosysid(grantee->groupname);
108 idtype = ACL_IDTYPE_GID;
112 aclitem. ai_grantee = ACL_ID_WORLD;
114 idtype = ACL_IDTYPE_WORLD;
118 * Grant options can only be granted to individual users, not
119 * groups or public. The reason is that if a user would re-grant
120 * a privilege that he held through a group having a grant option,
121 * and later the user is removed from the group, the situation is
122 * impossible to clean up.
124 if (is_grant && idtype != ACL_IDTYPE_UID && grant_option)
126 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
127 errmsg("grant options can only be granted to individual users")));
129 aclitem. ai_grantor = GetUserId();
131 ACLITEM_SET_PRIVS_IDTYPE(aclitem,
132 (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
133 (grant_option || !is_grant) ? privileges : ACL_NO_RIGHTS,
136 new_acl = aclinsert3(new_acl, &aclitem, modechg, behavior);
148 * Called to execute the utility commands GRANT and REVOKE
151 ExecuteGrantStmt(GrantStmt *stmt)
153 switch (stmt->objtype)
155 case ACL_OBJECT_RELATION:
156 ExecuteGrantStmt_Relation(stmt);
158 case ACL_OBJECT_DATABASE:
159 ExecuteGrantStmt_Database(stmt);
161 case ACL_OBJECT_FUNCTION:
162 ExecuteGrantStmt_Function(stmt);
164 case ACL_OBJECT_LANGUAGE:
165 ExecuteGrantStmt_Language(stmt);
167 case ACL_OBJECT_NAMESPACE:
168 ExecuteGrantStmt_Namespace(stmt);
171 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
172 (int) stmt->objtype);
177 ExecuteGrantStmt_Relation(GrantStmt *stmt)
182 if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
183 privileges = ACL_ALL_RIGHTS_RELATION;
186 privileges = ACL_NO_RIGHTS;
187 foreach(i, stmt->privileges)
189 AclMode priv = lfirsti(i);
191 if (priv & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
193 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
194 errmsg("invalid privilege type %s for table",
195 privilege_to_string(priv))));
200 foreach(i, stmt->objects)
202 RangeVar *relvar = (RangeVar *) lfirst(i);
206 Form_pg_class pg_class_tuple;
212 Datum values[Natts_pg_class];
213 char nulls[Natts_pg_class];
214 char replaces[Natts_pg_class];
217 relation = heap_openr(RelationRelationName, RowExclusiveLock);
218 relOid = RangeVarGetRelid(relvar, false);
219 tuple = SearchSysCache(RELOID,
220 ObjectIdGetDatum(relOid),
222 if (!HeapTupleIsValid(tuple))
223 elog(ERROR, "cache lookup failed for relation %u", relOid);
224 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
227 && !pg_class_ownercheck(relOid, GetUserId())
228 && pg_class_aclcheck(relOid, GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
229 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, relvar->relname);
231 /* Not sensible to grant on an index */
232 if (pg_class_tuple->relkind == RELKIND_INDEX)
234 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
235 errmsg("\"%s\" is an index",
239 * If there's no ACL, create a default using the pg_class.relowner
242 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
245 old_acl = acldefault(ACL_OBJECT_RELATION,
246 pg_class_tuple->relowner);
248 /* get a detoasted copy of the ACL */
249 old_acl = DatumGetAclPCopy(aclDatum);
251 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
252 stmt->grantees, privileges,
253 stmt->grant_option, stmt->behavior);
255 /* finished building new ACL value, now insert it */
256 MemSet(values, 0, sizeof(values));
257 MemSet(nulls, ' ', sizeof(nulls));
258 MemSet(replaces, ' ', sizeof(replaces));
260 replaces[Anum_pg_class_relacl - 1] = 'r';
261 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
263 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
265 ReleaseSysCache(tuple);
267 simple_heap_update(relation, &newtuple->t_self, newtuple);
269 /* keep the catalog indexes up to date */
270 CatalogUpdateIndexes(relation, newtuple);
275 heap_close(relation, RowExclusiveLock);
280 ExecuteGrantStmt_Database(GrantStmt *stmt)
285 if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
286 privileges = ACL_ALL_RIGHTS_DATABASE;
289 privileges = ACL_NO_RIGHTS;
290 foreach(i, stmt->privileges)
292 AclMode priv = lfirsti(i);
294 if (priv & ~((AclMode) ACL_ALL_RIGHTS_DATABASE))
296 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
297 errmsg("invalid privilege type %s for database",
298 privilege_to_string(priv))));
303 foreach(i, stmt->objects)
305 char *dbname = strVal(lfirst(i));
307 ScanKeyData entry[1];
310 Form_pg_database pg_database_tuple;
316 Datum values[Natts_pg_database];
317 char nulls[Natts_pg_database];
318 char replaces[Natts_pg_database];
320 relation = heap_openr(DatabaseRelationName, RowExclusiveLock);
321 ScanKeyEntryInitialize(&entry[0], 0,
322 Anum_pg_database_datname, F_NAMEEQ,
323 CStringGetDatum(dbname));
324 scan = heap_beginscan(relation, SnapshotNow, 1, entry);
325 tuple = heap_getnext(scan, ForwardScanDirection);
326 if (!HeapTupleIsValid(tuple))
328 (errcode(ERRCODE_UNDEFINED_DATABASE),
329 errmsg("database \"%s\" does not exist", dbname)));
330 pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
333 && pg_database_tuple->datdba != GetUserId()
334 && pg_database_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
335 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
336 NameStr(pg_database_tuple->datname));
339 * If there's no ACL, create a default.
341 aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
342 RelationGetDescr(relation), &isNull);
344 old_acl = acldefault(ACL_OBJECT_DATABASE,
345 pg_database_tuple->datdba);
347 /* get a detoasted copy of the ACL */
348 old_acl = DatumGetAclPCopy(aclDatum);
350 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
351 stmt->grantees, privileges,
352 stmt->grant_option, stmt->behavior);
354 /* finished building new ACL value, now insert it */
355 MemSet(values, 0, sizeof(values));
356 MemSet(nulls, ' ', sizeof(nulls));
357 MemSet(replaces, ' ', sizeof(replaces));
359 replaces[Anum_pg_database_datacl - 1] = 'r';
360 values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
362 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
364 simple_heap_update(relation, &newtuple->t_self, newtuple);
366 /* keep the catalog indexes up to date */
367 CatalogUpdateIndexes(relation, newtuple);
374 heap_close(relation, RowExclusiveLock);
379 ExecuteGrantStmt_Function(GrantStmt *stmt)
384 if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
385 privileges = ACL_ALL_RIGHTS_FUNCTION;
388 privileges = ACL_NO_RIGHTS;
389 foreach(i, stmt->privileges)
391 AclMode priv = lfirsti(i);
393 if (priv & ~((AclMode) ACL_ALL_RIGHTS_FUNCTION))
395 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
396 errmsg("invalid privilege type %s for function",
397 privilege_to_string(priv))));
402 foreach(i, stmt->objects)
404 FuncWithArgs *func = (FuncWithArgs *) lfirst(i);
408 Form_pg_proc pg_proc_tuple;
414 Datum values[Natts_pg_proc];
415 char nulls[Natts_pg_proc];
416 char replaces[Natts_pg_proc];
418 oid = LookupFuncNameTypeNames(func->funcname, func->funcargs, false);
420 relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
421 tuple = SearchSysCache(PROCOID,
422 ObjectIdGetDatum(oid),
424 if (!HeapTupleIsValid(tuple))
425 elog(ERROR, "cache lookup failed for function %u", oid);
426 pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
429 && !pg_proc_ownercheck(oid, GetUserId())
430 && pg_proc_aclcheck(oid, GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
431 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
432 NameStr(pg_proc_tuple->proname));
435 * If there's no ACL, create a default using the pg_proc.proowner
438 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
441 old_acl = acldefault(ACL_OBJECT_FUNCTION,
442 pg_proc_tuple->proowner);
444 /* get a detoasted copy of the ACL */
445 old_acl = DatumGetAclPCopy(aclDatum);
447 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
448 stmt->grantees, privileges,
449 stmt->grant_option, stmt->behavior);
451 /* finished building new ACL value, now insert it */
452 MemSet(values, 0, sizeof(values));
453 MemSet(nulls, ' ', sizeof(nulls));
454 MemSet(replaces, ' ', sizeof(replaces));
456 replaces[Anum_pg_proc_proacl - 1] = 'r';
457 values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
459 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
461 ReleaseSysCache(tuple);
463 simple_heap_update(relation, &newtuple->t_self, newtuple);
465 /* keep the catalog indexes up to date */
466 CatalogUpdateIndexes(relation, newtuple);
471 heap_close(relation, RowExclusiveLock);
476 ExecuteGrantStmt_Language(GrantStmt *stmt)
481 if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
482 privileges = ACL_ALL_RIGHTS_LANGUAGE;
485 privileges = ACL_NO_RIGHTS;
486 foreach(i, stmt->privileges)
488 AclMode priv = lfirsti(i);
490 if (priv & ~((AclMode) ACL_ALL_RIGHTS_LANGUAGE))
492 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
493 errmsg("invalid privilege type %s for language",
494 privilege_to_string(priv))));
499 foreach(i, stmt->objects)
501 char *langname = strVal(lfirst(i));
504 Form_pg_language pg_language_tuple;
510 Datum values[Natts_pg_language];
511 char nulls[Natts_pg_language];
512 char replaces[Natts_pg_language];
514 relation = heap_openr(LanguageRelationName, RowExclusiveLock);
515 tuple = SearchSysCache(LANGNAME,
516 PointerGetDatum(langname),
518 if (!HeapTupleIsValid(tuple))
520 (errcode(ERRCODE_UNDEFINED_OBJECT),
521 errmsg("language \"%s\" does not exist", langname)));
522 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
524 if (!pg_language_tuple->lanpltrusted && stmt->is_grant)
526 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
527 errmsg("language \"%s\" is not trusted", langname)));
531 && pg_language_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
532 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
533 NameStr(pg_language_tuple->lanname));
536 * If there's no ACL, create a default.
538 aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
541 old_acl = acldefault(ACL_OBJECT_LANGUAGE,
544 /* get a detoasted copy of the ACL */
545 old_acl = DatumGetAclPCopy(aclDatum);
547 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
548 stmt->grantees, privileges,
549 stmt->grant_option, stmt->behavior);
551 /* finished building new ACL value, now insert it */
552 MemSet(values, 0, sizeof(values));
553 MemSet(nulls, ' ', sizeof(nulls));
554 MemSet(replaces, ' ', sizeof(replaces));
556 replaces[Anum_pg_language_lanacl - 1] = 'r';
557 values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
559 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
561 ReleaseSysCache(tuple);
563 simple_heap_update(relation, &newtuple->t_self, newtuple);
565 /* keep the catalog indexes up to date */
566 CatalogUpdateIndexes(relation, newtuple);
571 heap_close(relation, RowExclusiveLock);
576 ExecuteGrantStmt_Namespace(GrantStmt *stmt)
581 if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
582 privileges = ACL_ALL_RIGHTS_NAMESPACE;
585 privileges = ACL_NO_RIGHTS;
586 foreach(i, stmt->privileges)
588 AclMode priv = lfirsti(i);
590 if (priv & ~((AclMode) ACL_ALL_RIGHTS_NAMESPACE))
592 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
593 errmsg("invalid privilege type %s for schema",
594 privilege_to_string(priv))));
599 foreach(i, stmt->objects)
601 char *nspname = strVal(lfirst(i));
604 Form_pg_namespace pg_namespace_tuple;
610 Datum values[Natts_pg_namespace];
611 char nulls[Natts_pg_namespace];
612 char replaces[Natts_pg_namespace];
614 relation = heap_openr(NamespaceRelationName, RowExclusiveLock);
615 tuple = SearchSysCache(NAMESPACENAME,
616 CStringGetDatum(nspname),
618 if (!HeapTupleIsValid(tuple))
620 (errcode(ERRCODE_UNDEFINED_SCHEMA),
621 errmsg("schema \"%s\" does not exist", nspname)));
622 pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
625 && !pg_namespace_ownercheck(HeapTupleGetOid(tuple), GetUserId())
626 && pg_namespace_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
627 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,
631 * If there's no ACL, create a default using the
632 * pg_namespace.nspowner field.
634 aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
635 Anum_pg_namespace_nspacl,
638 old_acl = acldefault(ACL_OBJECT_NAMESPACE,
639 pg_namespace_tuple->nspowner);
641 /* get a detoasted copy of the ACL */
642 old_acl = DatumGetAclPCopy(aclDatum);
644 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
645 stmt->grantees, privileges,
646 stmt->grant_option, stmt->behavior);
648 /* finished building new ACL value, now insert it */
649 MemSet(values, 0, sizeof(values));
650 MemSet(nulls, ' ', sizeof(nulls));
651 MemSet(replaces, ' ', sizeof(replaces));
653 replaces[Anum_pg_namespace_nspacl - 1] = 'r';
654 values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
656 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
658 ReleaseSysCache(tuple);
660 simple_heap_update(relation, &newtuple->t_self, newtuple);
662 /* keep the catalog indexes up to date */
663 CatalogUpdateIndexes(relation, newtuple);
668 heap_close(relation, RowExclusiveLock);
674 privilege_to_string(AclMode privilege)
698 case ACL_CREATE_TEMP:
701 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
703 return NULL; /* appease compiler */
708 get_grosysid(char *groname)
713 tuple = SearchSysCache(GRONAME,
714 PointerGetDatum(groname),
716 if (HeapTupleIsValid(tuple))
718 id = ((Form_pg_group) GETSTRUCT(tuple))->grosysid;
719 ReleaseSysCache(tuple);
723 (errcode(ERRCODE_UNDEFINED_OBJECT),
724 errmsg("group \"%s\" does not exist", groname)));
729 * Convert group ID to name, or return NULL if group can't be found
732 get_groname(AclId grosysid)
737 tuple = SearchSysCache(GROSYSID,
738 ObjectIdGetDatum(grosysid),
740 if (HeapTupleIsValid(tuple))
742 name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname));
743 ReleaseSysCache(tuple);
749 * Is user a member of group?
752 in_group(AclId uid, AclId gid)
763 tuple = SearchSysCache(GROSYSID,
764 ObjectIdGetDatum(gid),
766 if (HeapTupleIsValid(tuple))
768 att = SysCacheGetAttr(GROSYSID,
770 Anum_pg_group_grolist,
774 /* be sure the IdList is not toasted */
775 glist = DatumGetIdListP(att);
777 num = IDLIST_NUM(glist);
778 aidp = IDLIST_DAT(glist);
779 for (i = 0; i < num; ++i)
787 /* if IdList was toasted, free detoasted copy */
788 if ((Pointer) glist != DatumGetPointer(att))
791 ReleaseSysCache(tuple);
795 (errcode(ERRCODE_UNDEFINED_OBJECT),
796 errmsg("group with ID %u does not exist", gid)));
804 * Returns ACLCHECK_OK if the 'userid' has ACL entries in 'acl' to
805 * satisfy any one of the requirements of 'mode'. Returns an
806 * appropriate ACLCHECK_* error code otherwise.
809 aclcheck(Acl *acl, AclId userid, AclMode mode)
816 * Null ACL should not happen, since caller should have inserted
817 * appropriate default
821 elog(ERROR, "null ACL");
822 return ACLCHECK_NO_PRIV;
826 aidat = ACL_DAT(acl);
829 * See if privilege is granted directly to user or to public
831 for (i = 0; i < num; i++)
832 if (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_WORLD
833 || (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_UID
834 && aidat[i].ai_grantee == userid))
836 if (aidat[i].ai_privs & mode)
841 * See if he has the permission via any group (do this in a separate
842 * pass to avoid expensive(?) lookups in pg_group)
844 for (i = 0; i < num; i++)
845 if (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_GID
846 && aidat[i].ai_privs & mode
847 && in_group(userid, aidat[i].ai_grantee))
850 /* If here, doesn't have the privilege. */
851 return ACLCHECK_NO_PRIV;
856 * Standardized reporting of aclcheck permissions failures.
858 * Note: we do not double-quote the %s's below, because many callers
859 * supply strings that might be already quoted.
862 static const char *const no_priv_msg[MAX_ACL_KIND] =
865 gettext_noop("permission denied for relation %s"),
866 /* ACL_KIND_DATABASE */
867 gettext_noop("permission denied for database %s"),
869 gettext_noop("permission denied for function %s"),
871 gettext_noop("permission denied for operator %s"),
873 gettext_noop("permission denied for type %s"),
874 /* ACL_KIND_LANGUAGE */
875 gettext_noop("permission denied for language %s"),
876 /* ACL_KIND_NAMESPACE */
877 gettext_noop("permission denied for schema %s"),
878 /* ACL_KIND_OPCLASS */
879 gettext_noop("permission denied for operator class %s"),
880 /* ACL_KIND_CONVERSION */
881 gettext_noop("permission denied for conversion %s")
884 static const char *const not_owner_msg[MAX_ACL_KIND] =
887 gettext_noop("must be owner of relation %s"),
888 /* ACL_KIND_DATABASE */
889 gettext_noop("must be owner of database %s"),
891 gettext_noop("must be owner of function %s"),
893 gettext_noop("must be owner of operator %s"),
895 gettext_noop("must be owner of type %s"),
896 /* ACL_KIND_LANGUAGE */
897 gettext_noop("must be owner of language %s"),
898 /* ACL_KIND_NAMESPACE */
899 gettext_noop("must be owner of schema %s"),
900 /* ACL_KIND_OPCLASS */
901 gettext_noop("must be owner of operator class %s"),
902 /* ACL_KIND_CONVERSION */
903 gettext_noop("must be owner of conversion %s")
908 aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
909 const char *objectname)
914 /* no error, so return to caller */
916 case ACLCHECK_NO_PRIV:
918 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
919 errmsg(no_priv_msg[objectkind], objectname)));
921 case ACLCHECK_NOT_OWNER:
923 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
924 errmsg(not_owner_msg[objectkind], objectname)));
927 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
934 * Exported routine for checking a user's access privileges to a table
936 * Note: we give lookup failure the full ereport treatment because the
937 * has_table_privilege() family of functions allow users to pass
938 * any random OID to this function. Likewise for the sibling functions
942 pg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode)
953 * Validate userid, find out if he is superuser, also get usecatupd
955 tuple = SearchSysCache(SHADOWSYSID,
956 ObjectIdGetDatum(userid),
958 if (!HeapTupleIsValid(tuple))
960 (errcode(ERRCODE_UNDEFINED_OBJECT),
961 errmsg("user with ID %u does not exist", userid)));
963 usecatupd = ((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd;
965 ReleaseSysCache(tuple);
967 usesuper = superuser_arg(userid);
970 * Now get the relation's tuple from pg_class
972 tuple = SearchSysCache(RELOID,
973 ObjectIdGetDatum(table_oid),
975 if (!HeapTupleIsValid(tuple))
977 (errcode(ERRCODE_UNDEFINED_TABLE),
978 errmsg("relation with OID %u does not exist", table_oid)));
981 * Deny anyone permission to update a system catalog unless
982 * pg_shadow.usecatupd is set. (This is to let superusers protect
983 * themselves from themselves.)
985 if ((mode & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
986 !allowSystemTableMods &&
987 IsSystemClass((Form_pg_class) GETSTRUCT(tuple)) &&
991 elog(DEBUG2, "permission denied for system catalog update");
993 ReleaseSysCache(tuple);
994 return ACLCHECK_NO_PRIV;
998 * Otherwise, superusers bypass all permission-checking.
1003 elog(DEBUG2, "%u is superuser, home free", userid);
1005 ReleaseSysCache(tuple);
1010 * Normal case: get the relation's ACL from pg_class
1012 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1016 /* No ACL, so build default ACL for rel */
1019 ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
1020 acl = acldefault(ACL_OBJECT_RELATION, ownerId);
1021 aclDatum = (Datum) 0;
1025 /* detoast rel's ACL if necessary */
1026 acl = DatumGetAclP(aclDatum);
1029 result = aclcheck(acl, userid, mode);
1031 /* if we have a detoasted copy, free it */
1032 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1035 ReleaseSysCache(tuple);
1041 * Exported routine for checking a user's access privileges to a database
1044 pg_database_aclcheck(Oid db_oid, AclId userid, AclMode mode)
1047 Relation pg_database;
1048 ScanKeyData entry[1];
1055 /* Superusers bypass all permission checking. */
1056 if (superuser_arg(userid))
1060 * Get the database's ACL from pg_database
1062 * There's no syscache for pg_database, so must look the hard way
1064 pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
1065 ScanKeyEntryInitialize(&entry[0], 0x0,
1066 ObjectIdAttributeNumber, F_OIDEQ,
1067 ObjectIdGetDatum(db_oid));
1068 scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
1069 tuple = heap_getnext(scan, ForwardScanDirection);
1070 if (!HeapTupleIsValid(tuple))
1072 (errcode(ERRCODE_UNDEFINED_DATABASE),
1073 errmsg("database with OID %u does not exist", db_oid)));
1075 aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
1076 RelationGetDescr(pg_database), &isNull);
1080 /* No ACL, so build default ACL */
1083 ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
1084 acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
1085 aclDatum = (Datum) 0;
1089 /* detoast ACL if necessary */
1090 acl = DatumGetAclP(aclDatum);
1093 result = aclcheck(acl, userid, mode);
1095 /* if we have a detoasted copy, free it */
1096 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1100 heap_close(pg_database, AccessShareLock);
1106 * Exported routine for checking a user's access privileges to a function
1109 pg_proc_aclcheck(Oid proc_oid, AclId userid, AclMode mode)
1117 /* Superusers bypass all permission checking. */
1118 if (superuser_arg(userid))
1122 * Get the function's ACL from pg_proc
1124 tuple = SearchSysCache(PROCOID,
1125 ObjectIdGetDatum(proc_oid),
1127 if (!HeapTupleIsValid(tuple))
1129 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1130 errmsg("function with OID %u does not exist", proc_oid)));
1132 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
1136 /* No ACL, so build default ACL */
1139 ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
1140 acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
1141 aclDatum = (Datum) 0;
1145 /* detoast ACL if necessary */
1146 acl = DatumGetAclP(aclDatum);
1149 result = aclcheck(acl, userid, mode);
1151 /* if we have a detoasted copy, free it */
1152 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1155 ReleaseSysCache(tuple);
1161 * Exported routine for checking a user's access privileges to a language
1164 pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode)
1172 /* Superusers bypass all permission checking. */
1173 if (superuser_arg(userid))
1177 * Get the language's ACL from pg_language
1179 tuple = SearchSysCache(LANGOID,
1180 ObjectIdGetDatum(lang_oid),
1182 if (!HeapTupleIsValid(tuple))
1184 (errcode(ERRCODE_UNDEFINED_OBJECT),
1185 errmsg("language with OID %u does not exist", lang_oid)));
1187 aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
1191 /* No ACL, so build default ACL */
1192 acl = acldefault(ACL_OBJECT_LANGUAGE, InvalidOid);
1193 aclDatum = (Datum) 0;
1197 /* detoast ACL if necessary */
1198 acl = DatumGetAclP(aclDatum);
1201 result = aclcheck(acl, userid, mode);
1203 /* if we have a detoasted copy, free it */
1204 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1207 ReleaseSysCache(tuple);
1213 * Exported routine for checking a user's access privileges to a namespace
1216 pg_namespace_aclcheck(Oid nsp_oid, AclId userid, AclMode mode)
1225 * If we have been assigned this namespace as a temp namespace, assume
1226 * we have all grantable privileges on it.
1228 if (isTempNamespace(nsp_oid))
1231 /* Superusers bypass all permission checking. */
1232 if (superuser_arg(userid))
1236 * Get the schema's ACL from pg_namespace
1238 tuple = SearchSysCache(NAMESPACEOID,
1239 ObjectIdGetDatum(nsp_oid),
1241 if (!HeapTupleIsValid(tuple))
1243 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1244 errmsg("schema with OID %u does not exist", nsp_oid)));
1246 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
1250 /* No ACL, so build default ACL */
1253 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
1254 acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
1255 aclDatum = (Datum) 0;
1259 /* detoast ACL if necessary */
1260 acl = DatumGetAclP(aclDatum);
1263 result = aclcheck(acl, userid, mode);
1265 /* if we have a detoasted copy, free it */
1266 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1269 ReleaseSysCache(tuple);
1276 * Ownership check for a relation (specified by OID).
1279 pg_class_ownercheck(Oid class_oid, AclId userid)
1284 /* Superusers bypass all permission checking. */
1285 if (superuser_arg(userid))
1288 tuple = SearchSysCache(RELOID,
1289 ObjectIdGetDatum(class_oid),
1291 if (!HeapTupleIsValid(tuple))
1293 (errcode(ERRCODE_UNDEFINED_TABLE),
1294 errmsg("relation with OID %u does not exist", class_oid)));
1296 owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
1298 ReleaseSysCache(tuple);
1300 return userid == owner_id;
1304 * Ownership check for a type (specified by OID).
1307 pg_type_ownercheck(Oid type_oid, AclId userid)
1312 /* Superusers bypass all permission checking. */
1313 if (superuser_arg(userid))
1316 tuple = SearchSysCache(TYPEOID,
1317 ObjectIdGetDatum(type_oid),
1319 if (!HeapTupleIsValid(tuple))
1321 (errcode(ERRCODE_UNDEFINED_OBJECT),
1322 errmsg("type with OID %u does not exist", type_oid)));
1324 owner_id = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
1326 ReleaseSysCache(tuple);
1328 return userid == owner_id;
1332 * Ownership check for an operator (specified by OID).
1335 pg_oper_ownercheck(Oid oper_oid, AclId userid)
1340 /* Superusers bypass all permission checking. */
1341 if (superuser_arg(userid))
1344 tuple = SearchSysCache(OPEROID,
1345 ObjectIdGetDatum(oper_oid),
1347 if (!HeapTupleIsValid(tuple))
1349 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1350 errmsg("operator with OID %u does not exist", oper_oid)));
1352 owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
1354 ReleaseSysCache(tuple);
1356 return userid == owner_id;
1360 * Ownership check for a function (specified by OID).
1363 pg_proc_ownercheck(Oid proc_oid, AclId userid)
1368 /* Superusers bypass all permission checking. */
1369 if (superuser_arg(userid))
1372 tuple = SearchSysCache(PROCOID,
1373 ObjectIdGetDatum(proc_oid),
1375 if (!HeapTupleIsValid(tuple))
1377 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1378 errmsg("function with OID %u does not exist", proc_oid)));
1380 owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
1382 ReleaseSysCache(tuple);
1384 return userid == owner_id;
1388 * Ownership check for a namespace (specified by OID).
1391 pg_namespace_ownercheck(Oid nsp_oid, AclId userid)
1396 /* Superusers bypass all permission checking. */
1397 if (superuser_arg(userid))
1400 tuple = SearchSysCache(NAMESPACEOID,
1401 ObjectIdGetDatum(nsp_oid),
1403 if (!HeapTupleIsValid(tuple))
1405 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1406 errmsg("schema with OID %u does not exist", nsp_oid)));
1408 owner_id = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
1410 ReleaseSysCache(tuple);
1412 return userid == owner_id;
1416 * Ownership check for an operator class (specified by OID).
1419 pg_opclass_ownercheck(Oid opc_oid, AclId userid)
1424 /* Superusers bypass all permission checking. */
1425 if (superuser_arg(userid))
1428 tuple = SearchSysCache(CLAOID,
1429 ObjectIdGetDatum(opc_oid),
1431 if (!HeapTupleIsValid(tuple))
1433 (errcode(ERRCODE_UNDEFINED_OBJECT),
1434 errmsg("operator class with OID %u does not exist",
1437 owner_id = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
1439 ReleaseSysCache(tuple);
1441 return userid == owner_id;
1446 * Ownership check for database (specified as OID)
1449 pg_database_ownercheck(Oid db_oid, AclId userid)
1451 Relation pg_database;
1452 ScanKeyData entry[1];
1457 /* Superusers bypass all permission checking. */
1458 if (superuser_arg(userid))
1461 /* There's no syscache for pg_database, so must look the hard way */
1462 pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
1463 ScanKeyEntryInitialize(&entry[0], 0x0,
1464 ObjectIdAttributeNumber, F_OIDEQ,
1465 ObjectIdGetDatum(db_oid));
1466 scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
1468 dbtuple = heap_getnext(scan, ForwardScanDirection);
1470 if (!HeapTupleIsValid(dbtuple))
1472 (errcode(ERRCODE_UNDEFINED_DATABASE),
1473 errmsg("database with OID %u does not exist", db_oid)));
1475 dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
1478 heap_close(pg_database, AccessShareLock);
1480 return userid == dba;