s4:dsdb/subtree_delete: do an early return and avoid some nesting
[Samba/gebeck_regimport.git] / source4 / libcli / smb2 / connect.c
blob5cdf258e7c0517c129546dbd28baf2b44058156b
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 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;
53 static void smb2_connect_socket_done(struct composite_context *creq);
56 a composite function that does a full negprot/sesssetup/tcon, returning
57 a connected smb2_tree
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 struct smbcli_options *options,
68 const char *socket_options,
69 struct gensec_settings *gensec_settings)
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 };
76 req = tevent_req_create(mem_ctx, &state,
77 struct smb2_connect_state);
78 if (req == NULL) {
79 return NULL;
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;
93 if (state->ports == NULL) {
94 state->ports = default_ports;
97 make_nbt_name_client(&state->calling,
98 cli_credentials_get_workstation(credentials));
100 nbt_choose_called_name(state, &state->called,
101 host, NBT_NAME_SERVER);
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);
111 creq->async.fn = smb2_connect_socket_done;
112 creq->async.private_data = req;
114 return req;
117 static void smb2_connect_negprot_done(struct tevent_req *subreq);
119 static void smb2_connect_socket_done(struct composite_context *creq)
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;
132 status = smbcli_sock_connect_recv(creq, state, &sock);
133 if (tevent_req_nterror(req, status)) {
134 return;
137 state->transport = smb2_transport_init(sock, state, &state->options);
138 if (tevent_req_nomem(state->transport, req)) {
139 return;
142 timeout_msec = state->transport->options.request_timeout * 1000;
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;
150 tevent_req_set_callback(subreq, smb2_connect_negprot_done, req);
153 static void smb2_connect_session_done(struct tevent_req *subreq);
155 static void smb2_connect_negprot_done(struct tevent_req *subreq)
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;
166 status = smbXcli_negprot_recv(subreq);
167 TALLOC_FREE(subreq);
168 if (tevent_req_nterror(req, status)) {
169 return;
172 /* This is a hack... */
173 smb2cli_conn_set_max_credits(transport->conn, 30);
175 state->session = smb2_session_init(transport, state->gensec_settings, state, true);
176 if (tevent_req_nomem(state->session, req)) {
177 return;
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;
187 tevent_req_set_callback(subreq, smb2_connect_session_done, req);
190 static void smb2_connect_tcon_done(struct smb2_request *smb2req);
192 static void smb2_connect_session_done(struct tevent_req *subreq)
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;
203 status = smb2_session_setup_spnego_recv(subreq);
204 TALLOC_FREE(subreq);
205 if (tevent_req_nterror(req, status)) {
206 return;
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;
216 smb2req = smb2_tree_connect_send(state->session, &state->tcon);
217 if (tevent_req_nomem(smb2req, req)) {
218 return;
220 smb2req->async.fn = smb2_connect_tcon_done;
221 smb2req->async.private_data = req;
224 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
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;
234 status = smb2_tree_connect_recv(smb2req, &state->tcon);
235 if (tevent_req_nterror(req, status)) {
236 return;
239 state->tree = smb2_tree_init(state->session, state, true);
240 if (tevent_req_nomem(state->tree, req)) {
241 return;
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);
252 tevent_req_done(req);
255 NTSTATUS smb2_connect_recv(struct tevent_req *req,
256 TALLOC_CTX *mem_ctx,
257 struct smb2_tree **tree)
259 struct smb2_connect_state *state =
260 tevent_req_data(req,
261 struct smb2_connect_state);
262 NTSTATUS status;
264 if (tevent_req_is_nterror(req, &status)) {
265 tevent_req_received(req);
266 return status;
269 *tree = talloc_move(mem_ctx, &state->tree);
271 tevent_req_received(req);
272 return NT_STATUS_OK;
276 sync version of smb2_connect
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 struct smbcli_options *options,
288 const char *socket_options,
289 struct gensec_settings *gensec_settings)
291 struct tevent_req *subreq;
292 NTSTATUS status;
293 bool ok;
294 TALLOC_CTX *frame = talloc_stackframe();
296 if (frame == NULL) {
297 return NT_STATUS_NO_MEMORY;
300 subreq = smb2_connect_send(frame,
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;
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;
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;
330 TALLOC_FREE(frame);
331 return NT_STATUS_OK;
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)
346 NTSTATUS status;
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);
354 return status;