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 "wrepl_server/wrepl_out_helpers.h"
33 #include "nbt_server/wins/winsdb.h"
34 #include "ldb/include/ldb.h"
35 #include "libcli/composite/composite.h"
36 #include "libcli/wrepl/winsrepl.h"
45 static const char *_R_ACTION_enum_string(enum _R_ACTION action)
48 case R_DO_ADD: return "ADD";
49 case R_DO_REPLACE: return "REPLACE";
50 case R_NOT_REPLACE: return "NOT_REPLACE";
51 case R_DO_MERGE: return "MERGE";
54 return "enum _R_ACTION unknown";
57 #define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
58 #define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
59 #define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
61 #define R_IS_UNIQUE(r) ((r)->type == WREPL_TYPE_UNIQUE)
62 #define R_IS_GROUP(r) ((r)->type == WREPL_TYPE_GROUP)
63 #define R_IS_SGROUP(r) ((r)->type == WREPL_TYPE_SGROUP)
64 #define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
66 static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_name *r2)
68 /* TODO: we need to look closer at how special groups are handled */
75 UNIQUE,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
76 UNIQUE,ACTIVE vs. UNIQUE,TOMBSTONE with different ip(s) => NOT REPLACE
77 UNIQUE,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
78 UNIQUE,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
79 UNIQUE,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
80 UNIQUE,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
81 UNIQUE,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
82 UNIQUE,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
83 UNIQUE,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
84 UNIQUE,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
85 UNIQUE,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
86 UNIQUE,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
87 UNIQUE,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
88 UNIQUE,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
89 UNIQUE,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
90 UNIQUE,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
91 UNIQUE,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
92 UNIQUE,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
93 UNIQUE,ACTIVE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
94 UNIQUE,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
95 UNIQUE,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
96 UNIQUE,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
97 UNIQUE,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
98 UNIQUE,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
100 static enum _R_ACTION replace_replica_replica_unique_vs_X(struct winsdb_record *r1, struct wrepl_name *r2)
102 if (!R_IS_ACTIVE(r1)) {
107 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
113 return R_NOT_REPLACE;
117 GROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
118 GROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
119 GROUP,RELEASED vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
120 GROUP,RELEASED vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
121 GROUP,TOMBSTONE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
122 GROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
123 GROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
124 GROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
125 GROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
126 GROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
127 GROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
128 GROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
129 GROUP,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
130 GROUP,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
131 GROUP,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
132 GROUP,RELEASED vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
133 GROUP,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
134 GROUP,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
135 GROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
136 GROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
137 GROUP,RELEASED vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
138 GROUP,RELEASED vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
139 GROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
140 GROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
142 static enum _R_ACTION replace_replica_replica_group_vs_X(struct winsdb_record *r1, struct wrepl_name *r2)
144 if (!R_IS_ACTIVE(r1) && R_IS_GROUP(r2)) {
149 if (R_IS_TOMBSTONE(r1) && !R_IS_UNIQUE(r2)) {
155 return R_NOT_REPLACE;
159 SGROUP,ACTIVE vs. UNIQUE,ACTIVE with same ip(s) => NOT REPLACE
160 SGROUP,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
161 SGROUP,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
162 SGROUP,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
163 SGROUP,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
164 SGROUP,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
165 SGROUP,ACTIVE vs. GROUP,ACTIVE with same ip(s) => NOT REPLACE
166 SGROUP,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
167 SGROUP,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
168 SGROUP,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
169 SGROUP,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
170 SGROUP,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
171 SGROUP,ACTIVE vs. MHOMED,ACTIVE with same ip(s) => NOT REPLACE
172 SGROUP,ACTIVE vs. MHOMED,TOMBSTONE with same ip(s) => NOT REPLACE
173 SGROUP,RELEASED vs. MHOMED,ACTIVE with different ip(s) => REPLACE
174 SGROUP,RELEASED vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
175 SGROUP,TOMBSTONE vs. MHOMED,ACTIVE with different ip(s) => REPLACE
176 SGROUP,TOMBSTONE vs. MHOMED,TOMBSTONE with different ip(s) => REPLACE
178 static enum _R_ACTION replace_replica_replica_sgroup_vs_X(struct winsdb_record *r1, struct wrepl_name *r2)
180 if (R_IS_SGROUP(r2)) {
181 /* not handled here: MERGE */
185 if (!R_IS_ACTIVE(r1)) {
191 return R_NOT_REPLACE;
195 MHOMED,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
196 MHOMED,ACTIVE vs. UNIQUE,TOMBSTONE with same ip(s) => NOT REPLACE
197 MHOMED,RELEASED vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
198 MHOMED,RELEASED vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
199 MHOMED,TOMBSTONE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
200 MHOMED,TOMBSTONE vs. UNIQUE,TOMBSTONE with different ip(s) => REPLACE
201 MHOMED,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
202 MHOMED,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
203 MHOMED,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
204 MHOMED,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
205 MHOMED,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
206 MHOMED,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
207 MHOMED,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
208 MHOMED,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
209 MHOMED,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
210 MHOMED,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
211 MHOMED,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
212 MHOMED,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
214 static enum _R_ACTION replace_replica_replica_mhomed_vs_X(struct winsdb_record *r1, struct wrepl_name *r2)
216 if (R_IS_MHOMED(r2)) {
217 /* not handled here: MERGE */
221 if (!R_IS_ACTIVE(r1)) {
226 if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
232 return R_NOT_REPLACE;
235 static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
237 struct wrepl_wins_owner *owner,
238 struct wrepl_name *name)
241 struct winsdb_record *rec = NULL;
242 enum _R_ACTION action = R_NOT_REPLACE;
243 BOOL same_owner = False;
244 BOOL replica_vs_replica = False;
245 BOOL local_vs_replica = False;
247 status = winsdb_lookup(partner->service->wins_db,
248 &name->name, mem_ctx, &rec);
249 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
252 status = NT_STATUS_OK;
254 NT_STATUS_NOT_OK_RETURN(status);
257 if (strcmp(rec->wins_owner, WINSDB_OWNER_LOCAL)==0) {
258 local_vs_replica = True;
259 } else if (strcmp(rec->wins_owner, owner->address)==0) {
262 replica_vs_replica = True;
266 if (rec && same_owner) {
267 action = replace_same_owner(rec, name);
268 } else if (rec && replica_vs_replica) {
270 case WREPL_TYPE_UNIQUE:
271 action = replace_replica_replica_unique_vs_X(rec, name);
273 case WREPL_TYPE_GROUP:
274 action = replace_replica_replica_group_vs_X(rec, name);
276 case WREPL_TYPE_SGROUP:
277 action = replace_replica_replica_sgroup_vs_X(rec, name);
279 case WREPL_TYPE_MHOMED:
280 action = replace_replica_replica_mhomed_vs_X(rec, name);
283 } else if (rec && local_vs_replica) {
288 DEBUG(0,("TODO: apply record %s: %s\n",
289 nbt_name_string(mem_ctx, &name->name), _R_ACTION_enum_string(action)));
294 NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wreplsrv_pull_names_io *names_io)
296 TALLOC_CTX *tmp_mem = talloc_new(partner);
301 DEBUG(0,("TODO: apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
302 names_io->out.num_names, names_io->in.owner.address,
303 names_io->in.owner.min_version, names_io->in.owner.max_version,
306 for (i=0; i < names_io->out.num_names; i++) {
307 status = wreplsrv_apply_one_record(partner, tmp_mem,
309 &names_io->out.names[i]);
310 NT_STATUS_NOT_OK_RETURN(status);
313 status = wreplsrv_add_table(partner->service,
315 &partner->service->table,
316 names_io->in.owner.address,
317 names_io->in.owner.max_version);
318 NT_STATUS_NOT_OK_RETURN(status);