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