build: provide tevent-util as a public library
[Samba.git] / source4 / libcli / smb2 / connect.c
blob0e3bf1512bec505ed3eb3a2bc7aa14455b0098a7
1 /*
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/>.
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"
33 struct smb2_connect_state {
34 struct tevent_context *ev;
35 struct cli_credentials *credentials;
36 struct resolve_context *resolve_ctx;
37 const char *host;
38 const char *share;
39 const char **ports;
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
53 a connected smb2_tree
55 struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
56 struct tevent_context *ev,
57 const char *host,
58 const char **ports,
59 const char *share,
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;
68 struct nbt_name name;
69 struct composite_context *creq;
71 req = tevent_req_create(mem_ctx, &state,
72 struct smb2_connect_state);
73 if (req == NULL) {
74 return NULL;
77 state->ev = ev;
78 state->credentials = credentials;
79 state->options = *options;
80 state->host = host;
81 state->ports = ports;
82 state->share = share;
83 state->resolve_ctx = resolve_ctx;
84 state->socket_options = socket_options;
85 state->gensec_settings = gensec_settings;
87 ZERO_STRUCT(name);
88 name.name = host;
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;
96 return 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,
105 struct tevent_req);
106 struct smb2_connect_state *state =
107 tevent_req_data(req,
108 struct smb2_connect_state);
109 NTSTATUS status;
110 const char *addr;
111 const char **ports;
112 const char *default_ports[] = { "445", NULL };
114 status = resolve_name_recv(creq, state, &addr);
115 if (tevent_req_nterror(req, status)) {
116 return;
119 if (state->ports == NULL) {
120 ports = default_ports;
121 } else {
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)) {
129 return;
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,
141 struct tevent_req);
142 struct smb2_connect_state *state =
143 tevent_req_data(req,
144 struct smb2_connect_state);
145 struct smbcli_socket *sock;
146 struct smb2_transport *transport;
147 struct smb2_request *smb2req;
148 NTSTATUS status;
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)) {
157 return;
160 transport = smb2_transport_init(sock, state, &state->options);
161 if (tevent_req_nomem(transport, req)) {
162 return;
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;
170 break;
171 case SMB_SIGNING_SUPPORTED:
172 case SMB_SIGNING_AUTO:
173 state->negprot.in.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
174 break;
175 case SMB_SIGNING_REQUIRED:
176 state->negprot.in.security_mode =
177 SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
178 break;
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)) {
186 return;
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,
198 struct tevent_req);
199 struct smb2_connect_state *state =
200 tevent_req_data(req,
201 struct smb2_connect_state);
202 struct smb2_transport *transport = smb2req->transport;
203 struct tevent_req *subreq;
204 NTSTATUS status;
206 status = smb2_negprot_recv(smb2req, state, &state->negprot);
207 if (tevent_req_nterror(req, status)) {
208 return;
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);
222 return;
224 transport->signing_required = false;
225 break;
226 case SMB_SIGNING_SUPPORTED:
227 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
228 transport->signing_required = true;
229 } else {
230 transport->signing_required = false;
232 break;
233 case SMB_SIGNING_AUTO:
234 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED) {
235 transport->signing_required = true;
236 } else {
237 transport->signing_required = false;
239 break;
240 case SMB_SIGNING_REQUIRED:
241 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED) {
242 transport->signing_required = true;
243 } else {
244 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
245 return;
247 break;
250 state->session = smb2_session_init(transport, state->gensec_settings, state, true);
251 if (tevent_req_nomem(state->session, req)) {
252 return;
255 subreq = smb2_session_setup_spnego_send(state, state->ev,
256 state->session,
257 state->credentials);
258 if (tevent_req_nomem(subreq, req)) {
259 return;
261 tevent_req_set_callback(subreq, smb2_connect_session_done, req);
264 static void smb2_connect_tcon_done(struct smb2_request *smb2req);
266 static void smb2_connect_session_done(struct tevent_req *subreq)
268 struct tevent_req *req =
269 tevent_req_callback_data(subreq,
270 struct tevent_req);
271 struct smb2_connect_state *state =
272 tevent_req_data(req,
273 struct smb2_connect_state);
274 struct smb2_request *smb2req;
275 NTSTATUS status;
277 status = smb2_session_setup_spnego_recv(subreq);
278 TALLOC_FREE(subreq);
279 if (tevent_req_nterror(req, status)) {
280 return;
283 state->tree = smb2_tree_init(state->session, state, true);
284 if (tevent_req_nomem(state->tree, req)) {
285 return;
288 state->tcon.in.reserved = 0;
289 state->tcon.in.path = talloc_asprintf(state, "\\\\%s\\%s",
290 state->host, state->share);
291 if (tevent_req_nomem(state->tcon.in.path, req)) {
292 return;
295 smb2req = smb2_tree_connect_send(state->tree, &state->tcon);
296 if (tevent_req_nomem(smb2req, req)) {
297 return;
299 smb2req->async.fn = smb2_connect_tcon_done;
300 smb2req->async.private_data = req;
303 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
305 struct tevent_req *req =
306 talloc_get_type_abort(smb2req->async.private_data,
307 struct tevent_req);
308 struct smb2_connect_state *state =
309 tevent_req_data(req,
310 struct smb2_connect_state);
311 NTSTATUS status;
313 status = smb2_tree_connect_recv(smb2req, &state->tcon);
314 if (tevent_req_nterror(req, status)) {
315 return;
318 state->tree->tid = state->tcon.out.tid;
320 tevent_req_done(req);
323 NTSTATUS smb2_connect_recv(struct tevent_req *req,
324 TALLOC_CTX *mem_ctx,
325 struct smb2_tree **tree)
327 struct smb2_connect_state *state =
328 tevent_req_data(req,
329 struct smb2_connect_state);
330 NTSTATUS status;
332 if (tevent_req_is_nterror(req, &status)) {
333 tevent_req_received(req);
334 return status;
337 *tree = talloc_move(mem_ctx, &state->tree);
339 tevent_req_received(req);
340 return NT_STATUS_OK;
344 sync version of smb2_connect
346 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
347 const char *host,
348 const char **ports,
349 const char *share,
350 struct resolve_context *resolve_ctx,
351 struct cli_credentials *credentials,
352 struct smb2_tree **tree,
353 struct tevent_context *ev,
354 struct smbcli_options *options,
355 const char *socket_options,
356 struct gensec_settings *gensec_settings)
358 struct tevent_req *subreq;
359 NTSTATUS status;
360 bool ok;
361 TALLOC_CTX *frame = talloc_stackframe();
363 if (frame == NULL) {
364 return NT_STATUS_NO_MEMORY;
367 subreq = smb2_connect_send(frame,
369 host,
370 ports,
371 share,
372 resolve_ctx,
373 credentials,
374 options,
375 socket_options,
376 gensec_settings);
377 if (subreq == NULL) {
378 TALLOC_FREE(frame);
379 return NT_STATUS_NO_MEMORY;
382 ok = tevent_req_poll(subreq, ev);
383 if (!ok) {
384 status = map_nt_error_from_unix_common(errno);
385 TALLOC_FREE(frame);
386 return status;
389 status = smb2_connect_recv(subreq, mem_ctx, tree);
390 TALLOC_FREE(subreq);
391 if (!NT_STATUS_IS_OK(status)) {
392 TALLOC_FREE(frame);
393 return status;
396 TALLOC_FREE(frame);
397 return NT_STATUS_OK;