s4-dsdb: added new control DSDB_MODIFY_PARTIAL_REPLICA
[mat/samba.git] / source4 / dsdb / repl / replicated_objects.c
index 0def815c5f65029dc23bc9e0a07f671dd4b047c7..5ccf05255487213c7e3a76dec7a7a9b6743a1067 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "includes.h"
 #include "dsdb/samdb/samdb.h"
-#include "lib/ldb/include/ldb_errors.h"
+#include <ldb_errors.h>
 #include "../lib/util/dlinklist.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "librpc/gen_ndr/ndr_drsuapi.h"
@@ -61,6 +61,14 @@ WERROR dsdb_repl_make_working_schema(struct ldb_context *ldb,
        struct dsdb_schema *working_schema;
        const struct drsuapi_DsReplicaObjectListItemEx *cur;
        int ret, pass_no;
+       uint32_t ignore_attids[] = {
+                       DRSUAPI_ATTID_auxiliaryClass,
+                       DRSUAPI_ATTID_mayContain,
+                       DRSUAPI_ATTID_mustContain,
+                       DRSUAPI_ATTID_possSuperiors,
+                       DRSUAPI_ATTID_systemPossSuperiors,
+                       DRSUAPI_ATTID_INVALID
+       };
 
        /* make a copy of the iniatial_scheam so we don't mess with it */
        working_schema = dsdb_schema_copy_shallow(mem_ctx, ldb, initial_schema);
@@ -111,10 +119,12 @@ WERROR dsdb_repl_make_working_schema(struct ldb_context *ldb,
                         */
                        werr = dsdb_convert_object_ex(ldb, working_schema, pfm_remote,
                                                      cur, gensec_skey,
+                                                     ignore_attids,
+                                                     0,
                                                      tmp_ctx, &object);
                        if (!W_ERROR_IS_OK(werr)) {
-                               DEBUG(1,("Warning: Failed to convert schema object %s into ldb msg\n",
-                                        cur->object.identifier->dn));
+                               DEBUG(4,("debug: Failed to convert schema object %s into ldb msg, will try during next loop\n",
+                                         cur->object.identifier->dn));
 
                                failed_obj_count++;
                        } else {
@@ -127,7 +137,7 @@ WERROR dsdb_repl_make_working_schema(struct ldb_context *ldb,
                                                                       working_schema,
                                                                       object.msg);
                                if (!W_ERROR_IS_OK(werr)) {
-                                       DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n",
+                                       DEBUG(4,("debug: failed to convert object %s into a schema element, will try during next loop: %s\n",
                                                 ldb_dn_get_linearized(object.msg->dn),
                                                 win_errstr(werr)));
                                        failed_obj_count++;
@@ -163,11 +173,27 @@ WERROR dsdb_repl_make_working_schema(struct ldb_context *ldb,
        return WERR_OK;
 }
 
+static bool dsdb_attid_in_list(const uint32_t attid_list[], uint32_t attid)
+{
+       const uint32_t *cur;
+       if (!attid_list) {
+               return false;
+       }
+       for (cur = attid_list; *cur != DRSUAPI_ATTID_INVALID; cur++) {
+               if (*cur == attid) {
+                       return true;
+               }
+       }
+       return false;
+}
+
 WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
                              const struct dsdb_schema *schema,
                              const struct dsdb_schema_prefixmap *pfm_remote,
                              const struct drsuapi_DsReplicaObjectListItemEx *in,
                              const DATA_BLOB *gensec_skey,
+                             const uint32_t *ignore_attids,
+                             uint32_t dsdb_repl_flags,
                              TALLOC_CTX *mem_ctx,
                              struct dsdb_extended_replicated_object *out)
 {
@@ -189,6 +215,7 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
        struct replPropertyMetaData1 *rdn_m = NULL;
        struct dom_sid *sid = NULL;
        uint32_t rid = 0;
+       uint32_t attr_count;
        int ret;
 
        if (!in->object.identifier) {
@@ -243,7 +270,7 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
                                               md->ctr.ctr1.count + 1); /* +1 because of the RDN attribute */
        W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array);
 
-       for (i=0; i < in->meta_data_ctr->count; i++) {
+       for (i=0, attr_count=0; i < in->meta_data_ctr->count; i++, attr_count++) {
                struct drsuapi_DsReplicaAttribute *a;
                struct drsuapi_DsReplicaMetaData *d;
                struct replPropertyMetaData1 *m;
@@ -252,8 +279,13 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 
                a = &in->object.attribute_ctr.attributes[i];
                d = &in->meta_data_ctr->meta_data[i];
-               m = &md->ctr.ctr1.array[i];
-               e = &msg->elements[i];
+               m = &md->ctr.ctr1.array[attr_count];
+               e = &msg->elements[attr_count];
+
+               if (dsdb_attid_in_list(ignore_attids, a->attid)) {
+                       attr_count--;
+                       continue;
+               }
 
                for (j=0; j<a->value_ctr.num_values; j++) {
                        status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob, gensec_skey, rid, a);
@@ -278,10 +310,15 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
                if (a->attid == DRSUAPI_ATTID_name) {
                        name_a = a;
                        name_d = d;
-                       rdn_m = &md->ctr.ctr1.array[md->ctr.ctr1.count];
                }
        }
 
+       msg->num_elements = attr_count;
+       md->ctr.ctr1.count = attr_count;
+       if (name_a) {
+               rdn_m = &md->ctr.ctr1.array[md->ctr.ctr1.count];
+       }
+
        if (rdn_m) {
                struct ldb_message_element *el;
                el = ldb_msg_find_element(msg, rdn_attr->lDAPDisplayName);
@@ -314,6 +351,21 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 
        }
 
+       if (dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
+               /* the instanceType type for partial_replica
+                  replication is sent via DRS with TYPE_WRITE set, but
+                  must be used on the client with TYPE_WRITE removed
+               */
+               int instanceType = ldb_msg_find_attr_as_int(msg, "instanceType", 0);
+               if (instanceType & INSTANCE_TYPE_WRITE) {
+                       instanceType &= ~INSTANCE_TYPE_WRITE;
+                       ldb_msg_remove_attr(msg, "instanceType");
+                       if (ldb_msg_add_fmt(msg, "instanceType", "%d", instanceType) != LDB_SUCCESS) {
+                               return WERR_INTERNAL_ERROR;
+                       }
+               }
+       }
+
        whenChanged_t = nt_time_to_unix(whenChanged);
        whenChanged_s = ldb_timestring(msg, whenChanged_t);
        W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
@@ -341,6 +393,7 @@ WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
                                       const struct repsFromTo1 *source_dsa,
                                       const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
                                       const DATA_BLOB *gensec_skey,
+                                      uint32_t dsdb_repl_flags,
                                       TALLOC_CTX *mem_ctx,
                                       struct dsdb_extended_replicated_objects **objects)
 {
@@ -354,6 +407,7 @@ WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
        out = talloc_zero(mem_ctx, struct dsdb_extended_replicated_objects);
        W_ERROR_HAVE_NO_MEMORY(out);
        out->version            = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION;
+       out->dsdb_repl_flags    = dsdb_repl_flags;
 
        /*
         * Ensure schema is kept valid for as long as 'out'
@@ -412,6 +466,8 @@ WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
 
                status = dsdb_convert_object_ex(ldb, schema, pfm_remote,
                                                cur, gensec_skey,
+                                               NULL,
+                                               dsdb_repl_flags,
                                                out->objects, &out->objects[i]);
                if (!W_ERROR_IS_OK(status)) {
                        talloc_free(out);
@@ -634,6 +690,7 @@ WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
                                  TALLOC_CTX *mem_ctx,
                                  const struct drsuapi_DsReplicaObjectListItem *first_object,
                                  uint32_t *_num,
+                                 uint32_t dsdb_repl_flags,
                                  struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
 {
        WERROR status;
@@ -692,6 +749,32 @@ WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
                goto cancel;
        }
 
+       if (dsdb_repl_flags & DSDB_REPL_FLAG_ADD_NCNAME) {
+               /* check for possible NC creation */
+               for (i=0; i < num_objects; i++) {
+                       struct ldb_message *msg = objects[i];
+                       struct ldb_message_element *el;
+                       struct ldb_dn *nc_dn;
+
+                       if (ldb_msg_check_string_attribute(msg, "objectClass", "crossRef") == 0) {
+                               continue;
+                       }
+                       el = ldb_msg_find_element(msg, "nCName");
+                       if (el == NULL || el->num_values != 1) {
+                               continue;
+                       }
+                       nc_dn = ldb_dn_from_ldb_val(objects, ldb, &el->values[0]);
+                       if (!ldb_dn_validate(nc_dn)) {
+                               continue;
+                       }
+                       ret = dsdb_create_partial_replica_NC(ldb, nc_dn);
+                       if (ret != LDB_SUCCESS) {
+                               status = WERR_DS_INTERNAL_FAILURE;
+                               goto cancel;
+                       }
+               }
+       }
+
        for (i=0; i < num_objects; i++) {
                struct dom_sid *sid = NULL;
                struct ldb_request *add_req;