aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ri_triggers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/ri_triggers.c')
-rw-r--r--src/backend/utils/adt/ri_triggers.c87
1 files changed, 68 insertions, 19 deletions
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index e6dd4415077..f6bec8be9bc 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -43,6 +43,7 @@
#include "parser/parse_coerce.h"
#include "parser/parse_relation.h"
#include "miscadmin.h"
+#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
@@ -50,6 +51,7 @@
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
+#include "utils/rls.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
@@ -3197,6 +3199,9 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo,
bool onfk;
const int16 *attnums;
int idx;
+ Oid rel_oid;
+ AclResult aclresult;
+ bool has_perm = true;
if (spi_err)
ereport(ERROR,
@@ -3215,37 +3220,75 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo,
if (onfk)
{
attnums = riinfo->fk_attnums;
+ rel_oid = fk_rel->rd_id;
if (tupdesc == NULL)
tupdesc = fk_rel->rd_att;
}
else
{
attnums = riinfo->pk_attnums;
+ rel_oid = pk_rel->rd_id;
if (tupdesc == NULL)
tupdesc = pk_rel->rd_att;
}
- /* Get printable versions of the keys involved */
- initStringInfo(&key_names);
- initStringInfo(&key_values);
- for (idx = 0; idx < riinfo->nkeys; idx++)
+ /*
+ * Check permissions- if the user does not have access to view the data in
+ * any of the key columns then we don't include the errdetail() below.
+ *
+ * Check if RLS is enabled on the relation first. If so, we don't return
+ * any specifics to avoid leaking data.
+ *
+ * Check table-level permissions next and, failing that, column-level
+ * privileges.
+ */
+
+ if (check_enable_rls(rel_oid, GetUserId(), true) != RLS_ENABLED)
{
- int fnum = attnums[idx];
- char *name,
- *val;
+ aclresult = pg_class_aclcheck(rel_oid, GetUserId(), ACL_SELECT);
+ if (aclresult != ACLCHECK_OK)
+ {
+ /* Try for column-level permissions */
+ for (idx = 0; idx < riinfo->nkeys; idx++)
+ {
+ aclresult = pg_attribute_aclcheck(rel_oid, attnums[idx],
+ GetUserId(),
+ ACL_SELECT);
- name = SPI_fname(tupdesc, fnum);
- val = SPI_getvalue(violator, tupdesc, fnum);
- if (!val)
- val = "null";
+ /* No access to the key */
+ if (aclresult != ACLCHECK_OK)
+ {
+ has_perm = false;
+ break;
+ }
+ }
+ }
+ }
- if (idx > 0)
+ if (has_perm)
+ {
+ /* Get printable versions of the keys involved */
+ initStringInfo(&key_names);
+ initStringInfo(&key_values);
+ for (idx = 0; idx < riinfo->nkeys; idx++)
{
- appendStringInfoString(&key_names, ", ");
- appendStringInfoString(&key_values, ", ");
+ int fnum = attnums[idx];
+ char *name,
+ *val;
+
+ name = SPI_fname(tupdesc, fnum);
+ val = SPI_getvalue(violator, tupdesc, fnum);
+ if (!val)
+ val = "null";
+
+ if (idx > 0)
+ {
+ appendStringInfoString(&key_names, ", ");
+ appendStringInfoString(&key_values, ", ");
+ }
+ appendStringInfoString(&key_names, name);
+ appendStringInfoString(&key_values, val);
}
- appendStringInfoString(&key_names, name);
- appendStringInfoString(&key_values, val);
}
if (onfk)
@@ -3254,9 +3297,12 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo,
errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
RelationGetRelationName(fk_rel),
NameStr(riinfo->conname)),
- errdetail("Key (%s)=(%s) is not present in table \"%s\".",
- key_names.data, key_values.data,
- RelationGetRelationName(pk_rel)),
+ has_perm ?
+ errdetail("Key (%s)=(%s) is not present in table \"%s\".",
+ key_names.data, key_values.data,
+ RelationGetRelationName(pk_rel)) :
+ errdetail("Key is not present in table \"%s\".",
+ RelationGetRelationName(pk_rel)),
errtableconstraint(fk_rel, NameStr(riinfo->conname))));
else
ereport(ERROR,
@@ -3265,8 +3311,11 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo,
RelationGetRelationName(pk_rel),
NameStr(riinfo->conname),
RelationGetRelationName(fk_rel)),
+ has_perm ?
errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
key_names.data, key_values.data,
+ RelationGetRelationName(fk_rel)) :
+ errdetail("Key is still referenced from table \"%s\".",
RelationGetRelationName(fk_rel)),
errtableconstraint(fk_rel, NameStr(riinfo->conname))));
}