Add String object access hooks

This caters for cases where the access is to an object identified by
name rather than Oid.

The first user of these is the GUC access controls

Joshua Brindle and Mark Dilger

Discussion: https://postgr.es/m/47F87A0E-C0E5-43A6-89F6-D403F2B45175@enterprisedb.com
This commit is contained in:
Andrew Dunstan 2022-03-22 09:06:15 -04:00
parent 29992a6a50
commit d11e84ea46
5 changed files with 226 additions and 9 deletions

View File

@ -20,11 +20,13 @@
* and logging plugins.
*/
object_access_hook_type object_access_hook = NULL;
object_access_hook_type_str object_access_hook_str = NULL;
/*
* RunObjectPostCreateHook
*
* It is entrypoint of OAT_POST_CREATE event
* OAT_POST_CREATE object ID based event hook entrypoint
*/
void
RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
@ -46,7 +48,7 @@ RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
/*
* RunObjectDropHook
*
* It is entrypoint of OAT_DROP event
* OAT_DROP object ID based event hook entrypoint
*/
void
RunObjectDropHook(Oid classId, Oid objectId, int subId,
@ -68,7 +70,7 @@ RunObjectDropHook(Oid classId, Oid objectId, int subId,
/*
* RunObjectTruncateHook
*
* It is the entrypoint of OAT_TRUNCATE event
* OAT_TRUNCATE object ID based event hook entrypoint
*/
void
RunObjectTruncateHook(Oid objectId)
@ -84,7 +86,7 @@ RunObjectTruncateHook(Oid objectId)
/*
* RunObjectPostAlterHook
*
* It is entrypoint of OAT_POST_ALTER event
* OAT_POST_ALTER object ID based event hook entrypoint
*/
void
RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
@ -107,7 +109,7 @@ RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
/*
* RunNamespaceSearchHook
*
* It is entrypoint of OAT_NAMESPACE_SEARCH event
* OAT_NAMESPACE_SEARCH object ID based event hook entrypoint
*/
bool
RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation)
@ -131,7 +133,7 @@ RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation)
/*
* RunFunctionExecuteHook
*
* It is entrypoint of OAT_FUNCTION_EXECUTE event
* OAT_FUNCTION_EXECUTE object ID based event hook entrypoint
*/
void
RunFunctionExecuteHook(Oid objectId)
@ -143,3 +145,129 @@ RunFunctionExecuteHook(Oid objectId)
ProcedureRelationId, objectId, 0,
NULL);
}
/* String versions */
/*
* RunObjectPostCreateHookStr
*
* OAT_POST_CREATE object name based event hook entrypoint
*/
void
RunObjectPostCreateHookStr(Oid classId, const char *objectName, int subId,
bool is_internal)
{
ObjectAccessPostCreate pc_arg;
/* caller should check, but just in case... */
Assert(object_access_hook_str != NULL);
memset(&pc_arg, 0, sizeof(ObjectAccessPostCreate));
pc_arg.is_internal = is_internal;
(*object_access_hook_str) (OAT_POST_CREATE,
classId, objectName, subId,
(void *) &pc_arg);
}
/*
* RunObjectDropHookStr
*
* OAT_DROP object name based event hook entrypoint
*/
void
RunObjectDropHookStr(Oid classId, const char *objectName, int subId,
int dropflags)
{
ObjectAccessDrop drop_arg;
/* caller should check, but just in case... */
Assert(object_access_hook_str != NULL);
memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
drop_arg.dropflags = dropflags;
(*object_access_hook_str) (OAT_DROP,
classId, objectName, subId,
(void *) &drop_arg);
}
/*
* RunObjectTruncateHookStr
*
* OAT_TRUNCATE object name based event hook entrypoint
*/
void
RunObjectTruncateHookStr(const char *objectName)
{
/* caller should check, but just in case... */
Assert(object_access_hook_str != NULL);
(*object_access_hook_str) (OAT_TRUNCATE,
RelationRelationId, objectName, 0,
NULL);
}
/*
* RunObjectPostAlterHookStr
*
* OAT_POST_ALTER object name based event hook entrypoint
*/
void
RunObjectPostAlterHookStr(Oid classId, const char *objectName, int subId,
Oid auxiliaryId, bool is_internal)
{
ObjectAccessPostAlter pa_arg;
/* caller should check, but just in case... */
Assert(object_access_hook_str != NULL);
memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
pa_arg.auxiliary_id = auxiliaryId;
pa_arg.is_internal = is_internal;
(*object_access_hook_str) (OAT_POST_ALTER,
classId, objectName, subId,
(void *) &pa_arg);
}
/*
* RunNamespaceSearchHookStr
*
* OAT_NAMESPACE_SEARCH object name based event hook entrypoint
*/
bool
RunNamespaceSearchHookStr(const char *objectName, bool ereport_on_violation)
{
ObjectAccessNamespaceSearch ns_arg;
/* caller should check, but just in case... */
Assert(object_access_hook_str != NULL);
memset(&ns_arg, 0, sizeof(ObjectAccessNamespaceSearch));
ns_arg.ereport_on_violation = ereport_on_violation;
ns_arg.result = true;
(*object_access_hook_str) (OAT_NAMESPACE_SEARCH,
NamespaceRelationId, objectName, 0,
(void *) &ns_arg);
return ns_arg.result;
}
/*
* RunFunctionExecuteHookStr
*
* OAT_FUNCTION_EXECUTE object name based event hook entrypoint
*/
void
RunFunctionExecuteHookStr(const char *objectName)
{
/* caller should check, but just in case... */
Assert(object_access_hook_str != NULL);
(*object_access_hook_str) (OAT_FUNCTION_EXECUTE,
ProcedureRelationId, objectName, 0,
NULL);
}

