replmd: keep links sorted in replmd_process_linked_attribute
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>
Fri, 27 Jan 2017 04:46:22 +0000 (17:46 +1300)
committerDouglas Bagnall <dbagnall@samba.org>
Thu, 9 Feb 2017 02:17:16 +0000 (03:17 +0100)
This is where linked attributes get added during a replication.

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Pair-programmed-with: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/dsdb/samdb/ldb_modules/repl_meta_data.c

index 2de00e1f1975fb06a237a873bd175208c01148fe..dbdcb102928e75e62f455b75f446d9409f6b0392 100644 (file)
@@ -6643,7 +6643,9 @@ linked_attributes[0]:
        }
 
        /* parse the existing links */
-       ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
+       ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
+                                    attr->syntax->ldap_oid, parent);
+
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
                return ret;
@@ -6834,12 +6836,33 @@ linked_attributes[0]:
                        }
                }
        } else {
+               unsigned offset;
                /* get a seq_num for this change */
                ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
                if (ret != LDB_SUCCESS) {
                        talloc_free(tmp_ctx);
                        return ret;
                }
+               /*
+                * We know where the new one needs to be, from the *next
+                * pointer into pdn_list.
+                */
+               if (next == NULL) {
+                       offset = old_el->num_values;
+               } else {
+                       if (next->dsdb_dn == NULL) {
+                               ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
+                                                             attr->syntax->ldap_oid);
+                               if (ret != LDB_SUCCESS) {
+                                       return ret;
+                               }
+                       }
+                       offset = next - pdn_list;
+                       if (offset > old_el->num_values) {
+                               talloc_free(tmp_ctx);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+               }
 
                old_el->values = talloc_realloc(msg->elements, old_el->values,
                                                struct ldb_val, old_el->num_values+1);
@@ -6847,9 +6870,15 @@ linked_attributes[0]:
                        ldb_module_oom(module);
                        return LDB_ERR_OPERATIONS_ERROR;
                }
+
+               if (offset != old_el->num_values) {
+                       memmove(&old_el->values[offset + 1], &old_el->values[offset],
+                               (old_el->num_values - offset) * sizeof(old_el->values[0]));
+               }
+
                old_el->num_values++;
 
-               ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
+               ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
                                          &la->meta_data.originating_invocation_id,
                                          la->meta_data.originating_usn, seq_num,
                                          la->meta_data.originating_change_time,