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