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