Add context for libcli_resolve.
[samba-svnmirror.git] / source / 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 "libcli/raw/libcliraw.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "libcli/composite/composite.h"
27 #include "libcli/resolve/resolve.h"
28 #include "param/param.h"
29
30 struct smb2_connect_state {
31         struct cli_credentials *credentials;
32         const char *host;
33         const char *share;
34         struct smb2_negprot negprot;
35         struct smb2_tree_connect tcon;
36         struct smb2_session *session;
37         struct smb2_tree *tree;
38 };
39
40 /*
41   continue after tcon reply
42 */
43 static void continue_tcon(struct smb2_request *req)
44 {
45         struct composite_context *c = talloc_get_type(req->async.private, 
46                                                       struct composite_context);
47         struct smb2_connect_state *state = talloc_get_type(c->private_data, 
48                                                            struct smb2_connect_state);
49
50         c->status = smb2_tree_connect_recv(req, &state->tcon);
51         if (!composite_is_ok(c)) return;
52         
53         state->tree->tid = state->tcon.out.tid;
54
55         composite_done(c);
56 }
57
58 /*
59   continue after a session setup
60 */
61 static void continue_session(struct composite_context *creq)
62 {
63         struct composite_context *c = talloc_get_type(creq->async.private_data, 
64                                                       struct composite_context);
65         struct smb2_connect_state *state = talloc_get_type(c->private_data, 
66                                                            struct smb2_connect_state);
67         struct smb2_request *req;
68
69         c->status = smb2_session_setup_spnego_recv(creq);
70         if (!composite_is_ok(c)) return;
71
72         state->tree = smb2_tree_init(state->session, state, true);
73         if (composite_nomem(state->tree, c)) return;
74
75         state->tcon.in.unknown1 = 0x09;
76         state->tcon.in.path     = talloc_asprintf(state, "\\\\%s\\%s", 
77                                                   state->host, state->share);
78         if (composite_nomem(state->tcon.in.path, c)) return;
79         
80         req = smb2_tree_connect_send(state->tree, &state->tcon);
81         if (composite_nomem(req, c)) return;
82
83         req->async.fn = continue_tcon;
84         req->async.private = c; 
85 }
86
87 /*
88   continue after negprot reply
89 */
90 static void continue_negprot(struct smb2_request *req)
91 {
92         struct composite_context *c = talloc_get_type(req->async.private, 
93                                                       struct composite_context);
94         struct smb2_connect_state *state = talloc_get_type(c->private_data, 
95                                                            struct smb2_connect_state);
96         struct smb2_transport *transport = req->transport;
97         struct composite_context *creq;
98
99         c->status = smb2_negprot_recv(req, c, &state->negprot);
100         if (!composite_is_ok(c)) return;
101
102         state->session = smb2_session_init(transport, global_loadparm, state, true);
103         if (composite_nomem(state->session, c)) return;
104
105         creq = smb2_session_setup_spnego_send(state->session, state->credentials);
106
107         composite_continue(c, creq, continue_session, c);
108 }
109
110 /*
111   continue after a socket connect completes
112 */
113 static void continue_socket(struct composite_context *creq)
114 {
115         struct composite_context *c = talloc_get_type(creq->async.private_data, 
116                                                       struct composite_context);
117         struct smb2_connect_state *state = talloc_get_type(c->private_data, 
118                                                            struct smb2_connect_state);
119         struct smbcli_socket *sock;
120         struct smb2_transport *transport;
121         struct smb2_request *req;
122
123         c->status = smbcli_sock_connect_recv(creq, state, &sock);
124         if (!composite_is_ok(c)) return;
125
126         transport = smb2_transport_init(sock, state);
127         if (composite_nomem(transport, c)) return;
128
129         ZERO_STRUCT(state->negprot);
130         state->negprot.in.unknown1 = 0x0001;
131
132         req = smb2_negprot_send(transport, &state->negprot);
133         if (composite_nomem(req, c)) return;
134
135         req->async.fn = continue_negprot;
136         req->async.private = c;
137 }
138
139
140 /*
141   continue after a resolve finishes
142 */
143 static void continue_resolve(struct composite_context *creq)
144 {
145         struct composite_context *c = talloc_get_type(creq->async.private_data, 
146                                                       struct composite_context);
147         struct smb2_connect_state *state = talloc_get_type(c->private_data, 
148                                                            struct smb2_connect_state);
149         const char *addr;
150         
151         c->status = resolve_name_recv(creq, state, &addr);
152         if (!composite_is_ok(c)) return;
153
154         creq = smbcli_sock_connect_send(state, addr, 445, state->host, c->event_ctx);
155
156         composite_continue(c, creq, continue_socket, c);
157 }
158
159 /*
160   a composite function that does a full negprot/sesssetup/tcon, returning
161   a connected smb2_tree
162  */
163 struct composite_context *smb2_connect_send(TALLOC_CTX *mem_ctx,
164                                             const char *host,
165                                             const char *share,
166                                             struct resolve_context *resolve_ctx,
167                                             struct cli_credentials *credentials,
168                                             struct event_context *ev)
169 {
170         struct composite_context *c;
171         struct smb2_connect_state *state;
172         struct nbt_name name;
173         struct composite_context *creq;
174
175         c = composite_create(mem_ctx, ev);
176         if (c == NULL) return NULL;
177
178         state = talloc(c, struct smb2_connect_state);
179         if (composite_nomem(state, c)) return c;
180         c->private_data = state;
181
182         state->credentials = credentials;
183         state->host = talloc_strdup(c, host);
184         if (composite_nomem(state->host, c)) return c;
185         state->share = talloc_strdup(c, share);
186         if (composite_nomem(state->share, c)) return c;
187
188         ZERO_STRUCT(name);
189         name.name = host;
190
191         creq = resolve_name_send(resolve_ctx, &name, c->event_ctx);
192         composite_continue(c, creq, continue_resolve, c);
193         return c;
194 }
195
196 /*
197   receive a connect reply
198 */
199 NTSTATUS smb2_connect_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
200                            struct smb2_tree **tree)
201 {
202         NTSTATUS status;
203         struct smb2_connect_state *state = talloc_get_type(c->private_data, 
204                                                            struct smb2_connect_state);
205         status = composite_wait(c);
206         if (NT_STATUS_IS_OK(status)) {
207                 *tree = talloc_steal(mem_ctx, state->tree);
208         }
209         talloc_free(c);
210         return status;
211 }
212
213 /*
214   sync version of smb2_connect
215 */
216 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx, 
217                       const char *host, const char *share,
218                       struct resolve_context *resolve_ctx,
219                       struct cli_credentials *credentials,
220                       struct smb2_tree **tree,
221                       struct event_context *ev)
222 {
223         struct composite_context *c = smb2_connect_send(mem_ctx, host, share, 
224                                                         resolve_ctx,
225                                                         credentials, ev);
226         return smb2_connect_recv(c, mem_ctx, tree);
227 }