2 Unix SMB/CIFS implementation.
4 SMB2 composite connection setup
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "lib/util/tevent_ntstatus.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "libcli/raw/raw_proto.h"
27 #include "libcli/smb2/smb2.h"
28 #include "libcli/smb2/smb2_calls.h"
29 #include "libcli/composite/composite.h"
30 #include "libcli/resolve/resolve.h"
31 #include "param/param.h"
32 #include "auth/credentials/credentials.h"
33 #include "../libcli/smb/smbXcli_base.h"
35 struct smb2_connect_state {
36 struct tevent_context *ev;
37 struct cli_credentials *credentials;
38 struct resolve_context *resolve_ctx;
42 const char *socket_options;
43 struct nbt_name calling, called;
44 struct gensec_settings *gensec_settings;
45 struct smbcli_options options;
46 struct smb2_transport *transport;
47 struct smb2_tree_connect tcon;
48 struct smb2_session *session;
49 struct smb2_tree *tree;
52 static void smb2_connect_socket_done(struct composite_context *creq);
55 a composite function that does a full negprot/sesssetup/tcon, returning
58 struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
59 struct tevent_context *ev,
63 struct resolve_context *resolve_ctx,
64 struct cli_credentials *credentials,
65 struct smbcli_options *options,
66 const char *socket_options,
67 struct gensec_settings *gensec_settings)
69 struct tevent_req *req;
70 struct smb2_connect_state *state;
71 struct composite_context *creq;
72 static const char *default_ports[] = { "445", "139", NULL };
74 req = tevent_req_create(mem_ctx, &state,
75 struct smb2_connect_state);
81 state->credentials = credentials;
82 state->options = *options;
86 state->resolve_ctx = resolve_ctx;
87 state->socket_options = socket_options;
88 state->gensec_settings = gensec_settings;
90 if (state->ports == NULL) {
91 state->ports = default_ports;
94 make_nbt_name_client(&state->calling,
95 cli_credentials_get_workstation(credentials));
97 nbt_choose_called_name(state, &state->called,
98 host, NBT_NAME_SERVER);
100 creq = smbcli_sock_connect_send(state, NULL, state->ports,
101 state->host, state->resolve_ctx,
102 state->ev, state->socket_options,
105 if (tevent_req_nomem(creq, req)) {
106 return tevent_req_post(req, ev);
108 creq->async.fn = smb2_connect_socket_done;
109 creq->async.private_data = req;
114 static void smb2_connect_negprot_done(struct tevent_req *subreq);
116 static void smb2_connect_socket_done(struct composite_context *creq)
118 struct tevent_req *req =
119 talloc_get_type_abort(creq->async.private_data,
121 struct smb2_connect_state *state =
123 struct smb2_connect_state);
124 struct smbcli_socket *sock;
125 struct tevent_req *subreq;
127 uint32_t timeout_msec;
129 status = smbcli_sock_connect_recv(creq, state, &sock);
130 if (tevent_req_nterror(req, status)) {
134 state->transport = smb2_transport_init(sock, state, &state->options);
135 if (tevent_req_nomem(state->transport, req)) {
139 timeout_msec = state->transport->options.request_timeout * 1000;
141 subreq = smbXcli_negprot_send(state, state->ev,
142 state->transport->conn, timeout_msec,
143 PROTOCOL_SMB2_02, PROTOCOL_SMB2_22);
144 if (tevent_req_nomem(subreq, req)) {
147 tevent_req_set_callback(subreq, smb2_connect_negprot_done, req);
150 static void smb2_connect_session_done(struct tevent_req *subreq);
152 static void smb2_connect_negprot_done(struct tevent_req *subreq)
154 struct tevent_req *req =
155 tevent_req_callback_data(subreq,
157 struct smb2_connect_state *state =
159 struct smb2_connect_state);
160 struct smb2_transport *transport = state->transport;
163 status = smbXcli_negprot_recv(subreq);
165 if (tevent_req_nterror(req, status)) {
169 /* This is a hack... */
170 smb2cli_conn_set_max_credits(transport->conn, 30);
172 state->session = smb2_session_init(transport, state->gensec_settings, state, true);
173 if (tevent_req_nomem(state->session, req)) {
177 subreq = smb2_session_setup_spnego_send(state, state->ev,
180 0 /* previous_session_id */);
181 if (tevent_req_nomem(subreq, req)) {
184 tevent_req_set_callback(subreq, smb2_connect_session_done, req);
187 static void smb2_connect_tcon_done(struct smb2_request *smb2req);
189 static void smb2_connect_session_done(struct tevent_req *subreq)
191 struct tevent_req *req =
192 tevent_req_callback_data(subreq,
194 struct smb2_connect_state *state =
196 struct smb2_connect_state);
197 struct smb2_request *smb2req;
200 status = smb2_session_setup_spnego_recv(subreq);
202 if (tevent_req_nterror(req, status)) {
206 state->tcon.in.reserved = 0;
207 state->tcon.in.path = talloc_asprintf(state, "\\\\%s\\%s",
208 state->host, state->share);
209 if (tevent_req_nomem(state->tcon.in.path, req)) {
213 smb2req = smb2_tree_connect_send(state->session, &state->tcon);
214 if (tevent_req_nomem(smb2req, req)) {
217 smb2req->async.fn = smb2_connect_tcon_done;
218 smb2req->async.private_data = req;
221 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
223 struct tevent_req *req =
224 talloc_get_type_abort(smb2req->async.private_data,
226 struct smb2_connect_state *state =
228 struct smb2_connect_state);
231 status = smb2_tree_connect_recv(smb2req, &state->tcon);
232 if (tevent_req_nterror(req, status)) {
236 state->tree = smb2_tree_init(state->session, state, true);
237 if (tevent_req_nomem(state->tree, req)) {
241 state->tree->tid = state->tcon.out.tid;
243 tevent_req_done(req);
246 NTSTATUS smb2_connect_recv(struct tevent_req *req,
248 struct smb2_tree **tree)
250 struct smb2_connect_state *state =
252 struct smb2_connect_state);
255 if (tevent_req_is_nterror(req, &status)) {
256 tevent_req_received(req);
260 *tree = talloc_move(mem_ctx, &state->tree);
262 tevent_req_received(req);
267 sync version of smb2_connect
269 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
273 struct resolve_context *resolve_ctx,
274 struct cli_credentials *credentials,
275 struct smb2_tree **tree,
276 struct tevent_context *ev,
277 struct smbcli_options *options,
278 const char *socket_options,
279 struct gensec_settings *gensec_settings)
281 struct tevent_req *subreq;
284 TALLOC_CTX *frame = talloc_stackframe();
287 return NT_STATUS_NO_MEMORY;
290 subreq = smb2_connect_send(frame,
300 if (subreq == NULL) {
302 return NT_STATUS_NO_MEMORY;
305 ok = tevent_req_poll(subreq, ev);
307 status = map_nt_error_from_unix_common(errno);
312 status = smb2_connect_recv(subreq, mem_ctx, tree);
314 if (!NT_STATUS_IS_OK(status)) {