c5cacc3e0b29ead59df6f1e304e693bdb1a88310
[nivanova/samba-autobuild/.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_resolve_done(struct composite_context *creq);
50
51 /*
52   a composite function that does a full negprot/sesssetup/tcon, returning
53   a connected smb2_tree
54  */
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)
65 {
66         struct tevent_req *req;
67         struct smb2_connect_state *state;
68         struct nbt_name name;
69         struct composite_context *creq;
70
71         req = tevent_req_create(mem_ctx, &state,
72                                 struct smb2_connect_state);
73         if (req == NULL) {
74                 return NULL;
75         }
76
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;
86
87         ZERO_STRUCT(name);
88         name.name = host;
89
90         creq = resolve_name_send(resolve_ctx, state, &name, ev);
91         if (tevent_req_nomem(creq, req)) {
92                 return tevent_req_post(req, ev);
93         }
94         creq->async.fn = smb2_connect_resolve_done;
95         creq->async.private_data = req;
96         return req;
97 }
98
99 static void smb2_connect_socket_done(struct composite_context *creq);
100
101 static void smb2_connect_resolve_done(struct composite_context *creq)
102 {
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 };
113
114         status = resolve_name_recv(creq, state, &addr);
115         if (tevent_req_nterror(req, status)) {
116                 return;
117         }
118
119         if (state->ports == NULL) {
120                 ports = default_ports;
121         } else {
122                 ports = state->ports;
123         }
124
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;
130         }
131         creq->async.fn = smb2_connect_socket_done;
132         creq->async.private_data = req;
133 }
134
135 static void smb2_connect_negprot_done(struct smb2_request *smb2req);
136
137 static void smb2_connect_socket_done(struct composite_context *creq)
138 {
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
153         };
154
155         status = smbcli_sock_connect_recv(creq, state, &sock);
156         if (tevent_req_nterror(req, status)) {
157                 return;
158         }
159
160         transport = smb2_transport_init(sock, state, &state->options);
161         if (tevent_req_nomem(transport, req)) {
162                 return;
163         }
164
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;
179         }
180         state->negprot.in.capabilities  = 0;
181         unix_to_nt_time(&state->negprot.in.start_time, time(NULL));
182         state->negprot.in.dialects = dialects;
183
184         smb2req = smb2_negprot_send(transport, &state->negprot);
185         if (tevent_req_nomem(smb2req, req)) {
186                 return;
187         }
188         smb2req->async.fn = smb2_connect_negprot_done;
189         smb2req->async.private_data = req;
190 }
191
192 static void smb2_connect_session_done(struct tevent_req *subreq);
193
194 static void smb2_connect_negprot_done(struct smb2_request *smb2req)
195 {
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;
205
206         status = smb2_negprot_recv(smb2req, state, &state->negprot);
207         if (tevent_req_nterror(req, status)) {
208                 return;
209         }
210
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;
217
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;
223                 }
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;
231                 }
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;
238                 }
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;
246                 }
247                 break;
248         }
249
250         state->session = smb2_session_init(transport, state->gensec_settings, state, true);
251         if (tevent_req_nomem(state->session, req)) {
252                 return;
253         }
254
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;
260         }
261         tevent_req_set_callback(subreq, smb2_connect_session_done, req);
262 }
263
264 static void smb2_connect_tcon_done(struct smb2_request *smb2req);
265
266 static void smb2_connect_session_done(struct tevent_req *subreq)
267 {
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;
276
277         status = smb2_session_setup_spnego_recv(subreq);
278         TALLOC_FREE(subreq);
279         if (tevent_req_nterror(req, status)) {
280                 return;
281         }
282
283         state->tree = smb2_tree_init(state->session, state, true);
284         if (tevent_req_nomem(state->tree, req)) {
285                 return;
286         }
287
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;
293         }
294
295         smb2req = smb2_tree_connect_send(state->tree, &state->tcon);
296         if (tevent_req_nomem(smb2req, req)) {
297                 return;
298         }
299         smb2req->async.fn = smb2_connect_tcon_done;
300         smb2req->async.private_data = req;
301 }
302
303 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
304 {
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;
312
313         status = smb2_tree_connect_recv(smb2req, &state->tcon);
314         if (tevent_req_nterror(req, status)) {
315                 return;
316         }
317
318         state->tree->tid = state->tcon.out.tid;
319
320         tevent_req_done(req);
321 }
322
323 NTSTATUS smb2_connect_recv(struct tevent_req *req,
324                            TALLOC_CTX *mem_ctx,
325                            struct smb2_tree **tree)
326 {
327         struct smb2_connect_state *state =
328                 tevent_req_data(req,
329                 struct smb2_connect_state);
330         NTSTATUS status;
331
332         if (tevent_req_is_nterror(req, &status)) {
333                 tevent_req_received(req);
334                 return status;
335         }
336
337         *tree = talloc_move(mem_ctx, &state->tree);
338
339         tevent_req_received(req);
340         return NT_STATUS_OK;
341 }
342
343 /*
344   sync version of smb2_connect
345 */
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)
357 {
358         struct tevent_req *subreq;
359         NTSTATUS status;
360         bool ok;
361         TALLOC_CTX *frame = talloc_stackframe();
362
363         if (frame == NULL) {
364                 return NT_STATUS_NO_MEMORY;
365         }
366
367         subreq = smb2_connect_send(frame,
368                                    ev,
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;
380         }
381
382         ok = tevent_req_poll(subreq, ev);
383         if (!ok) {
384                 status = map_nt_error_from_unix(errno);
385                 TALLOC_FREE(frame);
386                 return status;
387         }
388
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;
394         }
395
396         TALLOC_FREE(frame);
397         return NT_STATUS_OK;
398 }