aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/misc/rls.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/misc/rls.c')
-rw-r--r--src/backend/utils/misc/rls.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/src/backend/utils/misc/rls.c b/src/backend/utils/misc/rls.c
index 44cb3743034..7b8d51d956f 100644
--- a/src/backend/utils/misc/rls.c
+++ b/src/backend/utils/misc/rls.c
@@ -16,9 +16,12 @@
#include "access/htup.h"
#include "access/htup_details.h"
+#include "access/transam.h"
#include "catalog/pg_class.h"
+#include "catalog/namespace.h"
#include "miscadmin.h"
#include "utils/acl.h"
+#include "utils/builtins.h"
#include "utils/elog.h"
#include "utils/rls.h"
#include "utils/syscache.h"
@@ -37,7 +40,10 @@ extern int check_enable_rls(Oid relid, Oid checkAsUser, bool noError);
* for the table and the plan cache needs to be invalidated if the environment
* changes.
*
- * Handle checking as another role via checkAsUser (for views, etc).
+ * Handle checking as another role via checkAsUser (for views, etc). Note that
+ * if *not* checking as another role, the caller should pass InvalidOid rather
+ * than GetUserId(). Otherwise the check for row_security = OFF is skipped, and
+ * so we may falsely report that RLS is active when the user has bypassed it.
*
* If noError is set to 'true' then we just return RLS_ENABLED instead of doing
* an ereport() if the user has attempted to bypass RLS and they are not
@@ -53,6 +59,17 @@ check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
bool relrowsecurity;
Oid user_id = checkAsUser ? checkAsUser : GetUserId();
+ /* Nothing to do for built-in relations */
+ if (relid < FirstNormalObjectId)
+ return RLS_NONE;
+
+ /*
+ * Check if we have been told to explicitly skip RLS (perhaps because this
+ * is a foreign key check)
+ */
+ if (InRowLevelSecurityDisabled())
+ return RLS_NONE;
+
tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tuple))
return RLS_NONE;
@@ -111,3 +128,37 @@ check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
/* RLS should be fully enabled for this relation. */
return RLS_ENABLED;
}
+
+/*
+ * row_security_active
+ *
+ * check_enable_rls wrapped as a SQL callable function except
+ * RLS_NONE_ENV and RLS_NONE are the same for this purpose.
+ */
+Datum
+row_security_active(PG_FUNCTION_ARGS)
+{
+ /* By OID */
+ Oid tableoid = PG_GETARG_OID(0);
+ int rls_status;
+
+ rls_status = check_enable_rls(tableoid, InvalidOid, true);
+ PG_RETURN_BOOL(rls_status == RLS_ENABLED);
+}
+
+Datum
+row_security_active_name(PG_FUNCTION_ARGS)
+{
+ /* By qualified name */
+ text *tablename = PG_GETARG_TEXT_P(0);
+ RangeVar *tablerel;
+ Oid tableoid;
+ int rls_status;
+
+ /* Look up table name. Can't lock it - we might not have privileges. */
+ tablerel = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
+ tableoid = RangeVarGetRelid(tablerel, NoLock, false);
+
+ rls_status = check_enable_rls(tableoid, InvalidOid, true);
+ PG_RETURN_BOOL(rls_status == RLS_ENABLED);
+}