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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 
23 #include "includes.h"
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"
35 
wreplsrv_terminate_in_connection(struct wreplsrv_in_connection * wreplconn,const char * reason)36 void wreplsrv_terminate_in_connection(struct wreplsrv_in_connection *wreplconn, const char *reason)
37 {
38 	stream_terminate_connection(wreplconn->conn, reason);
39 }
40 
terminate_after_send_destructor(struct wreplsrv_in_connection ** tas)41 static 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 */
wreplsrv_recv_request(void * private,DATA_BLOB blob)50 static NTSTATUS wreplsrv_recv_request(void *private, DATA_BLOB blob)
51 {
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;
57 	NTSTATUS status;
58 
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);
63 
64 	packet_in_blob.data = blob.data + 4;
65 	packet_in_blob.length = blob.length - 4;
66 
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);
70 
71 	if (DEBUGLVL(10)) {
72 		DEBUG(10,("Received WINS-Replication packet of length %u\n",
73 			  (unsigned)packet_in_blob.length + 4));
74 		NDR_PRINT_DEBUG(wrepl_packet, &call->req_packet);
75 	}
76 
77 	status = wreplsrv_in_call(call);
78 	NT_STATUS_IS_ERR_RETURN(status);
79 	if (!NT_STATUS_IS_OK(status)) {
80 		/* w2k just ignores invalid packets, so we do */
81 		DEBUG(10,("Received WINS-Replication packet was invalid, we just ignore it\n"));
82 		talloc_free(call);
83 		return NT_STATUS_OK;
84 	}
85 
86 	/* and now encode the reply */
87 	packet_out_wrap.packet = call->rep_packet;
88 	status = ndr_push_struct_blob(&packet_out_blob, call, &packet_out_wrap,
89 				      (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
90 	NT_STATUS_NOT_OK_RETURN(status);
91 
92 	if (DEBUGLVL(10)) {
93 		DEBUG(10,("Sending WINS-Replication packet of length %d\n", (int)packet_out_blob.length));
94 		NDR_PRINT_DEBUG(wrepl_packet, &call->rep_packet);
95 	}
96 
97 	if (call->terminate_after_send) {
98 		struct wreplsrv_in_connection **tas;
99 		tas = talloc(packet_out_blob.data, struct wreplsrv_in_connection *);
100 		NT_STATUS_HAVE_NO_MEMORY(tas);
101 		*tas = wreplconn;
102 		talloc_set_destructor(tas, terminate_after_send_destructor);
103 	}
104 
105 	status = packet_send(wreplconn->packet, packet_out_blob);
106 	NT_STATUS_NOT_OK_RETURN(status);
107 
108 	talloc_free(call);
109 	return NT_STATUS_OK;
110 }
111 
112 /*
113   called when the socket becomes readable
114 */
wreplsrv_recv(struct stream_connection * conn,uint16_t flags)115 static void wreplsrv_recv(struct stream_connection *conn, uint16_t flags)
116 {
117 	struct wreplsrv_in_connection *wreplconn = talloc_get_type(conn->private,
118 								   struct wreplsrv_in_connection);
119 
120 	packet_recv(wreplconn->packet);
121 }
122 
123 /*
124   called when the socket becomes writable
125 */
wreplsrv_send(struct stream_connection * conn,uint16_t flags)126 static void wreplsrv_send(struct stream_connection *conn, uint16_t flags)
127 {
128 	struct wreplsrv_in_connection *wreplconn = talloc_get_type(conn->private,
129 								   struct wreplsrv_in_connection);
130 	packet_queue_run(wreplconn->packet);
131 }
132 
133 /*
134   handle socket recv errors
135 */
wreplsrv_recv_error(void * private,NTSTATUS status)136 static void wreplsrv_recv_error(void *private, NTSTATUS status)
137 {
138 	struct wreplsrv_in_connection *wreplconn = talloc_get_type(private,
139 								   struct wreplsrv_in_connection);
140 	wreplsrv_terminate_in_connection(wreplconn, nt_errstr(status));
141 }
142 
143 /*
144   called when we get a new connection
145 */
wreplsrv_accept(struct stream_connection * conn)146 static void wreplsrv_accept(struct stream_connection *conn)
147 {
148 	struct wreplsrv_service *service = talloc_get_type(conn->private, struct wreplsrv_service);
149 	struct wreplsrv_in_connection *wreplconn;
150 	struct socket_address *peer_ip;
151 
152 	wreplconn = talloc_zero(conn, struct wreplsrv_in_connection);
153 	if (!wreplconn) {
154 		stream_terminate_connection(conn, "wreplsrv_accept: out of memory");
155 		return;
156 	}
157 
158 	wreplconn->packet = packet_init(wreplconn);
159 	if (!wreplconn->packet) {
160 		wreplsrv_terminate_in_connection(wreplconn, "wreplsrv_accept: out of memory");
161 		return;
162 	}
163 	packet_set_private(wreplconn->packet, wreplconn);
164 	packet_set_socket(wreplconn->packet, conn->socket);
165 	packet_set_callback(wreplconn->packet, wreplsrv_recv_request);
166 	packet_set_full_request(wreplconn->packet, packet_full_request_u32);
167 	packet_set_error_handler(wreplconn->packet, wreplsrv_recv_error);
168 	packet_set_event_context(wreplconn->packet, conn->event.ctx);
169 	packet_set_fde(wreplconn->packet, conn->event.fde);
170 	packet_set_serialise(wreplconn->packet);
171 
172 	wreplconn->conn		= conn;
173 	wreplconn->service	= service;
174 
175 	peer_ip	= socket_get_peer_addr(conn->socket, wreplconn);
176 	if (!peer_ip) {
177 		wreplsrv_terminate_in_connection(wreplconn, "wreplsrv_accept: could not obtain peer IP from kernel");
178 		return;
179 	}
180 
181 	wreplconn->partner	= wreplsrv_find_partner(service, peer_ip->addr);
182 
183 	conn->private = wreplconn;
184 
185 	irpc_add_name(conn->msg_ctx, "wreplsrv_connection");
186 }
187 
188 static const struct stream_server_ops wreplsrv_stream_ops = {
189 	.name			= "wreplsrv",
190 	.accept_connection	= wreplsrv_accept,
191 	.recv_handler		= wreplsrv_recv,
192 	.send_handler		= wreplsrv_send,
193 };
194 
195 /*
196   called when we get a new connection
197 */
wreplsrv_in_connection_merge(struct wreplsrv_partner * partner,struct socket_context * sock,struct packet_context * packet,struct wreplsrv_in_connection ** _wrepl_in)198 NTSTATUS wreplsrv_in_connection_merge(struct wreplsrv_partner *partner,
199 				      struct socket_context *sock,
200 				      struct packet_context *packet,
201 				      struct wreplsrv_in_connection **_wrepl_in)
202 {
203 	struct wreplsrv_service *service = partner->service;
204 	struct wreplsrv_in_connection *wrepl_in;
205 	const struct model_ops *model_ops;
206 	struct stream_connection *conn;
207 	NTSTATUS status;
208 
209 	/* within the wrepl task we want to be a single process, so
210 	   ask for the single process model ops and pass these to the
211 	   stream_setup_socket() call. */
212 	model_ops = process_model_byname("single");
213 	if (!model_ops) {
214 		DEBUG(0,("Can't find 'single' process model_ops"));
215 		return NT_STATUS_INTERNAL_ERROR;
216 	}
217 
218 	wrepl_in = talloc_zero(partner, struct wreplsrv_in_connection);
219 	NT_STATUS_HAVE_NO_MEMORY(wrepl_in);
220 
221 	wrepl_in->service	= service;
222 	wrepl_in->partner	= partner;
223 
224 	status = stream_new_connection_merge(service->task->event_ctx, model_ops,
225 					     sock, &wreplsrv_stream_ops, service->task->msg_ctx,
226 					     wrepl_in, &conn);
227 	NT_STATUS_NOT_OK_RETURN(status);
228 
229 	/*
230 	 * make the wreplsrv_in_connection structure a child of the
231 	 * stream_connection, to match the hierachie of wreplsrv_accept
232 	 */
233 	wrepl_in->conn		= conn;
234 	talloc_steal(conn, wrepl_in);
235 
236 	/*
237 	 * now update the packet handling callback,...
238 	 */
239 	wrepl_in->packet	= talloc_steal(wrepl_in, packet);
240 	packet_set_private(wrepl_in->packet, wrepl_in);
241 	packet_set_socket(wrepl_in->packet, conn->socket);
242 	packet_set_callback(wrepl_in->packet, wreplsrv_recv_request);
243 	packet_set_full_request(wrepl_in->packet, packet_full_request_u32);
244 	packet_set_error_handler(wrepl_in->packet, wreplsrv_recv_error);
245 	packet_set_event_context(wrepl_in->packet, conn->event.ctx);
246 	packet_set_fde(wrepl_in->packet, conn->event.fde);
247 	packet_set_serialise(wrepl_in->packet);
248 
249 	*_wrepl_in = wrepl_in;
250 	return NT_STATUS_OK;
251 }
252 
253 /*
254   startup the wrepl port 42 server sockets
255 */
wreplsrv_setup_sockets(struct wreplsrv_service * service)256 NTSTATUS wreplsrv_setup_sockets(struct wreplsrv_service *service)
257 {
258 	NTSTATUS status;
259 	struct task_server *task = service->task;
260 	const struct model_ops *model_ops;
261 	const char *address;
262 	uint16_t port = WINS_REPLICATION_PORT;
263 
264 	/* within the wrepl task we want to be a single process, so
265 	   ask for the single process model ops and pass these to the
266 	   stream_setup_socket() call. */
267 	model_ops = process_model_byname("single");
268 	if (!model_ops) {
269 		DEBUG(0,("Can't find 'single' process model_ops"));
270 		return NT_STATUS_INTERNAL_ERROR;
271 	}
272 
273 	if (lp_interfaces() && lp_bind_interfaces_only()) {
274 		int num_interfaces = iface_count();
275 		int i;
276 
277 		/* We have been given an interfaces line, and been
278 		   told to only bind to those interfaces. Create a
279 		   socket per interface and bind to only these.
280 		*/
281 		for(i = 0; i < num_interfaces; i++) {
282 			address = iface_n_ip(i);
283 			status = stream_setup_socket(task->event_ctx, model_ops, &wreplsrv_stream_ops,
284 						     "ipv4", address, &port, service);
285 			if (!NT_STATUS_IS_OK(status)) {
286 				DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
287 					 address, port, nt_errstr(status)));
288 				return status;
289 			}
290 		}
291 	} else {
292 		address = lp_socket_address();
293 		status = stream_setup_socket(task->event_ctx, model_ops, &wreplsrv_stream_ops,
294 					     "ipv4", address, &port, service);
295 		if (!NT_STATUS_IS_OK(status)) {
296 			DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
297 				 address, port, nt_errstr(status)));
298 			return status;
299 		}
300 	}
301 
302 	return NT_STATUS_OK;
303 }
304