s4-ldb: Add isRecycled when recycle-bin is not activated and attribute is valid is...
authorMatthieu Patou <mat@matws.net>
Tue, 1 Nov 2011 22:12:47 +0000 (23:12 +0100)
committerMatthieu Patou <mat@matws.net>
Wed, 9 Nov 2011 17:51:06 +0000 (18:51 +0100)
source4/dsdb/samdb/ldb_modules/repl_meta_data.c

index 194498e6ddbf2be04a4f07fa45c16ce0283528aa..2ff3aad2cd14d8abb4f07af426aa5cd0ca98b9f3 100644 (file)
@@ -86,6 +86,8 @@ struct replmd_replicated_request {
 
        uint64_t seq_num;
        bool is_urgent;
+       bool is_recycled_in_schema;
+       bool is_recycled_tested;
 };
 
 enum urgent_situation {
@@ -2709,6 +2711,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
 {
        int ret = LDB_ERR_OTHER;
        bool retb, disallow_move_on_delete;
+       bool add_recycled = false;
        struct ldb_dn *old_dn, *new_dn;
        const char *rdn_name;
        const struct ldb_val *rdn_value, *new_rdn_value;
@@ -2953,8 +2956,21 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
        case OBJECT_TOMBSTONE:
 
                /* we also mark it as recycled, meaning this object can't be
-                  recovered (we are stripping its attributes) */
-               if (functional_level >= DS_DOMAIN_FUNCTION_2008_R2) {
+                  recovered (we are stripping its attributes).
+                  This is done only if we have this schema object of course ...
+                  This behavior is identical to the one of Windows 2008R2 which
+                  always set the isRecycled attribute if the recycle-bin is
+                  not activated and what ever the forest level is.
+                  */
+               if (functional_level < DS_DOMAIN_FUNCTION_2008_R2) {
+                       if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
+                               add_recycled = true;
+                       }
+               } else {
+                       add_recycled = true;
+               }
+
+               if (add_recycled) {
                        ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
                        if (ret != LDB_SUCCESS) {
                                DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
@@ -3488,6 +3504,9 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
        struct replPropertyMetaDataBlob *md;
        struct ldb_val md_value;
        unsigned int i;
+       bool is_deleted = false;
+       bool is_recycled = false;
+       bool rcbin_enabled = false;
        int ret;
 
        /*
@@ -3528,10 +3547,33 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
                return replmd_replicated_request_error(ar, ret);
        }
 
+       if (!ar->is_recycled_tested) {
+               if (dsdb_attribute_by_lDAPDisplayName(ar->schema, "isRecycled") != NULL) {
+                       ar->is_recycled_in_schema = true;
+               }
+               ar->is_recycled_tested = true;
+       }
+
+       if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
+               ret = dsdb_recyclebin_enabled(ar->module, &rcbin_enabled);
+               if (ret != LDB_SUCCESS) {
+                       return replmd_replicated_request_error(ar, ret);
+               }
+       }
+
+
        /* remove any message elements that have zero values */
        for (i=0; i<msg->num_elements; i++) {
                struct ldb_message_element *el = &msg->elements[i];
 
+               if (ldb_attr_cmp(el->name, "isDeleted") == 0) {
+                       is_deleted = true;
+               }
+
+               if (ldb_attr_cmp(el->name, "isRecycled") == 0) {
+                       is_recycled = true;
+               }
+
                if (el->num_values == 0) {
                        DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
                                 el->name));
@@ -3542,6 +3584,60 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
                }
        }
 
+       if (is_deleted && ar->is_recycled_in_schema && !is_recycled && !rcbin_enabled) {
+               /*
+                * The object is deleted and we have the isRecycled attribute in
+                * the schema but it is missing on the object and the recycle-bin is not activated
+                * so we mark the object as deleted because it means that it comes from a
+                * pre windows 2008R2 server or from a Samba DC before changes related to isRecycled.*/
+
+               const struct dsdb_attribute *sa;
+               time_t t = time(NULL);
+               NTTIME now;
+               struct replPropertyMetaData1 *m;
+               const struct GUID *our_invocation_id;
+               const struct ldb_val* v;
+
+               v = ldb_dn_get_rdn_val(msg->dn);
+               if (!v || strcmp((char*)v->data, "Deleted Objects") == 0) {
+                       goto noadd;
+               }
+
+               our_invocation_id = samdb_ntds_invocation_id(ldb);
+               if (!our_invocation_id) {
+                       ldb_debug_set(ldb, LDB_DEBUG_ERROR,
+                               "replmd_add: unable to find invocationId\n");
+                       return replmd_replicated_request_error(ar, LDB_ERR_OPERATIONS_ERROR);
+               }
+
+               unix_to_nt_time(&now, t);
+
+               ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
+               if (ret != LDB_SUCCESS) {
+                       return replmd_replicated_request_error(ar, ret);
+               }
+
+               md->ctr.ctr1.count++;
+               md->ctr.ctr1.array = talloc_realloc(ar, md->ctr.ctr1.array,
+                                                       struct replPropertyMetaData1,
+                                                       md->ctr.ctr1.count);
+
+               /* rdn is at the end so shift it to end first */
+               m = &md->ctr.ctr1.array[md->ctr.ctr1.count - 2];
+               md->ctr.ctr1.array[md->ctr.ctr1.count - 1] = *m;
+
+               /* Allocate a new entry in the replPropertyMetadata */
+               sa = dsdb_attribute_by_lDAPDisplayName(ar->schema, "isRecycled");
+
+               m->attid                        = sa->attributeID_id;
+               m->version                      = 1;
+               m->originating_change_time      = now;
+               m->originating_invocation_id    = *our_invocation_id;
+               m->originating_usn              = ar->seq_num;
+               m->local_usn                    = ar->seq_num;
+       }
+noadd:
+
        /*
         * the meta data array is already sorted by the caller
         */