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"
33 struct smb2_connect_state {
34 struct tevent_context *ev;
35 struct cli_credentials *credentials;
36 struct resolve_context *resolve_ctx;
40 const char *socket_options;
41 struct gensec_settings *gensec_settings;
42 struct smbcli_options options;
43 struct smb2_negprot negprot;
44 struct smb2_tree_connect tcon;
45 struct smb2_session *session;
46 struct smb2_tree *tree;
49 static void smb2_connect_resolve_done(struct composite_context *creq);
52 a composite function that does a full negprot/sesssetup/tcon, returning
55 struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
56 struct tevent_context *ev,
60 struct resolve_context *resolve_ctx,
61 struct cli_credentials *credentials,
62 struct smbcli_options *options,
63 const char *socket_options,
64 struct gensec_settings *gensec_settings)
66 struct tevent_req *req;
67 struct smb2_connect_state *state;
69 struct composite_context *creq;
71 req = tevent_req_create(mem_ctx, &state,
72 struct smb2_connect_state);
78 state->credentials = credentials;
79 state->options = *options;
83 state->resolve_ctx = resolve_ctx;
84 state->socket_options = socket_options;
85 state->gensec_settings = gensec_settings;
90 creq = resolve_name_send(resolve_ctx, state, &name, ev);
91 if (tevent_req_nomem(creq, req)) {
92 return tevent_req_post(req, ev);
94 creq->async.fn = smb2_connect_resolve_done;
95 creq->async.private_data = req;
99 static void smb2_connect_socket_done(struct composite_context *creq);
101 static void smb2_connect_resolve_done(struct composite_context *creq)
103 struct tevent_req *req =
104 talloc_get_type_abort(creq->async.private_data,
106 struct smb2_connect_state *state =
108 struct smb2_connect_state);
112 const char *default_ports[] = { "445", NULL };
114 status = resolve_name_recv(creq, state, &addr);
115 if (tevent_req_nterror(req, status)) {
119 if (state->ports == NULL) {
120 ports = default_ports;
122 ports = state->ports;
125 creq = smbcli_sock_connect_send(state, addr, ports,
126 state->host, state->resolve_ctx,
127 state->ev, state->socket_options);
128 if (tevent_req_nomem(creq, req)) {
131 creq->async.fn = smb2_connect_socket_done;
132 creq->async.private_data = req;
135 static void smb2_connect_negprot_done(struct smb2_request *smb2req);
137 static void smb2_connect_socket_done(struct composite_context *creq)
139 struct tevent_req *req =
140 talloc_get_type_abort(creq->async.private_data,
142 struct smb2_connect_state *state =
144 struct smb2_connect_state);
145 struct smbcli_socket *sock;
146 struct smb2_transport *transport;
147 struct smb2_request *smb2req;
149 uint16_t dialects[3] = {
150 SMB2_DIALECT_REVISION_000,
151 SMB2_DIALECT_REVISION_202,
152 SMB2_DIALECT_REVISION_210
155 status = smbcli_sock_connect_recv(creq, state, &sock);
156 if (tevent_req_nterror(req, status)) {
160 transport = smb2_transport_init(sock, state, &state->options);
161 if (tevent_req_nomem(transport, req)) {
165 ZERO_STRUCT(state->negprot);
166 state->negprot.in.dialect_count = ARRAY_SIZE(dialects);
167 switch (transport->options.signing) {
168 case SMB_SIGNING_OFF:
169 state->negprot.in.security_mode = 0;
171 case SMB_SIGNING_DEFAULT:
172 case SMB_SIGNING_SUPPORTED:
173 state->negprot.in.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
175 case SMB_SIGNING_REQUIRED:
176 state->negprot.in.security_mode =
177 SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
180 state->negprot.in.capabilities = 0;
181 unix_to_nt_time(&state->negprot.in.start_time, time(NULL));
182 state->negprot.in.dialects = dialects;
184 smb2req = smb2_negprot_send(transport, &state->negprot);
185 if (tevent_req_nomem(smb2req, req)) {
188 smb2req->async.fn = smb2_connect_negprot_done;
189 smb2req->async.private_data = req;
192 static void smb2_connect_session_done(struct tevent_req *subreq);
194 static void smb2_connect_negprot_done(struct smb2_request *smb2req)
196 struct tevent_req *req =
197 talloc_get_type_abort(smb2req->async.private_data,
199 struct smb2_connect_state *state =
201 struct smb2_connect_state);
202 struct smb2_transport *transport = smb2req->transport;
203 struct tevent_req *subreq;
206 status = smb2_negprot_recv(smb2req, state, &state->negprot);
207 if (tevent_req_nterror(req, status)) {
211 transport->negotiate.secblob = state->negprot.out.secblob;
212 talloc_steal(transport, transport->negotiate.secblob.data);
213 transport->negotiate.system_time = state->negprot.out.system_time;
214 transport->negotiate.server_start_time = state->negprot.out.server_start_time;
215 transport->negotiate.security_mode = state->negprot.out.security_mode;
216 transport->negotiate.dialect_revision = state->negprot.out.dialect_revision;
218 switch (transport->options.signing) {
219 case SMB_SIGNING_OFF:
220 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
221 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
224 transport->signing_required = false;
226 case SMB_SIGNING_DEFAULT:
227 case SMB_SIGNING_SUPPORTED:
228 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
229 transport->signing_required = true;
231 transport->signing_required = false;
234 case SMB_SIGNING_REQUIRED:
235 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED) {
236 transport->signing_required = true;
238 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
244 state->session = smb2_session_init(transport, state->gensec_settings, state, true);
245 if (tevent_req_nomem(state->session, req)) {
249 subreq = smb2_session_setup_spnego_send(state, state->ev,
252 if (tevent_req_nomem(subreq, req)) {
255 tevent_req_set_callback(subreq, smb2_connect_session_done, req);
258 static void smb2_connect_tcon_done(struct smb2_request *smb2req);
260 static void smb2_connect_session_done(struct tevent_req *subreq)
262 struct tevent_req *req =
263 tevent_req_callback_data(subreq,
265 struct smb2_connect_state *state =
267 struct smb2_connect_state);
268 struct smb2_request *smb2req;
271 status = smb2_session_setup_spnego_recv(subreq);
273 if (tevent_req_nterror(req, status)) {
277 state->tree = smb2_tree_init(state->session, state, true);
278 if (tevent_req_nomem(state->tree, req)) {
282 state->tcon.in.reserved = 0;
283 state->tcon.in.path = talloc_asprintf(state, "\\\\%s\\%s",
284 state->host, state->share);
285 if (tevent_req_nomem(state->tcon.in.path, req)) {
289 smb2req = smb2_tree_connect_send(state->tree, &state->tcon);
290 if (tevent_req_nomem(smb2req, req)) {
293 smb2req->async.fn = smb2_connect_tcon_done;
294 smb2req->async.private_data = req;
297 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
299 struct tevent_req *req =
300 talloc_get_type_abort(smb2req->async.private_data,
302 struct smb2_connect_state *state =
304 struct smb2_connect_state);
307 status = smb2_tree_connect_recv(smb2req, &state->tcon);
308 if (tevent_req_nterror(req, status)) {
312 state->tree->tid = state->tcon.out.tid;
314 tevent_req_done(req);
317 NTSTATUS smb2_connect_recv(struct tevent_req *req,
319 struct smb2_tree **tree)
321 struct smb2_connect_state *state =
323 struct smb2_connect_state);
326 if (tevent_req_is_nterror(req, &status)) {
327 tevent_req_received(req);
331 *tree = talloc_move(mem_ctx, &state->tree);
333 tevent_req_received(req);
338 sync version of smb2_connect
340 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
344 struct resolve_context *resolve_ctx,
345 struct cli_credentials *credentials,
346 struct smb2_tree **tree,
347 struct tevent_context *ev,
348 struct smbcli_options *options,
349 const char *socket_options,
350 struct gensec_settings *gensec_settings)
352 struct tevent_req *subreq;
355 TALLOC_CTX *frame = talloc_stackframe();
358 return NT_STATUS_NO_MEMORY;
361 subreq = smb2_connect_send(frame,
371 if (subreq == NULL) {
373 return NT_STATUS_NO_MEMORY;
376 ok = tevent_req_poll(subreq, ev);
378 status = map_nt_error_from_unix_common(errno);
383 status = smb2_connect_recv(subreq, mem_ctx, tree);
385 if (!NT_STATUS_IS_OK(status)) {