2 Unix SMB/CIFS implementation.
3 Connect to 445 and 139/nbsesssetup
4 Copyright (C) Volker Lendecke 2010
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.
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.
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/>.
21 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
24 #include "libsmb/nmblib.h"
26 struct nb_connect_state
{
27 struct tevent_context
*ev
;
28 const struct sockaddr_storage
*addr
;
29 const char *called_name
;
32 struct nmb_name called
;
33 struct nmb_name calling
;
36 static int nb_connect_state_destructor(struct nb_connect_state
*state
);
37 static void nb_connect_connected(struct tevent_req
*subreq
);
38 static void nb_connect_done(struct tevent_req
*subreq
);
40 static struct tevent_req
*nb_connect_send(TALLOC_CTX
*mem_ctx
,
41 struct tevent_context
*ev
,
42 const struct sockaddr_storage
*addr
,
43 const char *called_name
,
45 const char *calling_name
,
48 struct tevent_req
*req
, *subreq
;
49 struct nb_connect_state
*state
;
51 req
= tevent_req_create(mem_ctx
, &state
, struct nb_connect_state
);
56 state
->called_name
= called_name
;
60 make_nmb_name(&state
->called
, called_name
, called_type
);
61 make_nmb_name(&state
->calling
, calling_name
, calling_type
);
63 talloc_set_destructor(state
, nb_connect_state_destructor
);
65 subreq
= open_socket_out_send(state
, ev
, addr
, 139, 5000);
66 if (tevent_req_nomem(subreq
, req
)) {
67 return tevent_req_post(req
, ev
);
69 tevent_req_set_callback(subreq
, nb_connect_connected
, req
);
73 static int nb_connect_state_destructor(struct nb_connect_state
*state
)
75 if (state
->sock
!= -1) {
81 static void nb_connect_connected(struct tevent_req
*subreq
)
83 struct tevent_req
*req
= tevent_req_callback_data(
84 subreq
, struct tevent_req
);
85 struct nb_connect_state
*state
= tevent_req_data(
86 req
, struct nb_connect_state
);
89 status
= open_socket_out_recv(subreq
, &state
->sock
);
91 if (!NT_STATUS_IS_OK(status
)) {
92 tevent_req_nterror(req
, status
);
95 subreq
= cli_session_request_send(state
, state
->ev
, state
->sock
,
96 &state
->called
, &state
->calling
);
97 if (tevent_req_nomem(subreq
, req
)) {
100 tevent_req_set_callback(subreq
, nb_connect_done
, req
);
103 static void nb_connect_done(struct tevent_req
*subreq
)
105 struct tevent_req
*req
= tevent_req_callback_data(
106 subreq
, struct tevent_req
);
107 struct nb_connect_state
*state
= tevent_req_data(
108 req
, struct nb_connect_state
);
113 ret
= cli_session_request_recv(subreq
, &err
, &resp
);
116 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
121 * RFC1002: 0x82 - POSITIVE SESSION RESPONSE
126 * The server did not like our session request
131 if (strequal(state
->called_name
, "*SMBSERVER")) {
133 * Here we could try a name status request and
134 * use the first 0x20 type name.
137 req
, NT_STATUS_RESOURCE_NAME_NOT_FOUND
);
142 * We could be subtle and distinguish between
143 * different failure modes, but what we do here
144 * instead is just retry with *SMBSERVER type 0x20.
146 state
->called_name
= "*SMBSERVER";
147 make_nmb_name(&state
->called
, state
->called_name
, 0x20);
149 subreq
= open_socket_out_send(state
, state
->ev
, state
->addr
,
151 if (tevent_req_nomem(subreq
, req
)) {
154 tevent_req_set_callback(subreq
, nb_connect_connected
, req
);
158 tevent_req_done(req
);
163 static NTSTATUS
nb_connect_recv(struct tevent_req
*req
, int *sock
)
165 struct nb_connect_state
*state
= tevent_req_data(
166 req
, struct nb_connect_state
);
169 if (tevent_req_is_nterror(req
, &status
)) {
177 struct smbsock_connect_state
{
178 struct tevent_context
*ev
;
179 const struct sockaddr_storage
*addr
;
180 const char *called_name
;
182 const char *calling_name
;
183 uint8_t calling_type
;
184 struct tevent_req
*req_139
;
185 struct tevent_req
*req_445
;
190 static int smbsock_connect_state_destructor(
191 struct smbsock_connect_state
*state
);
192 static void smbsock_connect_connected(struct tevent_req
*subreq
);
193 static void smbsock_connect_do_139(struct tevent_req
*subreq
);
195 struct tevent_req
*smbsock_connect_send(TALLOC_CTX
*mem_ctx
,
196 struct tevent_context
*ev
,
197 const struct sockaddr_storage
*addr
,
199 const char *called_name
,
201 const char *calling_name
,
204 struct tevent_req
*req
, *subreq
;
205 struct smbsock_connect_state
*state
;
207 req
= tevent_req_create(mem_ctx
, &state
, struct smbsock_connect_state
);
215 (called_name
!= NULL
) ? called_name
: "*SMBSERVER";
217 (called_type
!= -1) ? called_type
: 0x20;
218 state
->calling_name
=
219 (calling_name
!= NULL
) ? calling_name
: global_myname();
220 state
->calling_type
=
221 (calling_type
!= -1) ? calling_type
: 0x00;
223 talloc_set_destructor(state
, smbsock_connect_state_destructor
);
226 subreq
= tevent_wakeup_send(state
, ev
, timeval_set(0, 0));
227 if (tevent_req_nomem(subreq
, req
)) {
228 return tevent_req_post(req
, ev
);
230 tevent_req_set_callback(subreq
, smbsock_connect_do_139
, req
);
234 state
->req_445
= open_socket_out_send(state
, ev
, addr
, port
,
236 if (tevent_req_nomem(state
->req_445
, req
)) {
237 return tevent_req_post(req
, ev
);
239 tevent_req_set_callback(
240 state
->req_445
, smbsock_connect_connected
, req
);
248 state
->req_445
= open_socket_out_send(state
, ev
, addr
, 445, 5000);
249 if (tevent_req_nomem(state
->req_445
, req
)) {
250 return tevent_req_post(req
, ev
);
252 tevent_req_set_callback(state
->req_445
, smbsock_connect_connected
,
256 * After 5 msecs, fire the 139 request
258 state
->req_139
= tevent_wakeup_send(
259 state
, ev
, timeval_current_ofs(0, 5000));
260 if (tevent_req_nomem(state
->req_139
, req
)) {
261 TALLOC_FREE(state
->req_445
);
262 return tevent_req_post(req
, ev
);
264 tevent_req_set_callback(state
->req_139
, smbsock_connect_do_139
,
269 static int smbsock_connect_state_destructor(
270 struct smbsock_connect_state
*state
)
272 if (state
->sock
!= -1) {
279 static void smbsock_connect_do_139(struct tevent_req
*subreq
)
281 struct tevent_req
*req
= tevent_req_callback_data(
282 subreq
, struct tevent_req
);
283 struct smbsock_connect_state
*state
= tevent_req_data(
284 req
, struct smbsock_connect_state
);
287 ret
= tevent_wakeup_recv(subreq
);
290 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
293 state
->req_139
= nb_connect_send(state
, state
->ev
, state
->addr
,
297 state
->calling_type
);
298 if (tevent_req_nomem(state
->req_139
, req
)) {
301 tevent_req_set_callback(state
->req_139
, smbsock_connect_connected
,
305 static void smbsock_connect_connected(struct tevent_req
*subreq
)
307 struct tevent_req
*req
= tevent_req_callback_data(
308 subreq
, struct tevent_req
);
309 struct smbsock_connect_state
*state
= tevent_req_data(
310 req
, struct smbsock_connect_state
);
311 struct tevent_req
*unfinished_req
;
314 if (subreq
== state
->req_445
) {
316 status
= open_socket_out_recv(subreq
, &state
->sock
);
317 TALLOC_FREE(state
->req_445
);
318 unfinished_req
= state
->req_139
;
321 } else if (subreq
== state
->req_139
) {
323 status
= nb_connect_recv(subreq
, &state
->sock
);
324 TALLOC_FREE(state
->req_139
);
325 unfinished_req
= state
->req_445
;
329 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
333 if (NT_STATUS_IS_OK(status
)) {
334 TALLOC_FREE(unfinished_req
);
335 state
->req_139
= NULL
;
336 state
->req_445
= NULL
;
337 tevent_req_done(req
);
340 if (unfinished_req
== NULL
) {
342 * Both requests failed
344 tevent_req_nterror(req
, status
);
348 * Do nothing, wait for the second request to come here.
352 NTSTATUS
smbsock_connect_recv(struct tevent_req
*req
, int *sock
,
355 struct smbsock_connect_state
*state
= tevent_req_data(
356 req
, struct smbsock_connect_state
);
359 if (tevent_req_is_nterror(req
, &status
)) {
364 if (ret_port
!= NULL
) {
365 *ret_port
= state
->port
;
370 NTSTATUS
smbsock_connect(const struct sockaddr_storage
*addr
, uint16_t port
,
371 const char *called_name
, int called_type
,
372 const char *calling_name
, int calling_type
,
373 int *pfd
, uint16_t *ret_port
, int sec_timeout
)
375 TALLOC_CTX
*frame
= talloc_stackframe();
376 struct event_context
*ev
;
377 struct tevent_req
*req
;
378 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
380 ev
= event_context_init(frame
);
384 req
= smbsock_connect_send(frame
, ev
, addr
, port
,
385 called_name
, called_type
,
386 calling_name
, calling_type
);
390 if ((sec_timeout
!= 0) &&
391 !tevent_req_set_endtime(
392 req
, ev
, timeval_current_ofs(sec_timeout
, 0))) {
395 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
398 status
= smbsock_connect_recv(req
, pfd
, ret_port
);
404 struct smbsock_any_connect_state
{
405 struct tevent_context
*ev
;
406 const struct sockaddr_storage
*addrs
;
407 const char **called_names
;
409 const char **calling_names
;
414 struct tevent_req
**requests
;
419 uint16_t chosen_port
;
423 static bool smbsock_any_connect_send_next(
424 struct tevent_req
*req
, struct smbsock_any_connect_state
*state
);
425 static void smbsock_any_connect_trynext(struct tevent_req
*subreq
);
426 static void smbsock_any_connect_connected(struct tevent_req
*subreq
);
428 struct tevent_req
*smbsock_any_connect_send(TALLOC_CTX
*mem_ctx
,
429 struct tevent_context
*ev
,
430 const struct sockaddr_storage
*addrs
,
431 const char **called_names
,
433 const char **calling_names
,
435 size_t num_addrs
, uint16_t port
)
437 struct tevent_req
*req
, *subreq
;
438 struct smbsock_any_connect_state
*state
;
440 req
= tevent_req_create(mem_ctx
, &state
,
441 struct smbsock_any_connect_state
);
446 state
->addrs
= addrs
;
447 state
->num_addrs
= num_addrs
;
448 state
->called_names
= called_names
;
449 state
->called_types
= called_types
;
450 state
->calling_names
= calling_names
;
451 state
->calling_types
= calling_types
;
454 if (num_addrs
== 0) {
455 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
456 return tevent_req_post(req
, ev
);
459 state
->requests
= talloc_zero_array(state
, struct tevent_req
*,
461 if (tevent_req_nomem(state
->requests
, req
)) {
462 return tevent_req_post(req
, ev
);
464 if (!smbsock_any_connect_send_next(req
, state
)) {
465 return tevent_req_post(req
, ev
);
467 if (state
->num_sent
>= state
->num_addrs
) {
470 subreq
= tevent_wakeup_send(state
, ev
, timeval_current_ofs(0, 10000));
471 if (tevent_req_nomem(subreq
, req
)) {
472 return tevent_req_post(req
, ev
);
474 tevent_req_set_callback(subreq
, smbsock_any_connect_trynext
, req
);
478 static void smbsock_any_connect_trynext(struct tevent_req
*subreq
)
480 struct tevent_req
*req
= tevent_req_callback_data(
481 subreq
, struct tevent_req
);
482 struct smbsock_any_connect_state
*state
= tevent_req_data(
483 req
, struct smbsock_any_connect_state
);
486 ret
= tevent_wakeup_recv(subreq
);
489 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
492 if (!smbsock_any_connect_send_next(req
, state
)) {
495 if (state
->num_sent
>= state
->num_addrs
) {
498 subreq
= tevent_wakeup_send(state
, state
->ev
,
499 tevent_timeval_set(0, 10000));
500 if (tevent_req_nomem(subreq
, req
)) {
503 tevent_req_set_callback(subreq
, smbsock_any_connect_trynext
, req
);
506 static bool smbsock_any_connect_send_next(
507 struct tevent_req
*req
, struct smbsock_any_connect_state
*state
)
509 struct tevent_req
*subreq
;
511 if (state
->num_sent
>= state
->num_addrs
) {
512 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
515 subreq
= smbsock_connect_send(
516 state
->requests
, state
->ev
, &state
->addrs
[state
->num_sent
],
518 (state
->called_names
!= NULL
)
519 ? state
->called_names
[state
->num_sent
] : NULL
,
520 (state
->called_types
!= NULL
)
521 ? state
->called_types
[state
->num_sent
] : -1,
522 (state
->calling_names
!= NULL
)
523 ? state
->calling_names
[state
->num_sent
] : NULL
,
524 (state
->calling_types
!= NULL
)
525 ? state
->calling_types
[state
->num_sent
] : -1);
526 if (tevent_req_nomem(subreq
, req
)) {
529 tevent_req_set_callback(subreq
, smbsock_any_connect_connected
, req
);
531 state
->requests
[state
->num_sent
] = subreq
;
532 state
->num_sent
+= 1;
537 static void smbsock_any_connect_connected(struct tevent_req
*subreq
)
539 struct tevent_req
*req
= tevent_req_callback_data(
540 subreq
, struct tevent_req
);
541 struct smbsock_any_connect_state
*state
= tevent_req_data(
542 req
, struct smbsock_any_connect_state
);
545 uint16_t chosen_port
;
547 size_t chosen_index
= 0;
549 for (i
=0; i
<state
->num_sent
; i
++) {
550 if (state
->requests
[i
] == subreq
) {
555 if (i
== state
->num_sent
) {
556 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
560 status
= smbsock_connect_recv(subreq
, &fd
, &chosen_port
);
563 state
->requests
[chosen_index
] = NULL
;
565 if (NT_STATUS_IS_OK(status
)) {
567 * This will kill all the other requests
569 TALLOC_FREE(state
->requests
);
571 state
->chosen_port
= chosen_port
;
572 state
->chosen_index
= chosen_index
;
573 tevent_req_done(req
);
577 state
->num_received
+= 1;
578 if (state
->num_received
<= state
->num_addrs
) {
580 * More addrs pending, wait for the others
586 * This is the last response, none succeeded.
588 tevent_req_nterror(req
, status
);
592 NTSTATUS
smbsock_any_connect_recv(struct tevent_req
*req
, int *pfd
,
593 size_t *chosen_index
,
594 uint16_t *chosen_port
)
596 struct smbsock_any_connect_state
*state
= tevent_req_data(
597 req
, struct smbsock_any_connect_state
);
600 if (tevent_req_is_nterror(req
, &status
)) {
604 if (chosen_index
!= NULL
) {
605 *chosen_index
= state
->chosen_index
;
607 if (chosen_port
!= NULL
) {
608 *chosen_port
= state
->chosen_port
;
613 NTSTATUS
smbsock_any_connect(const struct sockaddr_storage
*addrs
,
614 const char **called_names
,
616 const char **calling_names
,
621 int *pfd
, size_t *chosen_index
,
622 uint16_t *chosen_port
)
624 TALLOC_CTX
*frame
= talloc_stackframe();
625 struct event_context
*ev
;
626 struct tevent_req
*req
;
627 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
629 ev
= event_context_init(frame
);
633 req
= smbsock_any_connect_send(frame
, ev
, addrs
,
634 called_names
, called_types
,
635 calling_names
, calling_types
,
640 if ((sec_timeout
!= 0) &&
641 !tevent_req_set_endtime(
642 req
, ev
, timeval_current_ofs(sec_timeout
, 0))) {
645 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
648 status
= smbsock_any_connect_recv(req
, pfd
, chosen_index
, chosen_port
);