• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/wrepl_server/
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 "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"
35
36void wreplsrv_terminate_in_connection(struct wreplsrv_in_connection *wreplconn, const char *reason)
37{
38	stream_terminate_connection(wreplconn->conn, reason);
39}
40
41static int terminate_after_send_destructor(struct wreplsrv_in_connection **tas)
42{
43	wreplsrv_terminate_in_connection(*tas, "wreplsrv_in_connection: terminate_after_send");
44	return 0;
45}
46
47/*
48  receive some data on a WREPL connection
49*/
50static NTSTATUS wreplsrv_recv_request(void *private_data, DATA_BLOB blob)
51{
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;
57	NTSTATUS status;
58	enum ndr_err_code ndr_err;
59
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);
64
65	packet_in_blob.data = blob.data + 4;
66	packet_in_blob.length = blob.length - 4;
67
68	ndr_err = ndr_pull_struct_blob(&packet_in_blob, call,
69				       lp_iconv_convenience(wreplconn->service->task->lp_ctx),
70				       &call->req_packet,
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);
74	}
75
76	if (DEBUGLVL(10)) {
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);
80	}
81
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"));
87		talloc_free(call);
88		return NT_STATUS_OK;
89	}
90
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),
95				       &packet_out_wrap,
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);
99	}
100
101	if (DEBUGLVL(10)) {
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);
104	}
105
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);
110		*tas = wreplconn;
111		talloc_set_destructor(tas, terminate_after_send_destructor);
112	}
113
114	status = packet_send(wreplconn->packet, packet_out_blob);
115	NT_STATUS_NOT_OK_RETURN(status);
116
117	talloc_free(call);
118	return NT_STATUS_OK;
119}
120
121/*
122  called when the socket becomes readable
123*/
124static void wreplsrv_recv(struct stream_connection *conn, uint16_t flags)
125{
126	struct wreplsrv_in_connection *wreplconn = talloc_get_type(conn->private_data,
127								   struct wreplsrv_in_connection);
128
129	packet_recv(wreplconn->packet);
130}
131
132/*
133  called when the socket becomes writable
134*/
135static void wreplsrv_send(struct stream_connection *conn, uint16_t flags)
136{
137	struct wreplsrv_in_connection *wreplconn = talloc_get_type(conn->private_data,
138								   struct wreplsrv_in_connection);
139	packet_queue_run(wreplconn->packet);
140}
141
142/*
143  handle socket recv errors
144*/
145static void wreplsrv_recv_error(void *private_data, NTSTATUS status)
146{
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));
150}
151
152/*
153  called when we get a new connection
154*/
155static void wreplsrv_accept(struct stream_connection *conn)
156{
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;
160
161	wreplconn = talloc_zero(conn, struct wreplsrv_in_connection);
162	if (!wreplconn) {
163		stream_terminate_connection(conn, "wreplsrv_accept: out of memory");
164		return;
165	}
166
167	wreplconn->packet = packet_init(wreplconn);
168	if (!wreplconn->packet) {
169		wreplsrv_terminate_in_connection(wreplconn, "wreplsrv_accept: out of memory");
170		return;
171	}
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);
180
181	wreplconn->conn		= conn;
182	wreplconn->service	= service;
183
184	peer_ip	= socket_get_peer_addr(conn->socket, wreplconn);
185	if (!peer_ip) {
186		wreplsrv_terminate_in_connection(wreplconn, "wreplsrv_accept: could not obtain peer IP from kernel");
187		return;
188	}
189
190	wreplconn->partner	= wreplsrv_find_partner(service, peer_ip->addr);
191
192	conn->private_data = wreplconn;
193
194	irpc_add_name(conn->msg_ctx, "wreplsrv_connection");
195}
196
197static const struct stream_server_ops wreplsrv_stream_ops = {
198	.name			= "wreplsrv",
199	.accept_connection	= wreplsrv_accept,
200	.recv_handler		= wreplsrv_recv,
201	.send_handler		= wreplsrv_send,
202};
203
204/*
205  called when we get a new connection
206*/
207NTSTATUS 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)
211{
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;
216	NTSTATUS status;
217
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");
222	if (!model_ops) {
223		DEBUG(0,("Can't find 'single' process model_ops"));
224		return NT_STATUS_INTERNAL_ERROR;
225	}
226
227	wrepl_in = talloc_zero(partner, struct wreplsrv_in_connection);
228	NT_STATUS_HAVE_NO_MEMORY(wrepl_in);
229
230	wrepl_in->service	= service;
231	wrepl_in->partner	= partner;
232
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,
235					     wrepl_in, &conn);
236	NT_STATUS_NOT_OK_RETURN(status);
237
238	/*
239	 * make the wreplsrv_in_connection structure a child of the
240	 * stream_connection, to match the hierarchy of wreplsrv_accept
241	 */
242	wrepl_in->conn		= conn;
243	talloc_steal(conn, wrepl_in);
244
245	/*
246	 * now update the packet handling callback,...
247	 */
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);
257
258	*_wrepl_in = wrepl_in;
259	return NT_STATUS_OK;
260}
261
262/*
263  startup the wrepl port 42 server sockets
264*/
265NTSTATUS wreplsrv_setup_sockets(struct wreplsrv_service *service, struct loadparm_context *lp_ctx)
266{
267	NTSTATUS status;
268	struct task_server *task = service->task;
269	const struct model_ops *model_ops;
270	const char *address;
271	uint16_t port = WINS_REPLICATION_PORT;
272
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");
277	if (!model_ops) {
278		DEBUG(0,("Can't find 'single' process model_ops"));
279		return NT_STATUS_INTERNAL_ERROR;
280	}
281
282	if (lp_interfaces(lp_ctx) && lp_bind_interfaces_only(lp_ctx)) {
283		int num_interfaces;
284		int i;
285		struct interface *ifaces;
286
287		load_interfaces(task, lp_interfaces(lp_ctx), &ifaces);
288
289		num_interfaces = iface_count(ifaces);
290
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.
294		*/
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),
302						     service);
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)));
306				return status;
307			}
308		}
309	} else {
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),
314					     service);
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)));
318			return status;
319		}
320	}
321
322	return NT_STATUS_OK;
323}
324