diff --git a/contrib/Makefile b/contrib/Makefile index 8e18785..ac9a2c5 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -9,6 +9,7 @@ SUBDIRS = \ auto_explain \ btree_gin \ btree_gist \ + check_dml \ chkpass \ citext \ cube \ diff --git a/contrib/check_dml/Makefile b/contrib/check_dml/Makefile new file mode 100644 index 0000000..4d9df0e --- /dev/null +++ b/contrib/check_dml/Makefile @@ -0,0 +1,15 @@ +# $PostgreSQL$ + +MODULE_big = check_dml +OBJS = check_dml.o + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/check_dml +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/check_dml/check_dml.c b/contrib/check_dml/check_dml.c new file mode 100644 index 0000000..0e9769d --- /dev/null +++ b/contrib/check_dml/check_dml.c @@ -0,0 +1,96 @@ +/*------------------------------------------------------------------------- + * + * check_dml.c + * + * + * Copyright (c) 2010, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $PostgreSQL$ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "executor/executor.h" +#include "utils/guc.h" +#include "utils/lsyscache.h" + +PG_MODULE_MAGIC; + +/* GUC variables */ +static char *check_dml_table_prefix = NULL; + +/* Saved hook values in case of unload */ +static ExecutorCheckPerms_hook_type prev_ExecutorCheckPerms = NULL; + +void _PG_init(void); +void _PG_fini(void); + +static void check_dml_ExecutorCheckPerms(List *rangeTable); + + +/* + * Module load callback + */ +void +_PG_init(void) +{ + /* Define custom GUC variables. */ + DefineCustomStringVariable("check_dml.table_prefix", + "Disallows DML access to tables whose names do not begin with this string.", + "An empty string effectively disables this feature.", + &check_dml_table_prefix, + "", + PGC_SUSET, + 0, + NULL, + NULL); + + /* Install hooks. */ + prev_ExecutorCheckPerms = ExecutorCheckPerms_hook; + ExecutorCheckPerms_hook = check_dml_ExecutorCheckPerms; +} + +/* + * Module unload callback + */ +void +_PG_fini(void) +{ + /* Uninstall hooks. */ + ExecutorCheckPerms_hook = prev_ExecutorCheckPerms; +} + +/* + * ExecutorStart hook: start up logging if needed + */ +static void +check_dml_ExecutorCheckPerms(List *rangeTable) +{ + if (check_dml_table_prefix && check_dml_table_prefix[0] != '\0') + { + ListCell *lc; + + foreach (lc, rangeTable) + { + RangeTblEntry *rte = lfirst(lc); + char *relname; + + /* Only need to check relations. */ + if (rte->rtekind != RTE_RELATION) + continue; + + /* Make sure it starts with the required prefix. */ + relname = get_rel_name(rte->relid); + if (strncmp(check_dml_table_prefix, + relname, + strlen(check_dml_table_prefix)) != 0) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("table name \"%s\" does not begin with \"%s\"", + relname, check_dml_table_prefix))); + pfree(relname); + } + } +} diff --git a/doc/src/sgml/check-dml.sgml b/doc/src/sgml/check-dml.sgml new file mode 100644 index 0000000..81701fe --- /dev/null +++ b/doc/src/sgml/check-dml.sgml @@ -0,0 +1,67 @@ + + + + check_dml + + + check_dml + + + + The check_dml allows DML statements to + be denied access to all tables whose names do not begin with a specified + prefix. This is mostly intended as an example of how ExecutorCheckPerms_hook + can be used to create a custom permissions-checking policy. + + + + The module provides no SQL-accessible functions. It should be loaded + into all sessions by including check_dml in + in + postgresql.conf. + + + + Configuration parameters + + + + + check_dml.table_prefix (string) + + + check_dml.table_prefix configuration parameter + + + + When check_dml.table_prefix is set to a non-empty + value, any attempt to access a table whose name does not begin with the + specified prefix will be rejected. + + + + + + + In order to set these parameters in your postgresql.conf file, + you will need to add auto_explain to + . Typical usage might be: + + + +# postgresql.conf +shared_preload_libraries = 'check_dml' + +custom_variable_classes = 'check_dml' + + + + check_dml could be used to implement per-user access policies + by using + ALTER USER ... SET (check_dml.table_prefix = ...). + Whether this is actually any better than existing permissions-checking + mechanisms is arguable. + + + + diff --git a/doc/src/sgml/contrib.sgml b/doc/src/sgml/contrib.sgml index 1d26aa9..77816a3 100644 --- a/doc/src/sgml/contrib.sgml +++ b/doc/src/sgml/contrib.sgml @@ -84,6 +84,7 @@ psql -d dbname -f SHAREDIR/contrib/module.sql &auto-explain; &btree-gin; &btree-gist; + &check-dml; &chkpass; &citext; &cube; diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml index 9dce7ba..e40735f 100644 --- a/doc/src/sgml/filelist.sgml +++ b/doc/src/sgml/filelist.sgml @@ -96,6 +96,7 @@ + diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index d299310..3d2082f 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -63,6 +63,9 @@ ExecutorStart_hook_type ExecutorStart_hook = NULL; ExecutorRun_hook_type ExecutorRun_hook = NULL; ExecutorEnd_hook_type ExecutorEnd_hook = NULL; +/* Hook for plugin to get control in ExecCheckRTPerms() */ +ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook = NULL; + /* decls for local routines only used within this module */ static void InitPlan(QueryDesc *queryDesc, int eflags); static void ExecEndPlan(PlanState *planstate, EState *estate); @@ -416,6 +419,9 @@ ExecCheckRTPerms(List *rangeTable) { ExecCheckRTEPerms((RangeTblEntry *) lfirst(l)); } + + if (ExecutorCheckPerms_hook) + (*ExecutorCheckPerms_hook)(rangeTable); } /* diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 820314c..caff1b4 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -74,6 +74,10 @@ extern PGDLLIMPORT ExecutorRun_hook_type ExecutorRun_hook; typedef void (*ExecutorEnd_hook_type) (QueryDesc *queryDesc); extern PGDLLIMPORT ExecutorEnd_hook_type ExecutorEnd_hook; +/* Hook for plugins to get control in ExecCheckRTPerms() */ +typedef void (*ExecutorCheckPerms_hook_type) (List *); +extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook; + /* * prototypes from functions in execAmi.c