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 "dlinklist.h"
25 #include "lib/events/events.h"
26 #include "lib/socket/socket.h"
27 #include "smbd/service_task.h"
28 #include "smbd/service_stream.h"
29 #include "lib/messaging/irpc.h"
30 #include "librpc/gen_ndr/ndr_winsrepl.h"
31 #include "wrepl_server/wrepl_server.h"
32 #include "nbt_server/wins/winsdb.h"
33 #include "ldb/include/ldb.h"
34 #include "ldb/include/ldb_errors.h"
35 #include "libcli/composite/composite.h"
36 #include "libcli/wrepl/winsrepl.h"
37 #include "wrepl_server/wrepl_out_helpers.h"
38 #include "system/time.h"
39 #include "libcli/nbt/libnbt.h"
41 static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
44 struct winsdb_record *rec = NULL;
45 struct ldb_result *res = NULL;
49 time_t now = time(NULL);
50 const char *now_timestr;
52 const char *old_state;
53 uint32_t modify_flags;
56 BOOL delete_tombstones;
57 struct timeval tombstone_extra_time;
59 now_timestr = ldb_timestring(tmp_mem, now);
60 NT_STATUS_HAVE_NO_MEMORY(now_timestr);
61 filter = talloc_asprintf(tmp_mem,
62 "(&(winsOwner=%s)(objectClass=winsRecord)"
63 "(expireTime<=%s)(!(isStatic=1)))",
64 WINSDB_OWNER_LOCAL, now_timestr);
65 NT_STATUS_HAVE_NO_MEMORY(filter);
66 ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
67 if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
68 talloc_steal(tmp_mem, res);
70 tombstone_extra_time = timeval_add(&service->startup_time,
71 service->config.tombstone_extra_timeout,
73 delete_tombstones = timeval_expired(&tombstone_extra_time);
75 for (i=0; i < res->count; i++) {
76 status = winsdb_record(res->msgs[i], tmp_mem, &rec);
77 NT_STATUS_NOT_OK_RETURN(status);
80 DEBUG(0,("%s: corrupted record: %s\n",
81 __location__, nbt_name_string(rec, rec->name)));
82 return NT_STATUS_INTERNAL_DB_CORRUPTION;
85 if (rec->expire_time > now) {
86 DEBUG(0,("%s: corrupted record: %s\n",
87 __location__, nbt_name_string(rec, rec->name)));
88 return NT_STATUS_INTERNAL_DB_CORRUPTION;
92 modify_record = False;
93 delete_record = False;
96 case WREPL_STATE_ACTIVE:
98 rec->state = WREPL_STATE_RELEASED;
99 rec->expire_time= service->config.tombstone_interval + now;
101 modify_record = True;
104 case WREPL_STATE_RELEASED:
105 old_state = "released";
106 rec->state = WREPL_STATE_TOMBSTONE;
107 rec->expire_time= service->config.tombstone_timeout + now;
108 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
109 modify_record = True;
112 case WREPL_STATE_TOMBSTONE:
113 old_state = "tombstone";
114 if (!delete_tombstones) break;
115 delete_record = True;
118 case WREPL_STATE_RESERVED:
119 DEBUG(0,("%s: corrupted record: %s\n",
120 __location__, nbt_name_string(rec, rec->name)));
121 return NT_STATUS_INTERNAL_DB_CORRUPTION;
126 ret = winsdb_modify(service->wins_db, rec, modify_flags);
127 } else if (delete_record) {
129 ret = winsdb_delete(service->wins_db, rec);
135 if (ret != NBT_RCODE_OK) {
136 DEBUG(1,("WINS scavenging: failed to %s name %s (owned:%s): error:%u\n",
137 action, nbt_name_string(rec, rec->name), old_state, ret));
139 DEBUG(4,("WINS scavenging: %s name: %s (owned:%s)\n",
140 action, nbt_name_string(rec, rec->name), old_state));
149 static NTSTATUS wreplsrv_scavenging_replica_non_active_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
152 struct winsdb_record *rec = NULL;
153 struct ldb_result *res = NULL;
157 time_t now = time(NULL);
158 const char *now_timestr;
160 const char *old_state;
161 uint32_t modify_flags;
164 BOOL delete_tombstones;
165 struct timeval tombstone_extra_time;
167 now_timestr = ldb_timestring(tmp_mem, now);
168 NT_STATUS_HAVE_NO_MEMORY(now_timestr);
169 filter = talloc_asprintf(tmp_mem,
170 "(&(!(winsOwner=%s))(objectClass=winsRecord)"
171 "(!(recordState=%u))(expireTime<=%s)(!(isStatic=1)))",
172 WINSDB_OWNER_LOCAL, WREPL_STATE_ACTIVE, now_timestr);
173 NT_STATUS_HAVE_NO_MEMORY(filter);
174 ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
175 if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
176 talloc_steal(tmp_mem, res);
178 tombstone_extra_time = timeval_add(&service->startup_time,
179 service->config.tombstone_extra_timeout,
181 delete_tombstones = timeval_expired(&tombstone_extra_time);
183 for (i=0; i < res->count; i++) {
184 status = winsdb_record(res->msgs[i], tmp_mem, &rec);
185 NT_STATUS_NOT_OK_RETURN(status);
187 if (rec->is_static) {
188 DEBUG(0,("%s: corrupted record: %s\n",
189 __location__, nbt_name_string(rec, rec->name)));
190 return NT_STATUS_INTERNAL_DB_CORRUPTION;
193 if (rec->expire_time > now) {
194 DEBUG(0,("%s: corrupted record: %s\n",
195 __location__, nbt_name_string(rec, rec->name)));
196 return NT_STATUS_INTERNAL_DB_CORRUPTION;
200 modify_record = False;
201 delete_record = False;
203 switch (rec->state) {
204 case WREPL_STATE_ACTIVE:
205 DEBUG(0,("%s: corrupted record: %s\n",
206 __location__, nbt_name_string(rec, rec->name)));
207 return NT_STATUS_INTERNAL_DB_CORRUPTION;
209 case WREPL_STATE_RELEASED:
210 old_state = "released";
211 rec->state = WREPL_STATE_TOMBSTONE;
212 rec->expire_time= service->config.tombstone_timeout + now;
214 modify_record = True;
217 case WREPL_STATE_TOMBSTONE:
218 old_state = "tombstone";
219 if (!delete_tombstones) break;
220 delete_record = True;
223 case WREPL_STATE_RESERVED:
224 DEBUG(0,("%s: corrupted record: %s\n",
225 __location__, nbt_name_string(rec, rec->name)));
226 return NT_STATUS_INTERNAL_DB_CORRUPTION;
231 ret = winsdb_modify(service->wins_db, rec, modify_flags);
232 } else if (delete_record) {
234 ret = winsdb_delete(service->wins_db, rec);
240 if (ret != NBT_RCODE_OK) {
241 DEBUG(1,("WINS scavenging: failed to %s name %s (replica:%s): error:%u\n",
242 action, nbt_name_string(rec, rec->name), old_state, ret));
244 DEBUG(4,("WINS scavenging: %s name: %s (replica:%s)\n",
245 action, nbt_name_string(rec, rec->name), old_state));
254 static NTSTATUS wreplsrv_scavenging_replica_active_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
257 struct winsdb_record *rec = NULL;
258 struct ldb_result *res = NULL;
262 time_t now = time(NULL);
263 const char *now_timestr;
265 const char *old_state;
270 now_timestr = ldb_timestring(tmp_mem, now);
271 NT_STATUS_HAVE_NO_MEMORY(now_timestr);
272 filter = talloc_asprintf(tmp_mem,
273 "(&(!(winsOwner=%s))(objectClass=winsRecord)"
274 "(recordState=%u)(expireTime<=%s)(!(isStatic=1)))",
275 WINSDB_OWNER_LOCAL, WREPL_STATE_ACTIVE, now_timestr);
276 NT_STATUS_HAVE_NO_MEMORY(filter);
277 ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
278 if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
279 talloc_steal(tmp_mem, res);
281 for (i=0; i < res->count; i++) {
282 status = winsdb_record(res->msgs[i], tmp_mem, &rec);
283 NT_STATUS_NOT_OK_RETURN(status);
285 if (rec->is_static) {
286 DEBUG(0,("%s: corrupted record: %s\n",
287 __location__, nbt_name_string(rec, rec->name)));
288 return NT_STATUS_INTERNAL_DB_CORRUPTION;
291 if (rec->expire_time > now) {
292 DEBUG(0,("%s: corrupted record: %s\n",
293 __location__, nbt_name_string(rec, rec->name)));
294 return NT_STATUS_INTERNAL_DB_CORRUPTION;
297 if (rec->state != WREPL_STATE_ACTIVE) {
298 DEBUG(0,("%s: corrupted record: %s\n",
299 __location__, nbt_name_string(rec, rec->name)));
300 return NT_STATUS_INTERNAL_DB_CORRUPTION;
303 old_state = "active";
306 modify_record = False;
307 delete_record = False;
310 * TODO: ask the owning wins server if the record still exists,
311 * if not delete the record
313 DEBUG(0,("TODO: ask wins server '%s' if '%s' with version_id:%llu still exists\n",
314 rec->wins_owner, nbt_name_string(rec, rec->name), rec->version));
318 ret = winsdb_modify(service->wins_db, rec, modify_flags);
319 } else if (delete_record) {
321 ret = winsdb_delete(service->wins_db, rec);
327 if (ret != NBT_RCODE_OK) {
328 DEBUG(1,("WINS scavenging: failed to %s name %s (replica:%s): error:%u\n",
329 action, nbt_name_string(rec, rec->name), old_state, ret));
331 DEBUG(4,("WINS scavenging: %s name: %s (replica:%s)\n",
332 action, nbt_name_string(rec, rec->name), old_state));
341 NTSTATUS wreplsrv_scavenging_run(struct wreplsrv_service *service)
346 if (!timeval_expired(&service->scavenging.next_run)) {
350 service->scavenging.next_run = timeval_current_ofs(service->config.scavenging_interval, 0);
351 status = wreplsrv_periodic_schedule(service, service->config.scavenging_interval);
352 NT_STATUS_NOT_OK_RETURN(status);
354 if (service->scavenging.processing) {
358 DEBUG(4,("wreplsrv_scavenging_run(): start\n"));
360 tmp_mem = talloc_new(service);
361 service->scavenging.processing = True;
362 status = wreplsrv_scavenging_owned_records(service,tmp_mem);
363 service->scavenging.processing = False;
364 talloc_free(tmp_mem);
365 NT_STATUS_NOT_OK_RETURN(status);
367 tmp_mem = talloc_new(service);
368 service->scavenging.processing = True;
369 status = wreplsrv_scavenging_replica_non_active_records(service, tmp_mem);
370 service->scavenging.processing = False;
371 talloc_free(tmp_mem);
372 NT_STATUS_NOT_OK_RETURN(status);
374 tmp_mem = talloc_new(service);
375 service->scavenging.processing = True;
376 status = wreplsrv_scavenging_replica_active_records(service, tmp_mem);
377 service->scavenging.processing = False;
378 talloc_free(tmp_mem);
379 NT_STATUS_NOT_OK_RETURN(status);
381 DEBUG(4,("wreplsrv_scavenging_run(): end\n"));