dsdb: Rework kcc_deleted() into dsdb_garbage_collect_tombstones()
[sfrench/samba-autobuild/.git] / source4 / dsdb / kcc / garbage_collect_tombstones.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    handle removal of deleted objects
5
6    Copyright (C) 2009 Andrew Tridgell
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 */
22
23 #include "includes.h"
24 #include <ldb_errors.h>
25 #include "../lib/util/dlinklist.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_drsuapi.h"
28 #include "librpc/gen_ndr/ndr_drsblobs.h"
29 #include "param/param.h"
30 #include "lib/util/dlinklist.h"
31 #include "ldb.h"
32 #include "dsdb/kcc/garbage_collect_tombstones.h"
33
34
35 NTSTATUS dsdb_garbage_collect_tombstones(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
36                                          struct ldb_context *samdb,
37                                          struct dsdb_ldb_dn_list_node *part,
38                                          time_t current_time, time_t *last_deleted_check,
39                                          time_t *last_full_scan_deleted_check)
40 {
41         int ret;
42         uint32_t tombstoneLifetime;
43         bool do_fs = false;
44
45         time_t interval = lpcfg_parm_int(lp_ctx, NULL, "kccsrv",
46                                          "check_deleted_full_scan_interval", 86400);
47
48         if (current_time - *last_deleted_check < lpcfg_parm_int(lp_ctx, NULL, "kccsrv",
49                                                                   "check_deleted_interval", 600)) {
50                 return NT_STATUS_OK;
51         }
52         *last_deleted_check = current_time;
53
54         ret = dsdb_tombstone_lifetime(samdb, &tombstoneLifetime);
55         if (ret != LDB_SUCCESS) {
56                 DEBUG(1,(__location__ ": Failed to get tombstone lifetime\n"));
57                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
58         }
59         if (*last_full_scan_deleted_check > 0 && ((current_time - *last_full_scan_deleted_check) > interval )) {
60                 do_fs = true;
61                 *last_full_scan_deleted_check = current_time;
62         }
63
64         if (*last_full_scan_deleted_check == 0) {
65                 /*
66                  * If we never made a full scan set the last full scan event to be in the past
67                  * and that 9/10 of the full scan interval has already passed.
68                  * This is done to avoid the full scan to fire just at the begining of samba
69                  * or a couple of minutes after the start.
70                  * With this "setup" and default values of interval, the full scan will fire
71                  * 2.4 hours after the start of samba
72                  */
73                 *last_full_scan_deleted_check = current_time - ((9 * interval) / 10);
74         }
75
76         for (; part != NULL; part = part->next) {
77                 struct ldb_dn *do_dn;
78                 struct ldb_result *res;
79                 const char *attrs[] = { "whenChanged", NULL };
80                 unsigned int i;
81                 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
82                 if (!tmp_ctx) {
83                         return NT_STATUS_NO_MEMORY;
84                 }
85
86                 ret = dsdb_get_deleted_objects_dn(samdb, tmp_ctx, part->dn, &do_dn);
87                 if (ret != LDB_SUCCESS) {
88                         TALLOC_FREE(tmp_ctx);
89                         /* some partitions have no Deleted Objects
90                            container */
91                         continue;
92                 }
93
94                 if (!do_fs && ldb_dn_compare(ldb_get_config_basedn(samdb), part->dn)) {
95                         ret = dsdb_search(samdb, tmp_ctx, &res, do_dn, LDB_SCOPE_ONELEVEL, attrs,
96                                         DSDB_SEARCH_SHOW_RECYCLED, NULL);
97                 } else {
98                         if (do_fs) {
99                                 DEBUG(1, ("Doing a full scan on %s and looking for deleted object\n",
100                                                 ldb_dn_get_linearized(part->dn)));
101                         }
102                         ret = dsdb_search(samdb, tmp_ctx, &res, part->dn, LDB_SCOPE_SUBTREE, attrs,
103                                         DSDB_SEARCH_SHOW_RECYCLED, "(|(isDeleted=TRUE))");
104                 }
105
106                 if (ret != LDB_SUCCESS) {
107                         DEBUG(1,(__location__ ": Failed to search for deleted objects in %s\n",
108                                  ldb_dn_get_linearized(do_dn)));
109                         TALLOC_FREE(tmp_ctx);
110                         continue;
111                 }
112
113                 for (i=0; i<res->count; i++) {
114                         const char *tstring;
115                         time_t whenChanged = 0;
116
117                         if (ldb_dn_compare(do_dn, res->msgs[i]->dn) == 0) {
118                                 /* Skip the Deleted Object Container */
119                                 continue;
120                         }
121                         tstring = ldb_msg_find_attr_as_string(res->msgs[i], "whenChanged", NULL);
122                         if (tstring) {
123                                 whenChanged = ldb_string_to_time(tstring);
124                         }
125                         if (current_time - whenChanged > tombstoneLifetime*60*60*24) {
126                                 ret = dsdb_delete(samdb, res->msgs[i]->dn, DSDB_SEARCH_SHOW_RECYCLED|DSDB_MODIFY_RELAX);
127                                 if (ret != LDB_SUCCESS) {
128                                         DEBUG(1,(__location__ ": Failed to remove deleted object %s\n",
129                                                  ldb_dn_get_linearized(res->msgs[i]->dn)));
130                                 } else {
131                                         DEBUG(4,("Removed deleted object %s\n",
132                                                  ldb_dn_get_linearized(res->msgs[i]->dn)));
133                                 }
134                         }
135                 }
136
137                 TALLOC_FREE(tmp_ctx);
138         }
139
140         return NT_STATUS_OK;
141 }