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