r4777: added a smb_composite_sesssetup() async composite function. This
[gd/samba-autobuild/.git] / source4 / libcli / composite / connect.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Andrew Tridgell 2005
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 /*
21   a composite API for making a full SMB connection
22 */
23
24 #include "includes.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "libcli/composite/composite.h"
27
28 /* the stages of this call */
29 enum connect_stage {CONNECT_SOCKET, 
30                     CONNECT_SESSION_REQUEST, 
31                     CONNECT_NEGPROT,
32                     CONNECT_SESSION_SETUP,
33                     CONNECT_TCON};
34
35 struct connect_state {
36         struct smbcli_socket *sock;
37         struct smbcli_transport *transport;
38         struct smbcli_session *session;
39 };
40
41
42 static void request_handler(struct smbcli_request *);
43 static void composite_handler(struct smbcli_composite *);
44
45 /*
46   setup a negprot send 
47 */
48 static NTSTATUS connect_send_negprot(struct smbcli_composite *c, 
49                                      struct smb_composite_connect *io)
50 {
51         struct connect_state *state = c->private;
52         struct smbcli_request *req;
53
54         req = smb_raw_negotiate_send(state->transport, lp_maxprotocol());
55         NT_STATUS_HAVE_NO_MEMORY(req);
56
57         req->async.fn = request_handler;
58         req->async.private = c;
59         c->stage = CONNECT_NEGPROT;
60         c->req = req;
61         
62         return NT_STATUS_OK;
63 }
64
65
66 /*
67   a tree connect request has competed
68 */
69 static NTSTATUS connect_tcon(struct smbcli_composite *c, 
70                              struct smb_composite_connect *io)
71 {
72         struct smbcli_request *req = c->req;
73         union smb_tcon *io_tcon = c->req_parms;
74         NTSTATUS status;
75
76         status = smb_tree_connect_recv(req, c, io_tcon);
77         NT_STATUS_NOT_OK_RETURN(status);
78
79         io->out.tree->tid = io_tcon->tconx.out.tid;
80         if (io_tcon->tconx.out.dev_type) {
81                 io->out.tree->device = talloc_strdup(io->out.tree, 
82                                                      io_tcon->tconx.out.dev_type);
83         }
84         if (io_tcon->tconx.out.fs_type) {
85                 io->out.tree->fs_type = talloc_strdup(io->out.tree, 
86                                                       io_tcon->tconx.out.fs_type);
87         }
88
89         /* all done! */
90         c->state = SMBCLI_REQUEST_DONE;
91         if (c->async.fn) {
92                 c->async.fn(c);
93         }
94
95         return NT_STATUS_OK;
96 }
97
98
99 /*
100   a session setup request has competed
101 */
102 static NTSTATUS connect_session_setup(struct smbcli_composite *c, 
103                                       struct smb_composite_connect *io)
104 {
105         struct connect_state *state = c->private;
106         struct smbcli_composite *req = c->req;
107         struct smbcli_request *req2;
108         struct smb_composite_sesssetup *io_setup = c->req_parms;
109         union smb_tcon *io_tcon;
110         NTSTATUS status;
111
112         status = smb_composite_sesssetup_recv(req);
113         NT_STATUS_NOT_OK_RETURN(status);
114         
115         state->session->vuid = io_setup->out.vuid;
116         
117         /* setup for a tconx */
118         io->out.tree = smbcli_tree_init(state->session);
119         NT_STATUS_HAVE_NO_MEMORY(io->out.tree);
120
121         io_tcon = talloc(c, union smb_tcon);
122         NT_STATUS_HAVE_NO_MEMORY(io_tcon);
123
124         /* connect to a share using a tree connect */
125         io_tcon->generic.level = RAW_TCON_TCONX;
126         io_tcon->tconx.in.flags = 0;
127         io_tcon->tconx.in.password = data_blob(NULL, 0);        
128         
129         io_tcon->tconx.in.path = talloc_asprintf(io_tcon, 
130                                                  "\\\\%s\\%s", 
131                                                  io->in.called_name, 
132                                                  io->in.service);
133         NT_STATUS_HAVE_NO_MEMORY(io_tcon->tconx.in.path);
134         if (!io->in.service_type) {
135                 io_tcon->tconx.in.device = "?????";
136         } else {
137                 io_tcon->tconx.in.device = io->in.service_type;
138         }
139
140         req2 = smb_tree_connect_send(io->out.tree, io_tcon);
141         NT_STATUS_HAVE_NO_MEMORY(req2);
142
143         req2->async.fn = request_handler;
144         req2->async.private = c;
145         c->req_parms = io_tcon;
146         c->req = req2;
147         c->stage = CONNECT_TCON;
148
149         return NT_STATUS_OK;
150 }
151
152 /*
153   a negprot request has competed
154 */
155 static NTSTATUS connect_negprot(struct smbcli_composite *c, 
156                                 struct smb_composite_connect *io)
157 {
158         struct connect_state *state = c->private;
159         struct smbcli_request *req = c->req;
160         struct smbcli_composite *req2;
161         NTSTATUS status;
162         struct smb_composite_sesssetup *io_setup;
163
164         status = smb_raw_negotiate_recv(req);
165         NT_STATUS_NOT_OK_RETURN(status);
166
167         /* next step is a session setup */
168         state->session = smbcli_session_init(state->transport);
169         NT_STATUS_HAVE_NO_MEMORY(state->session);
170
171         /* get rid of the extra reference to the transport */
172         talloc_free(state->transport);
173
174         io_setup = talloc(c, struct smb_composite_sesssetup);
175         NT_STATUS_HAVE_NO_MEMORY(io_setup);
176
177         /* prepare a session setup to establish a security context */
178         io_setup->in.sesskey      = state->transport->negotiate.sesskey;
179         io_setup->in.capabilities = state->transport->negotiate.capabilities;
180         io_setup->in.domain       = io->in.domain;
181         io_setup->in.user         = io->in.user;
182         io_setup->in.password     = io->in.password;
183
184         req2 = smb_composite_sesssetup_send(state->session, io_setup);
185         NT_STATUS_HAVE_NO_MEMORY(req2);
186
187         req2->async.fn = composite_handler;
188         req2->async.private = c;
189         c->req_parms = io_setup;
190         c->req = req2;
191         c->stage = CONNECT_SESSION_SETUP;
192         
193         return NT_STATUS_OK;
194 }
195
196
197 /*
198   a session request operation has competed
199 */
200 static NTSTATUS connect_session_request(struct smbcli_composite *c, 
201                                         struct smb_composite_connect *io)
202 {
203         struct smbcli_request *req = c->req;
204         NTSTATUS status;
205
206         status = smbcli_transport_connect_recv(req);
207         NT_STATUS_NOT_OK_RETURN(status);
208
209         /* next step is a negprot */
210         return connect_send_negprot(c, io);
211 }
212
213 /*
214   a socket connection operation has competed
215 */
216 static NTSTATUS connect_socket(struct smbcli_composite *c, 
217                                struct smb_composite_connect *io)
218 {
219         struct connect_state *state = c->private;
220         NTSTATUS status;
221         struct smbcli_request *req;
222         struct nmb_name calling, called;
223
224         status = smbcli_sock_connect_recv(c->req);
225         NT_STATUS_NOT_OK_RETURN(status);
226
227         /* the socket is up - we can initialise the smbcli transport layer */
228         state->transport = smbcli_transport_init(state->sock);
229         NT_STATUS_HAVE_NO_MEMORY(state->transport);
230
231         /* we have a connected socket - next step is a session
232            request, if needed. Port 445 doesn't need it, so it goes
233            straight to the negprot */
234         if (state->sock->port == 445) {
235                 return connect_send_negprot(c, io);
236         }
237
238         make_nmb_name(&calling, io->in.calling_name, 0x0);
239         choose_called_name(&called, io->in.called_name, 0x20);
240
241         req = smbcli_transport_connect_send(state->transport, &calling, &called);
242         NT_STATUS_HAVE_NO_MEMORY(req);
243
244         req->async.fn = request_handler;
245         req->async.private = c;
246         c->stage = CONNECT_SESSION_REQUEST;
247         c->req = req;
248
249         return NT_STATUS_OK;
250 }
251
252
253
254 /*
255   handle and dispatch state transitions
256 */
257 static void state_handler(struct smbcli_composite *c)
258 {
259         struct smb_composite_connect *io = c->composite_parms;
260         
261         switch (c->stage) {
262         case CONNECT_SOCKET:
263                 c->status = connect_socket(c, io);
264                 break;
265         case CONNECT_SESSION_REQUEST:
266                 c->status = connect_session_request(c, io);
267                 break;
268         case CONNECT_NEGPROT:
269                 c->status = connect_negprot(c, io);
270                 break;
271         case CONNECT_SESSION_SETUP:
272                 c->status = connect_session_setup(c, io);
273                 break;
274         case CONNECT_TCON:
275                 c->status = connect_tcon(c, io);
276                 break;
277         }
278
279         if (!NT_STATUS_IS_OK(c->status)) {
280                 c->state = SMBCLI_REQUEST_ERROR;
281                 if (c->async.fn) {
282                         c->async.fn(c);
283                 }
284         }
285 }
286
287
288 /*
289   handler for completion of a smbcli_request sub-request
290 */
291 static void request_handler(struct smbcli_request *req)
292 {
293         struct smbcli_composite *c = req->async.private;
294         return state_handler(c);
295 }
296
297 /*
298   handler for completion of a smbcli_composite sub-request
299 */
300 static void composite_handler(struct smbcli_composite *req)
301 {
302         struct smbcli_composite *c = req->async.private;
303         return state_handler(c);
304 }
305
306 /*
307   a function to establish a smbcli_tree from scratch
308 */
309 struct smbcli_composite *smb_composite_connect_send(struct smb_composite_connect *io)
310 {
311         struct smbcli_composite *c, *req;
312         struct connect_state *state;
313
314         c = talloc_zero(NULL, struct smbcli_composite);
315         if (c == NULL) goto failed;
316
317         state = talloc(c, struct connect_state);
318         if (state == NULL) goto failed;
319
320         state->sock = smbcli_sock_init(state);
321         if (state->sock == NULL) goto failed;
322
323         c->state = SMBCLI_REQUEST_SEND;
324         c->composite_parms = io;
325         c->stage = CONNECT_SOCKET;
326         c->event_ctx = state->sock->event.ctx;
327         c->private = state;
328
329         req = smbcli_sock_connect_send(state->sock, io->in.dest_host, io->in.port);
330         if (req == NULL) goto failed;
331
332         req->async.private = c;
333         req->async.fn = composite_handler;
334         c->req = req;
335
336         return c;
337 failed:
338         talloc_free(c);
339         return NULL;
340 }
341
342 /*
343   recv half of async composite connect code
344 */
345 NTSTATUS smb_composite_connect_recv(struct smbcli_composite *c, TALLOC_CTX *mem_ctx)
346 {
347         NTSTATUS status;
348
349         status = smb_composite_wait(c);
350
351         if (NT_STATUS_IS_OK(status)) {
352                 struct smb_composite_connect *io = c->composite_parms;
353                 talloc_steal(mem_ctx, io->out.tree);
354         }
355
356         talloc_free(c);
357         return status;
358 }
359
360 /*
361   sync version of smb_composite_connect 
362 */
363 NTSTATUS smb_composite_connect(struct smb_composite_connect *io, TALLOC_CTX *mem_ctx)
364 {
365         struct smbcli_composite *c = smb_composite_connect_send(io);
366         return smb_composite_connect_recv(c, mem_ctx);
367 }