2 Unix SMB/CIFS implementation.
4 WINS Replication server
6 Copyright (C) Stefan Metzmacher 2005
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "librpc/gen_ndr/ndr_winsrepl.h"
25 #include "wrepl_server/wrepl_server.h"
26 #include "nbt_server/wins/winsdb.h"
27 #include "ldb/include/ldb.h"
28 #include "ldb/include/ldb_errors.h"
29 #include "system/time.h"
31 const char *wreplsrv_owner_filter(struct wreplsrv_service *service,
33 const char *wins_owner)
35 if (strcmp(wins_owner, service->wins_db->local_owner) == 0) {
36 return talloc_asprintf(mem_ctx, "(|(winsOwner=%s)(winsOwner=0.0.0.0))",
40 return talloc_asprintf(mem_ctx, "(&(winsOwner=%s)(!(winsOwner=0.0.0.0)))",
44 static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
47 struct winsdb_record *rec = NULL;
48 struct ldb_result *res = NULL;
49 const char *owner_filter;
53 time_t now = time(NULL);
54 const char *now_timestr;
56 const char *old_state;
57 uint32_t modify_flags;
60 BOOL delete_tombstones;
61 struct timeval tombstone_extra_time;
63 now_timestr = ldb_timestring(tmp_mem, now);
64 NT_STATUS_HAVE_NO_MEMORY(now_timestr);
65 owner_filter = wreplsrv_owner_filter(service, tmp_mem,
66 service->wins_db->local_owner);
67 NT_STATUS_HAVE_NO_MEMORY(owner_filter);
68 filter = talloc_asprintf(tmp_mem,
69 "(&%s(objectClass=winsRecord)"
70 "(expireTime<=%s)(!(isStatic=1)))",
71 owner_filter, now_timestr);
72 NT_STATUS_HAVE_NO_MEMORY(filter);
73 ret = ldb_search(service->wins_db->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
74 if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
75 talloc_steal(tmp_mem, res);
76 DEBUG(10,("WINS scavenging: filter '%s' count %d\n", filter, res->count));
78 tombstone_extra_time = timeval_add(&service->startup_time,
79 service->config.tombstone_extra_timeout,
81 delete_tombstones = timeval_expired(&tombstone_extra_time);
83 for (i=0; i < res->count; i++) {
84 status = winsdb_record(service->wins_db, res->msgs[i], tmp_mem, &rec);
85 NT_STATUS_NOT_OK_RETURN(status);
88 DEBUG(0,("%s: corrupted record: %s\n",
89 __location__, nbt_name_string(rec, rec->name)));
90 return NT_STATUS_INTERNAL_DB_CORRUPTION;
93 if (rec->expire_time > now) {
94 DEBUG(0,("%s: corrupted record: %s\n",
95 __location__, nbt_name_string(rec, rec->name)));
96 return NT_STATUS_INTERNAL_DB_CORRUPTION;
100 modify_record = False;
101 delete_record = False;
103 switch (rec->state) {
104 case WREPL_STATE_ACTIVE:
105 old_state = "active";
106 rec->state = WREPL_STATE_RELEASED;
107 rec->expire_time= service->config.tombstone_interval + now;
109 modify_record = True;
112 case WREPL_STATE_RELEASED:
113 old_state = "released";
114 rec->state = WREPL_STATE_TOMBSTONE;
115 rec->expire_time= service->config.tombstone_timeout + now;
116 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
117 modify_record = True;
120 case WREPL_STATE_TOMBSTONE:
121 old_state = "tombstone";
122 if (!delete_tombstones) break;
123 delete_record = True;
126 case WREPL_STATE_RESERVED:
127 DEBUG(0,("%s: corrupted record: %s\n",
128 __location__, nbt_name_string(rec, rec->name)));
129 return NT_STATUS_INTERNAL_DB_CORRUPTION;
134 ret = winsdb_modify(service->wins_db, rec, modify_flags);
135 } else if (delete_record) {
137 ret = winsdb_delete(service->wins_db, rec);
143 if (ret != NBT_RCODE_OK) {
144 DEBUG(1,("WINS scavenging: failed to %s name %s (owned:%s): error:%u\n",
145 action, nbt_name_string(rec, rec->name), old_state, ret));
147 DEBUG(4,("WINS scavenging: %s name: %s (owned:%s)\n",
148 action, nbt_name_string(rec, rec->name), old_state));
157 static NTSTATUS wreplsrv_scavenging_replica_non_active_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
160 struct winsdb_record *rec = NULL;
161 struct ldb_result *res = NULL;
162 const char *owner_filter;
166 time_t now = time(NULL);
167 const char *now_timestr;
169 const char *old_state;
170 uint32_t modify_flags;
173 BOOL delete_tombstones;
174 struct timeval tombstone_extra_time;
176 now_timestr = ldb_timestring(tmp_mem, now);
177 NT_STATUS_HAVE_NO_MEMORY(now_timestr);
178 owner_filter = wreplsrv_owner_filter(service, tmp_mem,
179 service->wins_db->local_owner);
180 NT_STATUS_HAVE_NO_MEMORY(owner_filter);
181 filter = talloc_asprintf(tmp_mem,
182 "(&(!%s)(objectClass=winsRecord)"
183 "(!(recordState=%u))(expireTime<=%s)(!(isStatic=1)))",
184 owner_filter, WREPL_STATE_ACTIVE, now_timestr);
185 NT_STATUS_HAVE_NO_MEMORY(filter);
186 ret = ldb_search(service->wins_db->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
187 if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
188 talloc_steal(tmp_mem, res);
189 DEBUG(10,("WINS scavenging: filter '%s' count %d\n", filter, res->count));
191 tombstone_extra_time = timeval_add(&service->startup_time,
192 service->config.tombstone_extra_timeout,
194 delete_tombstones = timeval_expired(&tombstone_extra_time);
196 for (i=0; i < res->count; i++) {
197 status = winsdb_record(service->wins_db, res->msgs[i], tmp_mem, &rec);
198 NT_STATUS_NOT_OK_RETURN(status);
200 if (rec->is_static) {
201 DEBUG(0,("%s: corrupted record: %s\n",
202 __location__, nbt_name_string(rec, rec->name)));
203 return NT_STATUS_INTERNAL_DB_CORRUPTION;
206 if (rec->expire_time > now) {
207 DEBUG(0,("%s: corrupted record: %s\n",
208 __location__, nbt_name_string(rec, rec->name)));
209 return NT_STATUS_INTERNAL_DB_CORRUPTION;
213 modify_record = False;
214 delete_record = False;
216 switch (rec->state) {
217 case WREPL_STATE_ACTIVE:
218 DEBUG(0,("%s: corrupted record: %s\n",
219 __location__, nbt_name_string(rec, rec->name)));
220 return NT_STATUS_INTERNAL_DB_CORRUPTION;
222 case WREPL_STATE_RELEASED:
223 old_state = "released";
224 rec->state = WREPL_STATE_TOMBSTONE;
225 rec->expire_time= service->config.tombstone_timeout + now;
227 modify_record = True;
230 case WREPL_STATE_TOMBSTONE:
231 old_state = "tombstone";
232 if (!delete_tombstones) break;
233 delete_record = True;
236 case WREPL_STATE_RESERVED:
237 DEBUG(0,("%s: corrupted record: %s\n",
238 __location__, nbt_name_string(rec, rec->name)));
239 return NT_STATUS_INTERNAL_DB_CORRUPTION;
244 ret = winsdb_modify(service->wins_db, rec, modify_flags);
245 } else if (delete_record) {
247 ret = winsdb_delete(service->wins_db, rec);
253 if (ret != NBT_RCODE_OK) {
254 DEBUG(1,("WINS scavenging: failed to %s name %s (replica:%s): error:%u\n",
255 action, nbt_name_string(rec, rec->name), old_state, ret));
257 DEBUG(4,("WINS scavenging: %s name: %s (replica:%s)\n",
258 action, nbt_name_string(rec, rec->name), old_state));
267 static NTSTATUS wreplsrv_scavenging_replica_active_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
270 struct winsdb_record *rec = NULL;
271 struct ldb_result *res = NULL;
272 const char *owner_filter;
276 time_t now = time(NULL);
277 const char *now_timestr;
279 const char *old_state;
284 now_timestr = ldb_timestring(tmp_mem, now);
285 NT_STATUS_HAVE_NO_MEMORY(now_timestr);
286 owner_filter = wreplsrv_owner_filter(service, tmp_mem,
287 service->wins_db->local_owner);
288 NT_STATUS_HAVE_NO_MEMORY(owner_filter);
289 filter = talloc_asprintf(tmp_mem,
290 "(&(!%s)(objectClass=winsRecord)"
291 "(recordState=%u)(expireTime<=%s)(!(isStatic=1)))",
292 owner_filter, WREPL_STATE_ACTIVE, now_timestr);
293 NT_STATUS_HAVE_NO_MEMORY(filter);
294 ret = ldb_search(service->wins_db->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
295 if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
296 talloc_steal(tmp_mem, res);
297 DEBUG(10,("WINS scavenging: filter '%s' count %d\n", filter, res->count));
299 for (i=0; i < res->count; i++) {
300 status = winsdb_record(service->wins_db, res->msgs[i], tmp_mem, &rec);
301 NT_STATUS_NOT_OK_RETURN(status);
303 if (rec->is_static) {
304 DEBUG(0,("%s: corrupted record: %s\n",
305 __location__, nbt_name_string(rec, rec->name)));
306 return NT_STATUS_INTERNAL_DB_CORRUPTION;
309 if (rec->expire_time > now) {
310 DEBUG(0,("%s: corrupted record: %s\n",
311 __location__, nbt_name_string(rec, rec->name)));
312 return NT_STATUS_INTERNAL_DB_CORRUPTION;
315 if (rec->state != WREPL_STATE_ACTIVE) {
316 DEBUG(0,("%s: corrupted record: %s\n",
317 __location__, nbt_name_string(rec, rec->name)));
318 return NT_STATUS_INTERNAL_DB_CORRUPTION;
321 old_state = "active";
324 modify_record = False;
325 delete_record = False;
328 * TODO: ask the owning wins server if the record still exists,
329 * if not delete the record
331 DEBUG(0,("TODO: ask wins server '%s' if '%s' with version_id:%llu still exists\n",
332 rec->wins_owner, nbt_name_string(rec, rec->name), rec->version));
336 ret = winsdb_modify(service->wins_db, rec, modify_flags);
337 } else if (delete_record) {
339 ret = winsdb_delete(service->wins_db, rec);
345 if (ret != NBT_RCODE_OK) {
346 DEBUG(1,("WINS scavenging: failed to %s name %s (replica:%s): error:%u\n",
347 action, nbt_name_string(rec, rec->name), old_state, ret));
349 DEBUG(4,("WINS scavenging: %s name: %s (replica:%s)\n",
350 action, nbt_name_string(rec, rec->name), old_state));
359 NTSTATUS wreplsrv_scavenging_run(struct wreplsrv_service *service)
363 BOOL skip_first_run = False;
365 if (!timeval_expired(&service->scavenging.next_run)) {
369 if (timeval_is_zero(&service->scavenging.next_run)) {
370 skip_first_run = True;
373 service->scavenging.next_run = timeval_current_ofs(service->config.scavenging_interval, 0);
374 status = wreplsrv_periodic_schedule(service, service->config.scavenging_interval);
375 NT_STATUS_NOT_OK_RETURN(status);
378 * if it's the first time this functions is called (startup)
379 * the next_run is zero, in this case we should not do scavenging
381 if (skip_first_run) {
385 if (service->scavenging.processing) {
389 DEBUG(4,("wreplsrv_scavenging_run(): start\n"));
391 tmp_mem = talloc_new(service);
392 service->scavenging.processing = True;
393 status = wreplsrv_scavenging_owned_records(service,tmp_mem);
394 service->scavenging.processing = False;
395 talloc_free(tmp_mem);
396 NT_STATUS_NOT_OK_RETURN(status);
398 tmp_mem = talloc_new(service);
399 service->scavenging.processing = True;
400 status = wreplsrv_scavenging_replica_non_active_records(service, tmp_mem);
401 service->scavenging.processing = False;
402 talloc_free(tmp_mem);
403 NT_STATUS_NOT_OK_RETURN(status);
405 tmp_mem = talloc_new(service);
406 service->scavenging.processing = True;
407 status = wreplsrv_scavenging_replica_active_records(service, tmp_mem);
408 service->scavenging.processing = False;
409 talloc_free(tmp_mem);
410 NT_STATUS_NOT_OK_RETURN(status);
412 DEBUG(4,("wreplsrv_scavenging_run(): end\n"));