Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : SMB2 composite connection setup
5 :
6 : Copyright (C) Andrew Tridgell 2005
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include <tevent.h>
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"
34 : #include "smb2_constants.h"
35 :
36 : struct smb2_connect_state {
37 : struct tevent_context *ev;
38 : struct cli_credentials *credentials;
39 : bool fallback_to_anonymous;
40 : uint64_t previous_session_id;
41 : struct resolve_context *resolve_ctx;
42 : const char *host;
43 : const char *share;
44 : const char *unc;
45 : const char **ports;
46 : const char *socket_options;
47 : struct nbt_name calling, called;
48 : struct gensec_settings *gensec_settings;
49 : struct smbcli_options options;
50 : struct smb2_transport *transport;
51 : struct smb2_session *session;
52 : struct smb2_tree *tree;
53 : };
54 :
55 : static void smb2_connect_session_start(struct tevent_req *req);
56 : static void smb2_connect_socket_done(struct composite_context *creq);
57 :
58 : /*
59 : a composite function that does a full negprot/sesssetup/tcon, returning
60 : a connected smb2_tree
61 : */
62 12839 : struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
63 : struct tevent_context *ev,
64 : const char *host,
65 : const char **ports,
66 : const char *share,
67 : struct resolve_context *resolve_ctx,
68 : struct cli_credentials *credentials,
69 : bool fallback_to_anonymous,
70 : struct smbXcli_conn **existing_conn,
71 : uint64_t previous_session_id,
72 : const struct smbcli_options *options,
73 : const char *socket_options,
74 : struct gensec_settings *gensec_settings)
75 : {
76 701 : struct tevent_req *req;
77 701 : struct smb2_connect_state *state;
78 701 : struct composite_context *creq;
79 701 : static const char *default_ports[] = { "445", "139", NULL };
80 701 : enum smb_encryption_setting encryption_state =
81 12839 : cli_credentials_get_smb_encryption(credentials);
82 :
83 12839 : req = tevent_req_create(mem_ctx, &state,
84 : struct smb2_connect_state);
85 12839 : if (req == NULL) {
86 0 : return NULL;
87 : }
88 :
89 12839 : state->ev = ev;
90 12839 : state->credentials = credentials;
91 12839 : state->fallback_to_anonymous = fallback_to_anonymous;
92 12839 : state->previous_session_id = previous_session_id;
93 12839 : state->options = *options;
94 12839 : state->host = host;
95 12839 : state->ports = ports;
96 12839 : state->share = share;
97 12839 : state->resolve_ctx = resolve_ctx;
98 12839 : state->socket_options = socket_options;
99 12839 : state->gensec_settings = gensec_settings;
100 :
101 12839 : if (state->ports == NULL) {
102 124 : state->ports = default_ports;
103 : }
104 :
105 12839 : if (encryption_state >= SMB_ENCRYPTION_DESIRED) {
106 719 : state->options.signing = SMB_SIGNING_REQUIRED;
107 : }
108 :
109 12839 : make_nbt_name_client(&state->calling,
110 : cli_credentials_get_workstation(credentials));
111 :
112 12839 : nbt_choose_called_name(state, &state->called,
113 : host, NBT_NAME_SERVER);
114 :
115 25678 : state->unc = talloc_asprintf(state, "\\\\%s\\%s",
116 12839 : state->host, state->share);
117 12839 : if (tevent_req_nomem(state->unc, req)) {
118 0 : return tevent_req_post(req, ev);
119 : }
120 :
121 12839 : if (existing_conn != NULL) {
122 390 : NTSTATUS status;
123 :
124 6774 : status = smb2_transport_raw_init(state, ev,
125 : existing_conn,
126 6774 : &state->options,
127 6774 : &state->transport);
128 6774 : if (tevent_req_nterror(req, status)) {
129 0 : return tevent_req_post(req, ev);
130 : }
131 :
132 6774 : smb2_connect_session_start(req);
133 6774 : if (!tevent_req_is_in_progress(req)) {
134 124 : return tevent_req_post(req, ev);
135 : }
136 :
137 6260 : return req;
138 : }
139 :
140 6376 : creq = smbcli_sock_connect_send(state, NULL, state->ports,
141 5754 : state->host, state->resolve_ctx,
142 5754 : state->ev, state->socket_options,
143 5754 : &state->calling,
144 6065 : &state->called);
145 6065 : if (tevent_req_nomem(creq, req)) {
146 0 : return tevent_req_post(req, ev);
147 : }
148 6065 : creq->async.fn = smb2_connect_socket_done;
149 6065 : creq->async.private_data = req;
150 :
151 6065 : return req;
152 : }
153 :
154 : static void smb2_connect_negprot_done(struct tevent_req *subreq);
155 :
156 6065 : static void smb2_connect_socket_done(struct composite_context *creq)
157 : {
158 311 : struct tevent_req *req =
159 6065 : talloc_get_type_abort(creq->async.private_data,
160 : struct tevent_req);
161 311 : struct smb2_connect_state *state =
162 6065 : tevent_req_data(req,
163 : struct smb2_connect_state);
164 311 : struct smbcli_socket *sock;
165 311 : struct tevent_req *subreq;
166 311 : NTSTATUS status;
167 311 : uint32_t timeout_msec;
168 311 : enum protocol_types min_protocol;
169 :
170 6065 : status = smbcli_sock_connect_recv(creq, state, &sock);
171 6065 : if (tevent_req_nterror(req, status)) {
172 0 : return;
173 : }
174 :
175 6065 : state->transport = smb2_transport_init(sock, state, &state->options);
176 6065 : if (tevent_req_nomem(state->transport, req)) {
177 0 : return;
178 : }
179 :
180 6065 : timeout_msec = state->transport->options.request_timeout * 1000;
181 6065 : min_protocol = state->transport->options.min_protocol;
182 6065 : if (min_protocol < PROTOCOL_SMB2_02) {
183 4956 : min_protocol = PROTOCOL_SMB2_02;
184 : }
185 :
186 6376 : subreq = smbXcli_negprot_send(state, state->ev,
187 5754 : state->transport->conn, timeout_msec,
188 : min_protocol,
189 6065 : state->transport->options.max_protocol,
190 6065 : state->transport->options.max_credits,
191 : NULL);
192 6065 : if (tevent_req_nomem(subreq, req)) {
193 0 : return;
194 : }
195 6065 : tevent_req_set_callback(subreq, smb2_connect_negprot_done, req);
196 : }
197 :
198 : static void smb2_connect_session_done(struct tevent_req *subreq);
199 :
200 6065 : static void smb2_connect_negprot_done(struct tevent_req *subreq)
201 : {
202 311 : struct tevent_req *req =
203 6065 : tevent_req_callback_data(subreq,
204 : struct tevent_req);
205 311 : NTSTATUS status;
206 :
207 6065 : status = smbXcli_negprot_recv(subreq, NULL, NULL);
208 6065 : TALLOC_FREE(subreq);
209 6065 : if (tevent_req_nterror(req, status)) {
210 0 : return;
211 : }
212 :
213 6065 : smb2_connect_session_start(req);
214 : }
215 :
216 12851 : static void smb2_connect_session_start(struct tevent_req *req)
217 : {
218 701 : struct smb2_connect_state *state =
219 12851 : tevent_req_data(req,
220 : struct smb2_connect_state);
221 12851 : struct smb2_transport *transport = state->transport;
222 12851 : struct tevent_req *subreq = NULL;
223 :
224 12851 : state->session = smb2_session_init(transport, state->gensec_settings, state);
225 12851 : if (tevent_req_nomem(state->session, req)) {
226 0 : return;
227 : }
228 :
229 12851 : if (state->options.only_negprot) {
230 1306 : state->tree = smb2_tree_init(state->session, state, true);
231 1306 : if (tevent_req_nomem(state->tree, req)) {
232 0 : return;
233 : }
234 1306 : tevent_req_done(req);
235 1306 : return;
236 : }
237 :
238 11545 : subreq = smb2_session_setup_spnego_send(state, state->ev,
239 : state->session,
240 : state->credentials,
241 : state->previous_session_id);
242 11545 : if (tevent_req_nomem(subreq, req)) {
243 0 : return;
244 : }
245 11545 : tevent_req_set_callback(subreq, smb2_connect_session_done, req);
246 : }
247 :
248 : static void smb2_connect_enc_start(struct tevent_req *req);
249 : static void smb2_connect_tcon_start(struct tevent_req *req);
250 : static void smb2_connect_tcon_done(struct tevent_req *subreq);
251 :
252 11545 : static void smb2_connect_session_done(struct tevent_req *subreq)
253 : {
254 621 : struct tevent_req *req =
255 11545 : tevent_req_callback_data(subreq,
256 : struct tevent_req);
257 621 : struct smb2_connect_state *state =
258 11545 : tevent_req_data(req,
259 : struct smb2_connect_state);
260 621 : NTSTATUS status;
261 :
262 11545 : status = smb2_session_setup_spnego_recv(subreq);
263 11545 : TALLOC_FREE(subreq);
264 11545 : if (!NT_STATUS_IS_OK(status) &&
265 40 : !cli_credentials_is_anonymous(state->credentials) &&
266 40 : state->fallback_to_anonymous) {
267 12 : struct cli_credentials *anon_creds = NULL;
268 :
269 : /*
270 : * The transport was moved to session,
271 : * we need to revert that before removing
272 : * the old broken session.
273 : */
274 12 : state->transport = talloc_move(state, &state->session->transport);
275 12 : TALLOC_FREE(state->session);
276 :
277 12 : anon_creds = cli_credentials_init_anon(state);
278 12 : if (tevent_req_nomem(anon_creds, req)) {
279 40 : return;
280 : }
281 12 : cli_credentials_set_workstation(anon_creds,
282 : cli_credentials_get_workstation(state->credentials),
283 : CRED_SPECIFIED);
284 :
285 : /*
286 : * retry with anonymous credentials
287 : */
288 12 : state->credentials = anon_creds;
289 12 : smb2_connect_session_start(req);
290 12 : return;
291 : }
292 11533 : if (tevent_req_nterror(req, status)) {
293 28 : return;
294 : }
295 :
296 11505 : state->tree = smb2_tree_init(state->session, state, true);
297 11505 : if (tevent_req_nomem(state->tree, req)) {
298 0 : return;
299 : }
300 :
301 11505 : smb2_connect_enc_start(req);
302 : }
303 :
304 11505 : static void smb2_connect_enc_start(struct tevent_req *req)
305 : {
306 621 : struct smb2_connect_state *state =
307 11505 : tevent_req_data(req,
308 : struct smb2_connect_state);
309 621 : enum smb_encryption_setting encryption_state =
310 11505 : cli_credentials_get_smb_encryption(state->credentials);
311 621 : NTSTATUS status;
312 :
313 11505 : if (encryption_state < SMB_ENCRYPTION_DESIRED) {
314 11118 : smb2_connect_tcon_start(req);
315 11120 : return;
316 : }
317 :
318 387 : status = smb2cli_session_encryption_on(state->session->smbXcli);
319 387 : if (!NT_STATUS_IS_OK(status)) {
320 2 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
321 2 : if (encryption_state < SMB_ENCRYPTION_REQUIRED) {
322 0 : smb2_connect_tcon_start(req);
323 2 : return;
324 : }
325 :
326 2 : DBG_ERR("Encryption required and server doesn't support "
327 : "SMB3 encryption - failing connect\n");
328 2 : tevent_req_nterror(req, status);
329 2 : return;
330 : }
331 :
332 0 : DBG_ERR("Encryption required and setup failed with error %s.\n",
333 : nt_errstr(status));
334 0 : tevent_req_nterror(req, NT_STATUS_PROTOCOL_NOT_SUPPORTED);
335 0 : return;
336 : }
337 :
338 385 : smb2_connect_tcon_start(req);
339 : }
340 :
341 11503 : static void smb2_connect_tcon_start(struct tevent_req *req)
342 : {
343 621 : struct smb2_connect_state *state =
344 11503 : tevent_req_data(req,
345 : struct smb2_connect_state);
346 11503 : struct tevent_req *subreq = NULL;
347 621 : uint32_t timeout_msec;
348 :
349 11503 : timeout_msec = state->transport->options.request_timeout * 1000;
350 :
351 12124 : subreq = smb2cli_tcon_send(state, state->ev,
352 10882 : state->transport->conn,
353 : timeout_msec,
354 11503 : state->session->smbXcli,
355 11503 : state->tree->smbXcli,
356 : 0, /* flags */
357 : state->unc);
358 11503 : if (tevent_req_nomem(subreq, req)) {
359 0 : return;
360 : }
361 11503 : tevent_req_set_callback(subreq, smb2_connect_tcon_done, req);
362 : }
363 :
364 11503 : static void smb2_connect_tcon_done(struct tevent_req *subreq)
365 : {
366 621 : struct tevent_req *req =
367 11503 : tevent_req_callback_data(subreq,
368 : struct tevent_req);
369 621 : NTSTATUS status;
370 :
371 11503 : status = smb2cli_tcon_recv(subreq);
372 11503 : if (tevent_req_nterror(req, status)) {
373 0 : return;
374 : }
375 :
376 11503 : tevent_req_done(req);
377 : }
378 :
379 12839 : NTSTATUS smb2_connect_recv(struct tevent_req *req,
380 : TALLOC_CTX *mem_ctx,
381 : struct smb2_tree **tree)
382 : {
383 701 : struct smb2_connect_state *state =
384 12839 : tevent_req_data(req,
385 : struct smb2_connect_state);
386 701 : NTSTATUS status;
387 :
388 12839 : if (tevent_req_is_nterror(req, &status)) {
389 30 : tevent_req_received(req);
390 30 : return status;
391 : }
392 :
393 12809 : *tree = talloc_move(mem_ctx, &state->tree);
394 :
395 12809 : tevent_req_received(req);
396 12809 : return NT_STATUS_OK;
397 : }
398 :
399 : /*
400 : sync version of smb2_connect
401 : */
402 6189 : NTSTATUS smb2_connect_ext(TALLOC_CTX *mem_ctx,
403 : const char *host,
404 : const char **ports,
405 : const char *share,
406 : struct resolve_context *resolve_ctx,
407 : struct cli_credentials *credentials,
408 : struct smbXcli_conn **existing_conn,
409 : uint64_t previous_session_id,
410 : struct smb2_tree **tree,
411 : struct tevent_context *ev,
412 : const struct smbcli_options *options,
413 : const char *socket_options,
414 : struct gensec_settings *gensec_settings)
415 : {
416 311 : struct tevent_req *subreq;
417 311 : NTSTATUS status;
418 311 : bool ok;
419 6189 : TALLOC_CTX *frame = talloc_stackframe();
420 :
421 6189 : if (frame == NULL) {
422 0 : return NT_STATUS_NO_MEMORY;
423 : }
424 :
425 6189 : subreq = smb2_connect_send(frame,
426 : ev,
427 : host,
428 : ports,
429 : share,
430 : resolve_ctx,
431 : credentials,
432 : false, /* fallback_to_anonymous */
433 : existing_conn,
434 : previous_session_id,
435 : options,
436 : socket_options,
437 : gensec_settings);
438 6189 : if (subreq == NULL) {
439 0 : TALLOC_FREE(frame);
440 0 : return NT_STATUS_NO_MEMORY;
441 : }
442 :
443 6189 : ok = tevent_req_poll(subreq, ev);
444 6189 : if (!ok) {
445 0 : status = map_nt_error_from_unix_common(errno);
446 0 : TALLOC_FREE(frame);
447 0 : return status;
448 : }
449 :
450 6189 : status = smb2_connect_recv(subreq, mem_ctx, tree);
451 6189 : TALLOC_FREE(subreq);
452 6189 : if (!NT_STATUS_IS_OK(status)) {
453 0 : TALLOC_FREE(frame);
454 0 : return status;
455 : }
456 :
457 6189 : TALLOC_FREE(frame);
458 6189 : return NT_STATUS_OK;
459 : }
460 :
461 1896 : NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
462 : const char *host,
463 : const char **ports,
464 : const char *share,
465 : struct resolve_context *resolve_ctx,
466 : struct cli_credentials *credentials,
467 : struct smb2_tree **tree,
468 : struct tevent_context *ev,
469 : const struct smbcli_options *options,
470 : const char *socket_options,
471 : struct gensec_settings *gensec_settings)
472 : {
473 186 : NTSTATUS status;
474 :
475 1896 : status = smb2_connect_ext(mem_ctx, host, ports, share, resolve_ctx,
476 : credentials,
477 : NULL, /* existing_conn */
478 : 0, /* previous_session_id */
479 : tree, ev, options, socket_options,
480 : gensec_settings);
481 :
482 1896 : return status;
483 : }
|