s4:libcli:smb2: add a previous session argument to smb2_session_setup_spnego()
[Samba/gbeck.git] / source4 / libcli / smb2 / connect.c
blobf1cf1087237258bf5400e968a7e939f41ad1c7c9
1 /*
2 Unix SMB/CIFS implementation.
4 SMB2 composite connection setup
6 Copyright (C) Andrew Tridgell 2005
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.
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.
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/>.
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"
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;
52 static void smb2_connect_socket_done(struct composite_context *creq);
55 a composite function that does a full negprot/sesssetup/tcon, returning
56 a connected smb2_tree
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)
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 };
74 req = tevent_req_create(mem_ctx, &state,
75 struct smb2_connect_state);
76 if (req == NULL) {
77 return NULL;
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;
90 if (state->ports == NULL) {
91 state->ports = default_ports;
94 make_nbt_name_client(&state->calling,
95 cli_credentials_get_workstation(credentials));
97 nbt_choose_called_name(state, &state->called,
98 host, NBT_NAME_SERVER);
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);
108 creq->async.fn = smb2_connect_socket_done;
109 creq->async.private_data = req;
111 return req;
114 static void smb2_connect_negprot_done(struct tevent_req *subreq);
116 static void smb2_connect_socket_done(struct composite_context *creq)
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;
129 status = smbcli_sock_connect_recv(creq, state, &sock);
130 if (tevent_req_nterror(req, status)) {
131 return;
134 state->transport = smb2_transport_init(sock, state, &state->options);
135 if (tevent_req_nomem(state->transport, req)) {
136 return;
139 timeout_msec = state->transport->options.request_timeout * 1000;
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;
147 tevent_req_set_callback(subreq, smb2_connect_negprot_done, req);
150 static void smb2_connect_session_done(struct tevent_req *subreq);
152 static void smb2_connect_negprot_done(struct tevent_req *subreq)
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;
163 status = smbXcli_negprot_recv(subreq);
164 TALLOC_FREE(subreq);
165 if (tevent_req_nterror(req, status)) {
166 return;
169 /* This is a hack... */
170 smb2cli_conn_set_max_credits(transport->conn, 30);
172 state->session = smb2_session_init(transport, state->gensec_settings, state, true);
173 if (tevent_req_nomem(state->session, req)) {
174 return;
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;
184 tevent_req_set_callback(subreq, smb2_connect_session_done, req);
187 static void smb2_connect_tcon_done(struct smb2_request *smb2req);
189 static void smb2_connect_session_done(struct tevent_req *subreq)
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;
200 status = smb2_session_setup_spnego_recv(subreq);
201 TALLOC_FREE(subreq);
202 if (tevent_req_nterror(req, status)) {
203 return;
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;
213 smb2req = smb2_tree_connect_send(state->session, &state->tcon);
214 if (tevent_req_nomem(smb2req, req)) {
215 return;
217 smb2req->async.fn = smb2_connect_tcon_done;
218 smb2req->async.private_data = req;
221 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
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;
231 status = smb2_tree_connect_recv(smb2req, &state->tcon);
232 if (tevent_req_nterror(req, status)) {
233 return;
236 state->tree = smb2_tree_init(state->session, state, true);
237 if (tevent_req_nomem(state->tree, req)) {
238 return;
241 state->tree->tid = state->tcon.out.tid;
243 tevent_req_done(req);
246 NTSTATUS smb2_connect_recv(struct tevent_req *req,
247 TALLOC_CTX *mem_ctx,
248 struct smb2_tree **tree)
250 struct smb2_connect_state *state =
251 tevent_req_data(req,
252 struct smb2_connect_state);
253 NTSTATUS status;
255 if (tevent_req_is_nterror(req, &status)) {
256 tevent_req_received(req);
257 return status;
260 *tree = talloc_move(mem_ctx, &state->tree);
262 tevent_req_received(req);
263 return NT_STATUS_OK;
267 sync version of smb2_connect
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)
281 struct tevent_req *subreq;
282 NTSTATUS status;
283 bool ok;
284 TALLOC_CTX *frame = talloc_stackframe();
286 if (frame == NULL) {
287 return NT_STATUS_NO_MEMORY;
290 subreq = smb2_connect_send(frame,
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;
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;
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;
319 TALLOC_FREE(frame);
320 return NT_STATUS_OK;