18977d8523e5d46990b20219c8ea7bd163d4f8ed
[kamenim/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 #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 **ports;
43         const char *socket_options;
44         struct nbt_name calling, called;
45         struct gensec_settings *gensec_settings;
46         struct smbcli_options options;
47         struct smb2_transport *transport;
48         struct smb2_tree_connect tcon;
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         creq = smbcli_sock_connect_send(state, NULL, state->ports,
104                                         state->host, state->resolve_ctx,
105                                         state->ev, state->socket_options,
106                                         &state->calling,
107                                         &state->called);
108         if (tevent_req_nomem(creq, req)) {
109                 return tevent_req_post(req, ev);
110         }
111         creq->async.fn = smb2_connect_socket_done;
112         creq->async.private_data = req;
113
114         return req;
115 }
116
117 static void smb2_connect_negprot_done(struct tevent_req *subreq);
118
119 static void smb2_connect_socket_done(struct composite_context *creq)
120 {
121         struct tevent_req *req =
122                 talloc_get_type_abort(creq->async.private_data,
123                 struct tevent_req);
124         struct smb2_connect_state *state =
125                 tevent_req_data(req,
126                 struct smb2_connect_state);
127         struct smbcli_socket *sock;
128         struct tevent_req *subreq;
129         NTSTATUS status;
130         uint32_t timeout_msec;
131
132         status = smbcli_sock_connect_recv(creq, state, &sock);
133         if (tevent_req_nterror(req, status)) {
134                 return;
135         }
136
137         state->transport = smb2_transport_init(sock, state, &state->options);
138         if (tevent_req_nomem(state->transport, req)) {
139                 return;
140         }
141
142         timeout_msec = state->transport->options.request_timeout * 1000;
143
144         subreq = smbXcli_negprot_send(state, state->ev,
145                                       state->transport->conn, timeout_msec,
146                                       PROTOCOL_SMB2_02, PROTOCOL_LATEST);
147         if (tevent_req_nomem(subreq, req)) {
148                 return;
149         }
150         tevent_req_set_callback(subreq, smb2_connect_negprot_done, req);
151 }
152
153 static void smb2_connect_session_done(struct tevent_req *subreq);
154
155 static void smb2_connect_negprot_done(struct tevent_req *subreq)
156 {
157         struct tevent_req *req =
158                 tevent_req_callback_data(subreq,
159                 struct tevent_req);
160         struct smb2_connect_state *state =
161                 tevent_req_data(req,
162                 struct smb2_connect_state);
163         struct smb2_transport *transport = state->transport;
164         NTSTATUS status;
165
166         status = smbXcli_negprot_recv(subreq);
167         TALLOC_FREE(subreq);
168         if (tevent_req_nterror(req, status)) {
169                 return;
170         }
171
172         /* This is a hack... */
173         smb2cli_conn_set_max_credits(transport->conn, 30);
174
175         state->session = smb2_session_init(transport, state->gensec_settings, state, true);
176         if (tevent_req_nomem(state->session, req)) {
177                 return;
178         }
179
180         subreq = smb2_session_setup_spnego_send(state, state->ev,
181                                                 state->session,
182                                                 state->credentials,
183                                                 state->previous_session_id);
184         if (tevent_req_nomem(subreq, req)) {
185                 return;
186         }
187         tevent_req_set_callback(subreq, smb2_connect_session_done, req);
188 }
189
190 static void smb2_connect_tcon_done(struct smb2_request *smb2req);
191
192 static void smb2_connect_session_done(struct tevent_req *subreq)
193 {
194         struct tevent_req *req =
195                 tevent_req_callback_data(subreq,
196                 struct tevent_req);
197         struct smb2_connect_state *state =
198                 tevent_req_data(req,
199                 struct smb2_connect_state);
200         struct smb2_request *smb2req;
201         NTSTATUS status;
202
203         status = smb2_session_setup_spnego_recv(subreq);
204         TALLOC_FREE(subreq);
205         if (tevent_req_nterror(req, status)) {
206                 return;
207         }
208
209         state->tcon.in.reserved = 0;
210         state->tcon.in.path     = talloc_asprintf(state, "\\\\%s\\%s",
211                                                   state->host, state->share);
212         if (tevent_req_nomem(state->tcon.in.path, req)) {
213                 return;
214         }
215
216         smb2req = smb2_tree_connect_send(state->session, &state->tcon);
217         if (tevent_req_nomem(smb2req, req)) {
218                 return;
219         }
220         smb2req->async.fn = smb2_connect_tcon_done;
221         smb2req->async.private_data = req;
222 }
223
224 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
225 {
226         struct tevent_req *req =
227                 talloc_get_type_abort(smb2req->async.private_data,
228                 struct tevent_req);
229         struct smb2_connect_state *state =
230                 tevent_req_data(req,
231                 struct smb2_connect_state);
232         NTSTATUS status;
233
234         status = smb2_tree_connect_recv(smb2req, &state->tcon);
235         if (tevent_req_nterror(req, status)) {
236                 return;
237         }
238
239         state->tree = smb2_tree_init(state->session, state, true);
240         if (tevent_req_nomem(state->tree, req)) {
241                 return;
242         }
243
244         smb2cli_tcon_set_values(state->tree->smbXcli,
245                                 state->session->smbXcli,
246                                 state->tcon.out.tid,
247                                 state->tcon.out.share_type,
248                                 state->tcon.out.flags,
249                                 state->tcon.out.capabilities,
250                                 state->tcon.out.access_mask);
251
252         tevent_req_done(req);
253 }
254
255 NTSTATUS smb2_connect_recv(struct tevent_req *req,
256                            TALLOC_CTX *mem_ctx,
257                            struct smb2_tree **tree)
258 {
259         struct smb2_connect_state *state =
260                 tevent_req_data(req,
261                 struct smb2_connect_state);
262         NTSTATUS status;
263
264         if (tevent_req_is_nterror(req, &status)) {
265                 tevent_req_received(req);
266                 return status;
267         }
268
269         *tree = talloc_move(mem_ctx, &state->tree);
270
271         tevent_req_received(req);
272         return NT_STATUS_OK;
273 }
274
275 /*
276   sync version of smb2_connect
277 */
278 NTSTATUS smb2_connect_ext(TALLOC_CTX *mem_ctx,
279                           const char *host,
280                           const char **ports,
281                           const char *share,
282                           struct resolve_context *resolve_ctx,
283                           struct cli_credentials *credentials,
284                           uint64_t previous_session_id,
285                           struct smb2_tree **tree,
286                           struct tevent_context *ev,
287                           const struct smbcli_options *options,
288                           const char *socket_options,
289                           struct gensec_settings *gensec_settings)
290 {
291         struct tevent_req *subreq;
292         NTSTATUS status;
293         bool ok;
294         TALLOC_CTX *frame = talloc_stackframe();
295
296         if (frame == NULL) {
297                 return NT_STATUS_NO_MEMORY;
298         }
299
300         subreq = smb2_connect_send(frame,
301                                    ev,
302                                    host,
303                                    ports,
304                                    share,
305                                    resolve_ctx,
306                                    credentials,
307                                    previous_session_id,
308                                    options,
309                                    socket_options,
310                                    gensec_settings);
311         if (subreq == NULL) {
312                 TALLOC_FREE(frame);
313                 return NT_STATUS_NO_MEMORY;
314         }
315
316         ok = tevent_req_poll(subreq, ev);
317         if (!ok) {
318                 status = map_nt_error_from_unix_common(errno);
319                 TALLOC_FREE(frame);
320                 return status;
321         }
322
323         status = smb2_connect_recv(subreq, mem_ctx, tree);
324         TALLOC_FREE(subreq);
325         if (!NT_STATUS_IS_OK(status)) {
326                 TALLOC_FREE(frame);
327                 return status;
328         }
329
330         TALLOC_FREE(frame);
331         return NT_STATUS_OK;
332 }
333
334 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
335                       const char *host,
336                       const char **ports,
337                       const char *share,
338                       struct resolve_context *resolve_ctx,
339                       struct cli_credentials *credentials,
340                       struct smb2_tree **tree,
341                       struct tevent_context *ev,
342                       struct smbcli_options *options,
343                       const char *socket_options,
344                       struct gensec_settings *gensec_settings)
345 {
346         NTSTATUS status;
347
348         status = smb2_connect_ext(mem_ctx, host, ports, share, resolve_ctx,
349                                   credentials,
350                                   0, /* previous_session_id */
351                                   tree, ev, options, socket_options,
352                                   gensec_settings);
353
354         return status;
355 }