s4:libcli/smb2: move smb2_connect_resolve_done()
[samba.git] / source4 / libcli / smb2 / connect.c
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
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;
47 };
48
49 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
50 {
51         struct tevent_req *req =
52                 talloc_get_type_abort(smb2req->async.private_data,
53                 struct tevent_req);
54         struct smb2_connect_state *state =
55                 tevent_req_data(req,
56                 struct smb2_connect_state);
57         NTSTATUS status;
58
59         status = smb2_tree_connect_recv(smb2req, &state->tcon);
60         if (tevent_req_nterror(req, status)) {
61                 return;
62         }
63
64         state->tree->tid = state->tcon.out.tid;
65
66         tevent_req_done(req);
67 }
68
69 static void smb2_connect_session_done(struct composite_context *creq)
70 {
71         struct tevent_req *req =
72                 talloc_get_type_abort(creq->async.private_data,
73                 struct tevent_req);
74         struct smb2_connect_state *state =
75                 tevent_req_data(req,
76                 struct smb2_connect_state);
77         struct smb2_request *smb2req;
78         NTSTATUS status;
79
80         status = smb2_session_setup_spnego_recv(creq);
81         if (tevent_req_nterror(req, status)) {
82                 return;
83         }
84
85         state->tree = smb2_tree_init(state->session, state, true);
86         if (tevent_req_nomem(state->tree, req)) {
87                 return;
88         }
89
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)) {
94                 return;
95         }
96
97         smb2req = smb2_tree_connect_send(state->tree, &state->tcon);
98         if (tevent_req_nomem(smb2req, req)) {
99                 return;
100         }
101         smb2req->async.fn = smb2_connect_tcon_done;
102         smb2req->async.private_data = req;
103 }
104
105 static void smb2_connect_negprot_done(struct smb2_request *smb2req)
106 {
107         struct tevent_req *req =
108                 talloc_get_type_abort(smb2req->async.private_data,
109                 struct tevent_req);
110         struct smb2_connect_state *state =
111                 tevent_req_data(req,
112                 struct smb2_connect_state);
113         struct smb2_transport *transport = smb2req->transport;
114         struct composite_context *creq;
115         NTSTATUS status;
116
117         status = smb2_negprot_recv(smb2req, state, &state->negprot);
118         if (tevent_req_nterror(req, status)) {
119                 return;
120         }
121
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;
128
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);
133                         return;
134                 }
135                 transport->signing_required = false;
136                 break;
137         case SMB_SIGNING_SUPPORTED:
138                 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
139                         transport->signing_required = true;
140                 } else {
141                         transport->signing_required = false;
142                 }
143                 break;
144         case SMB_SIGNING_AUTO:
145                 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED) {
146                         transport->signing_required = true;
147                 } else {
148                         transport->signing_required = false;
149                 }
150                 break;
151         case SMB_SIGNING_REQUIRED:
152                 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED) {
153                         transport->signing_required = true;
154                 } else {
155                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
156                         return;
157                 }
158                 break;
159         }
160
161         state->session = smb2_session_init(transport, state->gensec_settings, state, true);
162         if (tevent_req_nomem(state->session, req)) {
163                 return;
164         }
165
166         creq = smb2_session_setup_spnego_send(state->session, state->credentials);
167         if (tevent_req_nomem(creq, req)) {
168                 return;
169         }
170         creq->async.fn = smb2_connect_session_done;
171         creq->async.private_data = req;
172 }
173
174 static void smb2_connect_socket_done(struct composite_context *creq)
175 {
176         struct tevent_req *req =
177                 talloc_get_type_abort(creq->async.private_data,
178                 struct tevent_req);
179         struct smb2_connect_state *state =
180                 tevent_req_data(req,
181                 struct smb2_connect_state);
182         struct smbcli_socket *sock;
183         struct smb2_transport *transport;
184         struct smb2_request *smb2req;
185         NTSTATUS status;
186         uint16_t dialects[3] = {
187                 SMB2_DIALECT_REVISION_000,
188                 SMB2_DIALECT_REVISION_202,
189                 SMB2_DIALECT_REVISION_210
190         };
191
192         status = smbcli_sock_connect_recv(creq, state, &sock);
193         if (tevent_req_nterror(req, status)) {
194                 return;
195         }
196
197         transport = smb2_transport_init(sock, state, &state->options);
198         if (tevent_req_nomem(transport, req)) {
199                 return;
200         }
201
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;
207                 break;
208         case SMB_SIGNING_SUPPORTED:
209         case SMB_SIGNING_AUTO:
210                 state->negprot.in.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
211                 break;
212         case SMB_SIGNING_REQUIRED:
213                 state->negprot.in.security_mode = 
214                         SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
215                 break;
216         }
217         state->negprot.in.capabilities  = 0;
218         unix_to_nt_time(&state->negprot.in.start_time, time(NULL));
219         state->negprot.in.dialects = dialects;
220
221         smb2req = smb2_negprot_send(transport, &state->negprot);
222         if (tevent_req_nomem(smb2req, req)) {
223                 return;
224         }
225         smb2req->async.fn = smb2_connect_negprot_done;
226         smb2req->async.private_data = req;
227 }
228
229 static void smb2_connect_resolve_done(struct composite_context *creq);
230
231 /*
232   a composite function that does a full negprot/sesssetup/tcon, returning
233   a connected smb2_tree
234  */
235 struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
236                                      struct tevent_context *ev,
237                                      const char *host,
238                                      const char **ports,
239                                      const char *share,
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)
245 {
246         struct tevent_req *req;
247         struct smb2_connect_state *state;
248         struct nbt_name name;
249         struct composite_context *creq;
250
251         req = tevent_req_create(mem_ctx, &state,
252                                 struct smb2_connect_state);
253         if (req == NULL) {
254                 return NULL;
255         }
256
257         state->ev = ev;
258         state->credentials = credentials;
259         state->options = *options;
260         state->host = host;
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;
266
267         ZERO_STRUCT(name);
268         name.name = host;
269
270         creq = resolve_name_send(resolve_ctx, state, &name, ev);
271         if (tevent_req_nomem(creq, req)) {
272                 return tevent_req_post(req, ev);
273         }
274         creq->async.fn = smb2_connect_resolve_done;
275         creq->async.private_data = req;
276         return req;
277 }
278
279 static void smb2_connect_resolve_done(struct composite_context *creq)
280 {
281         struct tevent_req *req =
282                 talloc_get_type_abort(creq->async.private_data,
283                 struct tevent_req);
284         struct smb2_connect_state *state =
285                 tevent_req_data(req,
286                 struct smb2_connect_state);
287         NTSTATUS status;
288         const char *addr;
289         const char **ports;
290         const char *default_ports[] = { "445", NULL };
291
292         status = resolve_name_recv(creq, state, &addr);
293         if (tevent_req_nterror(req, status)) {
294                 return;
295         }
296
297         if (state->ports == NULL) {
298                 ports = default_ports;
299         } else {
300                 ports = state->ports;
301         }
302
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)) {
307                 return;
308         }
309         creq->async.fn = smb2_connect_socket_done;
310         creq->async.private_data = req;
311 }
312
313 NTSTATUS smb2_connect_recv(struct tevent_req *req,
314                            TALLOC_CTX *mem_ctx,
315                            struct smb2_tree **tree)
316 {
317         struct smb2_connect_state *state =
318                 tevent_req_data(req,
319                 struct smb2_connect_state);
320         NTSTATUS status;
321
322         if (tevent_req_is_nterror(req, &status)) {
323                 tevent_req_received(req);
324                 return status;
325         }
326
327         *tree = talloc_move(mem_ctx, &state->tree);
328
329         tevent_req_received(req);
330         return NT_STATUS_OK;
331 }
332
333 /*
334   sync version of smb2_connect
335 */
336 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
337                       const char *host,
338                       const char **ports,
339                       const char *share,
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)
347 {
348         struct tevent_req *subreq;
349         NTSTATUS status;
350         bool ok;
351         TALLOC_CTX *frame = talloc_stackframe();
352
353         if (frame == NULL) {
354                 return NT_STATUS_NO_MEMORY;
355         }
356
357         subreq = smb2_connect_send(frame,
358                                    ev,
359                                    host,
360                                    ports,
361                                    share,
362                                    resolve_ctx,
363                                    credentials,
364                                    options,
365                                    socket_options,
366                                    gensec_settings);
367         if (subreq == NULL) {
368                 TALLOC_FREE(frame);
369                 return NT_STATUS_NO_MEMORY;
370         }
371
372         ok = tevent_req_poll(subreq, ev);
373         if (!ok) {
374                 status = map_nt_error_from_unix(errno);
375                 TALLOC_FREE(frame);
376                 return status;
377         }
378
379         status = smb2_connect_recv(subreq, mem_ctx, tree);
380         TALLOC_FREE(subreq);
381         if (!NT_STATUS_IS_OK(status)) {
382                 TALLOC_FREE(frame);
383                 return status;
384         }
385
386         TALLOC_FREE(frame);
387         return NT_STATUS_OK;
388 }