View File

@ -43,6 +43,7 @@
#include "access/xlog_internal.h"
#include "access/xlogrecovery.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_authid.h"
#include "catalog/storage.h"
#include "commands/async.h"
@ -8736,6 +8737,18 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
replace_auto_config_value(&head, &tail, name, value);
}
/*
* Invoke the post-alter hook for altering this GUC variable.
*
* We do this here rather than at the end, because ALTER SYSTEM is not
* transactional. If the hook aborts our transaction, it will be cleaner
* to do so before we touch any files.
*/
InvokeObjectPostAlterHookArgStr(InvalidOid, name,
ACL_ALTER_SYSTEM,
altersysstmt->setstmt->kind,
false);
/*
* To ensure crash safety, first write the new file data to a temp file,
* then atomically rename it into place.
@ -8907,6 +8920,10 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
ResetAllOptions();
break;
}
/* Invoke the post-alter hook for setting this GUC variable. */
InvokeObjectPostAlterHookArgStr(InvalidOid, stmt->name,
ACL_SET_VALUE, stmt->kind, false);
}
/*

View File

@ -121,15 +121,23 @@ typedef struct
bool result;
} ObjectAccessNamespaceSearch;
/* Plugin provides a hook function matching this signature. */
/* Plugin provides a hook function matching one or both of these signatures. */
typedef void (*object_access_hook_type) (ObjectAccessType access,
Oid classId,
Oid objectId,
int subId,
void *arg);
typedef void (*object_access_hook_type_str) (ObjectAccessType access,
Oid classId,
const char *objectStr,
int subId,
void *arg);
/* Plugin sets this variable to a suitable hook function. */
extern PGDLLIMPORT object_access_hook_type object_access_hook;
extern PGDLLIMPORT object_access_hook_type_str object_access_hook_str;
/* Core code uses these functions to call the hook (see macros below). */
extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
@ -142,6 +150,18 @@ extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation);
extern void RunFunctionExecuteHook(Oid objectId);
/* String versions */
extern void RunObjectPostCreateHookStr(Oid classId, const char *objectStr, int subId,
bool is_internal);
extern void RunObjectDropHookStr(Oid classId, const char *objectStr, int subId,
int dropflags);
extern void RunObjectTruncateHookStr(const char *objectStr);
extern void RunObjectPostAlterHookStr(Oid classId, const char *objectStr, int subId,
Oid auxiliaryId, bool is_internal);
extern bool RunNamespaceSearchHookStr(const char *objectStr, bool ereport_on_violation);
extern void RunFunctionExecuteHookStr(const char *objectStr);
/*
* The following macros are wrappers around the functions above; these should
* normally be used to invoke the hook in lieu of calling the above functions
@ -194,4 +214,52 @@ extern void RunFunctionExecuteHook(Oid objectId);
RunFunctionExecuteHook(objectId); \
} while(0)
#define InvokeObjectPostCreateHookStr(classId,objectName,subId) \
InvokeObjectPostCreateHookArgStr((classId),(objectName),(subId),false)
#define InvokeObjectPostCreateHookArgStr(classId,objectName,subId,is_internal) \
do { \
if (object_access_hook_str) \
RunObjectPostCreateHookStr((classId),(objectName),(subId), \
(is_internal)); \
} while(0)
#define InvokeObjectDropHookStr(classId,objectName,subId) \
InvokeObjectDropHookArgStr((classId),(objectName),(subId),0)
#define InvokeObjectDropHookArgStr(classId,objectName,subId,dropflags) \
do { \
if (object_access_hook_str) \
RunObjectDropHookStr((classId),(objectName),(subId), \
(dropflags)); \
} while(0)
#define InvokeObjectTruncateHookStr(objectName) \
do { \
if (object_access_hook_str) \
RunObjectTruncateHookStr(objectName); \
} while(0)
#define InvokeObjectPostAlterHookStr(className,objectName,subId) \
InvokeObjectPostAlterHookArgStr((classId),(objectName),(subId), \
InvalidOid,false)
#define InvokeObjectPostAlterHookArgStr(classId,objectName,subId, \
auxiliaryId,is_internal) \
do { \
if (object_access_hook_str) \
RunObjectPostAlterHookStr((classId),(objectName),(subId), \
(auxiliaryId),(is_internal)); \
} while(0)
#define InvokeNamespaceSearchHookStr(objectName, ereport_on_violation) \
(!object_access_hook_str \
? true \
: RunNamespaceSearchHookStr((objectName), (ereport_on_violation)))
#define InvokeFunctionExecuteHookStr(objectName) \
do { \
if (object_access_hook_str) \
RunFunctionExecuteHookStr(objectName); \
} while(0)
#endif /* OBJECTACCESS_H */

