s4:libcli/smb2: remove unused SMB_SIGNING_AUTO handling
[metze/samba/wip.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_DEFAULT:
172         case SMB_SIGNING_SUPPORTED:
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_DEFAULT:
227         case SMB_SIGNING_SUPPORTED:
228                 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
229                         transport->signing_required = true;
230                 } else {
231                         transport->signing_required = false;
232                 }
233                 break;
234         case SMB_SIGNING_REQUIRED:
235                 if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED) {
236                         transport->signing_required = true;
237                 } else {
238                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
239                         return;
240                 }
241                 break;
242         }
243
244         state->session = smb2_session_init(transport, state->gensec_settings, state, true);
245         if (tevent_req_nomem(state->session, req)) {
246                 return;
247         }
248
249         subreq = smb2_session_setup_spnego_send(state, state->ev,
250                                                 state->session,
251                                                 state->credentials);
252         if (tevent_req_nomem(subreq, req)) {
253                 return;
254         }
255         tevent_req_set_callback(subreq, smb2_connect_session_done, req);
256 }
257
258 static void smb2_connect_tcon_done(struct smb2_request *smb2req);
259
260 static void smb2_connect_session_done(struct tevent_req *subreq)
261 {
262         struct tevent_req *req =
263                 tevent_req_callback_data(subreq,
264                 struct tevent_req);
265         struct smb2_connect_state *state =
266                 tevent_req_data(req,
267                 struct smb2_connect_state);
268         struct smb2_request *smb2req;
269         NTSTATUS status;
270
271         status = smb2_session_setup_spnego_recv(subreq);
272         TALLOC_FREE(subreq);
273         if (tevent_req_nterror(req, status)) {
274                 return;
275         }
276
277         state->tree = smb2_tree_init(state->session, state, true);
278         if (tevent_req_nomem(state->tree, req)) {
279                 return;
280         }
281
282         state->tcon.in.reserved = 0;
283         state->tcon.in.path     = talloc_asprintf(state, "\\\\%s\\%s",
284                                                   state->host, state->share);
285         if (tevent_req_nomem(state->tcon.in.path, req)) {
286                 return;
287         }
288
289         smb2req = smb2_tree_connect_send(state->tree, &state->tcon);
290         if (tevent_req_nomem(smb2req, req)) {
291                 return;
292         }
293         smb2req->async.fn = smb2_connect_tcon_done;
294         smb2req->async.private_data = req;
295 }
296
297 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
298 {
299         struct tevent_req *req =
300                 talloc_get_type_abort(smb2req->async.private_data,
301                 struct tevent_req);
302         struct smb2_connect_state *state =
303                 tevent_req_data(req,
304                 struct smb2_connect_state);
305         NTSTATUS status;
306
307         status = smb2_tree_connect_recv(smb2req, &state->tcon);
308         if (tevent_req_nterror(req, status)) {
309                 return;
310         }
311
312         state->tree->tid = state->tcon.out.tid;
313
314         tevent_req_done(req);
315 }
316
317 NTSTATUS smb2_connect_recv(struct tevent_req *req,
318                            TALLOC_CTX *mem_ctx,
319                            struct smb2_tree **tree)
320 {
321         struct smb2_connect_state *state =
322                 tevent_req_data(req,
323                 struct smb2_connect_state);
324         NTSTATUS status;
325
326         if (tevent_req_is_nterror(req, &status)) {
327                 tevent_req_received(req);
328                 return status;
329         }
330
331         *tree = talloc_move(mem_ctx, &state->tree);
332
333         tevent_req_received(req);
334         return NT_STATUS_OK;
335 }
336
337 /*
338   sync version of smb2_connect
339 */
340 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
341                       const char *host,
342                       const char **ports,
343                       const char *share,
344                       struct resolve_context *resolve_ctx,
345                       struct cli_credentials *credentials,
346                       struct smb2_tree **tree,
347                       struct tevent_context *ev,
348                       struct smbcli_options *options,
349                       const char *socket_options,
350                       struct gensec_settings *gensec_settings)
351 {
352         struct tevent_req *subreq;
353         NTSTATUS status;
354         bool ok;
355         TALLOC_CTX *frame = talloc_stackframe();
356
357         if (frame == NULL) {
358                 return NT_STATUS_NO_MEMORY;
359         }
360
361         subreq = smb2_connect_send(frame,
362                                    ev,
363                                    host,
364                                    ports,
365                                    share,
366                                    resolve_ctx,
367                                    credentials,
368                                    options,
369                                    socket_options,
370                                    gensec_settings);
371         if (subreq == NULL) {
372                 TALLOC_FREE(frame);
373                 return NT_STATUS_NO_MEMORY;
374         }
375
376         ok = tevent_req_poll(subreq, ev);
377         if (!ok) {
378                 status = map_nt_error_from_unix_common(errno);
379                 TALLOC_FREE(frame);
380                 return status;
381         }
382
383         status = smb2_connect_recv(subreq, mem_ctx, tree);
384         TALLOC_FREE(subreq);
385         if (!NT_STATUS_IS_OK(status)) {
386                 TALLOC_FREE(frame);
387                 return status;
388         }
389
390         TALLOC_FREE(frame);
391         return NT_STATUS_OK;
392 }