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