Blob Blame Raw
From 8e9222ed1edb8f5f234fa2451d17e4f8ac726998 Mon Sep 17 00:00:00 2001
From: Thierry Bordaz <>
Date: Thu, 22 Sep 2016 20:48:13 +0200
Subject: [PATCH 51/55] Ticket 48992: Total init may fail if the pushed schema
 is rejected

Bug Description:
    In the early phase of total update (or incremental update), the supplier may send its schema.
    A supplier will send its schema to the consumer at the condition its nsSchemaCSN is greater than
    the consumer nsSchemaCSN.
    If it is the case, a 1.2.11 supplier will systematically send its schema, while a 1.3 supplier will
    check that its schema is a superset of the consumer schema before sending it.
    If a 1.2.11 supplier sends its schema and that schema is a subset of consumer one, then
    the >1.3 consumer will detect it is a subset and reject the update.
    In that case the >1.3 consumer rejects a replicated update.

    On the consumer side, with the fix, if a
    replication operation fails, it may trigger the closure of the replication connection.
    The fix decides, based on the type of failure, if the failure can be ignored (leave the connection
    opened) or is fatal (close the connection).
    This is detected, on the consumer side, in multimaster_postop_*->process_postop->ignore_error_and_keep_going.

    In the current version, if a replicated update of the schema fails it return LDAP_UNWILLING_TO_PERFORM.
    This is a fatal error regarding ignore_error_and_keep_going that then close the connection
    and interrupt the total/incremental update.

    Note this bug can be transient as, the schema learning mechanism (on consumer) may learn from
    the received schema (even if it is rejected) and update its local schema that increase
    nsSchemaCSN. If this occur, a later replication session finding a greater nsSchemaCSN on the
    consumer side will not push the schema

Fix Description:
    When the update of the schema is rejected make it not fatal, switching the returned

Reviewed by: Noriko Hosoi, Ludwig Krispenz (thanks to you !)

Platforms tested: 7.3

Flag Day: no

Doc impact: no

(cherry picked from commit e2bc8fd60bf232cd4c1bc9a6860b7bd570a9dff1)
 ldap/servers/slapd/schema.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c
index 7689aa9..4b8910d 100644
--- a/ldap/servers/slapd/schema.c
+++ b/ldap/servers/slapd/schema.c
@@ -2120,7 +2120,24 @@ modify_schema_dse (Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *entr
                   slapi_log_error(SLAPI_LOG_FATAL, "schema",
 			                  "[C] Local %s must not be overwritten (set replication log for additional info)\n",
-                  *returncode = LDAP_UNWILLING_TO_PERFORM;
+                  /*
+                   * If the update (replicated) of the schema is rejected then
+                   * process_postop->ignore_error_and_keep_going will decide if
+                   * this failure is fatal or can be ignored.
+                   * LDAP_UNWILLING_TO_PERFORM is considered as fatal error --> close the connection
+                   * 
+                   * A 6.x supplier may send a subset schema and trigger this error, that
+                   * will break the replication session.
+                   * 
+                   * With new "learning" mechanism this is not that important if the
+                   * update of the schema is successful or not. Just be permissive
+                   * ignoring that failure to let the full replication session going on
+                   * So return LDAP_CONSTRAINT_VIOLATION (in place of LDAP_UNWILLING_TO_PERFORM)
+                   * is pick up as best choice of non fatal returncode.
+                   * (others better choices UNWILLING_TO_PERFORM, OPERATION_ERROR or ldap_error
+                   * are unfortunately all fatal). 
+                   */
+                  *returncode = LDAP_CONSTRAINT_VIOLATION;
                   return (SLAPI_DSE_CALLBACK_ERROR);