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 "lib/socket/socket.h"
25 #include "lib/stream/packet.h"
26 #include "smbd/service_task.h"
27 #include "smbd/service_stream.h"
28 #include "smbd/service.h"
29 #include "lib/messaging/irpc.h"
30 #include "librpc/gen_ndr/ndr_winsrepl.h"
31 #include "wrepl_server/wrepl_server.h"
32 #include "smbd/process_model.h"
33 #include "system/network.h"
34 #include "lib/socket/netif.h"
36 void wreplsrv_terminate_in_connection(struct wreplsrv_in_connection
*wreplconn
, const char *reason
)
38 stream_terminate_connection(wreplconn
->conn
, reason
);
41 static int terminate_after_send_destructor(struct wreplsrv_in_connection
**tas
)
43 wreplsrv_terminate_in_connection(*tas
, "wreplsrv_in_connection: terminate_after_send");
48 receive some data on a WREPL connection
50 static NTSTATUS
wreplsrv_recv_request(void *private, DATA_BLOB blob
)
52 struct wreplsrv_in_connection
*wreplconn
= talloc_get_type(private, struct wreplsrv_in_connection
);
53 struct wreplsrv_in_call
*call
;
54 DATA_BLOB packet_in_blob
;
55 DATA_BLOB packet_out_blob
;
56 struct wrepl_wrap packet_out_wrap
;
59 call
= talloc_zero(wreplconn
, struct wreplsrv_in_call
);
60 NT_STATUS_HAVE_NO_MEMORY(call
);
61 call
->wreplconn
= wreplconn
;
62 talloc_steal(call
, blob
.data
);
64 packet_in_blob
.data
= blob
.data
+ 4;
65 packet_in_blob
.length
= blob
.length
- 4;
67 status
= ndr_pull_struct_blob(&packet_in_blob
, call
, &call
->req_packet
,
68 (ndr_pull_flags_fn_t
)ndr_pull_wrepl_packet
);
69 NT_STATUS_NOT_OK_RETURN(status
);
72 DEBUG(10,("Received WINS-Replication packet of length %u\n", packet_in_blob
.length
+ 4));
73 NDR_PRINT_DEBUG(wrepl_packet
, &call
->req_packet
);
76 status
= wreplsrv_in_call(call
);
77 NT_STATUS_IS_ERR_RETURN(status
);
78 if (!NT_STATUS_IS_OK(status
)) {
79 /* w2k just ignores invalid packets, so we do */
80 DEBUG(10,("Received WINS-Replication packet was invalid, we just ignore it\n"));
85 /* and now encode the reply */
86 packet_out_wrap
.packet
= call
->rep_packet
;
87 status
= ndr_push_struct_blob(&packet_out_blob
, call
, &packet_out_wrap
,
88 (ndr_push_flags_fn_t
)ndr_push_wrepl_wrap
);
89 NT_STATUS_NOT_OK_RETURN(status
);
92 DEBUG(10,("Sending WINS-Replication packet of length %d\n", (int)packet_out_blob
.length
));
93 NDR_PRINT_DEBUG(wrepl_packet
, &call
->rep_packet
);
96 if (call
->terminate_after_send
) {
97 struct wreplsrv_in_connection
**tas
;
98 tas
= talloc(packet_out_blob
.data
, struct wreplsrv_in_connection
*);
99 NT_STATUS_HAVE_NO_MEMORY(tas
);
101 talloc_set_destructor(tas
, terminate_after_send_destructor
);
104 status
= packet_send(wreplconn
->packet
, packet_out_blob
);
105 NT_STATUS_NOT_OK_RETURN(status
);
112 called when the socket becomes readable
114 static void wreplsrv_recv(struct stream_connection
*conn
, uint16_t flags
)
116 struct wreplsrv_in_connection
*wreplconn
= talloc_get_type(conn
->private,
117 struct wreplsrv_in_connection
);
119 packet_recv(wreplconn
->packet
);
123 called when the socket becomes writable
125 static void wreplsrv_send(struct stream_connection
*conn
, uint16_t flags
)
127 struct wreplsrv_in_connection
*wreplconn
= talloc_get_type(conn
->private,
128 struct wreplsrv_in_connection
);
129 packet_queue_run(wreplconn
->packet
);
133 handle socket recv errors
135 static void wreplsrv_recv_error(void *private, NTSTATUS status
)
137 struct wreplsrv_in_connection
*wreplconn
= talloc_get_type(private,
138 struct wreplsrv_in_connection
);
139 wreplsrv_terminate_in_connection(wreplconn
, nt_errstr(status
));
143 called when we get a new connection
145 static void wreplsrv_accept(struct stream_connection
*conn
)
147 struct wreplsrv_service
*service
= talloc_get_type(conn
->private, struct wreplsrv_service
);
148 struct wreplsrv_in_connection
*wreplconn
;
149 struct socket_address
*peer_ip
;
151 wreplconn
= talloc_zero(conn
, struct wreplsrv_in_connection
);
153 stream_terminate_connection(conn
, "wreplsrv_accept: out of memory");
157 wreplconn
->packet
= packet_init(wreplconn
);
158 if (!wreplconn
->packet
) {
159 wreplsrv_terminate_in_connection(wreplconn
, "wreplsrv_accept: out of memory");
162 packet_set_private(wreplconn
->packet
, wreplconn
);
163 packet_set_socket(wreplconn
->packet
, conn
->socket
);
164 packet_set_callback(wreplconn
->packet
, wreplsrv_recv_request
);
165 packet_set_full_request(wreplconn
->packet
, packet_full_request_u32
);
166 packet_set_error_handler(wreplconn
->packet
, wreplsrv_recv_error
);
167 packet_set_event_context(wreplconn
->packet
, conn
->event
.ctx
);
168 packet_set_fde(wreplconn
->packet
, conn
->event
.fde
);
169 packet_set_serialise(wreplconn
->packet
);
171 wreplconn
->conn
= conn
;
172 wreplconn
->service
= service
;
174 peer_ip
= socket_get_peer_addr(conn
->socket
, wreplconn
);
176 wreplsrv_terminate_in_connection(wreplconn
, "wreplsrv_accept: could not obtain peer IP from kernel");
180 wreplconn
->partner
= wreplsrv_find_partner(service
, peer_ip
->addr
);
182 conn
->private = wreplconn
;
184 irpc_add_name(conn
->msg_ctx
, "wreplsrv_connection");
187 static const struct stream_server_ops wreplsrv_stream_ops
= {
189 .accept_connection
= wreplsrv_accept
,
190 .recv_handler
= wreplsrv_recv
,
191 .send_handler
= wreplsrv_send
,
195 called when we get a new connection
197 NTSTATUS
wreplsrv_in_connection_merge(struct wreplsrv_partner
*partner
,
198 struct socket_context
*sock
,
199 struct packet_context
*packet
,
200 struct wreplsrv_in_connection
**_wrepl_in
)
202 struct wreplsrv_service
*service
= partner
->service
;
203 struct wreplsrv_in_connection
*wrepl_in
;
204 const struct model_ops
*model_ops
;
205 struct stream_connection
*conn
;
208 /* within the wrepl task we want to be a single process, so
209 ask for the single process model ops and pass these to the
210 stream_setup_socket() call. */
211 model_ops
= process_model_byname("single");
213 DEBUG(0,("Can't find 'single' process model_ops"));
214 return NT_STATUS_INTERNAL_ERROR
;
217 wrepl_in
= talloc_zero(partner
, struct wreplsrv_in_connection
);
218 NT_STATUS_HAVE_NO_MEMORY(wrepl_in
);
220 wrepl_in
->service
= service
;
221 wrepl_in
->partner
= partner
;
223 status
= stream_new_connection_merge(service
->task
->event_ctx
, model_ops
,
224 sock
, &wreplsrv_stream_ops
, service
->task
->msg_ctx
,
226 NT_STATUS_NOT_OK_RETURN(status
);
229 * make the wreplsrv_in_connection structure a child of the
230 * stream_connection, to match the hierachie of wreplsrv_accept
232 wrepl_in
->conn
= conn
;
233 talloc_steal(conn
, wrepl_in
);
236 * now update the packet handling callback,...
238 wrepl_in
->packet
= talloc_steal(wrepl_in
, packet
);
239 packet_set_private(wrepl_in
->packet
, wrepl_in
);
240 packet_set_socket(wrepl_in
->packet
, conn
->socket
);
241 packet_set_callback(wrepl_in
->packet
, wreplsrv_recv_request
);
242 packet_set_full_request(wrepl_in
->packet
, packet_full_request_u32
);
243 packet_set_error_handler(wrepl_in
->packet
, wreplsrv_recv_error
);
244 packet_set_event_context(wrepl_in
->packet
, conn
->event
.ctx
);
245 packet_set_fde(wrepl_in
->packet
, conn
->event
.fde
);
246 packet_set_serialise(wrepl_in
->packet
);
248 *_wrepl_in
= wrepl_in
;
253 startup the wrepl port 42 server sockets
255 NTSTATUS
wreplsrv_setup_sockets(struct wreplsrv_service
*service
)
258 struct task_server
*task
= service
->task
;
259 const struct model_ops
*model_ops
;
261 uint16_t port
= WINS_REPLICATION_PORT
;
263 /* within the wrepl task we want to be a single process, so
264 ask for the single process model ops and pass these to the
265 stream_setup_socket() call. */
266 model_ops
= process_model_byname("single");
268 DEBUG(0,("Can't find 'single' process model_ops"));
269 return NT_STATUS_INTERNAL_ERROR
;
272 if (lp_interfaces() && lp_bind_interfaces_only()) {
273 int num_interfaces
= iface_count();
276 /* We have been given an interfaces line, and been
277 told to only bind to those interfaces. Create a
278 socket per interface and bind to only these.
280 for(i
= 0; i
< num_interfaces
; i
++) {
281 address
= iface_n_ip(i
);
282 status
= stream_setup_socket(task
->event_ctx
, model_ops
, &wreplsrv_stream_ops
,
283 "ipv4", address
, &port
, service
);
284 if (!NT_STATUS_IS_OK(status
)) {
285 DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
286 address
, port
, nt_errstr(status
)));
291 address
= lp_socket_address();
292 status
= stream_setup_socket(task
->event_ctx
, model_ops
, &wreplsrv_stream_ops
,
293 "ipv4", address
, &port
, service
);
294 if (!NT_STATUS_IS_OK(status
)) {
295 DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
296 address
, port
, nt_errstr(status
)));