|
179 | 179 | #include "storage/proc.h"
|
180 | 180 | #include "storage/procarray.h"
|
181 | 181 | #include "tcop/tcopprot.h"
|
| 182 | +#include "utils/acl.h" |
182 | 183 | #include "utils/builtins.h"
|
183 | 184 | #include "utils/catcache.h"
|
184 | 185 | #include "utils/dynahash.h"
|
|
189 | 190 | #include "utils/lsyscache.h"
|
190 | 191 | #include "utils/memutils.h"
|
191 | 192 | #include "utils/rel.h"
|
| 193 | +#include "utils/rls.h" |
192 | 194 | #include "utils/syscache.h"
|
193 | 195 | #include "utils/timeout.h"
|
194 | 196 |
|
@@ -1530,6 +1532,38 @@ GetRelationIdentityOrPK(Relation rel)
|
1530 | 1532 | return idxoid;
|
1531 | 1533 | }
|
1532 | 1534 |
|
| 1535 | +/* |
| 1536 | + * Check that we (the subscription owner) have sufficient privileges on the |
| 1537 | + * target relation to perform the given operation. |
| 1538 | + */ |
| 1539 | +static void |
| 1540 | +TargetPrivilegesCheck(Relation rel, AclMode mode) |
| 1541 | +{ |
| 1542 | + Oid relid; |
| 1543 | + AclResult aclresult; |
| 1544 | + |
| 1545 | + relid = RelationGetRelid(rel); |
| 1546 | + aclresult = pg_class_aclcheck(relid, GetUserId(), mode); |
| 1547 | + if (aclresult != ACLCHECK_OK) |
| 1548 | + aclcheck_error(aclresult, |
| 1549 | + get_relkind_objtype(rel->rd_rel->relkind), |
| 1550 | + get_rel_name(relid)); |
| 1551 | + |
| 1552 | + /* |
| 1553 | + * We lack the infrastructure to honor RLS policies. It might be possible |
| 1554 | + * to add such infrastructure here, but tablesync workers lack it, too, so |
| 1555 | + * we don't bother. RLS does not ordinarily apply to TRUNCATE commands, |
| 1556 | + * but it seems dangerous to replicate a TRUNCATE and then refuse to |
| 1557 | + * replicate subsequent INSERTs, so we forbid all commands the same. |
| 1558 | + */ |
| 1559 | + if (check_enable_rls(relid, InvalidOid, false) == RLS_ENABLED) |
| 1560 | + ereport(ERROR, |
| 1561 | + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 1562 | + errmsg("\"%s\" cannot replicate into relation with row-level security enabled: \"%s\"", |
| 1563 | + GetUserNameFromId(GetUserId(), true), |
| 1564 | + RelationGetRelationName(rel)))); |
| 1565 | +} |
| 1566 | + |
1533 | 1567 | /*
|
1534 | 1568 | * Handle INSERT message.
|
1535 | 1569 | */
|
@@ -1613,6 +1647,7 @@ apply_handle_insert_internal(ApplyExecutionData *edata,
|
1613 | 1647 | ExecOpenIndices(relinfo, false);
|
1614 | 1648 |
|
1615 | 1649 | /* Do the insert. */
|
| 1650 | + TargetPrivilegesCheck(relinfo->ri_RelationDesc, ACL_INSERT); |
1616 | 1651 | ExecSimpleRelationInsert(relinfo, estate, remoteslot);
|
1617 | 1652 |
|
1618 | 1653 | /* Cleanup. */
|
@@ -1796,6 +1831,7 @@ apply_handle_update_internal(ApplyExecutionData *edata,
|
1796 | 1831 | EvalPlanQualSetSlot(&epqstate, remoteslot);
|
1797 | 1832 |
|
1798 | 1833 | /* Do the actual update. */
|
| 1834 | + TargetPrivilegesCheck(relinfo->ri_RelationDesc, ACL_UPDATE); |
1799 | 1835 | ExecSimpleRelationUpdate(relinfo, estate, &epqstate, localslot,
|
1800 | 1836 | remoteslot);
|
1801 | 1837 | }
|
@@ -1917,6 +1953,7 @@ apply_handle_delete_internal(ApplyExecutionData *edata,
|
1917 | 1953 | EvalPlanQualSetSlot(&epqstate, localslot);
|
1918 | 1954 |
|
1919 | 1955 | /* Do the actual delete. */
|
| 1956 | + TargetPrivilegesCheck(relinfo->ri_RelationDesc, ACL_DELETE); |
1920 | 1957 | ExecSimpleRelationDelete(relinfo, estate, &epqstate, localslot);
|
1921 | 1958 | }
|
1922 | 1959 | else
|
@@ -2110,6 +2147,8 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
|
2110 | 2147 | ExecOpenIndices(partrelinfo, false);
|
2111 | 2148 |
|
2112 | 2149 | EvalPlanQualSetSlot(&epqstate, remoteslot_part);
|
| 2150 | + TargetPrivilegesCheck(partrelinfo->ri_RelationDesc, |
| 2151 | + ACL_UPDATE); |
2113 | 2152 | ExecSimpleRelationUpdate(partrelinfo, estate, &epqstate,
|
2114 | 2153 | localslot, remoteslot_part);
|
2115 | 2154 | ExecCloseIndices(partrelinfo);
|
@@ -2236,6 +2275,7 @@ apply_handle_truncate(StringInfo s)
|
2236 | 2275 | }
|
2237 | 2276 |
|
2238 | 2277 | remote_rels = lappend(remote_rels, rel);
|
| 2278 | + TargetPrivilegesCheck(rel->localrel, ACL_TRUNCATE); |
2239 | 2279 | rels = lappend(rels, rel->localrel);
|
2240 | 2280 | relids = lappend_oid(relids, rel->localreloid);
|
2241 | 2281 | if (RelationIsLogicallyLogged(rel->localrel))
|
@@ -2273,6 +2313,7 @@ apply_handle_truncate(StringInfo s)
|
2273 | 2313 | continue;
|
2274 | 2314 | }
|
2275 | 2315 |
|
| 2316 | + TargetPrivilegesCheck(childrel, ACL_TRUNCATE); |
2276 | 2317 | rels = lappend(rels, childrel);
|
2277 | 2318 | part_rels = lappend(part_rels, childrel);
|
2278 | 2319 | relids = lappend_oid(relids, childrelid);
|
@@ -2915,6 +2956,7 @@ maybe_reread_subscription(void)
|
2915 | 2956 | strcmp(newsub->slotname, MySubscription->slotname) != 0 ||
|
2916 | 2957 | newsub->binary != MySubscription->binary ||
|
2917 | 2958 | newsub->stream != MySubscription->stream ||
|
| 2959 | + newsub->owner != MySubscription->owner || |
2918 | 2960 | !equal(newsub->publications, MySubscription->publications))
|
2919 | 2961 | {
|
2920 | 2962 | ereport(LOG,
|
|
0 commit comments