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/async_req/async_sock.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "../lib/util/tevent_unix.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"
30 struct cli_session_request_state {
31 struct tevent_context *ev;
35 uint8_t nb_session_response;
38 static void cli_session_request_sent(struct tevent_req *subreq);
39 static void cli_session_request_recvd(struct tevent_req *subreq);
41 static struct tevent_req *cli_session_request_send(TALLOC_CTX *mem_ctx,
42 struct tevent_context *ev,
44 const struct nmb_name *called,
45 const struct nmb_name *calling)
47 struct tevent_req *req, *subreq;
48 struct cli_session_request_state *state;
50 req = tevent_req_create(mem_ctx, &state,
51 struct cli_session_request_state);
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);
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));
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);
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));
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);
80 state->iov[0].iov_base = &state->len_hdr;
81 state->iov[0].iov_len = sizeof(state->len_hdr);
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);
87 tevent_req_set_callback(subreq, cli_session_request_sent, req);
91 static void cli_session_request_sent(struct tevent_req *subreq)
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);
100 ret = writev_recv(subreq, &err);
103 tevent_req_error(req, err);
106 subreq = read_smb_send(state, state->ev, state->sock);
107 if (tevent_req_nomem(subreq, req)) {
110 tevent_req_set_callback(subreq, cli_session_request_recvd, req);
113 static void cli_session_request_recvd(struct tevent_req *subreq)
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);
123 ret = read_smb_recv(subreq, talloc_tos(), &buf, &err);
131 tevent_req_error(req, err);
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
140 state->nb_session_response = CVAL(buf, 0);
141 tevent_req_done(req);
144 static bool cli_session_request_recv(struct tevent_req *req, int *err, uint8_t *resp)
146 struct cli_session_request_state *state = tevent_req_data(
147 req, struct cli_session_request_state);
149 if (tevent_req_is_unix_error(req, err)) {
152 *resp = state->nb_session_response;
156 struct nb_connect_state {
157 struct tevent_context *ev;
158 const struct sockaddr_storage *addr;
159 const char *called_name;
161 struct tevent_req *session_subreq;
162 struct nmb_name called;
163 struct nmb_name calling;
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);
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,
176 const char *calling_name,
179 struct tevent_req *req, *subreq;
180 struct nb_connect_state *state;
182 req = tevent_req_create(mem_ctx, &state, struct nb_connect_state);
187 state->called_name = called_name;
191 make_nmb_name(&state->called, called_name, called_type);
192 make_nmb_name(&state->calling, calling_name, calling_type);
194 tevent_req_set_cleanup_fn(req, nb_connect_cleanup);
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);
200 tevent_req_set_callback(subreq, nb_connect_connected, req);
204 static void nb_connect_cleanup(struct tevent_req *req,
205 enum tevent_req_state req_state)
207 struct nb_connect_state *state = tevent_req_data(
208 req, struct nb_connect_state);
211 * we need to free a pending request before closing the
212 * socket, see bug #11141
214 TALLOC_FREE(state->session_subreq);
216 if (req_state == TEVENT_REQ_DONE) {
218 * we keep the socket open for the caller to use
223 if (state->sock != -1) {
231 static void nb_connect_connected(struct tevent_req *subreq)
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);
239 status = open_socket_out_recv(subreq, &state->sock);
241 if (!NT_STATUS_IS_OK(status)) {
242 tevent_req_nterror(req, status);
245 subreq = cli_session_request_send(state, state->ev, state->sock,
246 &state->called, &state->calling);
247 if (tevent_req_nomem(subreq, req)) {
250 tevent_req_set_callback(subreq, nb_connect_done, req);
251 state->session_subreq = subreq;
254 static void nb_connect_done(struct tevent_req *subreq)
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);
264 state->session_subreq = NULL;
266 ret = cli_session_request_recv(subreq, &err, &resp);
269 tevent_req_nterror(req, map_nt_error_from_unix(err));
274 * RFC1002: 0x82 - POSITIVE SESSION RESPONSE
279 * The server did not like our session request
284 if (strequal(state->called_name, "*SMBSERVER")) {
286 * Here we could try a name status request and
287 * use the first 0x20 type name.
290 req, NT_STATUS_RESOURCE_NAME_NOT_FOUND);
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.
299 state->called_name = "*SMBSERVER";
300 make_nmb_name(&state->called, state->called_name, 0x20);
302 subreq = open_socket_out_send(state, state->ev, state->addr,
304 if (tevent_req_nomem(subreq, req)) {
307 tevent_req_set_callback(subreq, nb_connect_connected, req);
311 tevent_req_done(req);
315 static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
317 struct nb_connect_state *state = tevent_req_data(
318 req, struct nb_connect_state);
321 if (tevent_req_is_nterror(req, &status)) {
322 tevent_req_received(req);
327 tevent_req_received(req);
331 struct smbsock_connect_state {
332 struct tevent_context *ev;
333 const struct sockaddr_storage *addr;
334 const char *called_name;
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;
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);
352 struct tevent_req *smbsock_connect_send(TALLOC_CTX *mem_ctx,
353 struct tevent_context *ev,
354 const struct sockaddr_storage *addr,
356 const char *called_name,
358 const char *calling_name,
361 struct tevent_req *req;
362 struct smbsock_connect_state *state;
365 req = tevent_req_create(mem_ctx, &state, struct smbsock_connect_state);
373 (called_name != NULL) ? called_name : "*SMBSERVER";
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;
381 tevent_req_set_cleanup_fn(req, smbsock_connect_cleanup);
383 if (port == NBT_SMB_PORT) {
384 state->req_139 = nb_connect_send(state, state->ev, state->addr,
388 state->calling_type);
389 if (tevent_req_nomem(state->req_139, req)) {
390 return tevent_req_post(req, ev);
392 tevent_req_set_callback(
393 state->req_139, smbsock_connect_connected, req);
397 state->req_445 = open_socket_out_send(state, ev, addr, port,
399 if (tevent_req_nomem(state->req_445, req)) {
400 return tevent_req_post(req, ev);
402 tevent_req_set_callback(
403 state->req_445, smbsock_connect_connected, req);
411 status = smb_transport_direct_create(state, &state->smb_direct);
412 if (tevent_req_nterror(req, status)) {
413 return tevent_req_post(req, ev);
415 state->req_5445 = smb_transport_direct_connect_rdma_send(state, ev, state->smb_direct,
417 if (tevent_req_nomem(state->req_5445, req)) {
418 return tevent_req_post(req, ev);
420 tevent_req_set_callback(state->req_5445, smbsock_connect_do_5445,
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);
428 tevent_req_set_callback(state->req_445, smbsock_connect_connected,
432 * After 5 msecs, fire the 139 (NBT) request
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);
440 tevent_req_set_callback(state->req_139, smbsock_connect_do_139,
446 static void smbsock_connect_cleanup(struct tevent_req *req,
447 enum tevent_req_state req_state)
449 struct smbsock_connect_state *state = tevent_req_data(
450 req, struct smbsock_connect_state);
453 * we need to free a pending request before closing the
454 * socket, see bug #11141
456 TALLOC_FREE(state->req_445);
457 TALLOC_FREE(state->req_139);
459 if (req_state == TEVENT_REQ_DONE) {
461 * we keep the socket open for the caller to use
466 if (state->sock != -1) {
474 static void smbsock_connect_do_139(struct tevent_req *subreq)
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);
482 ret = tevent_wakeup_recv(subreq);
485 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
488 state->req_139 = nb_connect_send(state, state->ev, state->addr,
492 state->calling_type);
493 if (tevent_req_nomem(state->req_139, req)) {
496 tevent_req_set_callback(state->req_139, smbsock_connect_connected,
500 static void smbsock_connect_do_5445(struct tevent_req *subreq)
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);
508 status = smb_transport_direct_connect_rdma_recv(subreq);
510 if (tevent_req_nterror(req, status)) {
514 state->req_5445 = smb_transport_direct_connect_negotiate_send(state,
517 if (tevent_req_nomem(state->req_5445, req)) {
520 tevent_req_set_callback(state->req_5445, smbsock_connect_connected,
524 static void smbsock_connect_connected(struct tevent_req *subreq)
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);
532 if (subreq == state->req_5445) {
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;
540 } else if (subreq == state->req_445) {
542 status = open_socket_out_recv(subreq, &state->sock);
543 TALLOC_FREE(state->req_445);
544 state->port = TCP_SMB_PORT;
546 } else if (subreq == state->req_139) {
548 status = nb_connect_recv(subreq, &state->sock);
549 TALLOC_FREE(state->req_139);
550 state->port = NBT_SMB_PORT;
553 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
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);
564 if ((state->req_5445 == NULL) &&
565 (state->req_445 == NULL) &&
566 (state->req_139 == NULL))
569 * All requests failed
571 tevent_req_nterror(req, status);
575 * Do nothing, wait for the second request to come here.
579 NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
582 struct smbsock_connect_state *state = tevent_req_data(
583 req, struct smbsock_connect_state);
586 if (tevent_req_is_nterror(req, &status)) {
587 tevent_req_received(req);
592 if (ret_port != NULL) {
593 *ret_port = state->port;
595 tevent_req_received(req);
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)
604 TALLOC_CTX *frame = talloc_stackframe();
605 struct tevent_context *ev;
606 struct tevent_req *req;
607 NTSTATUS status = NT_STATUS_NO_MEMORY;
609 ev = samba_tevent_context_init(frame);
613 req = smbsock_connect_send(frame, ev, addr, port,
614 called_name, called_type,
615 calling_name, calling_type);
619 if ((sec_timeout != 0) &&
620 !tevent_req_set_endtime(
621 req, ev, timeval_current_ofs(sec_timeout, 0))) {
624 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
627 status = smbsock_connect_recv(req, pfd, ret_port);
633 struct smbsock_any_connect_state {
634 struct tevent_context *ev;
635 const struct sockaddr_storage *addrs;
636 const char **called_names;
638 const char **calling_names;
643 struct tevent_req **requests;
648 uint16_t chosen_port;
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);
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,
664 const char **calling_names,
666 size_t num_addrs, uint16_t port)
668 struct tevent_req *req, *subreq;
669 struct smbsock_any_connect_state *state;
671 req = tevent_req_create(mem_ctx, &state,
672 struct smbsock_any_connect_state);
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;
686 tevent_req_set_cleanup_fn(req, smbsock_any_connect_cleanup);
688 if (num_addrs == 0) {
689 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
690 return tevent_req_post(req, ev);
693 state->requests = talloc_zero_array(state, struct tevent_req *,
695 if (tevent_req_nomem(state->requests, req)) {
696 return tevent_req_post(req, ev);
698 if (!smbsock_any_connect_send_next(req, state)) {
699 return tevent_req_post(req, ev);
701 if (state->num_sent >= state->num_addrs) {
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);
708 tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
712 static void smbsock_any_connect_cleanup(struct tevent_req *req,
713 enum tevent_req_state req_state)
715 struct smbsock_any_connect_state *state = tevent_req_data(
716 req, struct smbsock_any_connect_state);
718 TALLOC_FREE(state->requests);
720 if (req_state == TEVENT_REQ_DONE) {
722 * Keep the socket open for the caller.
727 if (state->fd != -1) {
733 static void smbsock_any_connect_trynext(struct tevent_req *subreq)
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);
741 ret = tevent_wakeup_recv(subreq);
744 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
747 if (!smbsock_any_connect_send_next(req, state)) {
750 if (state->num_sent >= state->num_addrs) {
753 subreq = tevent_wakeup_send(state, state->ev,
754 tevent_timeval_set(0, 10000));
755 if (tevent_req_nomem(subreq, req)) {
758 tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
761 static bool smbsock_any_connect_send_next(
762 struct tevent_req *req, struct smbsock_any_connect_state *state)
764 struct tevent_req *subreq;
766 if (state->num_sent >= state->num_addrs) {
767 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
770 subreq = smbsock_connect_send(
771 state->requests, state->ev, &state->addrs[state->num_sent],
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)) {
784 tevent_req_set_callback(subreq, smbsock_any_connect_connected, req);
786 state->requests[state->num_sent] = subreq;
787 state->num_sent += 1;
792 static void smbsock_any_connect_connected(struct tevent_req *subreq)
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);
800 uint16_t chosen_port;
802 size_t chosen_index = 0;
804 for (i=0; i<state->num_sent; i++) {
805 if (state->requests[i] == subreq) {
810 if (i == state->num_sent) {
811 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
815 status = smbsock_connect_recv(subreq, &fd, &chosen_port);
818 state->requests[chosen_index] = NULL;
820 if (NT_STATUS_IS_OK(status)) {
822 * tevent_req_done() will kill all the other requests
823 * via smbsock_any_connect_cleanup().
826 state->chosen_port = chosen_port;
827 state->chosen_index = chosen_index;
828 tevent_req_done(req);
832 state->num_received += 1;
833 if (state->num_received < state->num_addrs) {
835 * More addrs pending, wait for the others
841 * This is the last response, none succeeded.
843 tevent_req_nterror(req, status);
847 NTSTATUS smbsock_any_connect_recv(struct tevent_req *req, int *pfd,
848 size_t *chosen_index,
849 uint16_t *chosen_port)
851 struct smbsock_any_connect_state *state = tevent_req_data(
852 req, struct smbsock_any_connect_state);
855 if (tevent_req_is_nterror(req, &status)) {
856 tevent_req_received(req);
861 if (chosen_index != NULL) {
862 *chosen_index = state->chosen_index;
864 if (chosen_port != NULL) {
865 *chosen_port = state->chosen_port;
867 tevent_req_received(req);
871 NTSTATUS smbsock_any_connect(const struct sockaddr_storage *addrs,
872 const char **called_names,
874 const char **calling_names,
879 int *pfd, size_t *chosen_index,
880 uint16_t *chosen_port)
882 TALLOC_CTX *frame = talloc_stackframe();
883 struct tevent_context *ev;
884 struct tevent_req *req;
885 NTSTATUS status = NT_STATUS_NO_MEMORY;
887 ev = samba_tevent_context_init(frame);
891 req = smbsock_any_connect_send(frame, ev, addrs,
892 called_names, called_types,
893 calling_names, calling_types,
898 if ((sec_timeout != 0) &&
899 !tevent_req_set_endtime(
900 req, ev, timeval_current_ofs(sec_timeout, 0))) {
903 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
906 status = smbsock_any_connect_recv(req, pfd, chosen_index, chosen_port);