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"
34 static NTSTATUS wreplsrv_in_start_association(struct wreplsrv_in_call *call)
36 struct wrepl_start *start = &call->req_packet.message.start;
37 struct wrepl_start *start_reply = &call->rep_packet.message.start_reply;
39 if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
41 *if the assoc_ctx doesn't match ignore the packet
43 if ((call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx)
44 && (call->req_packet.assoc_ctx != 0)) {
45 return ERROR_INVALID_PARAMETER;
48 call->wreplconn->assoc_ctx.our_ctx = WREPLSRV_INVALID_ASSOC_CTX;
52 if (start->minor_version != 2 || start->major_version != 5) {
53 /* w2k terminate the connection if the versions doesn't match */
54 return NT_STATUS_UNKNOWN_REVISION;
57 call->wreplconn->assoc_ctx.stopped = False;
58 call->wreplconn->assoc_ctx.our_ctx = WREPLSRV_VALID_ASSOC_CTX;
59 call->wreplconn->assoc_ctx.peer_ctx = start->assoc_ctx;
61 call->rep_packet.mess_type = WREPL_START_ASSOCIATION_REPLY;
62 start_reply->assoc_ctx = call->wreplconn->assoc_ctx.our_ctx;
63 start_reply->minor_version = 2;
64 start_reply->major_version = 5;
69 static NTSTATUS wreplsrv_in_stop_assoc_ctx(struct wreplsrv_in_call *call)
71 struct wrepl_stop *stop_out = &call->rep_packet.message.stop;
73 call->wreplconn->assoc_ctx.stopped = True;
75 call->rep_packet.mess_type = WREPL_STOP_ASSOCIATION;
81 static NTSTATUS wreplsrv_in_stop_association(struct wreplsrv_in_call *call)
84 * w2k only check the assoc_ctx if the opcode has the 0x00007800 bits are set
86 if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
88 *if the assoc_ctx doesn't match ignore the packet
90 if (call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx) {
91 return ERROR_INVALID_PARAMETER;
93 /* when the opcode bits are set the connection should be directly terminated */
94 return NT_STATUS_CONNECTION_RESET;
97 if (call->wreplconn->assoc_ctx.stopped) {
98 /* this causes the connection to be directly terminated */
99 return NT_STATUS_CONNECTION_RESET;
102 /* this will cause to not receive packets anymore and terminate the connection if the reply is send */
103 call->wreplconn->terminate = True;
104 return wreplsrv_in_stop_assoc_ctx(call);
107 static NTSTATUS wreplsrv_in_table_query(struct wreplsrv_in_call *call)
109 struct wreplsrv_service *service = call->wreplconn->service;
110 struct wrepl_replication *repl_out = &call->rep_packet.message.replication;
111 struct wrepl_table *table_out = &call->rep_packet.message.replication.info.table;
112 struct wreplsrv_owner *cur;
113 uint64_t local_max_version;
116 repl_out->command = WREPL_REPL_TABLE_REPLY;
118 table_out->partner_count = 0;
119 table_out->partners = NULL;
120 table_out->initiator = WINSDB_OWNER_LOCAL;
122 local_max_version = wreplsrv_local_max_version(service);
123 if (local_max_version > 0) {
124 table_out->partner_count++;
127 for (cur = service->table; cur; cur = cur->next) {
128 table_out->partner_count++;
131 table_out->partners = talloc_array(call, struct wrepl_wins_owner, table_out->partner_count);
132 NT_STATUS_HAVE_NO_MEMORY(table_out->partners);
134 if (local_max_version > 0) {
135 table_out->partners[i].address = call->wreplconn->our_ip;
136 table_out->partners[i].min_version = 0;
137 table_out->partners[i].max_version = local_max_version;
138 table_out->partners[i].type = 1;
142 for (cur = service->table; cur; cur = cur->next) {
143 table_out->partners[i] = cur->owner;
150 static NTSTATUS wreplsrv_in_send_request(struct wreplsrv_in_call *call)
152 struct wrepl_replication *repl_out = &call->rep_packet.message.replication;
153 struct wrepl_send_reply *reply_out = &call->rep_packet.message.replication.info.reply;
155 repl_out->command = WREPL_REPL_SEND_REPLY;
157 reply_out->num_names = 0;
158 reply_out->names = NULL;
163 static NTSTATUS wreplsrv_in_replication(struct wreplsrv_in_call *call)
165 struct wrepl_replication *repl_in = &call->req_packet.message.replication;
169 * w2k only check the assoc_ctx if the opcode has the 0x00007800 bits are set
171 if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
173 *if the assoc_ctx doesn't match ignore the packet
175 if (call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx) {
176 return ERROR_INVALID_PARAMETER;
180 if (!call->wreplconn->partner) {
181 return wreplsrv_in_stop_assoc_ctx(call);
184 switch (repl_in->command) {
185 case WREPL_REPL_TABLE_QUERY:
186 status = wreplsrv_in_table_query(call);
189 case WREPL_REPL_TABLE_REPLY:
190 return ERROR_INVALID_PARAMETER;
192 case WREPL_REPL_SEND_REQUEST:
193 status = wreplsrv_in_send_request(call);
196 case WREPL_REPL_SEND_REPLY:
197 return ERROR_INVALID_PARAMETER;
199 case WREPL_REPL_UPDATE:
200 return ERROR_INVALID_PARAMETER;
203 return ERROR_INVALID_PARAMETER;
205 case WREPL_REPL_INFORM:
206 return ERROR_INVALID_PARAMETER;
209 return ERROR_INVALID_PARAMETER;
212 return ERROR_INVALID_PARAMETER;
215 if (NT_STATUS_IS_OK(status)) {
216 call->rep_packet.mess_type = WREPL_REPLICATION;
222 static NTSTATUS wreplsrv_in_invalid_assoc_ctx(struct wreplsrv_in_call *call)
224 struct wrepl_start *start = &call->rep_packet.message.start;
226 call->rep_packet.opcode = 0x00008583;
227 call->rep_packet.assoc_ctx = 0;
228 call->rep_packet.mess_type = WREPL_START_ASSOCIATION;
230 start->assoc_ctx = 0x0000000a;
231 start->minor_version = 0x0001;
232 start->major_version = 0x0000;
234 call->rep_packet.padding = data_blob_talloc(call, NULL, 4);
235 memset(call->rep_packet.padding.data, '\0', call->rep_packet.padding.length);
240 NTSTATUS wreplsrv_in_call(struct wreplsrv_in_call *call)
244 if (!(call->req_packet.opcode & WREPL_OPCODE_BITS)
245 && (call->wreplconn->assoc_ctx.our_ctx == WREPLSRV_INVALID_ASSOC_CTX)) {
246 return wreplsrv_in_invalid_assoc_ctx(call);
249 switch (call->req_packet.mess_type) {
250 case WREPL_START_ASSOCIATION:
251 status = wreplsrv_in_start_association(call);
253 case WREPL_START_ASSOCIATION_REPLY:
254 /* this is not valid here, so we ignore it */
255 return ERROR_INVALID_PARAMETER;
257 case WREPL_STOP_ASSOCIATION:
258 status = wreplsrv_in_stop_association(call);
261 case WREPL_REPLICATION:
262 status = wreplsrv_in_replication(call);
265 /* everythingelse is also not valid here, so we ignore it */
266 return ERROR_INVALID_PARAMETER;
269 if (call->wreplconn->assoc_ctx.our_ctx == WREPLSRV_INVALID_ASSOC_CTX) {
270 return wreplsrv_in_invalid_assoc_ctx(call);
273 if (NT_STATUS_IS_OK(status)) {
274 call->rep_packet.opcode = WREPL_OPCODE_BITS;
275 call->rep_packet.assoc_ctx = call->wreplconn->assoc_ctx.peer_ctx;