r11178: add some logic functions for the replica_vs_replica conflict handling
[bbaumbach/samba-autobuild/.git] / source / wrepl_server / wrepl_apply_records.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    WINS Replication server
5    
6    Copyright (C) Stefan Metzmacher      2005
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
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"
37
38 enum _R_ACTION {
39         R_DO_ADD        = 1,
40         R_DO_REPLACE    = 2,
41         R_NOT_REPLACE   = 3,
42         R_DO_MERGE      = 4
43 };
44
45 static const char *_R_ACTION_enum_string(enum _R_ACTION action)
46 {
47         switch (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";
52         }
53
54         return "enum _R_ACTION unknown";
55 }
56
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)
60
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)
65
66 static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_name *r2)
67 {
68         /* TODO: we need to look closer at how special groups are handled */
69
70         /* REPLACE */
71         return R_DO_REPLACE;
72 }
73
74 /*
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
99 */
100 static enum _R_ACTION replace_replica_replica_unique_vs_X(struct winsdb_record *r1, struct wrepl_name *r2)
101 {
102         if (!R_IS_ACTIVE(r1)) {
103                 /* REPLACE */
104                 return R_DO_REPLACE;
105         }
106
107         if (!R_IS_SGROUP(r2) && R_IS_ACTIVE(r2)) {
108                 /* REPLACE */
109                 return R_DO_REPLACE;
110         }
111
112         /* NOT REPLACE */
113         return R_NOT_REPLACE;
114 }
115
116 /*
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
141 */
142 static enum _R_ACTION replace_replica_replica_group_vs_X(struct winsdb_record *r1, struct wrepl_name *r2)
143 {
144         if (!R_IS_ACTIVE(r1) && R_IS_GROUP(r2)) {
145                 /* REPLACE */
146                 return R_DO_REPLACE;
147         }
148
149         if (R_IS_TOMBSTONE(r1) && !R_IS_UNIQUE(r2)) {
150                 /* REPLACE */
151                 return R_DO_REPLACE;
152         }
153
154         /* NOT REPLACE */
155         return R_NOT_REPLACE;
156 }
157
158 /*
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
177 */
178 static enum _R_ACTION replace_replica_replica_sgroup_vs_X(struct winsdb_record *r1, struct wrepl_name *r2)
179 {
180         if (R_IS_SGROUP(r2)) {
181                 /* not handled here: MERGE */
182                 return R_DO_MERGE;
183         }
184
185         if (!R_IS_ACTIVE(r1)) {
186                 /* REPLACE */
187                 return R_DO_REPLACE;
188         }
189
190         /* NOT REPLACE */
191         return R_NOT_REPLACE;
192 }
193
194 /*
195 MHOMED,ACTIVE vs. GROUP,ACTIVE with different ip(s) => REPLACE
196 MHOMED,ACTIVE vs. GROUP,TOMBSTONE with same ip(s) => NOT REPLACE
197 MHOMED,RELEASED vs. GROUP,ACTIVE with different ip(s) => REPLACE
198 MHOMED,RELEASED vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
199 MHOMED,TOMBSTONE vs. GROUP,ACTIVE with different ip(s) => REPLACE
200 MHOMED,TOMBSTONE vs. GROUP,TOMBSTONE with different ip(s) => REPLACE
201 MHOMED,ACTIVE vs. SGROUP,ACTIVE with same ip(s) => NOT REPLACE
202 MHOMED,ACTIVE vs. SGROUP,TOMBSTONE with same ip(s) => NOT REPLACE
203 MHOMED,RELEASED vs. SGROUP,ACTIVE with different ip(s) => REPLACE
204 MHOMED,RELEASED vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
205 MHOMED,TOMBSTONE vs. SGROUP,ACTIVE with different ip(s) => REPLACE
206 MHOMED,TOMBSTONE vs. SGROUP,TOMBSTONE with different ip(s) => REPLACE
207 */
208 static enum _R_ACTION replace_replica_replica_mhomed_vs_X(struct winsdb_record *r1, struct wrepl_name *r2)
209 {
210         if (R_IS_UNIQUE(r2) || R_IS_MHOMED(r2)) {
211                 /* not handled here: MERGE */
212                 return R_DO_MERGE;
213         }
214
215         if (!R_IS_ACTIVE(r1)) {
216                 /* REPLACE */
217                 return R_DO_REPLACE;
218         }
219
220         if (R_IS_GROUP(r2) && R_IS_ACTIVE(r2)) {
221                 /* REPLACE */
222                 return R_DO_REPLACE;
223         }
224
225         /* NOT REPLACE */
226         return R_NOT_REPLACE;
227 }
228
229 static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
230                                           TALLOC_CTX *mem_ctx,
231                                           struct wrepl_wins_owner *owner,
232                                           struct wrepl_name *name)
233 {
234         NTSTATUS status;
235         struct winsdb_record *rec = NULL;
236         enum _R_ACTION action = R_NOT_REPLACE;
237         BOOL same_owner = False;
238         BOOL replica_vs_replica = False;
239         BOOL local_vs_replica = False;
240
241         status = winsdb_lookup(partner->service->wins_db,
242                                &name->name, mem_ctx, &rec);
243         if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
244                 rec = NULL;
245                 action = R_DO_ADD;
246                 status = NT_STATUS_OK;
247         }
248         NT_STATUS_NOT_OK_RETURN(status);
249
250         if (rec) {
251                 if (strcmp(rec->wins_owner, WINSDB_OWNER_LOCAL)==0) {
252                         local_vs_replica = True;
253                 } else if (strcmp(rec->wins_owner, owner->address)==0) {
254                         same_owner = True;
255                 } else {
256                         replica_vs_replica = True;
257                 }
258         }
259
260         if (rec && same_owner) {
261                 action = replace_same_owner(rec, name);
262         } else if (rec && replica_vs_replica) {
263                 switch (rec->type) {
264                 case WREPL_TYPE_UNIQUE:
265                         action = replace_replica_replica_unique_vs_X(rec, name);
266                         break;
267                 case WREPL_TYPE_GROUP:
268                         action = replace_replica_replica_group_vs_X(rec, name);
269                         break;
270                 case WREPL_TYPE_SGROUP:
271                         action = replace_replica_replica_sgroup_vs_X(rec, name);
272                         break;
273                 case WREPL_TYPE_MHOMED:
274                         action = replace_replica_replica_mhomed_vs_X(rec, name);
275                         break;
276                 }
277         } else if (rec && local_vs_replica) {
278                 /* TODO: */
279         }
280
281         /* TODO: !!! */
282         DEBUG(0,("TODO: apply record %s: %s\n",
283                  nbt_name_string(mem_ctx, &name->name), _R_ACTION_enum_string(action)));
284
285         return NT_STATUS_OK;
286 }
287
288 NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wreplsrv_pull_names_io *names_io)
289 {
290         TALLOC_CTX *tmp_mem = talloc_new(partner);
291         NTSTATUS status;
292         uint32_t i;
293
294         /* TODO: ! */
295         DEBUG(0,("TODO: apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
296                 names_io->out.num_names, names_io->in.owner.address,
297                 names_io->in.owner.min_version, names_io->in.owner.max_version,
298                 partner->address));
299
300         for (i=0; i < names_io->out.num_names; i++) {
301                 status = wreplsrv_apply_one_record(partner, tmp_mem,
302                                                    &names_io->in.owner,
303                                                    &names_io->out.names[i]);
304                 NT_STATUS_NOT_OK_RETURN(status);
305         }
306
307         status = wreplsrv_add_table(partner->service,
308                                     partner->service,
309                                     &partner->service->table,
310                                     names_io->in.owner.address,
311                                     names_io->in.owner.max_version);
312         NT_STATUS_NOT_OK_RETURN(status);
313
314         return NT_STATUS_OK;
315 }