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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "lib/socket/socket.h"
24 #include "lib/stream/packet.h"
25 #include "smbd/service_task.h"
26 #include "smbd/service_stream.h"
27 #include "smbd/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 "smbd/process_model.h"
32 #include "system/network.h"
33 #include "lib/socket/netif.h"
34 #include "param/param.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
, DATA_BLOB blob
)
52 struct wreplsrv_in_connection
*wreplconn
= talloc_get_type(private_data
, 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
;
58 enum ndr_err_code ndr_err
;
60 call
= talloc_zero(wreplconn
, struct wreplsrv_in_call
);
61 NT_STATUS_HAVE_NO_MEMORY(call
);
62 call
->wreplconn
= wreplconn
;
63 talloc_steal(call
, blob
.data
);
65 packet_in_blob
.data
= blob
.data
+ 4;
66 packet_in_blob
.length
= blob
.length
- 4;
68 ndr_err
= ndr_pull_struct_blob(&packet_in_blob
, call
,
69 lp_iconv_convenience(wreplconn
->service
->task
->lp_ctx
),
71 (ndr_pull_flags_fn_t
)ndr_pull_wrepl_packet
);
72 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
73 return ndr_map_error2ntstatus(ndr_err
);
77 DEBUG(10,("Received WINS-Replication packet of length %u\n",
78 (unsigned)packet_in_blob
.length
+ 4));
79 NDR_PRINT_DEBUG(wrepl_packet
, &call
->req_packet
);
82 status
= wreplsrv_in_call(call
);
83 NT_STATUS_IS_ERR_RETURN(status
);
84 if (!NT_STATUS_IS_OK(status
)) {
85 /* w2k just ignores invalid packets, so we do */
86 DEBUG(10,("Received WINS-Replication packet was invalid, we just ignore it\n"));
91 /* and now encode the reply */
92 packet_out_wrap
.packet
= call
->rep_packet
;
93 ndr_err
= ndr_push_struct_blob(&packet_out_blob
, call
,
94 lp_iconv_convenience(wreplconn
->service
->task
->lp_ctx
),
96 (ndr_push_flags_fn_t
)ndr_push_wrepl_wrap
);
97 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
98 return ndr_map_error2ntstatus(ndr_err
);
102 DEBUG(10,("Sending WINS-Replication packet of length %d\n", (int)packet_out_blob
.length
));
103 NDR_PRINT_DEBUG(wrepl_packet
, &call
->rep_packet
);
106 if (call
->terminate_after_send
) {
107 struct wreplsrv_in_connection
**tas
;
108 tas
= talloc(packet_out_blob
.data
, struct wreplsrv_in_connection
*);
109 NT_STATUS_HAVE_NO_MEMORY(tas
);
111 talloc_set_destructor(tas
, terminate_after_send_destructor
);
114 status
= packet_send(wreplconn
->packet
, packet_out_blob
);
115 NT_STATUS_NOT_OK_RETURN(status
);
122 called when the socket becomes readable
124 static void wreplsrv_recv(struct stream_connection
*conn
, uint16_t flags
)
126 struct wreplsrv_in_connection
*wreplconn
= talloc_get_type(conn
->private_data
,
127 struct wreplsrv_in_connection
);
129 packet_recv(wreplconn
->packet
);
133 called when the socket becomes writable
135 static void wreplsrv_send(struct stream_connection
*conn
, uint16_t flags
)
137 struct wreplsrv_in_connection
*wreplconn
= talloc_get_type(conn
->private_data
,
138 struct wreplsrv_in_connection
);
139 packet_queue_run(wreplconn
->packet
);
143 handle socket recv errors
145 static void wreplsrv_recv_error(void *private_data
, NTSTATUS status
)
147 struct wreplsrv_in_connection
*wreplconn
= talloc_get_type(private_data
,
148 struct wreplsrv_in_connection
);
149 wreplsrv_terminate_in_connection(wreplconn
, nt_errstr(status
));
153 called when we get a new connection
155 static void wreplsrv_accept(struct stream_connection
*conn
)
157 struct wreplsrv_service
*service
= talloc_get_type(conn
->private_data
, struct wreplsrv_service
);
158 struct wreplsrv_in_connection
*wreplconn
;
159 struct socket_address
*peer_ip
;
161 wreplconn
= talloc_zero(conn
, struct wreplsrv_in_connection
);
163 stream_terminate_connection(conn
, "wreplsrv_accept: out of memory");
167 wreplconn
->packet
= packet_init(wreplconn
);
168 if (!wreplconn
->packet
) {
169 wreplsrv_terminate_in_connection(wreplconn
, "wreplsrv_accept: out of memory");
172 packet_set_private(wreplconn
->packet
, wreplconn
);
173 packet_set_socket(wreplconn
->packet
, conn
->socket
);
174 packet_set_callback(wreplconn
->packet
, wreplsrv_recv_request
);
175 packet_set_full_request(wreplconn
->packet
, packet_full_request_u32
);
176 packet_set_error_handler(wreplconn
->packet
, wreplsrv_recv_error
);
177 packet_set_event_context(wreplconn
->packet
, conn
->event
.ctx
);
178 packet_set_fde(wreplconn
->packet
, conn
->event
.fde
);
179 packet_set_serialise(wreplconn
->packet
);
181 wreplconn
->conn
= conn
;
182 wreplconn
->service
= service
;
184 peer_ip
= socket_get_peer_addr(conn
->socket
, wreplconn
);
186 wreplsrv_terminate_in_connection(wreplconn
, "wreplsrv_accept: could not obtain peer IP from kernel");
190 wreplconn
->partner
= wreplsrv_find_partner(service
, peer_ip
->addr
);
192 conn
->private_data
= wreplconn
;
194 irpc_add_name(conn
->msg_ctx
, "wreplsrv_connection");
197 static const struct stream_server_ops wreplsrv_stream_ops
= {
199 .accept_connection
= wreplsrv_accept
,
200 .recv_handler
= wreplsrv_recv
,
201 .send_handler
= wreplsrv_send
,
205 called when we get a new connection
207 NTSTATUS
wreplsrv_in_connection_merge(struct wreplsrv_partner
*partner
,
208 struct socket_context
*sock
,
209 struct packet_context
*packet
,
210 struct wreplsrv_in_connection
**_wrepl_in
)
212 struct wreplsrv_service
*service
= partner
->service
;
213 struct wreplsrv_in_connection
*wrepl_in
;
214 const struct model_ops
*model_ops
;
215 struct stream_connection
*conn
;
218 /* within the wrepl task we want to be a single process, so
219 ask for the single process model ops and pass these to the
220 stream_setup_socket() call. */
221 model_ops
= process_model_startup(service
->task
->event_ctx
, "single");
223 DEBUG(0,("Can't find 'single' process model_ops"));
224 return NT_STATUS_INTERNAL_ERROR
;
227 wrepl_in
= talloc_zero(partner
, struct wreplsrv_in_connection
);
228 NT_STATUS_HAVE_NO_MEMORY(wrepl_in
);
230 wrepl_in
->service
= service
;
231 wrepl_in
->partner
= partner
;
233 status
= stream_new_connection_merge(service
->task
->event_ctx
, service
->task
->lp_ctx
, model_ops
,
234 sock
, &wreplsrv_stream_ops
, service
->task
->msg_ctx
,
236 NT_STATUS_NOT_OK_RETURN(status
);
239 * make the wreplsrv_in_connection structure a child of the
240 * stream_connection, to match the hierarchy of wreplsrv_accept
242 wrepl_in
->conn
= conn
;
243 talloc_steal(conn
, wrepl_in
);
246 * now update the packet handling callback,...
248 wrepl_in
->packet
= talloc_steal(wrepl_in
, packet
);
249 packet_set_private(wrepl_in
->packet
, wrepl_in
);
250 packet_set_socket(wrepl_in
->packet
, conn
->socket
);
251 packet_set_callback(wrepl_in
->packet
, wreplsrv_recv_request
);
252 packet_set_full_request(wrepl_in
->packet
, packet_full_request_u32
);
253 packet_set_error_handler(wrepl_in
->packet
, wreplsrv_recv_error
);
254 packet_set_event_context(wrepl_in
->packet
, conn
->event
.ctx
);
255 packet_set_fde(wrepl_in
->packet
, conn
->event
.fde
);
256 packet_set_serialise(wrepl_in
->packet
);
258 *_wrepl_in
= wrepl_in
;
263 startup the wrepl port 42 server sockets
265 NTSTATUS
wreplsrv_setup_sockets(struct wreplsrv_service
*service
, struct loadparm_context
*lp_ctx
)
268 struct task_server
*task
= service
->task
;
269 const struct model_ops
*model_ops
;
271 uint16_t port
= WINS_REPLICATION_PORT
;
273 /* within the wrepl task we want to be a single process, so
274 ask for the single process model ops and pass these to the
275 stream_setup_socket() call. */
276 model_ops
= process_model_startup(task
->event_ctx
, "single");
278 DEBUG(0,("Can't find 'single' process model_ops"));
279 return NT_STATUS_INTERNAL_ERROR
;
282 if (lp_interfaces(lp_ctx
) && lp_bind_interfaces_only(lp_ctx
)) {
285 struct interface
*ifaces
;
287 load_interfaces(task
, lp_interfaces(lp_ctx
), &ifaces
);
289 num_interfaces
= iface_count(ifaces
);
291 /* We have been given an interfaces line, and been
292 told to only bind to those interfaces. Create a
293 socket per interface and bind to only these.
295 for(i
= 0; i
< num_interfaces
; i
++) {
296 address
= iface_n_ip(ifaces
, i
);
297 status
= stream_setup_socket(task
->event_ctx
,
298 task
->lp_ctx
, model_ops
,
299 &wreplsrv_stream_ops
,
300 "ipv4", address
, &port
,
301 lp_socket_options(task
->lp_ctx
),
303 if (!NT_STATUS_IS_OK(status
)) {
304 DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
305 address
, port
, nt_errstr(status
)));
310 address
= lp_socket_address(lp_ctx
);
311 status
= stream_setup_socket(task
->event_ctx
, task
->lp_ctx
,
312 model_ops
, &wreplsrv_stream_ops
,
313 "ipv4", address
, &port
, lp_socket_options(task
->lp_ctx
),
315 if (!NT_STATUS_IS_OK(status
)) {
316 DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
317 address
, port
, nt_errstr(status
)));