4d250fdded47c15b630a1c04463c96b6ee205485
[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 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         const char *ports[2] = { "445", NULL };
151
152         c->status = resolve_name_recv(creq, state, &addr);
153         if (!composite_is_ok(c)) return;
154
155         creq = smbcli_sock_connect_send(state, addr, ports, state->host, c->event_ctx);
156
157         composite_continue(c, creq, continue_socket, c);
158 }
159
160 /*
161   a composite function that does a full negprot/sesssetup/tcon, returning
162   a connected smb2_tree
163  */
164 struct composite_context *smb2_connect_send(TALLOC_CTX *mem_ctx,
165                                             const char *host,
166                                             const char *share,
167                                             struct resolve_context *resolve_ctx,
168                                             struct cli_credentials *credentials,
169                                             struct event_context *ev)
170 {
171         struct composite_context *c;
172         struct smb2_connect_state *state;
173         struct nbt_name name;
174         struct composite_context *creq;
175
176         c = composite_create(mem_ctx, ev);
177         if (c == NULL) return NULL;
178
179         state = talloc(c, struct smb2_connect_state);
180         if (composite_nomem(state, c)) return c;
181         c->private_data = state;
182
183         state->credentials = credentials;
184         state->host = talloc_strdup(c, host);
185         if (composite_nomem(state->host, c)) return c;
186         state->share = talloc_strdup(c, share);
187         if (composite_nomem(state->share, c)) return c;
188
189         ZERO_STRUCT(name);
190         name.name = host;
191
192         creq = resolve_name_send(resolve_ctx, &name, c->event_ctx);
193         composite_continue(c, creq, continue_resolve, c);
194         return c;
195 }
196
197 /*
198   receive a connect reply
199 */
200 NTSTATUS smb2_connect_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
201                            struct smb2_tree **tree)
202 {
203         NTSTATUS status;
204         struct smb2_connect_state *state = talloc_get_type(c->private_data, 
205                                                            struct smb2_connect_state);
206         status = composite_wait(c);
207         if (NT_STATUS_IS_OK(status)) {
208                 *tree = talloc_steal(mem_ctx, state->tree);
209         }
210         talloc_free(c);
211         return status;
212 }
213
214 /*
215   sync version of smb2_connect
216 */
217 NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx, 
218                       const char *host, const char *share,
219                       struct resolve_context *resolve_ctx,
220                       struct cli_credentials *credentials,
221                       struct smb2_tree **tree,
222                       struct event_context *ev)
223 {
224         struct composite_context *c = smb2_connect_send(mem_ctx, host, share, 
225                                                         resolve_ctx,
226                                                         credentials, ev);
227         return smb2_connect_recv(c, mem_ctx, tree);
228 }