1/*
2   Unix SMB/CIFS implementation.
3   Connect to 445 and 139/nbsesssetup
4   Copyright (C) Volker Lendecke 2010
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "includes.h"
21#include "../lib/async_req/async_sock.h"
22#include "async_smb.h"
23
24struct nb_connect_state {
25	struct tevent_context *ev;
26	const struct sockaddr_storage *addr;
27	const char *called_name;
28	int sock;
29
30	struct nmb_name called;
31	struct nmb_name calling;
32};
33
34static int nb_connect_state_destructor(struct nb_connect_state *state);
35static void nb_connect_connected(struct tevent_req *subreq);
36static void nb_connect_done(struct tevent_req *subreq);
37
38static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx,
39					  struct tevent_context *ev,
40					  const struct sockaddr_storage *addr,
41					  const char *called_name,
42					  int called_type,
43					  const char *calling_name,
44					  int calling_type)
45{
46	struct tevent_req *req, *subreq;
47	struct nb_connect_state *state;
48
49	req = tevent_req_create(mem_ctx, &state, struct nb_connect_state);
50	if (req == NULL) {
51		return NULL;
52	}
53	state->ev = ev;
54	state->called_name = called_name;
55	state->addr = addr;
56
57	state->sock = -1;
58	make_nmb_name(&state->called, called_name, called_type);
59	make_nmb_name(&state->calling, calling_name, calling_type);
60
61	talloc_set_destructor(state, nb_connect_state_destructor);
62
63	subreq = open_socket_out_send(state, ev, addr, 139, 5000);
64	if (tevent_req_nomem(subreq, req)) {
65		return tevent_req_post(req, ev);
66	}
67	tevent_req_set_callback(subreq, nb_connect_connected, req);
68	return req;
69}
70
71static int nb_connect_state_destructor(struct nb_connect_state *state)
72{
73	if (state->sock != -1) {
74		close(state->sock);
75	}
76	return 0;
77}
78
79static void nb_connect_connected(struct tevent_req *subreq)
80{
81	struct tevent_req *req = tevent_req_callback_data(
82		subreq, struct tevent_req);
83	struct nb_connect_state *state = tevent_req_data(
84		req, struct nb_connect_state);
85	NTSTATUS status;
86
87	status = open_socket_out_recv(subreq, &state->sock);
88	TALLOC_FREE(subreq);
89	if (!NT_STATUS_IS_OK(status)) {
90		tevent_req_nterror(req, status);
91		return;
92	}
93	subreq = cli_session_request_send(state, state->ev, state->sock,
94					  &state->called, &state->calling);
95	if (tevent_req_nomem(subreq, req)) {
96		return;
97	}
98	tevent_req_set_callback(subreq, nb_connect_done, req);
99}
100
101static void nb_connect_done(struct tevent_req *subreq)
102{
103	struct tevent_req *req = tevent_req_callback_data(
104		subreq, struct tevent_req);
105	struct nb_connect_state *state = tevent_req_data(
106		req, struct nb_connect_state);
107	bool ret;
108	int err;
109	uint8_t resp;
110
111	ret = cli_session_request_recv(subreq, &err, &resp);
112	TALLOC_FREE(subreq);
113	if (!ret) {
114		tevent_req_nterror(req, map_nt_error_from_unix(err));
115		return;
116	}
117
118	/*
119	 * RFC1002: 0x82 - POSITIVE SESSION RESPONSE
120	 */
121
122	if (resp != 0x82) {
123		/*
124		 * The server did not like our session request
125		 */
126		close(state->sock);
127		state->sock = -1;
128
129		if (strequal(state->called_name, "*SMBSERVER")) {
130			/*
131			 * Here we could try a name status request and
132			 * use the first 0x20 type name.
133			 */
134			tevent_req_nterror(
135				req, NT_STATUS_RESOURCE_NAME_NOT_FOUND);
136			return;
137		}
138
139		/*
140		 * We could be subtle and distinguish between
141		 * different failure modes, but what we do here
142		 * instead is just retry with *SMBSERVER type 0x20.
143		 */
144		state->called_name = "*SMBSERVER";
145		make_nmb_name(&state->called, state->called_name, 0x20);
146
147		subreq = open_socket_out_send(state, state->ev, state->addr,
148					      139, 5000);
149		if (tevent_req_nomem(subreq, req)) {
150			return;
151		}
152		tevent_req_set_callback(subreq, nb_connect_connected, req);
153		return;
154	}
155
156	tevent_req_done(req);
157	return;
158
159}
160
161static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
162{
163	struct nb_connect_state *state = tevent_req_data(
164		req, struct nb_connect_state);
165	NTSTATUS status;
166
167	if (tevent_req_is_nterror(req, &status)) {
168		return status;
169	}
170	*sock = state->sock;
171	state->sock = -1;
172	return NT_STATUS_OK;
173}
174
175struct smbsock_connect_state {
176	struct tevent_context *ev;
177	const struct sockaddr_storage *addr;
178	const char *called_name;
179	const char *calling_name;
180	struct tevent_req *req_139;
181	struct tevent_req *req_445;
182	int sock;
183	uint16_t port;
184};
185
186static int smbsock_connect_state_destructor(
187	struct smbsock_connect_state *state);
188static void smbsock_connect_connected(struct tevent_req *subreq);
189static void smbsock_connect_do_139(struct tevent_req *subreq);
190
191struct tevent_req *smbsock_connect_send(TALLOC_CTX *mem_ctx,
192					struct tevent_context *ev,
193					const struct sockaddr_storage *addr,
194					const char *called_name,
195					const char *calling_name)
196{
197	struct tevent_req *req, *subreq;
198	struct smbsock_connect_state *state;
199
200	req = tevent_req_create(mem_ctx, &state, struct smbsock_connect_state);
201	if (req == NULL) {
202		return NULL;
203	}
204	state->ev = ev;
205	state->addr = addr;
206	state->sock = -1;
207	state->called_name =
208		(called_name != NULL) ? called_name : "*SMBSERVER";
209	state->calling_name =
210		(calling_name != NULL) ? calling_name : global_myname();
211
212	talloc_set_destructor(state, smbsock_connect_state_destructor);
213
214	state->req_445 = open_socket_out_send(state, ev, addr, 445, 5000);
215	if (tevent_req_nomem(state->req_445, req)) {
216		return tevent_req_post(req, ev);
217	}
218	tevent_req_set_callback(state->req_445, smbsock_connect_connected,
219				req);
220
221	/*
222	 * After 5 msecs, fire the 139 request
223	 */
224	state->req_139 = tevent_wakeup_send(
225		state, ev, timeval_current_ofs(0, 5000));
226	if (tevent_req_nomem(state->req_139, req)) {
227		TALLOC_FREE(state->req_445);
228		return tevent_req_post(req, ev);
229	}
230	tevent_req_set_callback(state->req_139, smbsock_connect_do_139,
231				req);
232	return req;
233}
234
235static int smbsock_connect_state_destructor(
236	struct smbsock_connect_state *state)
237{
238	if (state->sock != -1) {
239		close(state->sock);
240	}
241	return 0;
242}
243
244static void smbsock_connect_do_139(struct tevent_req *subreq)
245{
246	struct tevent_req *req = tevent_req_callback_data(
247		subreq, struct tevent_req);
248	struct smbsock_connect_state *state = tevent_req_data(
249		req, struct smbsock_connect_state);
250	bool ret;
251
252	ret = tevent_wakeup_recv(subreq);
253	TALLOC_FREE(subreq);
254	if (!ret) {
255		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
256		return;
257	}
258	state->req_139 = nb_connect_send(state, state->ev, state->addr,
259					 state->called_name, 0x20,
260					 state->calling_name, 0x0);
261	if (tevent_req_nomem(state->req_139, req)) {
262		return;
263	}
264	tevent_req_set_callback(state->req_139, smbsock_connect_connected,
265				req);
266}
267
268static void smbsock_connect_connected(struct tevent_req *subreq)
269{
270	struct tevent_req *req = tevent_req_callback_data(
271		subreq, struct tevent_req);
272	struct smbsock_connect_state *state = tevent_req_data(
273		req, struct smbsock_connect_state);
274	struct tevent_req *unfinished_req;
275	NTSTATUS status;
276
277	if (subreq == state->req_445) {
278
279		status = open_socket_out_recv(subreq, &state->sock);
280		TALLOC_FREE(state->req_445);
281		unfinished_req = state->req_139;
282		state->port = 445;
283
284	} else if (subreq == state->req_139) {
285
286		status = nb_connect_recv(subreq, &state->sock);
287		TALLOC_FREE(state->req_139);
288		unfinished_req = state->req_445;
289		state->port = 139;
290
291	} else {
292		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
293		return;
294	}
295
296	if (NT_STATUS_IS_OK(status)) {
297		TALLOC_FREE(unfinished_req);
298		state->req_139 = NULL;
299		state->req_445 = NULL;
300		tevent_req_done(req);
301		return;
302	}
303	if (unfinished_req == NULL) {
304		/*
305		 * Both requests failed
306		 */
307		tevent_req_nterror(req, status);
308		return;
309	}
310	/*
311	 * Do nothing, wait for the second request to come here.
312	 */
313}
314
315NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
316			  uint16_t *port)
317{
318	struct smbsock_connect_state *state = tevent_req_data(
319		req, struct smbsock_connect_state);
320	NTSTATUS status;
321
322	if (tevent_req_is_nterror(req, &status)) {
323		return status;
324	}
325	*sock = state->sock;
326	state->sock = -1;
327	if (port != NULL) {
328		*port = state->port;
329	}
330	return NT_STATUS_OK;
331}
332
333NTSTATUS smbsock_connect(const struct sockaddr_storage *addr,
334			 const char *called_name, const char *calling_name,
335			 int *pfd, uint16_t *port)
336{
337	TALLOC_CTX *frame = talloc_stackframe();
338	struct event_context *ev;
339	struct tevent_req *req;
340	NTSTATUS status = NT_STATUS_NO_MEMORY;
341
342	ev = event_context_init(frame);
343	if (ev == NULL) {
344		goto fail;
345	}
346	req = smbsock_connect_send(frame, ev, addr, called_name, calling_name);
347	if (req == NULL) {
348		goto fail;
349	}
350	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
351		goto fail;
352	}
353	status = smbsock_connect_recv(req, pfd, port);
354 fail:
355	TALLOC_FREE(frame);
356	return status;
357}
358
359struct smbsock_any_connect_state {
360	struct tevent_context *ev;
361	const struct sockaddr_storage *addrs;
362	const char **called_names;
363	size_t num_addrs;
364
365	struct tevent_req **requests;
366	size_t num_sent;
367	size_t num_received;
368
369	int fd;
370	uint16_t port;
371	size_t chosen_index;
372};
373
374static bool smbsock_any_connect_send_next(
375	struct tevent_req *req,	struct smbsock_any_connect_state *state);
376static void smbsock_any_connect_trynext(struct tevent_req *subreq);
377static void smbsock_any_connect_connected(struct tevent_req *subreq);
378
379struct tevent_req *smbsock_any_connect_send(TALLOC_CTX *mem_ctx,
380					    struct tevent_context *ev,
381					    const struct sockaddr_storage *addrs,
382					    const char **called_names,
383					    size_t num_addrs)
384{
385	struct tevent_req *req, *subreq;
386	struct smbsock_any_connect_state *state;
387
388	req = tevent_req_create(mem_ctx, &state,
389				struct smbsock_any_connect_state);
390	if (req == NULL) {
391		return NULL;
392	}
393	state->ev = ev;
394	state->addrs = addrs;
395	state->num_addrs = num_addrs;
396	state->called_names = called_names;
397
398	if (num_addrs == 0) {
399		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
400		return tevent_req_post(req, ev);
401	}
402
403	state->requests = talloc_zero_array(state, struct tevent_req *,
404					    num_addrs);
405	if (tevent_req_nomem(state->requests, req)) {
406		return tevent_req_post(req, ev);
407	}
408	if (!smbsock_any_connect_send_next(req, state)) {
409		return tevent_req_post(req, ev);
410	}
411	if (state->num_sent >= state->num_addrs) {
412		return req;
413	}
414	subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 10000));
415	if (tevent_req_nomem(subreq, req)) {
416		return tevent_req_post(req, ev);
417	}
418	tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
419	return req;
420}
421
422static void smbsock_any_connect_trynext(struct tevent_req *subreq)
423{
424	struct tevent_req *req = tevent_req_callback_data(
425		subreq, struct tevent_req);
426	struct smbsock_any_connect_state *state = tevent_req_data(
427		req, struct smbsock_any_connect_state);
428	bool ret;
429
430	ret = tevent_wakeup_recv(subreq);
431	TALLOC_FREE(subreq);
432	if (!ret) {
433		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
434		return;
435	}
436	if (!smbsock_any_connect_send_next(req, state)) {
437		return;
438	}
439	if (state->num_sent >= state->num_addrs) {
440		return;
441	}
442	subreq = tevent_wakeup_send(state, state->ev,
443				    tevent_timeval_set(0, 10000));
444	if (tevent_req_nomem(subreq, req)) {
445		return;
446	}
447	tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
448}
449
450static bool smbsock_any_connect_send_next(
451	struct tevent_req *req, struct smbsock_any_connect_state *state)
452{
453	struct tevent_req *subreq;
454
455	if (state->num_sent >= state->num_addrs) {
456		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
457		return false;
458	}
459	subreq = smbsock_connect_send(
460		state->requests, state->ev, &state->addrs[state->num_sent],
461		(state->called_names != NULL)
462		? state->called_names[state->num_sent] : NULL,
463		NULL);
464	if (tevent_req_nomem(subreq, req)) {
465		return false;
466	}
467	tevent_req_set_callback(subreq, smbsock_any_connect_connected, req);
468
469	state->requests[state->num_sent] = subreq;
470	state->num_sent += 1;
471
472	return true;
473}
474
475static void smbsock_any_connect_connected(struct tevent_req *subreq)
476{
477	struct tevent_req *req = tevent_req_callback_data(
478		subreq, struct tevent_req);
479	struct smbsock_any_connect_state *state = tevent_req_data(
480		req, struct smbsock_any_connect_state);
481	NTSTATUS status;
482	int fd;
483	uint16_t port;
484	size_t i;
485	size_t chosen_index = 0;
486
487	for (i=0; i<state->num_sent; i++) {
488		if (state->requests[i] == subreq) {
489			chosen_index = i;
490			break;
491		}
492	}
493	if (i == state->num_sent) {
494		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
495		return;
496	}
497
498	status = smbsock_connect_recv(subreq, &fd, &port);
499
500	TALLOC_FREE(subreq);
501	state->requests[chosen_index] = NULL;
502
503	if (NT_STATUS_IS_OK(status)) {
504		/*
505		 * This will kill all the other requests
506		 */
507		TALLOC_FREE(state->requests);
508		state->fd = fd;
509		state->port = port;
510		state->chosen_index = chosen_index;
511		tevent_req_done(req);
512		return;
513	}
514
515	state->num_received += 1;
516	if (state->num_received <= state->num_addrs) {
517		/*
518		 * More addrs pending, wait for the others
519		 */
520		return;
521	}
522
523	/*
524	 * This is the last response, none succeeded.
525	 */
526	tevent_req_nterror(req, status);
527	return;
528}
529
530NTSTATUS smbsock_any_connect_recv(struct tevent_req *req, int *pfd,
531				  size_t *chosen_index, uint16_t *port)
532{
533	struct smbsock_any_connect_state *state = tevent_req_data(
534		req, struct smbsock_any_connect_state);
535	NTSTATUS status;
536
537	if (tevent_req_is_nterror(req, &status)) {
538		return status;
539	}
540	*pfd = state->fd;
541	if (chosen_index != NULL) {
542		*chosen_index = state->chosen_index;
543	}
544	if (port != NULL) {
545		*port = state->port;
546	}
547	return NT_STATUS_OK;
548}
549
550NTSTATUS smbsock_any_connect(const struct sockaddr_storage *addrs,
551			     const char **called_names, size_t num_addrs,
552			     int *pfd, size_t *chosen_index, uint16_t *port)
553{
554	TALLOC_CTX *frame = talloc_stackframe();
555	struct event_context *ev;
556	struct tevent_req *req;
557	NTSTATUS status = NT_STATUS_NO_MEMORY;
558
559	ev = event_context_init(frame);
560	if (ev == NULL) {
561		goto fail;
562	}
563	req = smbsock_any_connect_send(frame, ev, addrs, called_names,
564				       num_addrs);
565	if (req == NULL) {
566		goto fail;
567	}
568	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
569		goto fail;
570	}
571	status = smbsock_any_connect_recv(req, pfd, chosen_index, port);
572 fail:
573	TALLOC_FREE(frame);
574	return status;
575}
576