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 "../lib/util/tevent_ntstatus.h"
23 #include "../lib/util/tevent_unix.h"
24 #include "client.h"
25 #include "async_smb.h"
26 #include "../libcli/smb/read_smb.h"
27 #include "libsmb/nmblib.h"
28 
29 struct cli_session_request_state {
30 	struct tevent_context *ev;
31 	int sock;
32 	uint32_t len_hdr;
33 	struct iovec iov[3];
34 	uint8_t nb_session_response;
35 };
36 
37 static void cli_session_request_sent(struct tevent_req *subreq);
38 static void cli_session_request_recvd(struct tevent_req *subreq);
39 
cli_session_request_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,int sock,const struct nmb_name * called,const struct nmb_name * calling)40 static struct tevent_req *cli_session_request_send(TALLOC_CTX *mem_ctx,
41 					struct tevent_context *ev,
42 					int sock,
43 					const struct nmb_name *called,
44 					const struct nmb_name *calling)
45 {
46 	struct tevent_req *req, *subreq;
47 	struct cli_session_request_state *state;
48 
49 	req = tevent_req_create(mem_ctx, &state,
50 				struct cli_session_request_state);
51 	if (req == NULL) {
52 		return NULL;
53 	}
54 	state->ev = ev;
55 	state->sock = sock;
56 
57 	state->iov[1].iov_base = name_mangle(
58 		state, called->name, called->name_type);
59 	if (tevent_req_nomem(state->iov[1].iov_base, req)) {
60 		return tevent_req_post(req, ev);
61 	}
62 	state->iov[1].iov_len = name_len(
63 		(unsigned char *)state->iov[1].iov_base,
64 		talloc_get_size(state->iov[1].iov_base));
65 
66 	state->iov[2].iov_base = name_mangle(
67 		state, calling->name, calling->name_type);
68 	if (tevent_req_nomem(state->iov[2].iov_base, req)) {
69 		return tevent_req_post(req, ev);
70 	}
71 	state->iov[2].iov_len = name_len(
72 		(unsigned char *)state->iov[2].iov_base,
73 		talloc_get_size(state->iov[2].iov_base));
74 
75 	_smb_setlen(((char *)&state->len_hdr),
76 		    state->iov[1].iov_len + state->iov[2].iov_len);
77 	SCVAL((char *)&state->len_hdr, 0, 0x81);
78 
79 	state->iov[0].iov_base = &state->len_hdr;
80 	state->iov[0].iov_len = sizeof(state->len_hdr);
81 
82 	subreq = writev_send(state, ev, NULL, sock, true, state->iov, 3);
83 	if (tevent_req_nomem(subreq, req)) {
84 		return tevent_req_post(req, ev);
85 	}
86 	tevent_req_set_callback(subreq, cli_session_request_sent, req);
87 	return req;
88 }
89 
cli_session_request_sent(struct tevent_req * subreq)90 static void cli_session_request_sent(struct tevent_req *subreq)
91 {
92 	struct tevent_req *req = tevent_req_callback_data(
93 		subreq, struct tevent_req);
94 	struct cli_session_request_state *state = tevent_req_data(
95 		req, struct cli_session_request_state);
96 	ssize_t ret;
97 	int err;
98 
99 	ret = writev_recv(subreq, &err);
100 	TALLOC_FREE(subreq);
101 	if (ret == -1) {
102 		tevent_req_error(req, err);
103 		return;
104 	}
105 	subreq = read_smb_send(state, state->ev, state->sock);
106 	if (tevent_req_nomem(subreq, req)) {
107 		return;
108 	}
109 	tevent_req_set_callback(subreq, cli_session_request_recvd, req);
110 }
111 
cli_session_request_recvd(struct tevent_req * subreq)112 static void cli_session_request_recvd(struct tevent_req *subreq)
113 {
114 	struct tevent_req *req = tevent_req_callback_data(
115 		subreq, struct tevent_req);
116 	struct cli_session_request_state *state = tevent_req_data(
117 		req, struct cli_session_request_state);
118 	uint8_t *buf;
119 	ssize_t ret;
120 	int err;
121 
122 	ret = read_smb_recv(subreq, talloc_tos(), &buf, &err);
123 	TALLOC_FREE(subreq);
124 
125 	if (ret < 4) {
126 		ret = -1;
127 		err = EIO;
128 	}
129 	if (ret == -1) {
130 		tevent_req_error(req, err);
131 		return;
132 	}
133 	/*
134 	 * In case of an error there is more information in the data
135 	 * portion according to RFC1002. We're not subtle enough to
136 	 * respond to the different error conditions, so drop the
137 	 * error info here.
138 	 */
139 	state->nb_session_response = CVAL(buf, 0);
140 	tevent_req_done(req);
141 }
142 
cli_session_request_recv(struct tevent_req * req,int * err,uint8_t * resp)143 static bool cli_session_request_recv(struct tevent_req *req, int *err, uint8_t *resp)
144 {
145 	struct cli_session_request_state *state = tevent_req_data(
146 		req, struct cli_session_request_state);
147 
148 	if (tevent_req_is_unix_error(req, err)) {
149 		return false;
150 	}
151 	*resp = state->nb_session_response;
152 	return true;
153 }
154 
155 struct nb_connect_state {
156 	struct tevent_context *ev;
157 	const struct sockaddr_storage *addr;
158 	const char *called_name;
159 	int sock;
160 	struct tevent_req *session_subreq;
161 	struct nmb_name called;
162 	struct nmb_name calling;
163 };
164 
165 static void nb_connect_cleanup(struct tevent_req *req,
166 			       enum tevent_req_state req_state);
167 static void nb_connect_connected(struct tevent_req *subreq);
168 static void nb_connect_done(struct tevent_req *subreq);
169 
nb_connect_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,const struct sockaddr_storage * addr,const char * called_name,int called_type,const char * calling_name,int calling_type)170 static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx,
171 					  struct tevent_context *ev,
172 					  const struct sockaddr_storage *addr,
173 					  const char *called_name,
174 					  int called_type,
175 					  const char *calling_name,
176 					  int calling_type)
177 {
178 	struct tevent_req *req, *subreq;
179 	struct nb_connect_state *state;
180 
181 	req = tevent_req_create(mem_ctx, &state, struct nb_connect_state);
182 	if (req == NULL) {
183 		return NULL;
184 	}
185 	state->ev = ev;
186 	state->called_name = called_name;
187 	state->addr = addr;
188 
189 	state->sock = -1;
190 	make_nmb_name(&state->called, called_name, called_type);
191 	make_nmb_name(&state->calling, calling_name, calling_type);
192 
193 	tevent_req_set_cleanup_fn(req, nb_connect_cleanup);
194 
195 	subreq = open_socket_out_send(state, ev, addr, NBT_SMB_PORT, 5000);
196 	if (tevent_req_nomem(subreq, req)) {
197 		return tevent_req_post(req, ev);
198 	}
199 	tevent_req_set_callback(subreq, nb_connect_connected, req);
200 	return req;
201 }
202 
nb_connect_cleanup(struct tevent_req * req,enum tevent_req_state req_state)203 static void nb_connect_cleanup(struct tevent_req *req,
204 			       enum tevent_req_state req_state)
205 {
206 	struct nb_connect_state *state = tevent_req_data(
207 		req, struct nb_connect_state);
208 
209 	/*
210 	 * we need to free a pending request before closing the
211 	 * socket, see bug #11141
212 	 */
213 	TALLOC_FREE(state->session_subreq);
214 
215 	if (req_state == TEVENT_REQ_DONE) {
216 		/*
217 		 * we keep the socket open for the caller to use
218 		 */
219 		return;
220 	}
221 
222 	if (state->sock != -1) {
223 		close(state->sock);
224 		state->sock = -1;
225 	}
226 
227 	return;
228 }
229 
nb_connect_connected(struct tevent_req * subreq)230 static void nb_connect_connected(struct tevent_req *subreq)
231 {
232 	struct tevent_req *req = tevent_req_callback_data(
233 		subreq, struct tevent_req);
234 	struct nb_connect_state *state = tevent_req_data(
235 		req, struct nb_connect_state);
236 	NTSTATUS status;
237 
238 	status = open_socket_out_recv(subreq, &state->sock);
239 	TALLOC_FREE(subreq);
240 	if (!NT_STATUS_IS_OK(status)) {
241 		tevent_req_nterror(req, status);
242 		return;
243 	}
244 	subreq = cli_session_request_send(state, state->ev, state->sock,
245 					  &state->called, &state->calling);
246 	if (tevent_req_nomem(subreq, req)) {
247 		return;
248 	}
249 	tevent_req_set_callback(subreq, nb_connect_done, req);
250 	state->session_subreq = subreq;
251 }
252 
nb_connect_done(struct tevent_req * subreq)253 static void nb_connect_done(struct tevent_req *subreq)
254 {
255 	struct tevent_req *req = tevent_req_callback_data(
256 		subreq, struct tevent_req);
257 	struct nb_connect_state *state = tevent_req_data(
258 		req, struct nb_connect_state);
259 	bool ret;
260 	int err;
261 	uint8_t resp;
262 
263 	state->session_subreq = NULL;
264 
265 	ret = cli_session_request_recv(subreq, &err, &resp);
266 	TALLOC_FREE(subreq);
267 	if (!ret) {
268 		tevent_req_nterror(req, map_nt_error_from_unix(err));
269 		return;
270 	}
271 
272 	/*
273 	 * RFC1002: 0x82 - POSITIVE SESSION RESPONSE
274 	 */
275 
276 	if (resp != 0x82) {
277 		/*
278 		 * The server did not like our session request
279 		 */
280 		close(state->sock);
281 		state->sock = -1;
282 
283 		if (strequal(state->called_name, "*SMBSERVER")) {
284 			/*
285 			 * Here we could try a name status request and
286 			 * use the first 0x20 type name.
287 			 */
288 			tevent_req_nterror(
289 				req, NT_STATUS_RESOURCE_NAME_NOT_FOUND);
290 			return;
291 		}
292 
293 		/*
294 		 * We could be subtle and distinguish between
295 		 * different failure modes, but what we do here
296 		 * instead is just retry with *SMBSERVER type 0x20.
297 		 */
298 		state->called_name = "*SMBSERVER";
299 		make_nmb_name(&state->called, state->called_name, 0x20);
300 
301 		subreq = open_socket_out_send(state, state->ev, state->addr,
302 					      NBT_SMB_PORT, 5000);
303 		if (tevent_req_nomem(subreq, req)) {
304 			return;
305 		}
306 		tevent_req_set_callback(subreq, nb_connect_connected, req);
307 		return;
308 	}
309 
310 	tevent_req_done(req);
311 	return;
312 }
313 
nb_connect_recv(struct tevent_req * req,int * sock)314 static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
315 {
316 	struct nb_connect_state *state = tevent_req_data(
317 		req, struct nb_connect_state);
318 	NTSTATUS status;
319 
320 	if (tevent_req_is_nterror(req, &status)) {
321 		tevent_req_received(req);
322 		return status;
323 	}
324 	*sock = state->sock;
325 	state->sock = -1;
326 	tevent_req_received(req);
327 	return NT_STATUS_OK;
328 }
329 
330 struct smbsock_connect_state {
331 	struct tevent_context *ev;
332 	const struct sockaddr_storage *addr;
333 	const char *called_name;
334 	uint8_t called_type;
335 	const char *calling_name;
336 	uint8_t calling_type;
337 	struct tevent_req *req_139;
338 	struct tevent_req *req_445;
339 	int sock;
340 	uint16_t port;
341 };
342 
343 static void smbsock_connect_cleanup(struct tevent_req *req,
344 				    enum tevent_req_state req_state);
345 static void smbsock_connect_connected(struct tevent_req *subreq);
346 static void smbsock_connect_do_139(struct tevent_req *subreq);
347 
smbsock_connect_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,const struct sockaddr_storage * addr,uint16_t port,const char * called_name,int called_type,const char * calling_name,int calling_type)348 struct tevent_req *smbsock_connect_send(TALLOC_CTX *mem_ctx,
349 					struct tevent_context *ev,
350 					const struct sockaddr_storage *addr,
351 					uint16_t port,
352 					const char *called_name,
353 					int called_type,
354 					const char *calling_name,
355 					int calling_type)
356 {
357 	struct tevent_req *req;
358 	struct smbsock_connect_state *state;
359 
360 	req = tevent_req_create(mem_ctx, &state, struct smbsock_connect_state);
361 	if (req == NULL) {
362 		return NULL;
363 	}
364 	state->ev = ev;
365 	state->addr = addr;
366 	state->sock = -1;
367 	state->called_name =
368 		(called_name != NULL) ? called_name : "*SMBSERVER";
369 	state->called_type =
370 		(called_type != -1) ? called_type : 0x20;
371 	state->calling_name =
372 		(calling_name != NULL) ? calling_name : lp_netbios_name();
373 	state->calling_type =
374 		(calling_type != -1) ? calling_type : 0x00;
375 
376 	tevent_req_set_cleanup_fn(req, smbsock_connect_cleanup);
377 
378 	if (port == NBT_SMB_PORT) {
379 		if (lp_disable_netbios()) {
380 			tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
381 			return tevent_req_post(req, ev);
382 		}
383 
384 		state->req_139 = nb_connect_send(state, state->ev, state->addr,
385 						 state->called_name,
386 						 state->called_type,
387 						 state->calling_name,
388 						 state->calling_type);
389 		if (tevent_req_nomem(state->req_139, req)) {
390 			return tevent_req_post(req, ev);
391 		}
392 		tevent_req_set_callback(
393 			state->req_139, smbsock_connect_connected, req);
394 		return req;
395 	}
396 	if (port != 0) {
397 		state->req_445 = open_socket_out_send(state, ev, addr, port,
398 						      5000);
399 		if (tevent_req_nomem(state->req_445, req)) {
400 			return tevent_req_post(req, ev);
401 		}
402 		tevent_req_set_callback(
403 			state->req_445, smbsock_connect_connected, req);
404 		return req;
405 	}
406 
407 	/*
408 	 * port==0, try both
409 	 */
410 
411 	state->req_445 = open_socket_out_send(state, ev, addr, TCP_SMB_PORT, 5000);
412 	if (tevent_req_nomem(state->req_445, req)) {
413 		return tevent_req_post(req, ev);
414 	}
415 	tevent_req_set_callback(state->req_445, smbsock_connect_connected,
416 				req);
417 
418 	/*
419 	 * Check for disable_netbios
420 	 */
421 	if (lp_disable_netbios()) {
422 		return req;
423 	}
424 
425 	/*
426 	 * After 5 msecs, fire the 139 (NBT) request
427 	 */
428 	state->req_139 = tevent_wakeup_send(
429 		state, ev, timeval_current_ofs(0, 5000));
430 	if (tevent_req_nomem(state->req_139, req)) {
431 		TALLOC_FREE(state->req_445);
432 		return tevent_req_post(req, ev);
433 	}
434 	tevent_req_set_callback(state->req_139, smbsock_connect_do_139,
435 				req);
436 	return req;
437 }
438 
smbsock_connect_cleanup(struct tevent_req * req,enum tevent_req_state req_state)439 static void smbsock_connect_cleanup(struct tevent_req *req,
440 				    enum tevent_req_state req_state)
441 {
442 	struct smbsock_connect_state *state = tevent_req_data(
443 		req, struct smbsock_connect_state);
444 
445 	/*
446 	 * we need to free a pending request before closing the
447 	 * socket, see bug #11141
448 	 */
449 	TALLOC_FREE(state->req_445);
450 	TALLOC_FREE(state->req_139);
451 
452 	if (req_state == TEVENT_REQ_DONE) {
453 		/*
454 		 * we keep the socket open for the caller to use
455 		 */
456 		return;
457 	}
458 
459 	if (state->sock != -1) {
460 		close(state->sock);
461 		state->sock = -1;
462 	}
463 
464 	return;
465 }
466 
smbsock_connect_do_139(struct tevent_req * subreq)467 static void smbsock_connect_do_139(struct tevent_req *subreq)
468 {
469 	struct tevent_req *req = tevent_req_callback_data(
470 		subreq, struct tevent_req);
471 	struct smbsock_connect_state *state = tevent_req_data(
472 		req, struct smbsock_connect_state);
473 	bool ret;
474 
475 	ret = tevent_wakeup_recv(subreq);
476 	TALLOC_FREE(subreq);
477 	if (!ret) {
478 		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
479 		return;
480 	}
481 	state->req_139 = nb_connect_send(state, state->ev, state->addr,
482 					 state->called_name,
483 					 state->called_type,
484 					 state->calling_name,
485 					 state->calling_type);
486 	if (tevent_req_nomem(state->req_139, req)) {
487 		return;
488 	}
489 	tevent_req_set_callback(state->req_139, smbsock_connect_connected,
490 				req);
491 }
492 
smbsock_connect_connected(struct tevent_req * subreq)493 static void smbsock_connect_connected(struct tevent_req *subreq)
494 {
495 	struct tevent_req *req = tevent_req_callback_data(
496 		subreq, struct tevent_req);
497 	struct smbsock_connect_state *state = tevent_req_data(
498 		req, struct smbsock_connect_state);
499 	struct tevent_req *unfinished_req;
500 	NTSTATUS status;
501 
502 	if (subreq == state->req_445) {
503 
504 		status = open_socket_out_recv(subreq, &state->sock);
505 		TALLOC_FREE(state->req_445);
506 		unfinished_req = state->req_139;
507 		state->port = TCP_SMB_PORT;
508 
509 	} else if (subreq == state->req_139) {
510 
511 		status = nb_connect_recv(subreq, &state->sock);
512 		TALLOC_FREE(state->req_139);
513 		unfinished_req = state->req_445;
514 		state->port = NBT_SMB_PORT;
515 
516 	} else {
517 		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
518 		return;
519 	}
520 
521 	if (NT_STATUS_IS_OK(status)) {
522 		TALLOC_FREE(unfinished_req);
523 		state->req_139 = NULL;
524 		state->req_445 = NULL;
525 		tevent_req_done(req);
526 		return;
527 	}
528 	if (unfinished_req == NULL) {
529 		/*
530 		 * Both requests failed
531 		 */
532 		tevent_req_nterror(req, status);
533 		return;
534 	}
535 	/*
536 	 * Do nothing, wait for the second request to come here.
537 	 */
538 }
539 
smbsock_connect_recv(struct tevent_req * req,int * sock,uint16_t * ret_port)540 NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
541 			      uint16_t *ret_port)
542 {
543 	struct smbsock_connect_state *state = tevent_req_data(
544 		req, struct smbsock_connect_state);
545 	NTSTATUS status;
546 
547 	if (tevent_req_is_nterror(req, &status)) {
548 		tevent_req_received(req);
549 		return status;
550 	}
551 	*sock = state->sock;
552 	state->sock = -1;
553 	if (ret_port != NULL) {
554 		*ret_port = state->port;
555 	}
556 	tevent_req_received(req);
557 	return NT_STATUS_OK;
558 }
559 
smbsock_connect(const struct sockaddr_storage * addr,uint16_t port,const char * called_name,int called_type,const char * calling_name,int calling_type,int * pfd,uint16_t * ret_port,int sec_timeout)560 NTSTATUS smbsock_connect(const struct sockaddr_storage *addr, uint16_t port,
561 			 const char *called_name, int called_type,
562 			 const char *calling_name, int calling_type,
563 			 int *pfd, uint16_t *ret_port, int sec_timeout)
564 {
565 	TALLOC_CTX *frame = talloc_stackframe();
566 	struct tevent_context *ev;
567 	struct tevent_req *req;
568 	NTSTATUS status = NT_STATUS_NO_MEMORY;
569 
570 	ev = samba_tevent_context_init(frame);
571 	if (ev == NULL) {
572 		goto fail;
573 	}
574 	req = smbsock_connect_send(frame, ev, addr, port,
575 				   called_name, called_type,
576 				   calling_name, calling_type);
577 	if (req == NULL) {
578 		goto fail;
579 	}
580 	if ((sec_timeout != 0) &&
581 	    !tevent_req_set_endtime(
582 		    req, ev, timeval_current_ofs(sec_timeout, 0))) {
583 		goto fail;
584 	}
585 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
586 		goto fail;
587 	}
588 	status = smbsock_connect_recv(req, pfd, ret_port);
589  fail:
590 	TALLOC_FREE(frame);
591 	return status;
592 }
593 
594 struct smbsock_any_connect_state {
595 	struct tevent_context *ev;
596 	const struct sockaddr_storage *addrs;
597 	const char **called_names;
598 	int *called_types;
599 	const char **calling_names;
600 	int *calling_types;
601 	size_t num_addrs;
602 	uint16_t port;
603 
604 	struct tevent_req **requests;
605 	size_t num_sent;
606 	size_t num_received;
607 
608 	int fd;
609 	uint16_t chosen_port;
610 	size_t chosen_index;
611 };
612 
613 static void smbsock_any_connect_cleanup(struct tevent_req *req,
614 					enum tevent_req_state req_state);
615 static bool smbsock_any_connect_send_next(
616 	struct tevent_req *req,	struct smbsock_any_connect_state *state);
617 static void smbsock_any_connect_trynext(struct tevent_req *subreq);
618 static void smbsock_any_connect_connected(struct tevent_req *subreq);
619 
smbsock_any_connect_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,const struct sockaddr_storage * addrs,const char ** called_names,int * called_types,const char ** calling_names,int * calling_types,size_t num_addrs,uint16_t port)620 struct tevent_req *smbsock_any_connect_send(TALLOC_CTX *mem_ctx,
621 					    struct tevent_context *ev,
622 					    const struct sockaddr_storage *addrs,
623 					    const char **called_names,
624 					    int *called_types,
625 					    const char **calling_names,
626 					    int *calling_types,
627 					    size_t num_addrs, uint16_t port)
628 {
629 	struct tevent_req *req, *subreq;
630 	struct smbsock_any_connect_state *state;
631 
632 	req = tevent_req_create(mem_ctx, &state,
633 				struct smbsock_any_connect_state);
634 	if (req == NULL) {
635 		return NULL;
636 	}
637 	state->ev = ev;
638 	state->addrs = addrs;
639 	state->num_addrs = num_addrs;
640 	state->called_names = called_names;
641 	state->called_types = called_types;
642 	state->calling_names = calling_names;
643 	state->calling_types = calling_types;
644 	state->port = port;
645 	state->fd = -1;
646 
647 	tevent_req_set_cleanup_fn(req, smbsock_any_connect_cleanup);
648 
649 	if (num_addrs == 0) {
650 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
651 		return tevent_req_post(req, ev);
652 	}
653 
654 	state->requests = talloc_zero_array(state, struct tevent_req *,
655 					    num_addrs);
656 	if (tevent_req_nomem(state->requests, req)) {
657 		return tevent_req_post(req, ev);
658 	}
659 	if (!smbsock_any_connect_send_next(req, state)) {
660 		return tevent_req_post(req, ev);
661 	}
662 	if (state->num_sent >= state->num_addrs) {
663 		return req;
664 	}
665 	subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 10000));
666 	if (tevent_req_nomem(subreq, req)) {
667 		return tevent_req_post(req, ev);
668 	}
669 	tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
670 	return req;
671 }
672 
smbsock_any_connect_cleanup(struct tevent_req * req,enum tevent_req_state req_state)673 static void smbsock_any_connect_cleanup(struct tevent_req *req,
674 					enum tevent_req_state req_state)
675 {
676 	struct smbsock_any_connect_state *state = tevent_req_data(
677 		req, struct smbsock_any_connect_state);
678 
679 	TALLOC_FREE(state->requests);
680 
681 	if (req_state == TEVENT_REQ_DONE) {
682 		/*
683 		 * Keep the socket open for the caller.
684 		 */
685 		return;
686 	}
687 
688 	if (state->fd != -1) {
689 		close(state->fd);
690 		state->fd = -1;
691 	}
692 }
693 
smbsock_any_connect_trynext(struct tevent_req * subreq)694 static void smbsock_any_connect_trynext(struct tevent_req *subreq)
695 {
696 	struct tevent_req *req = tevent_req_callback_data(
697 		subreq, struct tevent_req);
698 	struct smbsock_any_connect_state *state = tevent_req_data(
699 		req, struct smbsock_any_connect_state);
700 	bool ret;
701 
702 	ret = tevent_wakeup_recv(subreq);
703 	TALLOC_FREE(subreq);
704 	if (!ret) {
705 		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
706 		return;
707 	}
708 	if (!smbsock_any_connect_send_next(req, state)) {
709 		return;
710 	}
711 	if (state->num_sent >= state->num_addrs) {
712 		return;
713 	}
714 	subreq = tevent_wakeup_send(state, state->ev,
715 				    tevent_timeval_set(0, 10000));
716 	if (tevent_req_nomem(subreq, req)) {
717 		return;
718 	}
719 	tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
720 }
721 
smbsock_any_connect_send_next(struct tevent_req * req,struct smbsock_any_connect_state * state)722 static bool smbsock_any_connect_send_next(
723 	struct tevent_req *req, struct smbsock_any_connect_state *state)
724 {
725 	struct tevent_req *subreq;
726 
727 	if (state->num_sent >= state->num_addrs) {
728 		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
729 		return false;
730 	}
731 	subreq = smbsock_connect_send(
732 		state->requests, state->ev, &state->addrs[state->num_sent],
733 		state->port,
734 		(state->called_names != NULL)
735 		? state->called_names[state->num_sent] : NULL,
736 		(state->called_types != NULL)
737 		? state->called_types[state->num_sent] : -1,
738 		(state->calling_names != NULL)
739 		? state->calling_names[state->num_sent] : NULL,
740 		(state->calling_types != NULL)
741 		? state->calling_types[state->num_sent] : -1);
742 	if (tevent_req_nomem(subreq, req)) {
743 		return false;
744 	}
745 	tevent_req_set_callback(subreq, smbsock_any_connect_connected, req);
746 
747 	state->requests[state->num_sent] = subreq;
748 	state->num_sent += 1;
749 
750 	return true;
751 }
752 
smbsock_any_connect_connected(struct tevent_req * subreq)753 static void smbsock_any_connect_connected(struct tevent_req *subreq)
754 {
755 	struct tevent_req *req = tevent_req_callback_data(
756 		subreq, struct tevent_req);
757 	struct smbsock_any_connect_state *state = tevent_req_data(
758 		req, struct smbsock_any_connect_state);
759 	NTSTATUS status;
760 	int fd = 0;
761 	uint16_t chosen_port = 0;
762 	size_t i;
763 	size_t chosen_index = 0;
764 
765 	for (i=0; i<state->num_sent; i++) {
766 		if (state->requests[i] == subreq) {
767 			chosen_index = i;
768 			break;
769 		}
770 	}
771 	if (i == state->num_sent) {
772 		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
773 		return;
774 	}
775 
776 	status = smbsock_connect_recv(subreq, &fd, &chosen_port);
777 
778 	TALLOC_FREE(subreq);
779 	state->requests[chosen_index] = NULL;
780 
781 	if (NT_STATUS_IS_OK(status)) {
782 		/*
783 		 * tevent_req_done() will kill all the other requests
784 		 * via smbsock_any_connect_cleanup().
785 		 */
786 		state->fd = fd;
787 		state->chosen_port = chosen_port;
788 		state->chosen_index = chosen_index;
789 		tevent_req_done(req);
790 		return;
791 	}
792 
793 	state->num_received += 1;
794 	if (state->num_received < state->num_addrs) {
795 		/*
796 		 * More addrs pending, wait for the others
797 		 */
798 		return;
799 	}
800 
801 	/*
802 	 * This is the last response, none succeeded.
803 	 */
804 	tevent_req_nterror(req, status);
805 	return;
806 }
807 
smbsock_any_connect_recv(struct tevent_req * req,int * pfd,size_t * chosen_index,uint16_t * chosen_port)808 NTSTATUS smbsock_any_connect_recv(struct tevent_req *req, int *pfd,
809 				  size_t *chosen_index,
810 				  uint16_t *chosen_port)
811 {
812 	struct smbsock_any_connect_state *state = tevent_req_data(
813 		req, struct smbsock_any_connect_state);
814 	NTSTATUS status;
815 
816 	if (tevent_req_is_nterror(req, &status)) {
817 		tevent_req_received(req);
818 		return status;
819 	}
820 	*pfd = state->fd;
821 	state->fd = -1;
822 	if (chosen_index != NULL) {
823 		*chosen_index = state->chosen_index;
824 	}
825 	if (chosen_port != NULL) {
826 		*chosen_port = state->chosen_port;
827 	}
828 	tevent_req_received(req);
829 	return NT_STATUS_OK;
830 }
831 
smbsock_any_connect(const struct sockaddr_storage * addrs,const char ** called_names,int * called_types,const char ** calling_names,int * calling_types,size_t num_addrs,uint16_t port,int sec_timeout,int * pfd,size_t * chosen_index,uint16_t * chosen_port)832 NTSTATUS smbsock_any_connect(const struct sockaddr_storage *addrs,
833 			     const char **called_names,
834 			     int *called_types,
835 			     const char **calling_names,
836 			     int *calling_types,
837 			     size_t num_addrs,
838 			     uint16_t port,
839 			     int sec_timeout,
840 			     int *pfd, size_t *chosen_index,
841 			     uint16_t *chosen_port)
842 {
843 	TALLOC_CTX *frame = talloc_stackframe();
844 	struct tevent_context *ev;
845 	struct tevent_req *req;
846 	NTSTATUS status = NT_STATUS_NO_MEMORY;
847 
848 	ev = samba_tevent_context_init(frame);
849 	if (ev == NULL) {
850 		goto fail;
851 	}
852 	req = smbsock_any_connect_send(frame, ev, addrs,
853 				       called_names, called_types,
854 				       calling_names, calling_types,
855 				       num_addrs, port);
856 	if (req == NULL) {
857 		goto fail;
858 	}
859 	if ((sec_timeout != 0) &&
860 	    !tevent_req_set_endtime(
861 		    req, ev, timeval_current_ofs(sec_timeout, 0))) {
862 		goto fail;
863 	}
864 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
865 		goto fail;
866 	}
867 	status = smbsock_any_connect_recv(req, pfd, chosen_index, chosen_port);
868  fail:
869 	TALLOC_FREE(frame);
870 	return status;
871 }
872