Line data Source code
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 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 : #include "includes.h"
23 : #include "lib/events/events.h"
24 : #include "lib/tsocket/tsocket.h"
25 : #include "samba/service_task.h"
26 : #include "samba/service_stream.h"
27 : #include "libcli/wrepl/winsrepl.h"
28 : #include "wrepl_server/wrepl_server.h"
29 : #include "libcli/composite/composite.h"
30 : #include "nbt_server/wins/winsdb.h"
31 : #include <ldb.h>
32 : #include <ldb_errors.h>
33 : #include "system/time.h"
34 : #include "lib/util/tsort.h"
35 : #include "param/param.h"
36 :
37 681 : static NTSTATUS wreplsrv_in_start_association(struct wreplsrv_in_call *call)
38 : {
39 681 : struct wrepl_start *start = &call->req_packet.message.start;
40 681 : struct wrepl_start *start_reply = &call->rep_packet.message.start_reply;
41 :
42 681 : if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
43 : /*
44 : *if the assoc_ctx doesn't match ignore the packet
45 : */
46 681 : if ((call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx)
47 2 : && (call->req_packet.assoc_ctx != 0)) {
48 0 : return ERROR_INVALID_PARAMETER;
49 : }
50 : } else {
51 0 : call->wreplconn->assoc_ctx.our_ctx = WREPLSRV_INVALID_ASSOC_CTX;
52 0 : return NT_STATUS_OK;
53 : }
54 :
55 : /*
56 : * it seems that we don't know all details about the start_association
57 : * to support replication with NT4 (it sends 1.1 instead of 5.2)
58 : * we ignore the version numbers until we know all details
59 : */
60 : #if 0
61 : if (start->minor_version != 2 || start->major_version != 5) {
62 : /* w2k terminate the connection if the versions doesn't match */
63 : return NT_STATUS_UNKNOWN_REVISION;
64 : }
65 : #endif
66 :
67 681 : call->wreplconn->assoc_ctx.stopped = false;
68 681 : call->wreplconn->assoc_ctx.our_ctx = WREPLSRV_VALID_ASSOC_CTX;
69 681 : call->wreplconn->assoc_ctx.peer_ctx = start->assoc_ctx;
70 :
71 681 : call->rep_packet.mess_type = WREPL_START_ASSOCIATION_REPLY;
72 681 : start_reply->assoc_ctx = call->wreplconn->assoc_ctx.our_ctx;
73 681 : start_reply->minor_version = 2;
74 681 : start_reply->major_version = 5;
75 :
76 : /*
77 : * nt4 uses 41 bytes for the start_association call
78 : * so do it the same and as we don't know the meanings of these bytes
79 : * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
80 : *
81 : * if we don't do this nt4 uses an old version of the wins replication protocol
82 : * and that would break nt4 <-> samba replication
83 : */
84 681 : call->rep_packet.padding = data_blob_talloc(call, NULL, 21);
85 681 : NT_STATUS_HAVE_NO_MEMORY(call->rep_packet.padding.data);
86 :
87 681 : memset(call->rep_packet.padding.data, 0, call->rep_packet.padding.length);
88 :
89 681 : return NT_STATUS_OK;
90 : }
91 :
92 0 : static NTSTATUS wreplsrv_in_stop_assoc_ctx(struct wreplsrv_in_call *call)
93 : {
94 0 : struct wrepl_stop *stop_out = &call->rep_packet.message.stop;
95 :
96 0 : call->wreplconn->assoc_ctx.stopped = true;
97 :
98 0 : call->rep_packet.mess_type = WREPL_STOP_ASSOCIATION;
99 0 : stop_out->reason = 4;
100 :
101 0 : return NT_STATUS_OK;
102 : }
103 :
104 0 : static NTSTATUS wreplsrv_in_stop_association(struct wreplsrv_in_call *call)
105 : {
106 : /*
107 : * w2k only check the assoc_ctx if the opcode has the 0x00007800 bits are set
108 : */
109 0 : if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
110 : /*
111 : *if the assoc_ctx doesn't match ignore the packet
112 : */
113 0 : if (call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx) {
114 0 : return ERROR_INVALID_PARAMETER;
115 : }
116 : /* when the opcode bits are set the connection should be directly terminated */
117 0 : return NT_STATUS_CONNECTION_RESET;
118 : }
119 :
120 0 : if (call->wreplconn->assoc_ctx.stopped) {
121 : /* this causes the connection to be directly terminated */
122 0 : return NT_STATUS_CONNECTION_RESET;
123 : }
124 :
125 : /* this will cause to not receive packets anymore and terminate the connection if the reply is send */
126 0 : call->terminate_after_send = true;
127 0 : return wreplsrv_in_stop_assoc_ctx(call);
128 : }
129 :
130 3 : static NTSTATUS wreplsrv_in_table_query(struct wreplsrv_in_call *call)
131 : {
132 3 : struct wreplsrv_service *service = call->wreplconn->service;
133 3 : struct wrepl_replication *repl_out = &call->rep_packet.message.replication;
134 3 : struct wrepl_table *table_out = &call->rep_packet.message.replication.info.table;
135 :
136 3 : repl_out->command = WREPL_REPL_TABLE_REPLY;
137 :
138 6 : return wreplsrv_fill_wrepl_table(service, call, table_out,
139 3 : service->wins_db->local_owner, true);
140 : }
141 :
142 0 : static int wreplsrv_in_sort_wins_name(struct wrepl_wins_name *n1,
143 : struct wrepl_wins_name *n2)
144 : {
145 0 : if (n1->id < n2->id) return -1;
146 0 : if (n1->id > n2->id) return 1;
147 0 : return 0;
148 : }
149 :
150 527 : static NTSTATUS wreplsrv_record2wins_name(TALLOC_CTX *mem_ctx,
151 : struct wrepl_wins_name *name,
152 : struct winsdb_record *rec)
153 : {
154 0 : uint32_t num_ips, i;
155 0 : struct wrepl_ip *ips;
156 :
157 527 : name->name = rec->name;
158 527 : talloc_steal(mem_ctx, rec->name);
159 :
160 527 : name->id = rec->version;
161 527 : name->unknown = "255.255.255.255";
162 :
163 527 : name->flags = WREPL_NAME_FLAGS(rec->type, rec->state, rec->node, rec->is_static);
164 :
165 527 : switch (name->flags & 2) {
166 288 : case 0:
167 288 : name->addresses.ip = rec->addresses[0]->address;
168 288 : talloc_steal(mem_ctx, rec->addresses[0]->address);
169 288 : break;
170 239 : case 2:
171 239 : num_ips = winsdb_addr_list_length(rec->addresses);
172 239 : ips = talloc_array(mem_ctx, struct wrepl_ip, num_ips);
173 239 : NT_STATUS_HAVE_NO_MEMORY(ips);
174 :
175 629 : for (i = 0; i < num_ips; i++) {
176 390 : ips[i].owner = rec->addresses[i]->wins_owner;
177 390 : talloc_steal(ips, rec->addresses[i]->wins_owner);
178 390 : ips[i].ip = rec->addresses[i]->address;
179 390 : talloc_steal(ips, rec->addresses[i]->address);
180 : }
181 :
182 239 : name->addresses.addresses.num_ips = num_ips;
183 239 : name->addresses.addresses.ips = ips;
184 239 : break;
185 : }
186 :
187 527 : return NT_STATUS_OK;
188 : }
189 :
190 780 : static NTSTATUS wreplsrv_in_send_request(struct wreplsrv_in_call *call)
191 : {
192 780 : struct wreplsrv_service *service = call->wreplconn->service;
193 780 : struct wrepl_wins_owner *owner_in = &call->req_packet.message.replication.info.owner;
194 780 : struct wrepl_replication *repl_out = &call->rep_packet.message.replication;
195 780 : struct wrepl_send_reply *reply_out = &call->rep_packet.message.replication.info.reply;
196 0 : struct wreplsrv_owner *owner;
197 0 : const char *owner_filter;
198 0 : const char *filter;
199 780 : struct ldb_result *res = NULL;
200 0 : int ret;
201 0 : struct wrepl_wins_name *names;
202 0 : struct winsdb_record *rec;
203 0 : NTSTATUS status;
204 0 : unsigned int i, j;
205 780 : time_t now = time(NULL);
206 :
207 780 : owner = wreplsrv_find_owner(service, service->table, owner_in->address);
208 :
209 780 : repl_out->command = WREPL_REPL_SEND_REPLY;
210 780 : reply_out->num_names = 0;
211 780 : reply_out->names = NULL;
212 :
213 : /*
214 : * if we didn't know this owner, must be a bug in the partners client code...
215 : * return an empty list.
216 : */
217 780 : if (!owner) {
218 0 : DEBUG(2,("WINSREPL:reply [0] records unknown owner[%s] to partner[%s]\n",
219 : owner_in->address, call->wreplconn->partner->address));
220 0 : return NT_STATUS_OK;
221 : }
222 :
223 : /*
224 : * the client sends a max_version of 0, interpret it as
225 : * (uint64_t)-1
226 : */
227 780 : if (owner_in->max_version == 0) {
228 12 : owner_in->max_version = (uint64_t)-1;
229 : }
230 :
231 : /*
232 : * if the partner ask for nothing, or give invalid ranges,
233 : * return an empty list.
234 : */
235 780 : if (owner_in->min_version > owner_in->max_version) {
236 0 : DEBUG(2,("WINSREPL:reply [0] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
237 : owner_in->address,
238 : (long long)owner_in->min_version,
239 : (long long)owner_in->max_version,
240 : call->wreplconn->partner->address));
241 0 : return NT_STATUS_OK;
242 : }
243 :
244 : /*
245 : * if the partner has already all records for nothing, or give invalid ranges,
246 : * return an empty list.
247 : */
248 780 : if (owner_in->min_version > owner->owner.max_version) {
249 0 : DEBUG(2,("WINSREPL:reply [0] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
250 : owner_in->address,
251 : (long long)owner_in->min_version,
252 : (long long)owner_in->max_version,
253 : call->wreplconn->partner->address));
254 0 : return NT_STATUS_OK;
255 : }
256 :
257 780 : owner_filter = wreplsrv_owner_filter(service, call, owner->owner.address);
258 780 : NT_STATUS_HAVE_NO_MEMORY(owner_filter);
259 780 : filter = talloc_asprintf(call,
260 : "(&%s(objectClass=winsRecord)"
261 : "(|(recordState=%u)(recordState=%u))"
262 : "(versionID>=%llu)(versionID<=%llu))",
263 : owner_filter,
264 : WREPL_STATE_ACTIVE, WREPL_STATE_TOMBSTONE,
265 780 : (long long)owner_in->min_version,
266 780 : (long long)owner_in->max_version);
267 780 : NT_STATUS_HAVE_NO_MEMORY(filter);
268 780 : ret = ldb_search(service->wins_db->ldb, call, &res, NULL, LDB_SCOPE_SUBTREE, NULL, "%s", filter);
269 780 : if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
270 780 : DEBUG(10,("WINSREPL: filter '%s' count %d\n", filter, res->count));
271 :
272 780 : if (res->count == 0) {
273 253 : DEBUG(2,("WINSREPL:reply [%u] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
274 : res->count, owner_in->address,
275 : (long long)owner_in->min_version,
276 : (long long)owner_in->max_version,
277 : call->wreplconn->partner->address));
278 253 : return NT_STATUS_OK;
279 : }
280 :
281 527 : names = talloc_array(call, struct wrepl_wins_name, res->count);
282 527 : NT_STATUS_HAVE_NO_MEMORY(names);
283 :
284 1054 : for (i=0, j=0; i < res->count; i++) {
285 527 : status = winsdb_record(service->wins_db, res->msgs[i], call, now, &rec);
286 527 : NT_STATUS_NOT_OK_RETURN(status);
287 :
288 : /*
289 : * it's possible that winsdb_record() made the record RELEASED
290 : * because it's expired, but in the database it's still stored
291 : * as ACTIVE...
292 : *
293 : * make sure we really only replicate ACTIVE and TOMBSTONE records
294 : */
295 527 : if (rec->state == WREPL_STATE_ACTIVE || rec->state == WREPL_STATE_TOMBSTONE) {
296 527 : status = wreplsrv_record2wins_name(names, &names[j], rec);
297 527 : NT_STATUS_NOT_OK_RETURN(status);
298 527 : j++;
299 : }
300 :
301 527 : talloc_free(rec);
302 527 : talloc_free(res->msgs[i]);
303 : }
304 :
305 : /* sort the names before we send them */
306 527 : TYPESAFE_QSORT(names, j, wreplsrv_in_sort_wins_name);
307 :
308 527 : DEBUG(2,("WINSREPL:reply [%u] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
309 : j, owner_in->address,
310 : (long long)owner_in->min_version,
311 : (long long)owner_in->max_version,
312 : call->wreplconn->partner->address));
313 :
314 527 : reply_out->num_names = j;
315 527 : reply_out->names = names;
316 :
317 527 : return NT_STATUS_OK;
318 : }
319 :
320 : struct wreplsrv_in_update_state {
321 : struct wreplsrv_in_connection *wrepl_in;
322 : struct wreplsrv_out_connection *wrepl_out;
323 : struct composite_context *creq;
324 : struct wreplsrv_pull_cycle_io cycle_io;
325 : };
326 :
327 675 : static void wreplsrv_in_update_handler(struct composite_context *creq)
328 : {
329 675 : struct wreplsrv_in_update_state *update_state = talloc_get_type(creq->async.private_data,
330 : struct wreplsrv_in_update_state);
331 0 : NTSTATUS status;
332 :
333 675 : status = wreplsrv_pull_cycle_recv(creq);
334 :
335 675 : talloc_free(update_state->wrepl_out);
336 :
337 675 : wreplsrv_terminate_in_connection(update_state->wrepl_in, nt_errstr(status));
338 675 : }
339 :
340 675 : static NTSTATUS wreplsrv_in_update(struct wreplsrv_in_call *call)
341 : {
342 675 : struct wreplsrv_in_connection *wrepl_in = call->wreplconn;
343 0 : struct wreplsrv_out_connection *wrepl_out;
344 675 : struct wrepl_table *update_in = &call->req_packet.message.replication.info.table;
345 0 : struct wreplsrv_in_update_state *update_state;
346 0 : NTSTATUS status;
347 :
348 675 : DEBUG(2,("WREPL_REPL_UPDATE: partner[%s] initiator[%s] num_owners[%u]\n",
349 : call->wreplconn->partner->address,
350 : update_in->initiator, update_in->partner_count));
351 :
352 675 : update_state = talloc(wrepl_in, struct wreplsrv_in_update_state);
353 675 : NT_STATUS_HAVE_NO_MEMORY(update_state);
354 :
355 675 : wrepl_out = talloc(update_state, struct wreplsrv_out_connection);
356 675 : NT_STATUS_HAVE_NO_MEMORY(wrepl_out);
357 675 : wrepl_out->service = wrepl_in->service;
358 675 : wrepl_out->partner = wrepl_in->partner;
359 675 : wrepl_out->assoc_ctx.our_ctx = wrepl_in->assoc_ctx.our_ctx;
360 675 : wrepl_out->assoc_ctx.peer_ctx = wrepl_in->assoc_ctx.peer_ctx;
361 1350 : wrepl_out->sock = wrepl_socket_init(wrepl_out,
362 675 : wrepl_in->conn->event.ctx);
363 :
364 675 : if (wrepl_out->sock == NULL) {
365 0 : TALLOC_FREE(update_state);
366 0 : return NT_STATUS_NO_MEMORY;
367 : }
368 :
369 675 : TALLOC_FREE(wrepl_in->send_queue);
370 :
371 675 : status = wrepl_socket_donate_stream(wrepl_out->sock, &wrepl_in->tstream);
372 675 : if (!NT_STATUS_IS_OK(status)) {
373 0 : TALLOC_FREE(update_state);
374 0 : return status;
375 : }
376 :
377 675 : update_state->wrepl_in = wrepl_in;
378 675 : update_state->wrepl_out = wrepl_out;
379 675 : update_state->cycle_io.in.partner = wrepl_out->partner;
380 675 : update_state->cycle_io.in.num_owners = update_in->partner_count;
381 675 : update_state->cycle_io.in.owners = update_in->partners;
382 675 : talloc_steal(update_state, update_in->partners);
383 675 : update_state->cycle_io.in.wreplconn = wrepl_out;
384 675 : update_state->creq = wreplsrv_pull_cycle_send(update_state, &update_state->cycle_io);
385 675 : if (!update_state->creq) {
386 0 : talloc_free(update_state);
387 0 : return NT_STATUS_INTERNAL_ERROR;
388 : }
389 :
390 675 : update_state->creq->async.fn = wreplsrv_in_update_handler;
391 675 : update_state->creq->async.private_data = update_state;
392 :
393 675 : return ERROR_INVALID_PARAMETER;
394 : }
395 :
396 0 : static NTSTATUS wreplsrv_in_update2(struct wreplsrv_in_call *call)
397 : {
398 0 : return wreplsrv_in_update(call);
399 : }
400 :
401 0 : static NTSTATUS wreplsrv_in_inform(struct wreplsrv_in_call *call)
402 : {
403 0 : struct wrepl_table *inform_in = &call->req_packet.message.replication.info.table;
404 :
405 0 : DEBUG(2,("WREPL_REPL_INFORM: partner[%s] initiator[%s] num_owners[%u]\n",
406 : call->wreplconn->partner->address,
407 : inform_in->initiator, inform_in->partner_count));
408 :
409 0 : wreplsrv_out_partner_pull(call->wreplconn->partner, inform_in);
410 :
411 : /* we don't reply to WREPL_REPL_INFORM messages */
412 0 : return ERROR_INVALID_PARAMETER;
413 : }
414 :
415 0 : static NTSTATUS wreplsrv_in_inform2(struct wreplsrv_in_call *call)
416 : {
417 0 : return wreplsrv_in_inform(call);
418 : }
419 :
420 1458 : static NTSTATUS wreplsrv_in_replication(struct wreplsrv_in_call *call)
421 : {
422 1458 : struct wrepl_replication *repl_in = &call->req_packet.message.replication;
423 0 : NTSTATUS status;
424 :
425 : /*
426 : * w2k only check the assoc_ctx if the opcode has the 0x00007800 bits are set
427 : */
428 1458 : if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
429 : /*
430 : *if the assoc_ctx doesn't match ignore the packet
431 : */
432 1458 : if (call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx) {
433 0 : return ERROR_INVALID_PARAMETER;
434 : }
435 : }
436 :
437 1458 : if (!call->wreplconn->partner) {
438 0 : struct tsocket_address *peer_addr = call->wreplconn->conn->remote_address;
439 0 : char *peer_ip;
440 :
441 0 : if (!tsocket_address_is_inet(peer_addr, "ipv4")) {
442 0 : DEBUG(0,("wreplsrv_in_replication: non ipv4 peer addr '%s'\n",
443 : tsocket_address_string(peer_addr, call)));
444 0 : return NT_STATUS_INTERNAL_ERROR;
445 : }
446 :
447 0 : peer_ip = tsocket_address_inet_addr_string(peer_addr, call);
448 0 : if (peer_ip == NULL) {
449 0 : return NT_STATUS_NO_MEMORY;
450 : }
451 :
452 0 : call->wreplconn->partner = wreplsrv_find_partner(call->wreplconn->service, peer_ip);
453 0 : if (!call->wreplconn->partner) {
454 0 : DEBUG(1,("Failing WINS replication from non-partner %s\n", peer_ip));
455 0 : return wreplsrv_in_stop_assoc_ctx(call);
456 : }
457 : }
458 :
459 1458 : switch (repl_in->command) {
460 3 : case WREPL_REPL_TABLE_QUERY:
461 3 : if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PUSH)) {
462 0 : DEBUG(0,("Failing WINS replication TABLE_QUERY from non-push-partner %s\n",
463 : call->wreplconn->partner->address));
464 0 : return wreplsrv_in_stop_assoc_ctx(call);
465 : }
466 3 : status = wreplsrv_in_table_query(call);
467 3 : break;
468 :
469 0 : case WREPL_REPL_TABLE_REPLY:
470 0 : return ERROR_INVALID_PARAMETER;
471 :
472 780 : case WREPL_REPL_SEND_REQUEST:
473 780 : if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PUSH)) {
474 0 : DEBUG(0,("Failing WINS replication SEND_REQUESET from non-push-partner %s\n",
475 : call->wreplconn->partner->address));
476 0 : return wreplsrv_in_stop_assoc_ctx(call);
477 : }
478 780 : status = wreplsrv_in_send_request(call);
479 780 : break;
480 :
481 0 : case WREPL_REPL_SEND_REPLY:
482 0 : return ERROR_INVALID_PARAMETER;
483 :
484 675 : case WREPL_REPL_UPDATE:
485 675 : if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
486 0 : DEBUG(0,("Failing WINS replication UPDATE from non-pull-partner %s\n",
487 : call->wreplconn->partner->address));
488 0 : return wreplsrv_in_stop_assoc_ctx(call);
489 : }
490 675 : status = wreplsrv_in_update(call);
491 675 : break;
492 :
493 0 : case WREPL_REPL_UPDATE2:
494 0 : if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
495 0 : DEBUG(0,("Failing WINS replication UPDATE2 from non-pull-partner %s\n",
496 : call->wreplconn->partner->address));
497 0 : return wreplsrv_in_stop_assoc_ctx(call);
498 : }
499 0 : status = wreplsrv_in_update2(call);
500 0 : break;
501 :
502 0 : case WREPL_REPL_INFORM:
503 0 : if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
504 0 : DEBUG(0,("Failing WINS replication INFORM from non-pull-partner %s\n",
505 : call->wreplconn->partner->address));
506 0 : return wreplsrv_in_stop_assoc_ctx(call);
507 : }
508 0 : status = wreplsrv_in_inform(call);
509 0 : break;
510 :
511 0 : case WREPL_REPL_INFORM2:
512 0 : if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
513 0 : DEBUG(0,("Failing WINS replication INFORM2 from non-pull-partner %s\n",
514 : call->wreplconn->partner->address));
515 0 : return wreplsrv_in_stop_assoc_ctx(call);
516 : }
517 0 : status = wreplsrv_in_inform2(call);
518 0 : break;
519 :
520 0 : default:
521 0 : return ERROR_INVALID_PARAMETER;
522 : }
523 :
524 1458 : if (NT_STATUS_IS_OK(status)) {
525 783 : call->rep_packet.mess_type = WREPL_REPLICATION;
526 : }
527 :
528 1458 : return status;
529 : }
530 :
531 0 : static NTSTATUS wreplsrv_in_invalid_assoc_ctx(struct wreplsrv_in_call *call)
532 : {
533 0 : struct wrepl_start *start = &call->rep_packet.message.start;
534 :
535 0 : call->rep_packet.opcode = 0x00008583;
536 0 : call->rep_packet.assoc_ctx = 0;
537 0 : call->rep_packet.mess_type = WREPL_START_ASSOCIATION;
538 :
539 0 : start->assoc_ctx = 0x0000000a;
540 0 : start->minor_version = 0x0001;
541 0 : start->major_version = 0x0000;
542 :
543 0 : call->rep_packet.padding = data_blob_talloc(call, NULL, 4);
544 0 : memset(call->rep_packet.padding.data, '\0', call->rep_packet.padding.length);
545 :
546 0 : return NT_STATUS_OK;
547 : }
548 :
549 2139 : NTSTATUS wreplsrv_in_call(struct wreplsrv_in_call *call)
550 : {
551 0 : NTSTATUS status;
552 :
553 2139 : if (!(call->req_packet.opcode & WREPL_OPCODE_BITS)
554 0 : && (call->wreplconn->assoc_ctx.our_ctx == WREPLSRV_INVALID_ASSOC_CTX)) {
555 0 : return wreplsrv_in_invalid_assoc_ctx(call);
556 : }
557 :
558 2139 : switch (call->req_packet.mess_type) {
559 681 : case WREPL_START_ASSOCIATION:
560 681 : status = wreplsrv_in_start_association(call);
561 681 : break;
562 0 : case WREPL_START_ASSOCIATION_REPLY:
563 : /* this is not valid here, so we ignore it */
564 0 : return ERROR_INVALID_PARAMETER;
565 :
566 0 : case WREPL_STOP_ASSOCIATION:
567 0 : status = wreplsrv_in_stop_association(call);
568 0 : break;
569 :
570 1458 : case WREPL_REPLICATION:
571 1458 : status = wreplsrv_in_replication(call);
572 1458 : break;
573 0 : default:
574 : /* everythingelse is also not valid here, so we ignore it */
575 0 : return ERROR_INVALID_PARAMETER;
576 : }
577 :
578 2139 : if (call->wreplconn->assoc_ctx.our_ctx == WREPLSRV_INVALID_ASSOC_CTX) {
579 0 : return wreplsrv_in_invalid_assoc_ctx(call);
580 : }
581 :
582 2139 : if (NT_STATUS_IS_OK(status)) {
583 : /* let the backend to set some of the opcode bits, but always add the standards */
584 1464 : call->rep_packet.opcode |= WREPL_OPCODE_BITS;
585 1464 : call->rep_packet.assoc_ctx = call->wreplconn->assoc_ctx.peer_ctx;
586 : }
587 :
588 2139 : return status;
589 : }
|