static int replmd_update_rpmd_element(struct ldb_context *ldb,
				      struct ldb_message *msg,
				      struct ldb_message_element *el,
				      struct ldb_message_element *old_el,
				      struct replPropertyMetaDataBlob *omd,
				      const struct dsdb_schema *schema,
				      uint64_t *seq_num,
				      const struct GUID *our_invocation_id,
				      NTTIME now,
				      bool is_schema_nc,
				      bool is_forced_rodc,
				      struct ldb_request *req)
{
	uint32_t i;
	const struct dsdb_attribute *a;
	struct replPropertyMetaData1 *md1;
	bool may_skip = false;
	uint32_t attid;

	a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
	if (a == NULL) {
		if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
			/* allow this to make it possible for dbcheck
			   to remove bad attributes */
			return LDB_SUCCESS;
		}

		DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
			 el->name));
		return LDB_ERR_OPERATIONS_ERROR;
	}

	attid = dsdb_attribute_get_attid(a, is_schema_nc);

	if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
		return LDB_SUCCESS;
	}

	/*
	 * if the attribute's value haven't changed, and this isn't
	 * just a delete of everything then return LDB_SUCCESS Unless
	 * we have the provision control or if the attribute is
	 * interSiteTopologyGenerator as this page explain:
	 * http://support.microsoft.com/kb/224815 this attribute is
	 * periodicaly written by the DC responsible for the intersite
	 * generation in a given site
	 *
	 * Unchanged could be deleting or replacing an already-gone
	 * thing with an unconstrained delete/empty replace or a
	 * replace with the same value, but not an add with the same
	 * value because that could be about adding a duplicate (which
	 * is for someone else to error out on).
	 */
	if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
		if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
			may_skip = true;
		}
	} else if (old_el == NULL && el->num_values == 0) {
		if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
			may_skip = true;
		} else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
			may_skip = true;
		}
	} else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
		   ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
		/*
		 * We intentionally skip the version bump when attempting to
		 * vanish links.
		 *
		 * The control is set by dbcheck and expunge-tombstones which
		 * both attempt to be non-replicating. Otherwise, making an
		 * alteration to the replication state would trigger a
		 * broadcast of all expunged objects.
		 */
		may_skip = true;
	}

	if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
		may_skip = false;
		el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
	}

	if (may_skip) {
		if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
		    !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
			/*
			 * allow this to make it possible for dbcheck
			 * to rebuild broken metadata
			 */
			return LDB_SUCCESS;
		}
	}

	for (i=0; i<omd->ctr.ctr1.count; i++) {
		/*
		 * First check if we find it under the msDS-IntID,
		 * then check if we find it under the OID and
		 * prefixMap ID.
		 *
		 * This allows the administrator to simply re-write
		 * the attributes and so restore replication, which is
		 * likely what they will try to do.
		 */
		if (attid == omd->ctr.ctr1.array[i].attid) {
			break;
		}

		if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
			break;
		}
	}

	if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
		/* linked attributes are not stored in
		   replPropertyMetaData in FL above w2k, but we do
		   raise the seqnum for the object  */
		if (*seq_num == 0 &&
		    ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
			return LDB_ERR_OPERATIONS_ERROR;
		}
		return LDB_SUCCESS;
	}

	if (i == omd->ctr.ctr1.count) {
		/* we need to add a new one */
		omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
						     struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
		if (omd->ctr.ctr1.array == NULL) {
			ldb_oom(ldb);
			return LDB_ERR_OPERATIONS_ERROR;
		}
		omd->ctr.ctr1.count++;
		ZERO_STRUCT(omd->ctr.ctr1.array[i]);
	}

	/* Get a new sequence number from the backend. We only do this
	 * if we have a change that requires a new
	 * replPropertyMetaData element
	 */
	if (*seq_num == 0) {
		int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
		if (ret != LDB_SUCCESS) {
			return LDB_ERR_OPERATIONS_ERROR;
		}
	}

	md1 = &omd->ctr.ctr1.array[i];
	md1->version++;
	md1->attid = attid;

	if (md1->attid == DRSUAPI_ATTID_isDeleted) {
		const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
		const char* rdn;

		if (rdn_val == NULL) {
			ldb_oom(ldb);
			return LDB_ERR_OPERATIONS_ERROR;
		}

		rdn = (const char*)rdn_val->data;
		if (strcmp(rdn, "Deleted Objects") == 0) {
			/*
			 * Set the originating_change_time to 29/12/9999 at 23:59:59
			 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
			 */
			md1->originating_change_time	= DELETED_OBJECT_CONTAINER_CHANGE_TIME;
		} else {
			md1->originating_change_time	= now;
		}
	} else {
		md1->originating_change_time	= now;
	}
	md1->originating_invocation_id = *our_invocation_id;
	md1->originating_usn           = *seq_num;
	md1->local_usn                 = *seq_num;

	if (is_forced_rodc) {
		/* Force version to 0 to be overridden later via replication */
		md1->version = 0;
	}

	return LDB_SUCCESS;
}
static int replmd_update_rpmd_element(struct ldb_context *ldb,
				      struct ldb_message *msg,
				      struct ldb_message_element *el,
				      struct ldb_message_element *old_el,
				      struct replPropertyMetaDataBlob *omd,
				      const struct dsdb_schema *schema,
				      uint64_t *seq_num,
				      const struct GUID *our_invocation_id,
				      NTTIME now,
				      bool is_schema_nc,
				      bool is_forced_rodc,
				      struct ldb_request *req)
{
	uint32_t i;
	const struct dsdb_attribute *a;
	struct replPropertyMetaData1 *md1;
	bool may_skip = false;
	uint32_t attid;

