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/socket/socket.h"
24 : #include "lib/stream/packet.h"
25 : #include "samba/service_task.h"
26 : #include "samba/service_stream.h"
27 : #include "samba/service.h"
28 : #include "lib/messaging/irpc.h"
29 : #include "librpc/gen_ndr/ndr_winsrepl.h"
30 : #include "wrepl_server/wrepl_server.h"
31 : #include "samba/process_model.h"
32 : #include "system/network.h"
33 : #include "lib/socket/netif.h"
34 : #include "lib/tsocket/tsocket.h"
35 : #include "libcli/util/tstream.h"
36 : #include "param/param.h"
37 :
38 679 : void wreplsrv_terminate_in_connection(struct wreplsrv_in_connection *wreplconn, const char *reason)
39 : {
40 679 : stream_terminate_connection(wreplconn->conn, reason);
41 679 : }
42 :
43 : /*
44 : receive some data on a WREPL connection
45 : */
46 2139 : static NTSTATUS wreplsrv_process(struct wreplsrv_in_connection *wrepl_conn,
47 : struct wreplsrv_in_call **_call)
48 : {
49 : struct wrepl_wrap packet_out_wrap;
50 : NTSTATUS status;
51 : enum ndr_err_code ndr_err;
52 2139 : struct wreplsrv_in_call *call = *_call;
53 :
54 2139 : ndr_err = ndr_pull_struct_blob(&call->in, call,
55 2139 : &call->req_packet,
56 : (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
57 2139 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
58 0 : return ndr_map_error2ntstatus(ndr_err);
59 : }
60 :
61 2139 : if (DEBUGLVL(10)) {
62 0 : DEBUG(10,("Received WINS-Replication packet of length %u\n",
63 : (unsigned int) call->in.length + 4));
64 0 : NDR_PRINT_DEBUG(wrepl_packet, &call->req_packet);
65 : }
66 :
67 2139 : status = wreplsrv_in_call(call);
68 2139 : if (NT_STATUS_IS_ERR(status)) {
69 0 : return status;
70 : }
71 2139 : if (!NT_STATUS_IS_OK(status)) {
72 : /* w2k just ignores invalid packets, so we do */
73 675 : DEBUG(10,("Received WINS-Replication packet was invalid, we just ignore it\n"));
74 675 : TALLOC_FREE(call);
75 675 : *_call = NULL;
76 675 : return NT_STATUS_OK;
77 : }
78 :
79 : /* and now encode the reply */
80 1464 : packet_out_wrap.packet = call->rep_packet;
81 1464 : ndr_err = ndr_push_struct_blob(&call->out, call,
82 : &packet_out_wrap,
83 : (ndr_push_flags_fn_t) ndr_push_wrepl_wrap);
84 1464 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
85 0 : return ndr_map_error2ntstatus(ndr_err);
86 : }
87 :
88 1464 : if (DEBUGLVL(10)) {
89 0 : DEBUG(10,("Sending WINS-Replication packet of length %u\n",
90 : (unsigned int) call->out.length));
91 0 : NDR_PRINT_DEBUG(wrepl_packet, &call->rep_packet);
92 : }
93 :
94 1464 : return NT_STATUS_OK;
95 : }
96 :
97 : static void wreplsrv_call_loop(struct tevent_req *subreq);
98 :
99 : /*
100 : called when we get a new connection
101 : */
102 679 : static void wreplsrv_accept(struct stream_connection *conn)
103 : {
104 679 : struct wreplsrv_service *service = talloc_get_type(conn->private_data, struct wreplsrv_service);
105 : struct wreplsrv_in_connection *wrepl_conn;
106 : struct tsocket_address *peer_addr;
107 : char *peer_ip;
108 : struct tevent_req *subreq;
109 : int rc;
110 :
111 679 : wrepl_conn = talloc_zero(conn, struct wreplsrv_in_connection);
112 679 : if (wrepl_conn == NULL) {
113 0 : stream_terminate_connection(conn,
114 : "wreplsrv_accept: out of memory");
115 0 : return;
116 : }
117 :
118 679 : wrepl_conn->send_queue = tevent_queue_create(conn, "wrepl_accept");
119 679 : if (wrepl_conn->send_queue == NULL) {
120 0 : stream_terminate_connection(conn,
121 : "wrepl_accept: out of memory");
122 0 : return;
123 : }
124 :
125 679 : TALLOC_FREE(conn->event.fde);
126 :
127 679 : rc = tstream_bsd_existing_socket(wrepl_conn,
128 : socket_get_fd(conn->socket),
129 : &wrepl_conn->tstream);
130 679 : if (rc < 0) {
131 0 : stream_terminate_connection(conn,
132 : "wrepl_accept: out of memory");
133 0 : return;
134 : }
135 679 : socket_set_flags(conn->socket, SOCKET_FLAG_NOCLOSE);
136 :
137 679 : wrepl_conn->conn = conn;
138 679 : wrepl_conn->service = service;
139 :
140 679 : peer_addr = conn->remote_address;
141 :
142 679 : if (!tsocket_address_is_inet(peer_addr, "ipv4")) {
143 0 : DEBUG(0,("wreplsrv_accept: non ipv4 peer addr '%s'\n",
144 : tsocket_address_string(peer_addr, wrepl_conn)));
145 0 : wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_accept: "
146 : "invalid peer IP");
147 0 : return;
148 : }
149 :
150 679 : peer_ip = tsocket_address_inet_addr_string(peer_addr, wrepl_conn);
151 679 : if (peer_ip == NULL) {
152 0 : wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_accept: "
153 : "could not convert peer IP into a string");
154 0 : return;
155 : }
156 :
157 679 : wrepl_conn->partner = wreplsrv_find_partner(service, peer_ip);
158 679 : irpc_add_name(conn->msg_ctx, "wreplsrv_connection");
159 :
160 : /*
161 : * The wrepl pdu's has the length as 4 byte (initial_read_size),
162 : * packet_full_request_u32 provides the pdu length then.
163 : */
164 1358 : subreq = tstream_read_pdu_blob_send(wrepl_conn,
165 679 : wrepl_conn->conn->event.ctx,
166 : wrepl_conn->tstream,
167 : 4, /* initial_read_size */
168 : packet_full_request_u32,
169 : wrepl_conn);
170 679 : if (subreq == NULL) {
171 0 : wreplsrv_terminate_in_connection(wrepl_conn, "wrepl_accept: "
172 : "no memory for tstream_read_pdu_blob_send");
173 0 : return;
174 : }
175 679 : tevent_req_set_callback(subreq, wreplsrv_call_loop, wrepl_conn);
176 : }
177 :
178 : static void wreplsrv_call_writev_done(struct tevent_req *subreq);
179 :
180 2143 : static void wreplsrv_call_loop(struct tevent_req *subreq)
181 : {
182 2143 : struct wreplsrv_in_connection *wrepl_conn = tevent_req_callback_data(subreq,
183 : struct wreplsrv_in_connection);
184 : struct wreplsrv_in_call *call;
185 : NTSTATUS status;
186 :
187 2143 : call = talloc_zero(wrepl_conn, struct wreplsrv_in_call);
188 2143 : if (call == NULL) {
189 0 : wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_call_loop: "
190 : "no memory for wrepl_samba3_call");
191 0 : return;
192 : }
193 2143 : call->wreplconn = wrepl_conn;
194 :
195 2143 : status = tstream_read_pdu_blob_recv(subreq,
196 : call,
197 2143 : &call->in);
198 2143 : TALLOC_FREE(subreq);
199 2143 : if (!NT_STATUS_IS_OK(status)) {
200 : const char *reason;
201 :
202 4 : reason = talloc_asprintf(call, "wreplsrv_call_loop: "
203 : "tstream_read_pdu_blob_recv() - %s",
204 : nt_errstr(status));
205 4 : if (!reason) {
206 0 : reason = nt_errstr(status);
207 : }
208 :
209 4 : wreplsrv_terminate_in_connection(wrepl_conn, reason);
210 4 : return;
211 : }
212 :
213 2139 : DEBUG(10,("Received wrepl packet of length %lu from %s\n",
214 : (long) call->in.length,
215 : tsocket_address_string(wrepl_conn->conn->remote_address, call)));
216 :
217 : /* skip length header */
218 2139 : call->in.data += 4;
219 2139 : call->in.length -= 4;
220 :
221 2139 : status = wreplsrv_process(wrepl_conn, &call);
222 2139 : if (!NT_STATUS_IS_OK(status)) {
223 : const char *reason;
224 :
225 0 : reason = talloc_asprintf(call, "wreplsrv_call_loop: "
226 : "tstream_read_pdu_blob_recv() - %s",
227 : nt_errstr(status));
228 0 : if (reason == NULL) {
229 0 : reason = nt_errstr(status);
230 : }
231 :
232 0 : wreplsrv_terminate_in_connection(wrepl_conn, reason);
233 0 : return;
234 : }
235 :
236 : /* We handed over the connection so we're done here */
237 2139 : if (wrepl_conn->tstream == NULL) {
238 675 : return;
239 : }
240 :
241 : /* Invalid WINS-Replication packet, we just ignore it */
242 1464 : if (call == NULL) {
243 0 : goto noreply;
244 : }
245 :
246 1464 : call->out_iov[0].iov_base = (char *) call->out.data;
247 1464 : call->out_iov[0].iov_len = call->out.length;
248 :
249 2928 : subreq = tstream_writev_queue_send(call,
250 1464 : wrepl_conn->conn->event.ctx,
251 : wrepl_conn->tstream,
252 : wrepl_conn->send_queue,
253 1464 : call->out_iov, 1);
254 1464 : if (subreq == NULL) {
255 0 : wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_call_loop: "
256 : "no memory for tstream_writev_queue_send");
257 0 : return;
258 : }
259 1464 : tevent_req_set_callback(subreq, wreplsrv_call_writev_done, call);
260 :
261 1464 : noreply:
262 : /*
263 : * The wrepl pdu's has the length as 4 byte (initial_read_size),
264 : * provides the pdu length then.
265 : */
266 2928 : subreq = tstream_read_pdu_blob_send(wrepl_conn,
267 1464 : wrepl_conn->conn->event.ctx,
268 : wrepl_conn->tstream,
269 : 4, /* initial_read_size */
270 : packet_full_request_u32,
271 : wrepl_conn);
272 1464 : if (subreq == NULL) {
273 0 : wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_call_loop: "
274 : "no memory for tstream_read_pdu_blob_send");
275 0 : return;
276 : }
277 1464 : tevent_req_set_callback(subreq, wreplsrv_call_loop, wrepl_conn);
278 : }
279 :
280 1464 : static void wreplsrv_call_writev_done(struct tevent_req *subreq)
281 : {
282 1464 : struct wreplsrv_in_call *call = tevent_req_callback_data(subreq,
283 : struct wreplsrv_in_call);
284 : int sys_errno;
285 : int rc;
286 :
287 1464 : rc = tstream_writev_queue_recv(subreq, &sys_errno);
288 1464 : TALLOC_FREE(subreq);
289 1464 : if (rc == -1) {
290 : const char *reason;
291 :
292 0 : reason = talloc_asprintf(call, "wreplsrv_call_writev_done: "
293 : "tstream_writev_queue_recv() - %d:%s",
294 : sys_errno, strerror(sys_errno));
295 0 : if (reason == NULL) {
296 0 : reason = "wreplsrv_call_writev_done: "
297 : "tstream_writev_queue_recv() failed";
298 : }
299 :
300 0 : wreplsrv_terminate_in_connection(call->wreplconn, reason);
301 0 : return;
302 : }
303 :
304 1464 : if (call->terminate_after_send) {
305 0 : wreplsrv_terminate_in_connection(call->wreplconn,
306 : "wreplsrv_in_connection: terminate_after_send");
307 0 : return;
308 : }
309 :
310 1464 : talloc_free(call);
311 : }
312 :
313 : /*
314 : called on a tcp recv
315 : */
316 0 : static void wreplsrv_recv(struct stream_connection *conn, uint16_t flags)
317 : {
318 0 : struct wreplsrv_in_connection *wrepl_conn = talloc_get_type(conn->private_data,
319 : struct wreplsrv_in_connection);
320 : /* this should never be triggered! */
321 0 : DEBUG(0,("Terminating connection - '%s'\n", "wrepl_recv: called"));
322 0 : wreplsrv_terminate_in_connection(wrepl_conn, "wrepl_recv: called");
323 0 : }
324 :
325 : /*
326 : called when we can write to a connection
327 : */
328 0 : static void wreplsrv_send(struct stream_connection *conn, uint16_t flags)
329 : {
330 0 : struct wreplsrv_in_connection *wrepl_conn = talloc_get_type(conn->private_data,
331 : struct wreplsrv_in_connection);
332 : /* this should never be triggered! */
333 0 : DEBUG(0,("Terminating connection - '%s'\n", "wrepl_send: called"));
334 0 : wreplsrv_terminate_in_connection(wrepl_conn, "wrepl_send: called");
335 0 : }
336 :
337 : static const struct stream_server_ops wreplsrv_stream_ops = {
338 : .name = "wreplsrv",
339 : .accept_connection = wreplsrv_accept,
340 : .recv_handler = wreplsrv_recv,
341 : .send_handler = wreplsrv_send,
342 : };
343 :
344 : /*
345 : called when we get a new connection
346 : */
347 0 : NTSTATUS wreplsrv_in_connection_merge(struct wreplsrv_partner *partner,
348 : uint32_t peer_assoc_ctx,
349 : struct tstream_context **stream,
350 : struct wreplsrv_in_connection **_wrepl_in,
351 : void* process_context)
352 : {
353 0 : struct wreplsrv_service *service = partner->service;
354 : struct wreplsrv_in_connection *wrepl_in;
355 : struct stream_connection *conn;
356 : struct tevent_req *subreq;
357 : NTSTATUS status;
358 :
359 0 : wrepl_in = talloc_zero(partner, struct wreplsrv_in_connection);
360 0 : NT_STATUS_HAVE_NO_MEMORY(wrepl_in);
361 :
362 0 : wrepl_in->service = service;
363 0 : wrepl_in->partner = partner;
364 0 : wrepl_in->tstream = talloc_move(wrepl_in, stream);
365 0 : wrepl_in->assoc_ctx.peer_ctx = peer_assoc_ctx;
366 :
367 0 : status = stream_new_connection_merge(service->task->event_ctx,
368 0 : service->task->lp_ctx,
369 0 : service->task->model_ops,
370 : &wreplsrv_stream_ops,
371 0 : service->task->msg_ctx,
372 : wrepl_in,
373 : &conn,
374 : process_context);
375 0 : NT_STATUS_NOT_OK_RETURN(status);
376 :
377 : /*
378 : * make the wreplsrv_in_connection structure a child of the
379 : * stream_connection, to match the hierarchy of wreplsrv_accept
380 : */
381 0 : wrepl_in->conn = conn;
382 0 : talloc_steal(conn, wrepl_in);
383 :
384 0 : wrepl_in->send_queue = tevent_queue_create(wrepl_in, "wreplsrv_in_connection_merge");
385 0 : if (wrepl_in->send_queue == NULL) {
386 0 : stream_terminate_connection(conn,
387 : "wreplsrv_in_connection_merge: out of memory");
388 0 : return NT_STATUS_NO_MEMORY;
389 : }
390 :
391 : /*
392 : * The wrepl pdu's has the length as 4 byte (initial_read_size),
393 : * packet_full_request_u32 provides the pdu length then.
394 : */
395 0 : subreq = tstream_read_pdu_blob_send(wrepl_in,
396 0 : wrepl_in->conn->event.ctx,
397 : wrepl_in->tstream,
398 : 4, /* initial_read_size */
399 : packet_full_request_u32,
400 : wrepl_in);
401 0 : if (subreq == NULL) {
402 0 : wreplsrv_terminate_in_connection(wrepl_in, "wreplsrv_in_connection_merge: "
403 : "no memory for tstream_read_pdu_blob_send");
404 0 : return NT_STATUS_NO_MEMORY;
405 : }
406 0 : tevent_req_set_callback(subreq, wreplsrv_call_loop, wrepl_in);
407 :
408 0 : *_wrepl_in = wrepl_in;
409 :
410 0 : return NT_STATUS_OK;
411 : }
412 :
413 : /*
414 : startup the wrepl port 42 server sockets
415 : */
416 53 : NTSTATUS wreplsrv_setup_sockets(struct wreplsrv_service *service, struct loadparm_context *lp_ctx)
417 : {
418 : NTSTATUS status;
419 53 : struct task_server *task = service->task;
420 : const char *address;
421 53 : uint16_t port = WINS_REPLICATION_PORT;
422 :
423 53 : if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
424 : int num_interfaces;
425 : int i;
426 : struct interface *ifaces;
427 :
428 0 : load_interface_list(task, lp_ctx, &ifaces);
429 :
430 0 : num_interfaces = iface_list_count(ifaces);
431 :
432 : /* We have been given an interfaces line, and been
433 : told to only bind to those interfaces. Create a
434 : socket per interface and bind to only these.
435 : */
436 0 : for(i = 0; i < num_interfaces; i++) {
437 0 : if (!iface_list_n_is_v4(ifaces, i)) {
438 0 : continue;
439 : }
440 0 : address = iface_list_n_ip(ifaces, i);
441 0 : status = stream_setup_socket(
442 : task, task->event_ctx,
443 : task->lp_ctx,
444 : task->model_ops,
445 : &wreplsrv_stream_ops,
446 : "ipv4", address, &port,
447 : lpcfg_socket_options(task->lp_ctx),
448 : service, task->process_context);
449 0 : if (!NT_STATUS_IS_OK(status)) {
450 0 : DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
451 : address, port, nt_errstr(status)));
452 0 : return status;
453 : }
454 : }
455 : } else {
456 53 : address = "0.0.0.0";
457 53 : status = stream_setup_socket(task, task->event_ctx,
458 : task->lp_ctx, task->model_ops,
459 : &wreplsrv_stream_ops,
460 : "ipv4", address, &port,
461 : lpcfg_socket_options(task->lp_ctx),
462 : service, task->process_context);
463 53 : if (!NT_STATUS_IS_OK(status)) {
464 0 : DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
465 : address, port, nt_errstr(status)));
466 0 : return status;
467 : }
468 : }
469 :
470 53 : return NT_STATUS_OK;
471 : }
|