1a6ae34d2cd9a98f3ba8bc69126add43e20cff57
[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 #include "auth/credentials/credentials.h"
33 #include "../libcli/smb/smbXcli_base.h"
34
35 struct smb2_connect_state {
36         struct tevent_context *ev;
37         struct cli_credentials *credentials;
38         uint64_t previous_session_id;
39         struct resolve_context *resolve_ctx;
40         const char *host;
41         const char *share;
42         const char *unc;
43         const char **ports;
44         const char *socket_options;
45         struct nbt_name calling, called;
46         struct gensec_settings *gensec_settings;
47         struct smbcli_options options;
48         struct smb2_transport *transport;
49         struct smb2_session *session;
50         struct smb2_tree *tree;
51 };
52
53 static void smb2_connect_socket_done(struct composite_context *creq);
54
55 /*
56   a composite function that does a full negprot/sesssetup/tcon, returning
57   a connected smb2_tree
58  */
59 struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
60                                      struct tevent_context *ev,
61                                      const char *host,
62                                      const char **ports,
63                                      const char *share,
64                                      struct resolve_context *resolve_ctx,
65                                      struct cli_credentials *credentials,
66                                      uint64_t previous_session_id,
67                                      const struct smbcli_options *options,
68                                      const char *socket_options,
69                                      struct gensec_settings *gensec_settings)
70 {
71         struct tevent_req *req;
72         struct smb2_connect_state *state;
73         struct composite_context *creq;
74         static const char *default_ports[] = { "445", "139", NULL };
75
76         req = tevent_req_create(mem_ctx, &state,
77                                 struct smb2_connect_state);
78         if (req == NULL) {
79                 return NULL;
80         }
81
82         state->ev = ev;
83         state->credentials = credentials;
84         state->previous_session_id = previous_session_id;
85         state->options = *options;
86         state->host = host;
87         state->ports = ports;
88         state->share = share;
89         state->resolve_ctx = resolve_ctx;
90         state->socket_options = socket_options;
91         state->gensec_settings = gensec_settings;
92
93         if (state->ports == NULL) {
94                 state->ports = default_ports;
95         }
96
97         make_nbt_name_client(&state->calling,
98                              cli_credentials_get_workstation(credentials));
99
100         nbt_choose_called_name(state, &state->called,
101                                host, NBT_NAME_SERVER);
102
103         state->unc = talloc_asprintf(state, "\\\\%s\\%s",
104                                     state->host, state->share);
105         if (tevent_req_nomem(state->unc, req)) {
106                 return tevent_req_post(req, ev);
107         }
108
109         creq = smbcli_sock_connect_send(state, NULL, state->ports,
110                                         state->host, state->resolve_ctx,
111                                         state->ev, state->socket_options,
112                                         &state->calling,
113                                         &state->called);
114         if (tevent_req_nomem(creq, req)) {
115                 return tevent_req_post(req, ev);
116         }
117         creq->async.fn = smb2_connect_socket_done;
118         creq->async.private_data = req;
119
120         return req;
121 }
122
123 static void smb2_connect_negprot_done(struct tevent_req *subreq);
124
125 static void smb2_connect_socket_done(struct composite_context *creq)
126 {
127         struct tevent_req *req =
128                 talloc_get_type_abort(creq->async.private_data,
129                 struct tevent_req);
130         struct smb2_connect_state *state =
131                 tevent_req_data(req,
132                 struct smb2_connect_state);
133         struct smbcli_socket *sock;
134         struct tevent_req *subreq;
135         NTSTATUS status;
136         uint32_t timeout_msec;
137         enum protocol_types min_protocol;
138
139         status = smbcli_sock_connect_recv(creq, state, &sock);
140         if (tevent_req_nterror(req, status)) {
141                 return;
142         }
143
144         state->transport = smb2_transport_init(sock, state, &state->options);
145         if (tevent_req_nomem(state->transport, req)) {
146                 return;
147         }
148
149         timeout_msec = state->transport->options.request_timeout * 1000;
150         min_protocol = state->transport->options.min_protocol;
151         if (min_protocol < PROTOCOL_SMB2_02) {
152                 min_protocol = PROTOCOL_SMB2_02;
153         }
154
155         subreq = smbXcli_negprot_send(state, state->ev,
156                                       state->transport->conn, timeout_msec,
157                                       min_protocol,
158                                       state->transport->options.max_protocol);
159         if (tevent_req_nomem(subreq, req)) {
160                 return;
161         }
162         tevent_req_set_callback(subreq, smb2_connect_negprot_done, req);
163 }
164
165 static void smb2_connect_session_done(struct tevent_req *subreq);
166
167 static void smb2_connect_negprot_done(struct tevent_req *subreq)
168 {
169         struct tevent_req *req =
170                 tevent_req_callback_data(subreq,
171                 struct tevent_req);
172         struct smb2_connect_state *state =
173                 tevent_req_data(req,
174                 struct smb2_connect_state);
175         struct smb2_transport *transport = state->transport;
176         NTSTATUS status;
177
178         status = smbXcli_negprot_recv(subreq);
179         TALLOC_FREE(subreq);
180         if (tevent_req_nterror(req, status)) {
181                 return;
182         }
183
184         /* This is a hack... */
185         smb2cli_conn_set_max_credits(transport->conn, 30);
186
187         state->session = smb2_session_init(transport, state->gensec_settings, state);
188         if (tevent_req_nomem(state->session, req)) {
189                 return;
190         }
191
192         subreq = smb2_session_setup_spnego_send(state, state->ev,
193                                                 state->session,
194                                                 state->credentials,
195                                                 state->previous_session_id);
196         if (tevent_req_nomem(subreq, req)) {
197                 return;
198         }
199         tevent_req_set_callback(subreq, smb2_connect_session_done, req);
200 }
201
202 static void smb2_connect_tcon_done(struct tevent_req *subreq);
203
204 static void smb2_connect_session_done(struct tevent_req *subreq)
205 {
206         struct tevent_req *req =
207                 tevent_req_callback_data(subreq,
208                 struct tevent_req);
209         struct smb2_connect_state *state =
210                 tevent_req_data(req,
211                 struct smb2_connect_state);
212         NTSTATUS status;
213         uint32_t timeout_msec;
214
215         status = smb2_session_setup_spnego_recv(subreq);
216         TALLOC_FREE(subreq);
217         if (tevent_req_nterror(req, status)) {
218                 return;
219         }
220
221         state->tree = smb2_tree_init(state->session, state, true);
222         if (tevent_req_nomem(state->tree, req)) {
223                 return;
224         }
225
226         timeout_msec = state->transport->options.request_timeout * 1000;
227
228         subreq = smb2cli_tcon_send(state, state->ev,
229                                    state->transport->conn,
230                                    timeout_msec,
231                                    state->session->smbXcli,
232                                    state->tree->smbXcli,
233                                    0, /* flags */
234                                    state->unc);
235         if (tevent_req_nomem(subreq, req)) {
236                 return;
237         }
238         tevent_req_set_callback(subreq, smb2_connect_tcon_done, req);
239 }
240
241 static void smb2_connect_tcon_done(struct tevent_req *subreq)
242 {
243         struct tevent_req *req =
244                 tevent_req_callback_data(subreq,
245                 struct tevent_req);
246         NTSTATUS status;
247
248         status = smb2cli_tcon_recv(subreq);
249         if (tevent_req_nterror(req, status)) {
250                 return;
251         }
252
253         tevent_req_done(req);
254 }
255
256 NTSTATUS smb2_connect_recv(struct tevent_req *req,
257                            TALLOC_CTX *mem_ctx,
258                            struct smb2_tree **tree)
259 {
260         struct smb2_connect_state *state =
261                 tevent_req_data(req,
262                 struct smb2_connect_state);
263         NTSTATUS status;
264
265         if (tevent_req_is_nterror(req, &status)) {
266                 tevent_req_received(req);
267                 return status;
268         }
269
270         *tree = talloc_move(mem_ctx, &state->tree);
271
272         tevent_req_received(req);
273         return NT_STATUS_OK;
274 }
275
276 /*
277   sync version of smb2_connect
278 */
279 NTSTATUS smb2_connect_ext(TALLOC_CTX *mem_ctx,
280                           const char *host,
281                           const char **ports,
282                           const char *share,
283                           struct resolve_context *resolve_ctx,
284                           struct cli_credentials *credentials,
285                           uint64_t previous_session_id,
286                           struct smb2_tree **tree,
287                           struct tevent_context *ev,
288                           const struct smbcli_options *options,
289                           const char *socket_options,
290                           struct gensec_settings *gensec_settings)
291 {
292         struct tevent_req *subreq;
293         NTSTATUS status;
294         bool ok;
295         TALLOC_CTX *frame = talloc_stackframe();
296
297         if (frame == NULL) {
298                 return NT_STATUS_NO_MEMORY;
299         }
300
301         subreq = smb2_connect_send(frame,
302                                    ev,
303                                    host,
304                                    ports,
305                                    share,
306                                    resolve_ctx,
307                                    credentials,
308                                    previous_session_id,
309                                    options,
310                                    socket_options,
311                                    gensec_settings);
312         if (subreq == NULL) {
313                 TALLOC_FREE(frame);
314                 return NT_STATUS_NO_MEMORY;
315         }
316
317         ok = tevent_req_poll(subreq, ev);
318         if (!ok) {
319                 status = map_nt_error_from_unix_common(errno);
320                 TALLOC_FREE(frame);
321                 return status;
322         }
323
324         status = smb2_connect_recv(subreq, mem_ctx, tree);
325         TALLOC_FREE(subreq);
326         if (!NT_STATUS_IS_OK(status)) {
327                 TALLOC_FREE(frame);
328                 return status;
329         }
330
331         TALLOC_FREE(frame);
332         return NT_STATUS_OK;
333 }
334
335 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
336                       const char *host,
337                       const char **ports,
338                       const char *share,
339                       struct resolve_context *resolve_ctx,
340                       struct cli_credentials *credentials,
341                       struct smb2_tree **tree,
342                       struct tevent_context *ev,
343                       struct smbcli_options *options,
344                       const char *socket_options,
345                       struct gensec_settings *gensec_settings)
346 {
347         NTSTATUS status;
348
349         status = smb2_connect_ext(mem_ctx, host, ports, share, resolve_ctx,
350                                   credentials,
351                                   0, /* previous_session_id */
352                                   tree, ev, options, socket_options,
353                                   gensec_settings);
354
355         return status;
356 }