s4:libcli/smb2: implement on top of smbXcli_conn/req
[Samba/gebeck_regimport.git] / source4 / libcli / smb2 / connect.c
blob0d97691a440582bf2dd66dbdc7cf747f392be614
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 "../libcli/smb/smbXcli_base.h"
34 struct smb2_connect_state {
35 struct tevent_context *ev;
36 struct cli_credentials *credentials;
37 struct resolve_context *resolve_ctx;
38 const char *host;
39 const char *share;
40 const char **ports;
41 const char *socket_options;
42 struct gensec_settings *gensec_settings;
43 struct smbcli_options options;
44 struct smb2_transport *transport;
45 struct smb2_tree_connect tcon;
46 struct smb2_session *session;
47 struct smb2_tree *tree;
50 static void smb2_connect_resolve_done(struct composite_context *creq);
53 a composite function that does a full negprot/sesssetup/tcon, returning
54 a connected smb2_tree
56 struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
57 struct tevent_context *ev,
58 const char *host,
59 const char **ports,
60 const char *share,
61 struct resolve_context *resolve_ctx,
62 struct cli_credentials *credentials,
63 struct smbcli_options *options,
64 const char *socket_options,
65 struct gensec_settings *gensec_settings)
67 struct tevent_req *req;
68 struct smb2_connect_state *state;
69 struct nbt_name name;
70 struct composite_context *creq;
72 req = tevent_req_create(mem_ctx, &state,
73 struct smb2_connect_state);
74 if (req == NULL) {
75 return NULL;
78 state->ev = ev;
79 state->credentials = credentials;
80 state->options = *options;
81 state->host = host;
82 state->ports = ports;
83 state->share = share;
84 state->resolve_ctx = resolve_ctx;
85 state->socket_options = socket_options;
86 state->gensec_settings = gensec_settings;
88 ZERO_STRUCT(name);
89 name.name = host;
91 creq = resolve_name_send(resolve_ctx, state, &name, ev);
92 if (tevent_req_nomem(creq, req)) {
93 return tevent_req_post(req, ev);
95 creq->async.fn = smb2_connect_resolve_done;
96 creq->async.private_data = req;
97 return req;
100 static void smb2_connect_socket_done(struct composite_context *creq);
102 static void smb2_connect_resolve_done(struct composite_context *creq)
104 struct tevent_req *req =
105 talloc_get_type_abort(creq->async.private_data,
106 struct tevent_req);
107 struct smb2_connect_state *state =
108 tevent_req_data(req,
109 struct smb2_connect_state);
110 NTSTATUS status;
111 const char *addr;
112 const char **ports;
113 const char *default_ports[] = { "445", NULL };
115 status = resolve_name_recv(creq, state, &addr);
116 if (tevent_req_nterror(req, status)) {
117 return;
120 if (state->ports == NULL) {
121 ports = default_ports;
122 } else {
123 ports = state->ports;
126 creq = smbcli_sock_connect_send(state, addr, ports,
127 state->host, state->resolve_ctx,
128 state->ev, state->socket_options);
129 if (tevent_req_nomem(creq, req)) {
130 return;
132 creq->async.fn = smb2_connect_socket_done;
133 creq->async.private_data = req;
136 static void smb2_connect_negprot_done(struct tevent_req *subreq);
138 static void smb2_connect_socket_done(struct composite_context *creq)
140 struct tevent_req *req =
141 talloc_get_type_abort(creq->async.private_data,
142 struct tevent_req);
143 struct smb2_connect_state *state =
144 tevent_req_data(req,
145 struct smb2_connect_state);
146 struct smbcli_socket *sock;
147 struct tevent_req *subreq;
148 NTSTATUS status;
149 uint32_t timeout_msec;
151 status = smbcli_sock_connect_recv(creq, state, &sock);
152 if (tevent_req_nterror(req, status)) {
153 return;
156 state->transport = smb2_transport_init(sock, state, &state->options);
157 if (tevent_req_nomem(state->transport, req)) {
158 return;
161 timeout_msec = state->transport->options.request_timeout * 1000;
163 subreq = smbXcli_negprot_send(state, state->ev,
164 state->transport->conn, timeout_msec,
165 PROTOCOL_SMB2_02, PROTOCOL_SMB2_22);
166 if (tevent_req_nomem(subreq, req)) {
167 return;
169 tevent_req_set_callback(subreq, smb2_connect_negprot_done, req);
172 static void smb2_connect_session_done(struct tevent_req *subreq);
174 static void smb2_connect_negprot_done(struct tevent_req *subreq)
176 struct tevent_req *req =
177 tevent_req_callback_data(subreq,
178 struct tevent_req);
179 struct smb2_connect_state *state =
180 tevent_req_data(req,
181 struct smb2_connect_state);
182 struct smb2_transport *transport = state->transport;
183 NTSTATUS status;
185 status = smbXcli_negprot_recv(subreq);
186 TALLOC_FREE(subreq);
187 if (tevent_req_nterror(req, status)) {
188 return;
191 /* This is a hack... */
192 smb2cli_conn_set_max_credits(transport->conn, 30);
194 state->session = smb2_session_init(transport, state->gensec_settings, state, true);
195 if (tevent_req_nomem(state->session, req)) {
196 return;
199 subreq = smb2_session_setup_spnego_send(state, state->ev,
200 state->session,
201 state->credentials);
202 if (tevent_req_nomem(subreq, req)) {
203 return;
205 tevent_req_set_callback(subreq, smb2_connect_session_done, req);
208 static void smb2_connect_tcon_done(struct smb2_request *smb2req);
210 static void smb2_connect_session_done(struct tevent_req *subreq)
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 struct smb2_request *smb2req;
219 NTSTATUS status;
221 status = smb2_session_setup_spnego_recv(subreq);
222 TALLOC_FREE(subreq);
223 if (tevent_req_nterror(req, status)) {
224 return;
227 state->tree = smb2_tree_init(state->session, state, true);
228 if (tevent_req_nomem(state->tree, req)) {
229 return;
232 state->tcon.in.reserved = 0;
233 state->tcon.in.path = talloc_asprintf(state, "\\\\%s\\%s",
234 state->host, state->share);
235 if (tevent_req_nomem(state->tcon.in.path, req)) {
236 return;
239 smb2req = smb2_tree_connect_send(state->tree, &state->tcon);
240 if (tevent_req_nomem(smb2req, req)) {
241 return;
243 smb2req->async.fn = smb2_connect_tcon_done;
244 smb2req->async.private_data = req;
247 static void smb2_connect_tcon_done(struct smb2_request *smb2req)
249 struct tevent_req *req =
250 talloc_get_type_abort(smb2req->async.private_data,
251 struct tevent_req);
252 struct smb2_connect_state *state =
253 tevent_req_data(req,
254 struct smb2_connect_state);
255 NTSTATUS status;
257 status = smb2_tree_connect_recv(smb2req, &state->tcon);
258 if (tevent_req_nterror(req, status)) {
259 return;
262 state->tree->tid = state->tcon.out.tid;
264 tevent_req_done(req);
267 NTSTATUS smb2_connect_recv(struct tevent_req *req,
268 TALLOC_CTX *mem_ctx,
269 struct smb2_tree **tree)
271 struct smb2_connect_state *state =
272 tevent_req_data(req,
273 struct smb2_connect_state);
274 NTSTATUS status;
276 if (tevent_req_is_nterror(req, &status)) {
277 tevent_req_received(req);
278 return status;
281 *tree = talloc_move(mem_ctx, &state->tree);
283 tevent_req_received(req);
284 return NT_STATUS_OK;
288 sync version of smb2_connect
290 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
291 const char *host,
292 const char **ports,
293 const char *share,
294 struct resolve_context *resolve_ctx,
295 struct cli_credentials *credentials,
296 struct smb2_tree **tree,
297 struct tevent_context *ev,
298 struct smbcli_options *options,
299 const char *socket_options,
300 struct gensec_settings *gensec_settings)
302 struct tevent_req *subreq;
303 NTSTATUS status;
304 bool ok;
305 TALLOC_CTX *frame = talloc_stackframe();
307 if (frame == NULL) {
308 return NT_STATUS_NO_MEMORY;
311 subreq = smb2_connect_send(frame,
313 host,
314 ports,
315 share,
316 resolve_ctx,
317 credentials,
318 options,
319 socket_options,
320 gensec_settings);
321 if (subreq == NULL) {
322 TALLOC_FREE(frame);
323 return NT_STATUS_NO_MEMORY;
326 ok = tevent_req_poll(subreq, ev);
327 if (!ok) {
328 status = map_nt_error_from_unix_common(errno);
329 TALLOC_FREE(frame);
330 return status;
333 status = smb2_connect_recv(subreq, mem_ctx, tree);
334 TALLOC_FREE(subreq);
335 if (!NT_STATUS_IS_OK(status)) {
336 TALLOC_FREE(frame);
337 return status;
340 TALLOC_FREE(frame);
341 return NT_STATUS_OK;