diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 0ad84f9035e..6ddf97e6093 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -74,6 +74,7 @@ typedef struct EventTriggerQueryState } EventTriggerQueryState; static EventTriggerQueryState *currentEventTriggerState = NULL; +EventTrigger_hook_type EventTrigger_hook = NULL; /* Support for dropped objects */ typedef struct SQLDropObject @@ -922,7 +923,10 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata) InitFunctionCallInfoData(*fcinfo, &flinfo, 0, InvalidOid, (Node *) trigdata, NULL); pgstat_init_function_usage(fcinfo, &fcusage); - FunctionCallInvoke(fcinfo); + if (EventTrigger_hook) + EventTrigger_hook(fcinfo); + else + FunctionCallInvoke(fcinfo); pgstat_end_function_usage(&fcusage, true); /* Reclaim memory. */ diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 8bb2b35a8b8..8d5f4858aed 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -70,6 +70,8 @@ int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN; /* How many levels deep into trigger execution are we? */ static int MyTriggerDepth = 0; +DataTrigger_hook_type DataTrigger_hook = NULL; + /* Local function prototypes */ static void renametrig_internal(Relation tgrel, Relation targetrel, HeapTuple trigtup, const char *newname, @@ -2429,7 +2431,10 @@ ExecCallTriggerFunc(TriggerData *trigdata, MyTriggerDepth++; PG_TRY(); { - result = FunctionCallInvoke(fcinfo); + if (DataTrigger_hook) + result = DataTrigger_hook(fcinfo); + else + result = FunctionCallInvoke(fcinfo); } PG_FINALLY(); { diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 81d43a84271..2e918dc903e 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -123,6 +123,24 @@ static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue */ char *privileged_role_name = NULL; +static bool +is_privileged_role_arg_super(Oid roleid, bool nosuper) +{ + Oid privileged_role_oid; + + if (privileged_role_name == NULL) + return false; + + privileged_role_oid = get_role_oid(privileged_role_name, true /* missing_ok */); + + if (privileged_role_oid == InvalidOid) + return false; + + if (nosuper) + return has_privs_of_role_nosuper(roleid, privileged_role_oid); + return has_privs_of_role(roleid, privileged_role_oid); +} + bool is_privileged_role(void) { @@ -132,14 +150,12 @@ is_privileged_role(void) bool is_privileged_role_arg(Oid roleid) { - Oid privileged_role_oid; - - if (privileged_role_name == NULL) - return false; - - privileged_role_oid = get_role_oid(privileged_role_name, true /* missing_ok */); + return is_privileged_role_arg_super(roleid, false); +} - return privileged_role_oid != InvalidOid && has_privs_of_role(roleid, privileged_role_oid); +bool is_privileged_role_nosuper(void) +{ + return is_privileged_role_arg_super(GetUserId(), true); } /* @@ -5008,6 +5024,23 @@ has_privs_of_role(Oid member, Oid role) role); } +/* + * Same as has_privs_of_role, but ignores checking superuser. + */ + bool + has_privs_of_role_nosuper(Oid member, Oid role) + { + /* Fast path for simple case */ + if (member == role) + return true; + /* + * Find all the roles that member has the privileges of, including + * multi-level recursion, then see if target role is any one of them. + */ + return list_member_oid(roles_is_member_of(member, ROLERECURSE_PRIVS, + InvalidOid, NULL), + role); + } /* * Is member a member of role (directly or indirectly)? diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index d20e7af7970..d1064f03076 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -35,6 +35,7 @@ static Oid last_roleid = InvalidOid; /* InvalidOid == cache not valid */ static bool last_roleid_is_super = false; static bool roleid_callback_registered = false; +SUForUser_hook_type SUForUser_hook = NULL; static void RoleidCallback(Datum arg, int cacheid, uint32 hashvalue); @@ -72,6 +73,11 @@ superuser_arg(Oid roleid) { result = ((Form_pg_authid) GETSTRUCT(rtup))->rolsuper; ReleaseSysCache(rtup); + + if (!result && SUForUser_hook != NULL) + { + result = SUForUser_hook(roleid); + } } else { diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h index 321e6a6ca07..b1545f99279 100644 --- a/src/include/commands/event_trigger.h +++ b/src/include/commands/event_trigger.h @@ -16,6 +16,7 @@ #include "catalog/dependency.h" #include "catalog/objectaddress.h" #include "catalog/pg_event_trigger.h" +#include "fmgr.h" #include "nodes/parsenodes.h" #include "tcop/cmdtag.h" #include "tcop/deparse_utility.h" @@ -47,6 +48,9 @@ typedef struct EventTriggerData #define CALLED_AS_EVENT_TRIGGER(fcinfo) \ ((fcinfo)->context != NULL && IsA((fcinfo)->context, EventTriggerData)) +typedef void (*EventTrigger_hook_type)(FunctionCallInfo fcinfo); +extern PGDLLEXPORT EventTrigger_hook_type EventTrigger_hook; + extern Oid CreateEventTrigger(CreateEventTrigStmt *stmt); extern Oid get_event_trigger_oid(const char *trigname, bool missing_ok); diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h index fff8d16c416..48d3302f06b 100644 --- a/src/include/commands/trigger.h +++ b/src/include/commands/trigger.h @@ -151,6 +151,9 @@ extern PGDLLIMPORT int SessionReplicationRole; #define TRIGGER_FIRES_ON_REPLICA 'R' #define TRIGGER_DISABLED 'D' +typedef Datum (*DataTrigger_hook_type)(FunctionCallInfo fcinfo); +extern PGDLLEXPORT DataTrigger_hook_type DataTrigger_hook; + extern ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, Oid funcoid, Oid parentTriggerOid, Node *whenClause, diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 89a7b62208b..2e4f4bccb80 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -379,9 +379,13 @@ extern void SetCurrentRoleId(Oid roleid, bool is_superuser); extern bool superuser(void); /* current user is superuser */ extern bool superuser_arg(Oid roleid); /* given user is superuser */ +typedef bool (*SUForUser_hook_type) (Oid roleid); +extern SUForUser_hook_type SUForUser_hook; + /* in utils/adt/acl.c */ extern PGDLLIMPORT char *privileged_role_name; extern bool is_privileged_role(void); /* current user is a privileged role */ +extern bool is_privileged_role_nosuper(void); /* current user is a privileged role */ extern bool is_privileged_role_arg(Oid roleid); /* given user is a privileged role */ diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 48f7d72add5..2429e1f893d 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -209,6 +209,7 @@ extern AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, extern int aclmembers(const Acl *acl, Oid **roleids); extern bool has_privs_of_role(Oid member, Oid role); +extern bool has_privs_of_role_nosuper(Oid member, Oid role); extern bool is_member_of_role(Oid member, Oid role); extern bool is_member_of_role_nosuper(Oid member, Oid role); extern bool is_admin_of_role(Oid member, Oid role);