View File

@ -92,7 +92,9 @@ typedef uint32 AclMode; /* a bitmask of privilege bits */
#define ACL_CREATE (1<<9) /* for namespaces and databases */
#define ACL_CREATE_TEMP (1<<10) /* for databases */
#define ACL_CONNECT (1<<11) /* for databases */
#define N_ACL_RIGHTS 12 /* 1 plus the last 1<<x */
#define ACL_SET_VALUE (1<<12) /* for configuration parameters */
#define ACL_ALTER_SYSTEM (1<<13) /* for configuration parameters */
#define N_ACL_RIGHTS 14 /* 1 plus the last 1<<x */
#define ACL_NO_RIGHTS 0
/* Currently, SELECT ... FOR [KEY] UPDATE/SHARE requires UPDATE privileges */
#define ACL_SELECT_FOR_UPDATE ACL_UPDATE

View File

@ -146,9 +146,11 @@ typedef struct ArrayType Acl;
#define ACL_CREATE_CHR 'C'
#define ACL_CREATE_TEMP_CHR 'T'
#define ACL_CONNECT_CHR 'c'
#define ACL_SET_VALUE_CHR 's'
#define ACL_ALTER_SYSTEM_CHR 'A'
/* string holding all privilege code chars, in order by bitmask position */
#define ACL_ALL_RIGHTS_STR "arwdDxtXUCTc"
#define ACL_ALL_RIGHTS_STR "arwdDxtXUCTcsA"
/*
* Bitmasks defining "all rights" for each supported object type