1 /*-------------------------------------------------------------------------
4 * Routines to check access control permissions.
6 * Portions Copyright (c) 1996-2001, 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.54 2002/02/18 23:11:07 petere Exp $
16 *-------------------------------------------------------------------------
20 #include "access/heapam.h"
21 #include "access/transam.h"
22 #include "catalog/catalog.h"
23 #include "catalog/catname.h"
24 #include "catalog/indexing.h"
25 #include "catalog/pg_aggregate.h"
26 #include "catalog/pg_group.h"
27 #include "catalog/pg_language.h"
28 #include "catalog/pg_operator.h"
29 #include "catalog/pg_proc.h"
30 #include "catalog/pg_shadow.h"
31 #include "catalog/pg_type.h"
32 #include "miscadmin.h"
33 #include "nodes/parsenodes.h"
34 #include "parser/keywords.h"
35 #include "parser/parse.h"
36 #include "parser/parse_agg.h"
37 #include "parser/parse_func.h"
38 #include "parser/parse_expr.h"
39 #include "utils/acl.h"
40 #include "utils/syscache.h"
41 #include "utils/temprel.h"
44 static void ExecuteGrantStmt_Table(GrantStmt *stmt);
45 static void ExecuteGrantStmt_Function(GrantStmt *stmt);
46 static void ExecuteGrantStmt_Lang(GrantStmt *stmt);
48 static const char *privilege_token_string(int token);
50 static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode);
52 /* warning messages, now more explicit. */
53 /* MUST correspond to the order of the ACLCHK_* result codes in acl.h. */
54 char *aclcheck_error_strings[] = {
57 "Table does not exist.",
58 "Must be table owner."
69 elog(DEBUG, "acl size = %d, # acls = %d",
70 ACL_SIZE(acl), ACL_NUM(acl));
72 for (i = 0; i < ACL_NUM(acl); ++i)
73 elog(DEBUG, " acl[%d]: %s", i,
74 DatumGetCString(DirectFunctionCall1(aclitemout,
75 PointerGetDatum(aip + i))));
81 * If is_grant is true, adds the given privileges for the list of
82 * grantees to the existing old_acl. If is_grant is false, the
83 * privileges for the given grantees are removed from old_acl.
86 merge_acl_with_grant(Acl *old_acl, bool is_grant, List *grantees, char *privileges)
98 PrivGrantee *grantee = (PrivGrantee *) lfirst(j);
104 if (grantee->username)
105 granteeString = aclmakeuser("U", grantee->username);
106 else if (grantee->groupname)
107 granteeString = aclmakeuser("G", grantee->groupname);
109 granteeString = aclmakeuser("A", "");
111 aclString = makeAclString(privileges, granteeString,
112 is_grant ? '+' : '-');
114 /* Convert string ACL spec into internal form */
115 aclparse(aclString, &aclitem, &modechg);
116 new_acl = aclinsert3(new_acl, &aclitem, modechg);
128 * Called to execute the utility commands GRANT and REVOKE
131 ExecuteGrantStmt(GrantStmt *stmt)
133 /* see comment in pg_type.h */
134 Assert(ACLITEMSIZE == sizeof(AclItem));
136 switch(stmt->objtype)
139 ExecuteGrantStmt_Table(stmt);
142 ExecuteGrantStmt_Function(stmt);
145 ExecuteGrantStmt_Lang(stmt);
148 elog(ERROR, "bogus GrantStmt.objtype %d", stmt->objtype);
154 ExecuteGrantStmt_Table(GrantStmt *stmt)
159 if (lfirsti(stmt->privileges) == ALL)
160 privstring = aclmakepriv(ACL_MODE_STR, 0);
164 foreach(i, stmt->privileges)
171 c = ACL_MODE_SELECT_CHR;
174 c = ACL_MODE_INSERT_CHR;
177 c = ACL_MODE_UPDATE_CHR;
180 c = ACL_MODE_DELETE_CHR;
183 c = ACL_MODE_RULE_CHR;
186 c = ACL_MODE_REFERENCES_CHR;
189 c = ACL_MODE_TRIGGER_CHR;
192 elog(ERROR, "invalid privilege type %s for table object",
193 privilege_token_string(lfirsti(i)));
196 privstring = aclmakepriv(privstring, c);
201 foreach(i, stmt->objects)
203 char *relname = strVal(lfirst(i));
206 Form_pg_class pg_class_tuple;
213 Datum values[Natts_pg_class];
214 char nulls[Natts_pg_class];
215 char replaces[Natts_pg_class];
218 if (!pg_ownercheck(GetUserId(), relname, RELNAME))
219 elog(ERROR, "permission denied");
222 relation = heap_openr(RelationRelationName, RowExclusiveLock);
223 tuple = SearchSysCache(RELNAME,
224 PointerGetDatum(relname),
226 if (!HeapTupleIsValid(tuple))
228 heap_close(relation, RowExclusiveLock);
229 elog(ERROR, "relation \"%s\" not found",
232 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
234 if (pg_class_tuple->relkind == RELKIND_INDEX)
235 elog(ERROR, "\"%s\" is an index",
239 * If there's no ACL, create a default using the pg_class.relowner
242 aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl,
245 old_acl = acldefault(pg_class_tuple->relowner);
247 /* get a detoasted copy of the rel's ACL */
248 old_acl = DatumGetAclPCopy(aclDatum);
250 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
251 stmt->grantees, privstring);
253 /* finished building new ACL value, now insert it */
254 for (i = 0; i < Natts_pg_class; ++i)
257 nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */
258 values[i] = (Datum) NULL; /* ignored if replaces[i]==' '
261 replaces[Anum_pg_class_relacl - 1] = 'r';
262 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);
270 /* keep the catalog indexes up to date */
271 Relation idescs[Num_pg_class_indices];
273 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
275 CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newtuple);
276 CatalogCloseIndices(Num_pg_class_indices, idescs);
282 heap_close(relation, RowExclusiveLock);
288 find_function_with_arglist(char *name, List *arguments)
291 Oid argoids[FUNC_MAX_ARGS];
295 MemSet(argoids, 0, FUNC_MAX_ARGS * sizeof(Oid));
296 argcount = length(arguments);
297 if (argcount > FUNC_MAX_ARGS)
298 elog(ERROR, "functions cannot have more than %d arguments",
301 for (i = 0; i < argcount; i++)
303 TypeName *t = (TypeName *) lfirst(arguments);
304 char *typnam = TypeNameToInternalName(t);
306 arguments = lnext(arguments);
308 if (strcmp(typnam, "opaque") == 0)
309 argoids[i] = InvalidOid;
312 argoids[i] = GetSysCacheOid(TYPENAME,
313 PointerGetDatum(typnam),
315 if (!OidIsValid(argoids[i]))
316 elog(ERROR, "type '%s' not found", typnam);
320 oid = GetSysCacheOid(PROCNAME,
321 PointerGetDatum(name),
322 Int16GetDatum(argcount),
323 PointerGetDatum(argoids),
326 if (!OidIsValid(oid))
327 func_error(NULL, name, argcount, argoids, NULL);
334 ExecuteGrantStmt_Function(GrantStmt *stmt)
337 char *privstring = NULL;
339 if (lfirsti(stmt->privileges) == ALL)
340 privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
343 foreach(i, stmt->privileges)
345 if (lfirsti(i) != EXECUTE)
346 elog(ERROR, "invalid privilege type %s for function object",
347 privilege_token_string(lfirsti(i)));
350 privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
353 foreach(i, stmt->objects)
355 FuncWithArgs *func = (FuncWithArgs *) lfirst(i);
359 Form_pg_proc pg_proc_tuple;
366 Datum values[Natts_pg_proc];
367 char nulls[Natts_pg_proc];
368 char replaces[Natts_pg_proc];
370 oid = find_function_with_arglist(func->funcname, func->funcargs);
371 relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
372 tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(oid), 0, 0, 0);
373 if (!HeapTupleIsValid(tuple))
375 heap_close(relation, RowExclusiveLock);
376 elog(ERROR, "function %u not found", oid);
378 pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
380 if (pg_proc_tuple->proowner != GetUserId())
381 elog(ERROR, "permission denied");
384 * If there's no ACL, create a default using the pg_proc.proowner
387 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
390 old_acl = acldefault(pg_proc_tuple->proowner);
392 /* get a detoasted copy of the rel's ACL */
393 old_acl = DatumGetAclPCopy(aclDatum);
395 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
396 stmt->grantees, privstring);
398 /* finished building new ACL value, now insert it */
399 for (i = 0; i < Natts_pg_proc; ++i)
402 nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */
403 values[i] = (Datum) NULL; /* ignored if replaces[i]==' '
406 replaces[Anum_pg_proc_proacl - 1] = 'r';
407 values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
408 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
410 ReleaseSysCache(tuple);
412 simple_heap_update(relation, &newtuple->t_self, newtuple);
415 /* keep the catalog indexes up to date */
416 Relation idescs[Num_pg_proc_indices];
418 CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices,
420 CatalogIndexInsert(idescs, Num_pg_proc_indices, relation, newtuple);
421 CatalogCloseIndices(Num_pg_proc_indices, idescs);
427 heap_close(relation, RowExclusiveLock);
433 ExecuteGrantStmt_Lang(GrantStmt *stmt)
436 char *privstring = NULL;
438 if (lfirsti(stmt->privileges) == ALL)
439 privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
442 foreach(i, stmt->privileges)
444 if (lfirsti(i) != USAGE)
445 elog(ERROR, "invalid privilege type %s for language object",
446 privilege_token_string(lfirsti(i)));
449 privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
452 foreach(i, stmt->objects)
454 char *langname = strVal(lfirst(i));
457 Form_pg_language pg_language_tuple;
464 Datum values[Natts_pg_language];
465 char nulls[Natts_pg_language];
466 char replaces[Natts_pg_language];
469 elog(ERROR, "permission denied");
471 relation = heap_openr(LanguageRelationName, RowExclusiveLock);
472 tuple = SearchSysCache(LANGNAME, PointerGetDatum(langname), 0, 0, 0);
473 if (!HeapTupleIsValid(tuple))
475 heap_close(relation, RowExclusiveLock);
476 elog(ERROR, "language \"%s\" not found", langname);
478 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
480 if (!pg_language_tuple->lanpltrusted)
482 heap_close(relation, RowExclusiveLock);
483 elog(ERROR, "language \"%s\" is not trusted", langname);
487 * If there's no ACL, create a default.
489 aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
492 old_acl = acldefault(InvalidOid);
494 /* get a detoasted copy of the rel's ACL */
495 old_acl = DatumGetAclPCopy(aclDatum);
497 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
498 stmt->grantees, privstring);
500 /* finished building new ACL value, now insert it */
501 for (i = 0; i < Natts_pg_language; ++i)
504 nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */
505 values[i] = (Datum) NULL; /* ignored if replaces[i]==' '
508 replaces[Anum_pg_language_lanacl - 1] = 'r';
509 values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
510 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
512 ReleaseSysCache(tuple);
514 simple_heap_update(relation, &newtuple->t_self, newtuple);
517 /* keep the catalog indexes up to date */
518 Relation idescs[Num_pg_language_indices];
520 CatalogOpenIndices(Num_pg_language_indices, Name_pg_language_indices,
522 CatalogIndexInsert(idescs, Num_pg_language_indices, relation, newtuple);
523 CatalogCloseIndices(Num_pg_language_indices, idescs);
529 heap_close(relation, RowExclusiveLock);
536 privilege_token_string(int token)
538 const char *s = TokenString(token);
543 elog(ERROR, "privilege_token_string: invalid token number");
544 return NULL; /* appease compiler */
550 get_grosysid(char *groname)
555 tuple = SearchSysCache(GRONAME,
556 PointerGetDatum(groname),
558 if (HeapTupleIsValid(tuple))
560 id = ((Form_pg_group) GETSTRUCT(tuple))->grosysid;
561 ReleaseSysCache(tuple);
564 elog(ERROR, "non-existent group \"%s\"", groname);
569 * Convert group ID to name, or return NULL if group can't be found
572 get_groname(AclId grosysid)
577 tuple = SearchSysCache(GROSYSID,
578 ObjectIdGetDatum(grosysid),
580 if (HeapTupleIsValid(tuple))
582 name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname));
583 ReleaseSysCache(tuple);
589 * Is user a member of group?
592 in_group(AclId uid, AclId gid)
603 tuple = SearchSysCache(GROSYSID,
604 ObjectIdGetDatum(gid),
606 if (HeapTupleIsValid(tuple))
608 att = SysCacheGetAttr(GROSYSID,
610 Anum_pg_group_grolist,
614 /* be sure the IdList is not toasted */
615 glist = DatumGetIdListP(att);
617 num = IDLIST_NUM(glist);
618 aidp = IDLIST_DAT(glist);
619 for (i = 0; i < num; ++i)
627 /* if IdList was toasted, free detoasted copy */
628 if ((Pointer) glist != DatumGetPointer(att))
631 ReleaseSysCache(tuple);
634 elog(NOTICE, "in_group: group %u not found", gid);
641 * Returns ACLCHECK_OK if the 'id' of type 'idtype' has ACL entries in 'acl'
642 * to satisfy any one of the requirements of 'mode'. Returns an appropriate
643 * ACLCHECK_* error code otherwise.
645 * The ACL list is expected to be sorted in standard order.
648 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
656 * If ACL is null, default to "OK" --- this should not happen, since
657 * caller should have inserted appropriate default
661 elog(DEBUG, "aclcheck: null ACL, returning OK");
666 aidat = ACL_DAT(acl);
669 * We'll treat the empty ACL like that, too, although this is more
670 * like an error (i.e., you manually blew away your ACL array) -- the
671 * system never creates an empty ACL, since there must always be a
672 * "world" entry in the first slot.
676 elog(DEBUG, "aclcheck: zero-length ACL, returning OK");
681 * "World" rights are applicable regardless of the passed-in ID, and
682 * since they're much the cheapest to check, check 'em first.
684 if (aidat->ai_idtype != ACL_IDTYPE_WORLD)
685 elog(ERROR, "aclcheck: first entry in ACL is not 'world' entry");
686 if (aidat->ai_mode & mode)
689 elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode);
697 /* See if permission is granted directly to user */
698 for (i = 1, aip = aidat + 1; /* skip world entry */
699 i < num && aip->ai_idtype == ACL_IDTYPE_UID;
702 if (aip->ai_id == id)
705 elog(DEBUG, "aclcheck: found user %u/%d",
706 aip->ai_id, aip->ai_mode);
708 if (aip->ai_mode & mode)
712 /* See if he has the permission via any group */
714 i < num && aip->ai_idtype == ACL_IDTYPE_GID;
717 if (aip->ai_mode & mode)
719 if (in_group(id, aip->ai_id))
722 elog(DEBUG, "aclcheck: found group %u/%d",
723 aip->ai_id, aip->ai_mode);
731 /* Look for this group ID */
732 for (i = 1, aip = aidat + 1; /* skip world entry */
733 i < num && aip->ai_idtype == ACL_IDTYPE_UID;
735 /* skip UID entry */ ;
737 i < num && aip->ai_idtype == ACL_IDTYPE_GID;
740 if (aip->ai_id == id)
743 elog(DEBUG, "aclcheck: found group %u/%d",
744 aip->ai_id, aip->ai_mode);
746 if (aip->ai_mode & mode)
751 case ACL_IDTYPE_WORLD:
752 /* Only check the world entry */
755 elog(ERROR, "aclcheck: bogus ACL id type: %d", idtype);
759 /* If get here, he doesn't have the privilege nohow */
760 return ACLCHECK_NO_PRIV;
764 * Exported routine for checking a user's access privileges to a table
766 * Returns an ACLCHECK_* result code.
769 pg_aclcheck(char *relname, Oid userid, AclMode mode)
779 * Validate userid, find out if he is superuser
781 tuple = SearchSysCache(SHADOWSYSID,
782 ObjectIdGetDatum(userid),
784 if (!HeapTupleIsValid(tuple))
785 elog(ERROR, "pg_aclcheck: invalid user id %u",
788 usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
791 * Deny anyone permission to update a system catalog unless
792 * pg_shadow.usecatupd is set. (This is to let superusers protect
793 * themselves from themselves.)
795 if ((mode & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
796 !allowSystemTableMods && IsSystemRelationName(relname) &&
797 !is_temp_relname(relname) &&
798 !((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd)
801 elog(DEBUG, "pg_aclcheck: catalog update to \"%s\": permission denied",
804 ReleaseSysCache(tuple);
805 return ACLCHECK_NO_PRIV;
809 * Otherwise, superusers bypass all permission-checking.
811 if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
814 elog(DEBUG, "pg_aclcheck: \"%s\" is superuser",
817 ReleaseSysCache(tuple);
821 ReleaseSysCache(tuple);
822 /* caution: usename is inaccessible beyond this point... */
825 * Normal case: get the relation's ACL from pg_class
827 tuple = SearchSysCache(RELNAME,
828 PointerGetDatum(relname),
830 if (!HeapTupleIsValid(tuple))
831 elog(ERROR, "pg_aclcheck: class \"%s\" not found", relname);
833 aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl,
837 /* No ACL, so build default ACL for rel */
840 ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
841 acl = acldefault(ownerId);
842 aclDatum = (Datum) 0;
846 /* detoast rel's ACL if necessary */
847 acl = DatumGetAclP(aclDatum);
850 result = aclcheck(acl, userid, (AclIdType) ACL_IDTYPE_UID, mode);
852 /* if we have a detoasted copy, free it */
853 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
856 ReleaseSysCache(tuple);
862 * Check ownership of an object identified by name (which will be looked
863 * up in the system cache identified by cacheid).
865 * Returns true if userid owns the item, or should be allowed to modify
866 * the item as if he owned it.
869 pg_ownercheck(Oid userid,
877 tuple = SearchSysCache(SHADOWSYSID,
878 ObjectIdGetDatum(userid),
880 if (!HeapTupleIsValid(tuple))
881 elog(ERROR, "pg_ownercheck: invalid user id %u",
883 usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
886 * Superusers bypass all permission-checking.
888 if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
891 elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
894 ReleaseSysCache(tuple);
898 ReleaseSysCache(tuple);
899 /* caution: usename is inaccessible beyond this point... */
901 tuple = SearchSysCache(cacheid,
902 PointerGetDatum(name),
907 if (!HeapTupleIsValid(tuple))
908 elog(ERROR, "pg_ownercheck: class \"%s\" not found",
910 owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
913 if (!HeapTupleIsValid(tuple))
914 elog(ERROR, "pg_ownercheck: type \"%s\" not found",
916 owner_id = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
919 elog(ERROR, "pg_ownercheck: invalid cache id: %d", cacheid);
920 owner_id = 0; /* keep compiler quiet */
924 ReleaseSysCache(tuple);
926 return userid == owner_id;
930 * Ownership check for an operator (specified by OID).
933 pg_oper_ownercheck(Oid userid, Oid oprid)
939 tuple = SearchSysCache(SHADOWSYSID,
940 ObjectIdGetDatum(userid),
942 if (!HeapTupleIsValid(tuple))
943 elog(ERROR, "pg_oper_ownercheck: invalid user id %u",
945 usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
948 * Superusers bypass all permission-checking.
950 if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
953 elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
956 ReleaseSysCache(tuple);
960 ReleaseSysCache(tuple);
961 /* caution: usename is inaccessible beyond this point... */
963 tuple = SearchSysCache(OPEROID,
964 ObjectIdGetDatum(oprid),
966 if (!HeapTupleIsValid(tuple))
967 elog(ERROR, "pg_ownercheck: operator %u not found",
970 owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
972 ReleaseSysCache(tuple);
974 return userid == owner_id;
978 * Ownership check for a function (specified by name and argument types).
981 pg_func_ownercheck(Oid userid,
990 tuple = SearchSysCache(SHADOWSYSID,
991 ObjectIdGetDatum(userid),
993 if (!HeapTupleIsValid(tuple))
994 elog(ERROR, "pg_func_ownercheck: invalid user id %u",
996 usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
999 * Superusers bypass all permission-checking.
1001 if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
1004 elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
1007 ReleaseSysCache(tuple);
1011 ReleaseSysCache(tuple);
1012 /* caution: usename is inaccessible beyond this point... */
1014 tuple = SearchSysCache(PROCNAME,
1015 PointerGetDatum(funcname),
1016 Int32GetDatum(nargs),
1017 PointerGetDatum(arglist),
1019 if (!HeapTupleIsValid(tuple))
1020 func_error("pg_func_ownercheck", funcname, nargs, arglist, NULL);
1022 owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
1024 ReleaseSysCache(tuple);
1026 return userid == owner_id;
1030 * Ownership check for an aggregate function (specified by name and
1034 pg_aggr_ownercheck(Oid userid,
1042 tuple = SearchSysCache(SHADOWSYSID,
1043 PointerGetDatum(userid),
1045 if (!HeapTupleIsValid(tuple))
1046 elog(ERROR, "pg_aggr_ownercheck: invalid user id %u",
1048 usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
1051 * Superusers bypass all permission-checking.
1053 if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
1056 elog(DEBUG, "pg_aggr_ownercheck: user \"%s\" is superuser",
1059 ReleaseSysCache(tuple);
1063 ReleaseSysCache(tuple);
1064 /* caution: usename is inaccessible beyond this point... */
1066 tuple = SearchSysCache(AGGNAME,
1067 PointerGetDatum(aggname),
1068 ObjectIdGetDatum(basetypeID),
1070 if (!HeapTupleIsValid(tuple))
1071 agg_error("pg_aggr_ownercheck", aggname, basetypeID);
1073 owner_id = ((Form_pg_aggregate) GETSTRUCT(tuple))->aggowner;
1075 ReleaseSysCache(tuple);
1077 return userid == owner_id;
1083 * Exported routine for checking a user's access privileges to a function
1085 * Returns an ACLCHECK_* result code.
1088 pg_proc_aclcheck(Oid proc_oid, Oid userid)
1096 if (superuser_arg(userid))
1102 tuple = SearchSysCache(SHADOWSYSID,
1103 ObjectIdGetDatum(userid),
1105 if (!HeapTupleIsValid(tuple))
1106 elog(ERROR, "pg_proc_aclcheck: invalid user id %u",
1108 ReleaseSysCache(tuple);
1111 * Normal case: get the function's ACL from pg_proc
1113 tuple = SearchSysCache(PROCOID,
1114 ObjectIdGetDatum(proc_oid),
1116 if (!HeapTupleIsValid(tuple))
1117 elog(ERROR, "pg_proc_aclcheck: function %u not found", proc_oid);
1119 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
1123 /* No ACL, so build default ACL */
1126 ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
1127 acl = acldefault(ownerId);
1128 aclDatum = (Datum) 0;
1132 /* detoast ACL if necessary */
1133 acl = DatumGetAclP(aclDatum);
1137 * Functions only have one kind of privilege, which is encoded as
1140 result = aclcheck(acl, userid, (AclIdType) ACL_IDTYPE_UID, ACL_SELECT);
1142 /* if we have a detoasted copy, free it */
1143 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1146 ReleaseSysCache(tuple);
1154 * Exported routine for checking a user's access privileges to a language
1156 * Returns an ACLCHECK_* result code.
1159 pg_language_aclcheck(Oid lang_oid, Oid userid)
1167 if (superuser_arg(userid))
1173 tuple = SearchSysCache(SHADOWSYSID,
1174 ObjectIdGetDatum(userid),
1176 if (!HeapTupleIsValid(tuple))
1177 elog(ERROR, "pg_language_aclcheck: invalid user id %u",
1179 ReleaseSysCache(tuple);
1182 * Normal case: get the function's ACL from pg_language
1184 tuple = SearchSysCache(LANGOID,
1185 ObjectIdGetDatum(lang_oid),
1187 if (!HeapTupleIsValid(tuple))
1188 elog(ERROR, "pg_language_aclcheck: language %u not found", lang_oid);
1190 aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
1194 /* No ACL, so build default ACL */
1195 acl = acldefault(InvalidOid);
1196 aclDatum = (Datum) 0;
1200 /* detoast ACL if necessary */
1201 acl = DatumGetAclP(aclDatum);
1205 * Languages only have one kind of privilege, which is encoded as
1208 result = aclcheck(acl, userid, (AclIdType) ACL_IDTYPE_UID, ACL_SELECT);
1210 /* if we have a detoasted copy, free it */
1211 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1214 ReleaseSysCache(tuple);