a365f25d4957286ec34aa4a5e4b0f96eae4dc385
[kai/samba-autobuild/.git] / source4 / 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
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 = composite_create(mem_ctx, ev);
174         if (c == NULL) return NULL;
175
176         state = talloc(c, struct smb2_connect_state);
177         if (composite_nomem(state, c)) return c;
178         c->private_data = state;
179
180         state->credentials = credentials;
181         state->host = talloc_strdup(c, host);
182         if (composite_nomem(state->host, c)) return c;
183         state->share = talloc_strdup(c, share);
184         if (composite_nomem(state->share, c)) return c;
185
186         ZERO_STRUCT(name);
187         name.name = host;
188
189         creq = resolve_name_send(&name, c->event_ctx, lp_name_resolve_order());
190         composite_continue(c, creq, continue_resolve, c);
191         return c;
192 }
193
194 /*
195   receive a connect reply
196 */
197 NTSTATUS smb2_connect_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
198                            struct smb2_tree **tree)
199 {
200         NTSTATUS status;
201         struct smb2_connect_state *state = talloc_get_type(c->private_data, 
202                                                            struct smb2_connect_state);
203         status = composite_wait(c);
204         if (NT_STATUS_IS_OK(status)) {
205                 *tree = talloc_steal(mem_ctx, state->tree);
206         }
207         talloc_free(c);
208         return status;
209 }
210
211 /*
212   sync version of smb2_connect
213 */
214 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx, 
215                       const char *host, const char *share,
216                       struct cli_credentials *credentials,
217                       struct smb2_tree **tree,
218                       struct event_context *ev)
219 {
220         struct composite_context *c = smb2_connect_send(mem_ctx, host, share, 
221                                                         credentials, ev);
222         return smb2_connect_recv(c, mem_ctx, tree);
223 }