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)
committerKarolin Seeger <kseeger@samba.org>
Tue, 15 Jul 2014 10:46:15 +0000 (12:46 +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>
(cherry picked from commit b19d80d0a97faffc165f068612f74d4ef8d7e5da)

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 7784c2bd7812e53a57d9a8eef2b173b84a357ac5..30b3012682941870431c8bf19935ca5b501313ef 100644 (file)
@@ -2998,6 +2998,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);
@@ -3041,17 +3055,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);