Line data Source code
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 :
40 385 : 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 385 : req = tevent_req_create(mem_ctx, &state,
50 : struct cli_session_request_state);
51 385 : if (req == NULL) {
52 0 : return NULL;
53 : }
54 385 : state->ev = ev;
55 385 : state->sock = sock;
56 :
57 770 : state->iov[1].iov_base = name_mangle(
58 597 : state, called->name, called->name_type);
59 385 : if (tevent_req_nomem(state->iov[1].iov_base, req)) {
60 0 : return tevent_req_post(req, ev);
61 : }
62 943 : state->iov[1].iov_len = name_len(
63 385 : (unsigned char *)state->iov[1].iov_base,
64 385 : talloc_get_size(state->iov[1].iov_base));
65 :
66 770 : state->iov[2].iov_base = name_mangle(
67 597 : state, calling->name, calling->name_type);
68 385 : if (tevent_req_nomem(state->iov[2].iov_base, req)) {
69 0 : return tevent_req_post(req, ev);
70 : }
71 943 : state->iov[2].iov_len = name_len(
72 385 : (unsigned char *)state->iov[2].iov_base,
73 385 : talloc_get_size(state->iov[2].iov_base));
74 :
75 385 : _smb_setlen(((char *)&state->len_hdr),
76 : state->iov[1].iov_len + state->iov[2].iov_len);
77 385 : SCVAL((char *)&state->len_hdr, 0, 0x81);
78 :
79 385 : state->iov[0].iov_base = &state->len_hdr;
80 385 : state->iov[0].iov_len = sizeof(state->len_hdr);
81 :
82 385 : subreq = writev_send(state, ev, NULL, sock, true, state->iov, 3);
83 385 : if (tevent_req_nomem(subreq, req)) {
84 0 : return tevent_req_post(req, ev);
85 : }
86 385 : tevent_req_set_callback(subreq, cli_session_request_sent, req);
87 385 : return req;
88 : }
89 :
90 385 : static void cli_session_request_sent(struct tevent_req *subreq)
91 : {
92 385 : struct tevent_req *req = tevent_req_callback_data(
93 : subreq, struct tevent_req);
94 385 : 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 385 : ret = writev_recv(subreq, &err);
100 385 : TALLOC_FREE(subreq);
101 385 : if (ret == -1) {
102 0 : tevent_req_error(req, err);
103 0 : return;
104 : }
105 385 : subreq = read_smb_send(state, state->ev, state->sock);
106 385 : if (tevent_req_nomem(subreq, req)) {
107 0 : return;
108 : }
109 385 : tevent_req_set_callback(subreq, cli_session_request_recvd, req);
110 : }
111 :
112 372 : static void cli_session_request_recvd(struct tevent_req *subreq)
113 : {
114 372 : struct tevent_req *req = tevent_req_callback_data(
115 : subreq, struct tevent_req);
116 372 : 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 372 : ret = read_smb_recv(subreq, talloc_tos(), &buf, &err);
123 372 : TALLOC_FREE(subreq);
124 :
125 372 : if (ret < 4) {
126 0 : ret = -1;
127 0 : err = EIO;
128 : }
129 372 : if (ret == -1) {
130 0 : tevent_req_error(req, err);
131 0 : 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 372 : state->nb_session_response = CVAL(buf, 0);
140 372 : tevent_req_done(req);
141 : }
142 :
143 372 : static bool cli_session_request_recv(struct tevent_req *req, int *err, uint8_t *resp)
144 : {
145 372 : struct cli_session_request_state *state = tevent_req_data(
146 : req, struct cli_session_request_state);
147 :
148 372 : if (tevent_req_is_unix_error(req, err)) {
149 0 : return false;
150 : }
151 372 : *resp = state->nb_session_response;
152 372 : 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 :
170 385 : 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 385 : req = tevent_req_create(mem_ctx, &state, struct nb_connect_state);
182 385 : if (req == NULL) {
183 0 : return NULL;
184 : }
185 385 : state->ev = ev;
186 385 : state->called_name = called_name;
187 385 : state->addr = addr;
188 :
189 385 : state->sock = -1;
190 385 : make_nmb_name(&state->called, called_name, called_type);
191 385 : make_nmb_name(&state->calling, calling_name, calling_type);
192 :
193 385 : tevent_req_set_cleanup_fn(req, nb_connect_cleanup);
194 :
195 385 : subreq = open_socket_out_send(state, ev, addr, NBT_SMB_PORT, 5000);
196 385 : if (tevent_req_nomem(subreq, req)) {
197 0 : return tevent_req_post(req, ev);
198 : }
199 385 : tevent_req_set_callback(subreq, nb_connect_connected, req);
200 385 : return req;
201 : }
202 :
203 757 : static void nb_connect_cleanup(struct tevent_req *req,
204 : enum tevent_req_state req_state)
205 : {
206 757 : 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 757 : TALLOC_FREE(state->session_subreq);
214 :
215 757 : if (req_state == TEVENT_REQ_DONE) {
216 : /*
217 : * we keep the socket open for the caller to use
218 : */
219 372 : return;
220 : }
221 :
222 385 : if (state->sock != -1) {
223 13 : close(state->sock);
224 13 : state->sock = -1;
225 : }
226 :
227 385 : return;
228 : }
229 :
230 385 : static void nb_connect_connected(struct tevent_req *subreq)
231 : {
232 385 : struct tevent_req *req = tevent_req_callback_data(
233 : subreq, struct tevent_req);
234 385 : struct nb_connect_state *state = tevent_req_data(
235 : req, struct nb_connect_state);
236 : NTSTATUS status;
237 :
238 385 : status = open_socket_out_recv(subreq, &state->sock);
239 385 : TALLOC_FREE(subreq);
240 385 : if (!NT_STATUS_IS_OK(status)) {
241 0 : tevent_req_nterror(req, status);
242 0 : return;
243 : }
244 385 : subreq = cli_session_request_send(state, state->ev, state->sock,
245 385 : &state->called, &state->calling);
246 385 : if (tevent_req_nomem(subreq, req)) {
247 0 : return;
248 : }
249 385 : tevent_req_set_callback(subreq, nb_connect_done, req);
250 385 : state->session_subreq = subreq;
251 : }
252 :
253 372 : static void nb_connect_done(struct tevent_req *subreq)
254 : {
255 372 : struct tevent_req *req = tevent_req_callback_data(
256 : subreq, struct tevent_req);
257 372 : 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 372 : state->session_subreq = NULL;
264 :
265 372 : ret = cli_session_request_recv(subreq, &err, &resp);
266 372 : TALLOC_FREE(subreq);
267 372 : if (!ret) {
268 0 : tevent_req_nterror(req, map_nt_error_from_unix(err));
269 0 : return;
270 : }
271 :
272 : /*
273 : * RFC1002: 0x82 - POSITIVE SESSION RESPONSE
274 : */
275 :
276 372 : if (resp != 0x82) {
277 : /*
278 : * The server did not like our session request
279 : */
280 0 : close(state->sock);
281 0 : state->sock = -1;
282 :
283 0 : 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 0 : tevent_req_nterror(
289 : req, NT_STATUS_RESOURCE_NAME_NOT_FOUND);
290 0 : 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 0 : state->called_name = "*SMBSERVER";
299 0 : make_nmb_name(&state->called, state->called_name, 0x20);
300 :
301 0 : subreq = open_socket_out_send(state, state->ev, state->addr,
302 : NBT_SMB_PORT, 5000);
303 0 : if (tevent_req_nomem(subreq, req)) {
304 0 : return;
305 : }
306 0 : tevent_req_set_callback(subreq, nb_connect_connected, req);
307 0 : return;
308 : }
309 :
310 372 : tevent_req_done(req);
311 372 : return;
312 : }
313 :
314 372 : static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
315 : {
316 372 : struct nb_connect_state *state = tevent_req_data(
317 : req, struct nb_connect_state);
318 : NTSTATUS status;
319 :
320 372 : if (tevent_req_is_nterror(req, &status)) {
321 0 : tevent_req_received(req);
322 0 : return status;
323 : }
324 372 : *sock = state->sock;
325 372 : state->sock = -1;
326 372 : tevent_req_received(req);
327 372 : 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 :
348 2498 : 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 2498 : req = tevent_req_create(mem_ctx, &state, struct smbsock_connect_state);
361 2498 : if (req == NULL) {
362 0 : return NULL;
363 : }
364 2498 : state->ev = ev;
365 2498 : state->addr = addr;
366 2498 : state->sock = -1;
367 2498 : state->called_name =
368 2498 : (called_name != NULL) ? called_name : "*SMBSERVER";
369 2498 : state->called_type =
370 : (called_type != -1) ? called_type : 0x20;
371 2498 : state->calling_name =
372 2498 : (calling_name != NULL) ? calling_name : lp_netbios_name();
373 2498 : state->calling_type =
374 : (calling_type != -1) ? calling_type : 0x00;
375 :
376 2498 : tevent_req_set_cleanup_fn(req, smbsock_connect_cleanup);
377 :
378 2498 : if (port == NBT_SMB_PORT) {
379 385 : if (lp_disable_netbios()) {
380 0 : tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
381 0 : return tevent_req_post(req, ev);
382 : }
383 :
384 1194 : state->req_139 = nb_connect_send(state, state->ev, state->addr,
385 385 : state->called_name,
386 385 : state->called_type,
387 385 : state->calling_name,
388 385 : state->calling_type);
389 385 : if (tevent_req_nomem(state->req_139, req)) {
390 0 : return tevent_req_post(req, ev);
391 : }
392 385 : tevent_req_set_callback(
393 385 : state->req_139, smbsock_connect_connected, req);
394 385 : return req;
395 : }
396 2113 : if (port != 0) {
397 0 : state->req_445 = open_socket_out_send(state, ev, addr, port,
398 : 5000);
399 0 : if (tevent_req_nomem(state->req_445, req)) {
400 0 : return tevent_req_post(req, ev);
401 : }
402 0 : tevent_req_set_callback(
403 0 : state->req_445, smbsock_connect_connected, req);
404 0 : return req;
405 : }
406 :
407 : /*
408 : * port==0, try both
409 : */
410 :
411 2113 : state->req_445 = open_socket_out_send(state, ev, addr, TCP_SMB_PORT, 5000);
412 2113 : if (tevent_req_nomem(state->req_445, req)) {
413 0 : return tevent_req_post(req, ev);
414 : }
415 2113 : tevent_req_set_callback(state->req_445, smbsock_connect_connected,
416 : req);
417 :
418 : /*
419 : * Check for disable_netbios
420 : */
421 2113 : if (lp_disable_netbios()) {
422 0 : return req;
423 : }
424 :
425 : /*
426 : * After 5 msecs, fire the 139 (NBT) request
427 : */
428 2113 : state->req_139 = tevent_wakeup_send(
429 : state, ev, timeval_current_ofs(0, 5000));
430 2113 : if (tevent_req_nomem(state->req_139, req)) {
431 0 : TALLOC_FREE(state->req_445);
432 0 : return tevent_req_post(req, ev);
433 : }
434 2113 : tevent_req_set_callback(state->req_139, smbsock_connect_do_139,
435 : req);
436 2113 : return req;
437 : }
438 :
439 4983 : static void smbsock_connect_cleanup(struct tevent_req *req,
440 : enum tevent_req_state req_state)
441 : {
442 4983 : 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 4983 : TALLOC_FREE(state->req_445);
450 4983 : TALLOC_FREE(state->req_139);
451 :
452 4983 : if (req_state == TEVENT_REQ_DONE) {
453 : /*
454 : * we keep the socket open for the caller to use
455 : */
456 2485 : return;
457 : }
458 :
459 2498 : if (state->sock != -1) {
460 0 : close(state->sock);
461 0 : state->sock = -1;
462 : }
463 :
464 2498 : return;
465 : }
466 :
467 0 : static void smbsock_connect_do_139(struct tevent_req *subreq)
468 : {
469 0 : struct tevent_req *req = tevent_req_callback_data(
470 : subreq, struct tevent_req);
471 0 : struct smbsock_connect_state *state = tevent_req_data(
472 : req, struct smbsock_connect_state);
473 : bool ret;
474 :
475 0 : ret = tevent_wakeup_recv(subreq);
476 0 : TALLOC_FREE(subreq);
477 0 : if (!ret) {
478 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
479 0 : return;
480 : }
481 0 : state->req_139 = nb_connect_send(state, state->ev, state->addr,
482 : state->called_name,
483 0 : state->called_type,
484 : state->calling_name,
485 0 : state->calling_type);
486 0 : if (tevent_req_nomem(state->req_139, req)) {
487 0 : return;
488 : }
489 0 : tevent_req_set_callback(state->req_139, smbsock_connect_connected,
490 : req);
491 : }
492 :
493 2485 : static void smbsock_connect_connected(struct tevent_req *subreq)
494 : {
495 2485 : struct tevent_req *req = tevent_req_callback_data(
496 : subreq, struct tevent_req);
497 2485 : 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 2485 : if (subreq == state->req_445) {
503 :
504 2113 : status = open_socket_out_recv(subreq, &state->sock);
505 2113 : TALLOC_FREE(state->req_445);
506 2113 : unfinished_req = state->req_139;
507 2113 : state->port = TCP_SMB_PORT;
508 :
509 372 : } else if (subreq == state->req_139) {
510 :
511 372 : status = nb_connect_recv(subreq, &state->sock);
512 372 : TALLOC_FREE(state->req_139);
513 372 : unfinished_req = state->req_445;
514 372 : state->port = NBT_SMB_PORT;
515 :
516 : } else {
517 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
518 0 : return;
519 : }
520 :
521 2485 : if (NT_STATUS_IS_OK(status)) {
522 2485 : TALLOC_FREE(unfinished_req);
523 2485 : state->req_139 = NULL;
524 2485 : state->req_445 = NULL;
525 2485 : tevent_req_done(req);
526 2485 : return;
527 : }
528 0 : if (unfinished_req == NULL) {
529 : /*
530 : * Both requests failed
531 : */
532 0 : tevent_req_nterror(req, status);
533 0 : return;
534 : }
535 : /*
536 : * Do nothing, wait for the second request to come here.
537 : */
538 : }
539 :
540 2485 : NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
541 : uint16_t *ret_port)
542 : {
543 2485 : struct smbsock_connect_state *state = tevent_req_data(
544 : req, struct smbsock_connect_state);
545 : NTSTATUS status;
546 :
547 2485 : if (tevent_req_is_nterror(req, &status)) {
548 0 : tevent_req_received(req);
549 0 : return status;
550 : }
551 2485 : *sock = state->sock;
552 2485 : state->sock = -1;
553 2485 : if (ret_port != NULL) {
554 2483 : *ret_port = state->port;
555 : }
556 2485 : tevent_req_received(req);
557 2485 : return NT_STATUS_OK;
558 : }
559 :
560 2 : 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 2 : TALLOC_CTX *frame = talloc_stackframe();
566 : struct tevent_context *ev;
567 : struct tevent_req *req;
568 2 : NTSTATUS status = NT_STATUS_NO_MEMORY;
569 :
570 2 : ev = samba_tevent_context_init(frame);
571 2 : if (ev == NULL) {
572 0 : goto fail;
573 : }
574 2 : req = smbsock_connect_send(frame, ev, addr, port,
575 : called_name, called_type,
576 : calling_name, calling_type);
577 2 : if (req == NULL) {
578 0 : goto fail;
579 : }
580 3 : if ((sec_timeout != 0) &&
581 2 : !tevent_req_set_endtime(
582 : req, ev, timeval_current_ofs(sec_timeout, 0))) {
583 0 : goto fail;
584 : }
585 2 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
586 0 : goto fail;
587 : }
588 2 : status = smbsock_connect_recv(req, pfd, ret_port);
589 2 : fail:
590 2 : TALLOC_FREE(frame);
591 2 : 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 :
620 2483 : 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 2483 : req = tevent_req_create(mem_ctx, &state,
633 : struct smbsock_any_connect_state);
634 2483 : if (req == NULL) {
635 0 : return NULL;
636 : }
637 2483 : state->ev = ev;
638 2483 : state->addrs = addrs;
639 2483 : state->num_addrs = num_addrs;
640 2483 : state->called_names = called_names;
641 2483 : state->called_types = called_types;
642 2483 : state->calling_names = calling_names;
643 2483 : state->calling_types = calling_types;
644 2483 : state->port = port;
645 2483 : state->fd = -1;
646 :
647 2483 : tevent_req_set_cleanup_fn(req, smbsock_any_connect_cleanup);
648 :
649 2483 : if (num_addrs == 0) {
650 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
651 0 : return tevent_req_post(req, ev);
652 : }
653 :
654 2483 : state->requests = talloc_zero_array(state, struct tevent_req *,
655 : num_addrs);
656 2483 : if (tevent_req_nomem(state->requests, req)) {
657 0 : return tevent_req_post(req, ev);
658 : }
659 2483 : if (!smbsock_any_connect_send_next(req, state)) {
660 0 : return tevent_req_post(req, ev);
661 : }
662 2483 : if (state->num_sent >= state->num_addrs) {
663 1215 : return req;
664 : }
665 1268 : subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 10000));
666 1268 : if (tevent_req_nomem(subreq, req)) {
667 0 : return tevent_req_post(req, ev);
668 : }
669 1268 : tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
670 1268 : return req;
671 : }
672 :
673 4966 : static void smbsock_any_connect_cleanup(struct tevent_req *req,
674 : enum tevent_req_state req_state)
675 : {
676 4966 : struct smbsock_any_connect_state *state = tevent_req_data(
677 : req, struct smbsock_any_connect_state);
678 :
679 4966 : TALLOC_FREE(state->requests);
680 :
681 4966 : if (req_state == TEVENT_REQ_DONE) {
682 : /*
683 : * Keep the socket open for the caller.
684 : */
685 2483 : return;
686 : }
687 :
688 2483 : if (state->fd != -1) {
689 0 : close(state->fd);
690 0 : state->fd = -1;
691 : }
692 : }
693 :
694 13 : static void smbsock_any_connect_trynext(struct tevent_req *subreq)
695 : {
696 13 : struct tevent_req *req = tevent_req_callback_data(
697 : subreq, struct tevent_req);
698 13 : struct smbsock_any_connect_state *state = tevent_req_data(
699 : req, struct smbsock_any_connect_state);
700 : bool ret;
701 :
702 13 : ret = tevent_wakeup_recv(subreq);
703 13 : TALLOC_FREE(subreq);
704 13 : if (!ret) {
705 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
706 0 : return;
707 : }
708 13 : if (!smbsock_any_connect_send_next(req, state)) {
709 0 : return;
710 : }
711 13 : if (state->num_sent >= state->num_addrs) {
712 13 : return;
713 : }
714 0 : subreq = tevent_wakeup_send(state, state->ev,
715 : tevent_timeval_set(0, 10000));
716 0 : if (tevent_req_nomem(subreq, req)) {
717 0 : return;
718 : }
719 0 : tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
720 : }
721 :
722 2496 : 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 2496 : if (state->num_sent >= state->num_addrs) {
728 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
729 0 : return false;
730 : }
731 17490 : subreq = smbsock_connect_send(
732 4162 : state->requests, state->ev, &state->addrs[state->num_sent],
733 2496 : state->port,
734 2496 : (state->called_names != NULL)
735 2496 : ? state->called_names[state->num_sent] : NULL,
736 2496 : (state->called_types != NULL)
737 2494 : ? state->called_types[state->num_sent] : -1,
738 2496 : (state->calling_names != NULL)
739 2494 : ? state->calling_names[state->num_sent] : NULL,
740 2496 : (state->calling_types != NULL)
741 0 : ? state->calling_types[state->num_sent] : -1);
742 2496 : if (tevent_req_nomem(subreq, req)) {
743 0 : return false;
744 : }
745 2496 : tevent_req_set_callback(subreq, smbsock_any_connect_connected, req);
746 :
747 2496 : state->requests[state->num_sent] = subreq;
748 2496 : state->num_sent += 1;
749 :
750 2496 : return true;
751 : }
752 :
753 2483 : static void smbsock_any_connect_connected(struct tevent_req *subreq)
754 : {
755 2483 : struct tevent_req *req = tevent_req_callback_data(
756 : subreq, struct tevent_req);
757 2483 : struct smbsock_any_connect_state *state = tevent_req_data(
758 : req, struct smbsock_any_connect_state);
759 : NTSTATUS status;
760 2483 : int fd = 0;
761 2483 : uint16_t chosen_port = 0;
762 : size_t i;
763 2483 : size_t chosen_index = 0;
764 :
765 2483 : for (i=0; i<state->num_sent; i++) {
766 2483 : if (state->requests[i] == subreq) {
767 2483 : chosen_index = i;
768 2483 : break;
769 : }
770 : }
771 2483 : if (i == state->num_sent) {
772 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
773 0 : return;
774 : }
775 :
776 2483 : status = smbsock_connect_recv(subreq, &fd, &chosen_port);
777 :
778 2483 : TALLOC_FREE(subreq);
779 2483 : state->requests[chosen_index] = NULL;
780 :
781 2483 : 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 2483 : state->fd = fd;
787 2483 : state->chosen_port = chosen_port;
788 2483 : state->chosen_index = chosen_index;
789 2483 : tevent_req_done(req);
790 2483 : return;
791 : }
792 :
793 0 : state->num_received += 1;
794 0 : if (state->num_received < state->num_addrs) {
795 : /*
796 : * More addrs pending, wait for the others
797 : */
798 0 : return;
799 : }
800 :
801 : /*
802 : * This is the last response, none succeeded.
803 : */
804 0 : tevent_req_nterror(req, status);
805 0 : return;
806 : }
807 :
808 2483 : NTSTATUS smbsock_any_connect_recv(struct tevent_req *req, int *pfd,
809 : size_t *chosen_index,
810 : uint16_t *chosen_port)
811 : {
812 2483 : struct smbsock_any_connect_state *state = tevent_req_data(
813 : req, struct smbsock_any_connect_state);
814 : NTSTATUS status;
815 :
816 2483 : if (tevent_req_is_nterror(req, &status)) {
817 0 : tevent_req_received(req);
818 0 : return status;
819 : }
820 2483 : *pfd = state->fd;
821 2483 : state->fd = -1;
822 2483 : if (chosen_index != NULL) {
823 2 : *chosen_index = state->chosen_index;
824 : }
825 2483 : if (chosen_port != NULL) {
826 2481 : *chosen_port = state->chosen_port;
827 : }
828 2483 : tevent_req_received(req);
829 2483 : return NT_STATUS_OK;
830 : }
831 :
832 2 : 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 2 : TALLOC_CTX *frame = talloc_stackframe();
844 : struct tevent_context *ev;
845 : struct tevent_req *req;
846 2 : NTSTATUS status = NT_STATUS_NO_MEMORY;
847 :
848 2 : ev = samba_tevent_context_init(frame);
849 2 : if (ev == NULL) {
850 0 : goto fail;
851 : }
852 2 : req = smbsock_any_connect_send(frame, ev, addrs,
853 : called_names, called_types,
854 : calling_names, calling_types,
855 : num_addrs, port);
856 2 : if (req == NULL) {
857 0 : goto fail;
858 : }
859 3 : if ((sec_timeout != 0) &&
860 2 : !tevent_req_set_endtime(
861 : req, ev, timeval_current_ofs(sec_timeout, 0))) {
862 0 : goto fail;
863 : }
864 2 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
865 0 : goto fail;
866 : }
867 2 : status = smbsock_any_connect_recv(req, pfd, chosen_index, chosen_port);
868 2 : fail:
869 2 : TALLOC_FREE(frame);
870 2 : return status;
871 : }
|