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 uint64_t previous_session_id;
39 struct resolve_context *resolve_ctx;
43 const char *socket_options;
44 struct nbt_name calling, called;
45 struct gensec_settings *gensec_settings;
46 struct smbcli_options options;
47 struct smb2_transport *transport;
48 struct smb2_tree_connect tcon;
49 struct smb2_session *session;
50 struct smb2_tree *tree;
53 static void smb2_connect_socket_done(struct composite_context *creq);
56 a composite function that does a full negprot/sesssetup/tcon, returning
59 struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
60 struct tevent_context *ev,
64 struct resolve_context *resolve_ctx,
65 struct cli_credentials *credentials,
66 uint64_t previous_session_id,
67 const struct smbcli_options *options,
68 const char *socket_options,
69 struct gensec_settings *gensec_settings)
71 struct tevent_req *req;
72 struct smb2_connect_state *state;
73 struct composite_context *creq;
74 static const char *default_ports[] = { "445", "139", NULL };
76 req = tevent_req_create(mem_ctx, &state,
77 struct smb2_connect_state);
83 state->credentials = credentials;
84 state->previous_session_id = previous_session_id;
85 state->options = *options;
89 state->resolve_ctx = resolve_ctx;
90 state->socket_options = socket_options;
91 state->gensec_settings = gensec_settings;
93 if (state->ports == NULL) {
94 state->ports = default_ports;
97 make_nbt_name_client(&state->calling,
98 cli_credentials_get_workstation(credentials));
100 nbt_choose_called_name(state, &state->called,
101 host, NBT_NAME_SERVER);
103 creq = smbcli_sock_connect_send(state, NULL, state->ports,
104 state->host, state->resolve_ctx,
105 state->ev, state->socket_options,
108 if (tevent_req_nomem(creq, req)) {
109 return tevent_req_post(req, ev);
111 creq->async.fn = smb2_connect_socket_done;
112 creq->async.private_data = req;
117 static void smb2_connect_negprot_done(struct tevent_req *subreq);
119 static void smb2_connect_socket_done(struct composite_context *creq)
121 struct tevent_req *req =
122 talloc_get_type_abort(creq->async.private_data,
124 struct smb2_connect_state *state =
126 struct smb2_connect_state);
127 struct smbcli_socket *sock;
128 struct tevent_req *subreq;
130 uint32_t timeout_msec;
132 status = smbcli_sock_connect_recv(creq, state, &sock);
133 if (tevent_req_nterror(req, status)) {
137 state->transport = smb2_transport_init(sock, state, &state->options);
138 if (tevent_req_nomem(state->transport, req)) {
142 timeout_msec = state->transport->options.request_timeout * 1000;
144 subreq = smbXcli_negprot_send(state, state->ev,
145 state->transport->conn, timeout_msec,
146 PROTOCOL_SMB2_02, PROTOCOL_LATEST);
147 if (tevent_req_nomem(subreq, req)) {
150 tevent_req_set_callback(subreq, smb2_connect_negprot_done, req);
153 static void smb2_connect_session_done(struct tevent_req *subreq);
155 static void smb2_connect_negprot_done(struct tevent_req *subreq)
157 struct tevent_req *req =
158 tevent_req_callback_data(subreq,
160 struct smb2_connect_state *state =
162 struct smb2_connect_state);
163 struct smb2_transport *transport = state->transport;
166 status = smbXcli_negprot_recv(subreq);
168 if (tevent_req_nterror(req, status)) {
172 /* This is a hack... */
173 smb2cli_conn_set_max_credits(transport->conn, 30);
175 state->session = smb2_session_init(transport, state->gensec_settings, state, true);
176 if (tevent_req_nomem(state->session, req)) {
180 subreq = smb2_session_setup_spnego_send(state, state->ev,
183 state->previous_session_id);
184 if (tevent_req_nomem(subreq, req)) {
187 tevent_req_set_callback(subreq, smb2_connect_session_done, req);
190 static void smb2_connect_tcon_done(struct smb2_request *smb2req);
192 static void smb2_connect_session_done(struct tevent_req *subreq)
194 struct tevent_req *req =
195 tevent_req_callback_data(subreq,
197 struct smb2_connect_state *state =
199 struct smb2_connect_state);
200 struct smb2_request *smb2req;
203 status = smb2_session_setup_spnego_recv(subreq);
205 if (tevent_req_nterror(req, status)) {
209 state->tcon.in.reserved = 0;
210 state->tcon.in.path = talloc_asprintf(state, "\\\\%s\\%s",
211 state->host, state->share);
212 if (tevent_req_nomem(state->tcon.in.path, req)) {
216 smb2req = smb2_tree_connect_send(state->session, &state->tcon);
217 if (tevent_req_nomem(smb2req, req)) {
220 smb2req->async.fn = smb2_connect_tcon_done;
221 smb2req->async.private_data = req;
224 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
226 struct tevent_req *req =
227 talloc_get_type_abort(smb2req->async.private_data,
229 struct smb2_connect_state *state =
231 struct smb2_connect_state);
234 status = smb2_tree_connect_recv(smb2req, &state->tcon);
235 if (tevent_req_nterror(req, status)) {
239 state->tree = smb2_tree_init(state->session, state, true);
240 if (tevent_req_nomem(state->tree, req)) {
244 smb2cli_tcon_set_values(state->tree->smbXcli,
245 state->session->smbXcli,
247 state->tcon.out.share_type,
248 state->tcon.out.flags,
249 state->tcon.out.capabilities,
250 state->tcon.out.access_mask);
252 tevent_req_done(req);
255 NTSTATUS smb2_connect_recv(struct tevent_req *req,
257 struct smb2_tree **tree)
259 struct smb2_connect_state *state =
261 struct smb2_connect_state);
264 if (tevent_req_is_nterror(req, &status)) {
265 tevent_req_received(req);
269 *tree = talloc_move(mem_ctx, &state->tree);
271 tevent_req_received(req);
276 sync version of smb2_connect
278 NTSTATUS smb2_connect_ext(TALLOC_CTX *mem_ctx,
282 struct resolve_context *resolve_ctx,
283 struct cli_credentials *credentials,
284 uint64_t previous_session_id,
285 struct smb2_tree **tree,
286 struct tevent_context *ev,
287 const struct smbcli_options *options,
288 const char *socket_options,
289 struct gensec_settings *gensec_settings)
291 struct tevent_req *subreq;
294 TALLOC_CTX *frame = talloc_stackframe();
297 return NT_STATUS_NO_MEMORY;
300 subreq = smb2_connect_send(frame,
311 if (subreq == NULL) {
313 return NT_STATUS_NO_MEMORY;
316 ok = tevent_req_poll(subreq, ev);
318 status = map_nt_error_from_unix_common(errno);
323 status = smb2_connect_recv(subreq, mem_ctx, tree);
325 if (!NT_STATUS_IS_OK(status)) {
334 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
338 struct resolve_context *resolve_ctx,
339 struct cli_credentials *credentials,
340 struct smb2_tree **tree,
341 struct tevent_context *ev,
342 struct smbcli_options *options,
343 const char *socket_options,
344 struct gensec_settings *gensec_settings)
348 status = smb2_connect_ext(mem_ctx, host, ports, share, resolve_ctx,
350 0, /* previous_session_id */
351 tree, ev, options, socket_options,