dsdb: Make it harder to corrupt the database by requiring DBCHECK or RELAX for final...
authorAndrew Bartlett <abartlet@samba.org>
Thu, 3 Apr 2014 01:50:05 +0000 (14:50 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 3 May 2014 05:57:12 +0000 (07:57 +0200)
This kind of deletion can cause us to then replicate back a partial
object.  We allow dbcheck to directly remove totally corrupt objects
(missing an objectclass) by specifying both DBCHECK and RELAX, and the
tombstone sweep after 180 days is done with the RELAX control.

Andrew Bartlett

Change-Id: Ic21f68e507ba9b65e035ca568430e35e2d001c7d
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source4/dsdb/kcc/kcc_deleted.c
source4/dsdb/samdb/ldb_modules/repl_meta_data.c

index 63bb97c08dcc4a5f20f8681a87a2bbc8d3bd4203..331d4fbe677eacf6bedcfe57584e9e0aab8e76e5 100644 (file)
@@ -128,7 +128,7 @@ NTSTATUS kccsrv_check_deleted(struct kccsrv_service *s, TALLOC_CTX *mem_ctx)
                                whenChanged = ldb_string_to_time(tstring);
                        }
                        if (t - whenChanged > tombstoneLifetime*60*60*24) {
-                               ret = dsdb_delete(s->samdb, res->msgs[i]->dn, DSDB_SEARCH_SHOW_DELETED);
+                               ret = dsdb_delete(s->samdb, res->msgs[i]->dn, DSDB_SEARCH_SHOW_DELETED|DSDB_MODIFY_RELAX);
                                if (ret != LDB_SUCCESS) {
                                        DEBUG(1,(__location__ ": Failed to remove deleted object %s\n",
                                                 ldb_dn_get_linearized(res->msgs[i]->dn)));
index b01c956d1c3249e1ac9fe19f4c2f212cde101916..83dabdfdf3b1195e9174a14e4b44240a197fbef3 100644 (file)
@@ -2991,6 +2991,20 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
                return ldb_next_request(module, req);
        }
 
+       /*
+        * We have to allow dbcheck to remove an object that
+        * is beyond repair, and to do so totally.  This could
+        * mean we we can get a partial object from the other
+        * DC, causing havoc, so dbcheck suggests
+        * re-replication first.  dbcheck sets both DBCHECK
+        * and RELAX in this situation.
+        */
+       if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
+           && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
+               /* really, really remove it */
+               return ldb_next_request(module, req);
+       }
+
        tmp_ctx = talloc_new(ldb);
        if (!tmp_ctx) {
                ldb_oom(ldb);
@@ -3034,17 +3048,25 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
        }
 
        if (next_deletion_state == OBJECT_REMOVED) {
-               struct auth_session_info *session_info =
-                               (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
-               if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
-                       ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
-                                       ldb_dn_get_linearized(old_msg->dn));
-                       return LDB_ERR_UNWILLING_TO_PERFORM;
+               /*
+                * We have to prevent objects being deleted, even if
+                * the administrator really wants them gone, as
+                * without the tombstone, we can get a partial object
+                * from the other DC, causing havoc.
+                *
+                * The only other valid case is when the 180 day
+                * timeout has expired, when relax is specified.
+                */
+               if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
+                       /* it is already deleted - really remove it this time */
+                       talloc_free(tmp_ctx);
+                       return ldb_next_request(module, req);
                }
 
-               /* it is already deleted - really remove it this time */
-               talloc_free(tmp_ctx);
-               return ldb_next_request(module, req);
+               ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s.  "
+                                      "This check is to prevent corruption of the replicated state.",
+                                      ldb_dn_get_linearized(old_msg->dn));
+               return LDB_ERR_UNWILLING_TO_PERFORM;
        }
 
        rdn_name = ldb_dn_get_rdn_name(old_dn);