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_tcon_done(struct smb2_request *smb2req)
51 struct tevent_req *req =
52 talloc_get_type_abort(smb2req->async.private_data,
54 struct smb2_connect_state *state =
56 struct smb2_connect_state);
59 status = smb2_tree_connect_recv(smb2req, &state->tcon);
60 if (tevent_req_nterror(req, status)) {
64 state->tree->tid = state->tcon.out.tid;
69 static void smb2_connect_session_done(struct composite_context *creq)
71 struct tevent_req *req =
72 talloc_get_type_abort(creq->async.private_data,
74 struct smb2_connect_state *state =
76 struct smb2_connect_state);
77 struct smb2_request *smb2req;
80 status = smb2_session_setup_spnego_recv(creq);
81 if (tevent_req_nterror(req, status)) {
85 state->tree = smb2_tree_init(state->session, state, true);
86 if (tevent_req_nomem(state->tree, req)) {
90 state->tcon.in.reserved = 0;
91 state->tcon.in.path = talloc_asprintf(state, "\\\\%s\\%s",
92 state->host, state->share);
93 if (tevent_req_nomem(state->tcon.in.path, req)) {
97 smb2req = smb2_tree_connect_send(state->tree, &state->tcon);
98 if (tevent_req_nomem(smb2req, req)) {
101 smb2req->async.fn = smb2_connect_tcon_done;
102 smb2req->async.private_data = req;
105 static void smb2_connect_negprot_done(struct smb2_request *smb2req)
107 struct tevent_req *req =
108 talloc_get_type_abort(smb2req->async.private_data,
110 struct smb2_connect_state *state =
112 struct smb2_connect_state);
113 struct smb2_transport *transport = smb2req->transport;
114 struct composite_context *creq;
117 status = smb2_negprot_recv(smb2req, state, &state->negprot);
118 if (tevent_req_nterror(req, status)) {
122 transport->negotiate.secblob = state->negprot.out.secblob;
123 talloc_steal(transport, transport->negotiate.secblob.data);
124 transport->negotiate.system_time = state->negprot.out.system_time;
125 transport->negotiate.server_start_time = state->negprot.out.server_start_time;
126 transport->negotiate.security_mode = state->negprot.out.security_mode;
127 transport->negotiate.dialect_revision = state->negprot.out.dialect_revision;
129 switch (transport->options.signing) {
130 case SMB_SIGNING_OFF:
131 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
132 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
135 transport->signing_required = false;
137 case SMB_SIGNING_SUPPORTED:
138 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
139 transport->signing_required = true;
141 transport->signing_required = false;
144 case SMB_SIGNING_AUTO:
145 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED) {
146 transport->signing_required = true;
148 transport->signing_required = false;
151 case SMB_SIGNING_REQUIRED:
152 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED) {
153 transport->signing_required = true;
155 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
161 state->session = smb2_session_init(transport, state->gensec_settings, state, true);
162 if (tevent_req_nomem(state->session, req)) {
166 creq = smb2_session_setup_spnego_send(state->session, state->credentials);
167 if (tevent_req_nomem(creq, req)) {
170 creq->async.fn = smb2_connect_session_done;
171 creq->async.private_data = req;
174 static void smb2_connect_socket_done(struct composite_context *creq)
176 struct tevent_req *req =
177 talloc_get_type_abort(creq->async.private_data,
179 struct smb2_connect_state *state =
181 struct smb2_connect_state);
182 struct smbcli_socket *sock;
183 struct smb2_transport *transport;
184 struct smb2_request *smb2req;
186 uint16_t dialects[3] = {
187 SMB2_DIALECT_REVISION_000,
188 SMB2_DIALECT_REVISION_202,
189 SMB2_DIALECT_REVISION_210
192 status = smbcli_sock_connect_recv(creq, state, &sock);
193 if (tevent_req_nterror(req, status)) {
197 transport = smb2_transport_init(sock, state, &state->options);
198 if (tevent_req_nomem(transport, req)) {
202 ZERO_STRUCT(state->negprot);
203 state->negprot.in.dialect_count = ARRAY_SIZE(dialects);
204 switch (transport->options.signing) {
205 case SMB_SIGNING_OFF:
206 state->negprot.in.security_mode = 0;
208 case SMB_SIGNING_SUPPORTED:
209 case SMB_SIGNING_AUTO:
210 state->negprot.in.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
212 case SMB_SIGNING_REQUIRED:
213 state->negprot.in.security_mode =
214 SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
217 state->negprot.in.capabilities = 0;
218 unix_to_nt_time(&state->negprot.in.start_time, time(NULL));
219 state->negprot.in.dialects = dialects;
221 smb2req = smb2_negprot_send(transport, &state->negprot);
222 if (tevent_req_nomem(smb2req, req)) {
225 smb2req->async.fn = smb2_connect_negprot_done;
226 smb2req->async.private_data = req;
229 static void smb2_connect_resolve_done(struct composite_context *creq);
232 a composite function that does a full negprot/sesssetup/tcon, returning
233 a connected smb2_tree
235 struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
236 struct tevent_context *ev,
240 struct resolve_context *resolve_ctx,
241 struct cli_credentials *credentials,
242 struct smbcli_options *options,
243 const char *socket_options,
244 struct gensec_settings *gensec_settings)
246 struct tevent_req *req;
247 struct smb2_connect_state *state;
248 struct nbt_name name;
249 struct composite_context *creq;
251 req = tevent_req_create(mem_ctx, &state,
252 struct smb2_connect_state);
258 state->credentials = credentials;
259 state->options = *options;
261 state->ports = ports;
262 state->share = share;
263 state->resolve_ctx = resolve_ctx;
264 state->socket_options = socket_options;
265 state->gensec_settings = gensec_settings;
270 creq = resolve_name_send(resolve_ctx, state, &name, ev);
271 if (tevent_req_nomem(creq, req)) {
272 return tevent_req_post(req, ev);
274 creq->async.fn = smb2_connect_resolve_done;
275 creq->async.private_data = req;
279 static void smb2_connect_resolve_done(struct composite_context *creq)
281 struct tevent_req *req =
282 talloc_get_type_abort(creq->async.private_data,
284 struct smb2_connect_state *state =
286 struct smb2_connect_state);
290 const char *default_ports[] = { "445", NULL };
292 status = resolve_name_recv(creq, state, &addr);
293 if (tevent_req_nterror(req, status)) {
297 if (state->ports == NULL) {
298 ports = default_ports;
300 ports = state->ports;
303 creq = smbcli_sock_connect_send(state, addr, ports,
304 state->host, state->resolve_ctx,
305 state->ev, state->socket_options);
306 if (tevent_req_nomem(creq, req)) {
309 creq->async.fn = smb2_connect_socket_done;
310 creq->async.private_data = req;
313 NTSTATUS smb2_connect_recv(struct tevent_req *req,
315 struct smb2_tree **tree)
317 struct smb2_connect_state *state =
319 struct smb2_connect_state);
322 if (tevent_req_is_nterror(req, &status)) {
323 tevent_req_received(req);
327 *tree = talloc_move(mem_ctx, &state->tree);
329 tevent_req_received(req);
334 sync version of smb2_connect
336 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
340 struct resolve_context *resolve_ctx,
341 struct cli_credentials *credentials,
342 struct smb2_tree **tree,
343 struct tevent_context *ev,
344 struct smbcli_options *options,
345 const char *socket_options,
346 struct gensec_settings *gensec_settings)
348 struct tevent_req *subreq;
351 TALLOC_CTX *frame = talloc_stackframe();
354 return NT_STATUS_NO_MEMORY;
357 subreq = smb2_connect_send(frame,
367 if (subreq == NULL) {
369 return NT_STATUS_NO_MEMORY;
372 ok = tevent_req_poll(subreq, ev);
374 status = map_nt_error_from_unix(errno);
379 status = smb2_connect_recv(subreq, mem_ctx, tree);
381 if (!NT_STATUS_IS_OK(status)) {