	a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
	if (a == NULL) {
		if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
			 
			return LDB_SUCCESS;
		}

		DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
			 el->name));
		return LDB_ERR_OPERATIONS_ERROR;
	}

	attid = dsdb_attribute_get_attid(a, is_schema_nc);

	if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
		return LDB_SUCCESS;
	}

	 
	if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
		if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
			may_skip = true;
		}
	} else if (old_el == NULL && el->num_values == 0) {
		if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
			may_skip = true;
		} else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
			may_skip = true;
		}
	} else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
		   ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
		 
		may_skip = true;
	}

	if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
		may_skip = false;
		el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
	}

	if (may_skip) {
		if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
		    !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
			 
			return LDB_SUCCESS;
		}
	}

	for (i=0; i<omd->ctr.ctr1.count; i++) {
		 
		if (attid == omd->ctr.ctr1.array[i].attid) {
			break;
		}

		if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
			break;
		}
	}

	if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
		 
		if (*seq_num == 0 &&
		    ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
			return LDB_ERR_OPERATIONS_ERROR;
		}
		return LDB_SUCCESS;
	}

	if (i == omd->ctr.ctr1.count) {
		 
		omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
						     struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
		if (omd->ctr.ctr1.array == NULL) {
			ldb_oom(ldb);
			return LDB_ERR_OPERATIONS_ERROR;
		}
		omd->ctr.ctr1.count++;
		ZERO_STRUCT(omd->ctr.ctr1.array[i]);
	}

	 
	if (*seq_num == 0) {
		int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
		if (ret != LDB_SUCCESS) {
			return LDB_ERR_OPERATIONS_ERROR;
		}
	}

	md1 = &omd->ctr.ctr1.array[i];
	md1->version++;
	md1->attid = attid;

	if (md1->attid == DRSUAPI_ATTID_isDeleted) {
		const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
		const char* rdn;

		if (rdn_val == NULL) {
			ldb_oom(ldb);
			return LDB_ERR_OPERATIONS_ERROR;
		}

		rdn = (const char*)rdn_val->data;
		if (strcmp(rdn, "Deleted Objects") == 0) {
			 
			md1->originating_change_time	= DELETED_OBJECT_CONTAINER_CHANGE_TIME;
		} else {
			md1->originating_change_time	= now;
		}
	} else {
		md1->originating_change_time	= now;
	}
	md1->originating_invocation_id = *our_invocation_id;
	md1->originating_usn           = *seq_num;
	md1->local_usn                 = *seq_num;

	if (is_forced_rodc) {
		 
		md1->version = 0;
	}

	return LDB_SUCCESS;
}