Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : SMB client socket context management functions
5 :
6 : Copyright (C) Andrew Tridgell 1994-2005
7 : Copyright (C) James Myers 2003 <myersjj@samba.org>
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/network.h"
25 : #include "../lib/async_req/async_sock.h"
26 : #include "../lib/util/tevent_ntstatus.h"
27 : #include "lib/events/events.h"
28 : #include "libcli/raw/libcliraw.h"
29 : #include "libcli/composite/composite.h"
30 : #include "lib/socket/socket.h"
31 : #include "libcli/resolve/resolve.h"
32 : #include "param/param.h"
33 : #include "libcli/raw/raw_proto.h"
34 : #include "../libcli/smb/read_smb.h"
35 :
36 : struct smbcli_transport_connect_state {
37 : struct tevent_context *ev;
38 : struct socket_context *sock;
39 : struct tevent_req *io_req;
40 : uint8_t *request;
41 : struct iovec iov;
42 : uint8_t *response;
43 : };
44 :
45 : static void smbcli_transport_connect_cleanup(struct tevent_req *req,
46 : enum tevent_req_state req_state);
47 : static void smbcli_transport_connect_writev_done(struct tevent_req *subreq);
48 : static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq);
49 :
50 15578 : static struct tevent_req *smbcli_transport_connect_send(TALLOC_CTX *mem_ctx,
51 : struct tevent_context *ev,
52 : struct socket_context *sock,
53 : uint16_t port,
54 : uint32_t timeout_msec,
55 : struct nbt_name *calling,
56 : struct nbt_name *called)
57 : {
58 842 : struct tevent_req *req;
59 842 : struct smbcli_transport_connect_state *state;
60 842 : struct tevent_req *subreq;
61 842 : DATA_BLOB calling_blob, called_blob;
62 842 : uint8_t *p;
63 842 : NTSTATUS status;
64 :
65 15578 : req = tevent_req_create(mem_ctx, &state,
66 : struct smbcli_transport_connect_state);
67 15578 : if (req == NULL) {
68 0 : return NULL;
69 : }
70 15578 : state->ev = ev;
71 15578 : state->sock = sock;
72 :
73 15578 : if (port != 139) {
74 15578 : tevent_req_done(req);
75 15578 : return tevent_req_post(req, ev);
76 : }
77 :
78 0 : tevent_req_set_cleanup_fn(req, smbcli_transport_connect_cleanup);
79 :
80 0 : status = nbt_name_to_blob(state, &calling_blob, calling);
81 0 : if (tevent_req_nterror(req, status)) {
82 0 : return tevent_req_post(req, ev);
83 : }
84 :
85 0 : status = nbt_name_to_blob(state, &called_blob, called);
86 0 : if (tevent_req_nterror(req, status)) {
87 0 : return tevent_req_post(req, ev);
88 : }
89 :
90 0 : state->request = talloc_array(state, uint8_t,
91 : NBT_HDR_SIZE +
92 : called_blob.length +
93 : calling_blob.length);
94 0 : if (tevent_req_nomem(state->request, req)) {
95 0 : return tevent_req_post(req, ev);
96 : }
97 :
98 : /* put in the destination name */
99 0 : p = state->request + NBT_HDR_SIZE;
100 0 : memcpy(p, called_blob.data, called_blob.length);
101 0 : p += called_blob.length;
102 :
103 0 : memcpy(p, calling_blob.data, calling_blob.length);
104 0 : p += calling_blob.length;
105 :
106 0 : _smb_setlen_nbt(state->request,
107 : PTR_DIFF(p, state->request) - NBT_HDR_SIZE);
108 0 : SCVAL(state->request, 0, NBSSrequest);
109 :
110 0 : state->iov.iov_len = talloc_array_length(state->request);
111 0 : state->iov.iov_base = (void *)state->request;
112 :
113 0 : subreq = writev_send(state, ev, NULL,
114 : sock->fd,
115 : true, /* err_on_readability */
116 0 : &state->iov, 1);
117 0 : if (tevent_req_nomem(subreq, req)) {
118 0 : return tevent_req_post(req, ev);
119 : }
120 0 : tevent_req_set_callback(subreq,
121 : smbcli_transport_connect_writev_done,
122 : req);
123 0 : state->io_req = subreq;
124 :
125 0 : if (timeout_msec > 0) {
126 0 : struct timeval endtime;
127 :
128 0 : endtime = timeval_current_ofs_msec(timeout_msec);
129 0 : if (!tevent_req_set_endtime(req, ev, endtime)) {
130 0 : return tevent_req_post(req, ev);
131 : }
132 : }
133 :
134 0 : return req;
135 : }
136 :
137 0 : static void smbcli_transport_connect_cleanup(struct tevent_req *req,
138 : enum tevent_req_state req_state)
139 : {
140 0 : struct smbcli_transport_connect_state *state =
141 0 : tevent_req_data(req,
142 : struct smbcli_transport_connect_state);
143 :
144 0 : TALLOC_FREE(state->io_req);
145 :
146 0 : if (state->sock == NULL) {
147 0 : return;
148 : }
149 :
150 0 : if (state->sock->fd == -1) {
151 0 : return;
152 : }
153 :
154 0 : if (req_state == TEVENT_REQ_DONE) {
155 : /*
156 : * we keep the socket open for the caller to use
157 : */
158 0 : state->sock = NULL;
159 0 : return;
160 : }
161 :
162 0 : close(state->sock->fd);
163 0 : state->sock->fd = -1;
164 0 : state->sock = NULL;
165 : }
166 :
167 0 : static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
168 : {
169 0 : struct tevent_req *req =
170 0 : tevent_req_callback_data(subreq,
171 : struct tevent_req);
172 0 : struct smbcli_transport_connect_state *state =
173 0 : tevent_req_data(req,
174 : struct smbcli_transport_connect_state);
175 0 : ssize_t ret;
176 0 : int err;
177 :
178 0 : state->io_req = NULL;
179 :
180 0 : ret = writev_recv(subreq, &err);
181 0 : TALLOC_FREE(subreq);
182 0 : if (ret == -1) {
183 0 : NTSTATUS status = map_nt_error_from_unix_common(err);
184 0 : tevent_req_nterror(req, status);
185 0 : return;
186 : }
187 :
188 0 : subreq = read_smb_send(state, state->ev,
189 0 : state->sock->fd);
190 0 : if (tevent_req_nomem(subreq, req)) {
191 0 : return;
192 : }
193 0 : tevent_req_set_callback(subreq,
194 : smbcli_transport_connect_read_smb_done,
195 : req);
196 0 : state->io_req = subreq;
197 : }
198 :
199 0 : static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
200 : {
201 0 : struct tevent_req *req =
202 0 : tevent_req_callback_data(subreq,
203 : struct tevent_req);
204 0 : struct smbcli_transport_connect_state *state =
205 0 : tevent_req_data(req,
206 : struct smbcli_transport_connect_state);
207 0 : ssize_t ret;
208 0 : int err;
209 0 : NTSTATUS status;
210 0 : uint8_t error;
211 :
212 0 : state->io_req = NULL;
213 :
214 0 : ret = read_smb_recv(subreq, state,
215 : &state->response, &err);
216 0 : TALLOC_FREE(subreq);
217 0 : if (ret == -1) {
218 0 : status = map_nt_error_from_unix_common(err);
219 0 : tevent_req_nterror(req, status);
220 0 : return;
221 : }
222 :
223 0 : if (ret < 4) {
224 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
225 0 : return;
226 : }
227 :
228 0 : switch (CVAL(state->response, 0)) {
229 0 : case NBSSpositive:
230 0 : tevent_req_done(req);
231 0 : return;
232 :
233 0 : case NBSSnegative:
234 0 : if (ret < 5) {
235 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
236 0 : return;
237 : }
238 :
239 0 : error = CVAL(state->response, 4);
240 0 : switch (error) {
241 0 : case 0x80:
242 : case 0x81:
243 0 : status = NT_STATUS_REMOTE_NOT_LISTENING;
244 0 : break;
245 0 : case 0x82:
246 0 : status = NT_STATUS_RESOURCE_NAME_NOT_FOUND;
247 0 : break;
248 0 : case 0x83:
249 0 : status = NT_STATUS_REMOTE_RESOURCES;
250 0 : break;
251 0 : default:
252 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
253 0 : break;
254 : }
255 0 : break;
256 :
257 0 : case NBSSretarget:
258 0 : DEBUG(1,("Warning: session retarget not supported\n"));
259 0 : status = NT_STATUS_NOT_SUPPORTED;
260 0 : break;
261 :
262 0 : default:
263 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
264 0 : break;
265 : }
266 :
267 0 : tevent_req_nterror(req, status);
268 : }
269 :
270 15578 : static NTSTATUS smbcli_transport_connect_recv(struct tevent_req *req)
271 : {
272 15578 : return tevent_req_simple_recv_ntstatus(req);
273 : }
274 :
275 : struct sock_connect_state {
276 : struct composite_context *ctx;
277 : const char *host_name;
278 : int num_ports;
279 : uint16_t *ports;
280 : const char *socket_options;
281 : struct smbcli_socket *result;
282 : struct socket_connect_multi_ex multi_ex;
283 : struct nbt_name calling;
284 : struct nbt_name called;
285 : };
286 :
287 : /*
288 : connect a smbcli_socket context to an IP/port pair
289 : if port is 0 then choose 445 then 139
290 : */
291 :
292 15578 : static struct tevent_req *smbcli_sock_establish_send(TALLOC_CTX *mem_ctx,
293 : struct tevent_context *ev,
294 : struct socket_context *sock,
295 : struct socket_address *addr,
296 : void *private_data)
297 : {
298 842 : struct sock_connect_state *state =
299 15578 : talloc_get_type_abort(private_data,
300 : struct sock_connect_state);
301 15578 : uint32_t timeout_msec = 15 * 1000;
302 :
303 31156 : return smbcli_transport_connect_send(state,
304 : ev,
305 : sock,
306 15578 : addr->port,
307 : timeout_msec,
308 : &state->calling,
309 : &state->called);
310 : }
311 :
312 15578 : static NTSTATUS smbcli_sock_establish_recv(struct tevent_req *req)
313 : {
314 15578 : return smbcli_transport_connect_recv(req);
315 : }
316 :
317 : static void smbcli_sock_connect_recv_conn(struct composite_context *ctx);
318 :
319 15579 : struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx,
320 : const char *host_addr,
321 : const char **ports,
322 : const char *host_name,
323 : struct resolve_context *resolve_ctx,
324 : struct tevent_context *event_ctx,
325 : const char *socket_options,
326 : struct nbt_name *calling,
327 : struct nbt_name *called)
328 : {
329 842 : struct composite_context *result, *ctx;
330 842 : struct sock_connect_state *state;
331 842 : NTSTATUS status;
332 842 : int i;
333 :
334 15579 : result = talloc_zero(mem_ctx, struct composite_context);
335 15579 : if (result == NULL) goto failed;
336 15579 : result->state = COMPOSITE_STATE_IN_PROGRESS;
337 :
338 15579 : result->event_ctx = event_ctx;
339 15579 : if (result->event_ctx == NULL) goto failed;
340 :
341 15579 : state = talloc(result, struct sock_connect_state);
342 15579 : if (state == NULL) goto failed;
343 15579 : state->ctx = result;
344 15579 : result->private_data = state;
345 :
346 15579 : state->host_name = talloc_strdup(state, host_name);
347 15579 : if (state->host_name == NULL) goto failed;
348 :
349 15579 : state->num_ports = str_list_length(ports);
350 15579 : state->ports = talloc_array(state, uint16_t, state->num_ports);
351 15579 : if (state->ports == NULL) goto failed;
352 46737 : for (i=0;ports[i];i++) {
353 31158 : state->ports[i] = atoi(ports[i]);
354 : }
355 15579 : state->socket_options = talloc_reference(state, socket_options);
356 :
357 15579 : if (!host_addr) {
358 14792 : host_addr = host_name;
359 : }
360 :
361 15579 : state->multi_ex.private_data = state;
362 15579 : state->multi_ex.establish_send = smbcli_sock_establish_send;
363 15579 : state->multi_ex.establish_recv = smbcli_sock_establish_recv;
364 :
365 15579 : status = nbt_name_dup(state, calling, &state->calling);
366 15579 : if (!NT_STATUS_IS_OK(status)) {
367 0 : goto failed;
368 : }
369 15579 : status = nbt_name_dup(state, called, &state->called);
370 15579 : if (!NT_STATUS_IS_OK(status)) {
371 0 : goto failed;
372 : }
373 :
374 16421 : ctx = socket_connect_multi_ex_send(state, host_addr,
375 : state->num_ports, state->ports,
376 : resolve_ctx,
377 15579 : state->ctx->event_ctx,
378 : &state->multi_ex);
379 15579 : if (ctx == NULL) goto failed;
380 15579 : ctx->async.fn = smbcli_sock_connect_recv_conn;
381 15579 : ctx->async.private_data = state;
382 15579 : return result;
383 :
384 0 : failed:
385 0 : talloc_free(result);
386 0 : return NULL;
387 : }
388 :
389 15579 : static void smbcli_sock_connect_recv_conn(struct composite_context *ctx)
390 : {
391 842 : struct sock_connect_state *state =
392 15579 : talloc_get_type(ctx->async.private_data,
393 : struct sock_connect_state);
394 842 : struct socket_context *sock;
395 842 : uint16_t port;
396 :
397 15579 : state->ctx->status = socket_connect_multi_ex_recv(ctx, state, &sock,
398 : &port);
399 15579 : if (!composite_is_ok(state->ctx)) return;
400 :
401 15578 : state->ctx->status =
402 15578 : socket_set_option(sock, state->socket_options, NULL);
403 15578 : if (!composite_is_ok(state->ctx)) return;
404 :
405 :
406 15578 : state->result = talloc_zero(state, struct smbcli_socket);
407 15578 : if (composite_nomem(state->result, state->ctx)) return;
408 :
409 15578 : state->result->sock = talloc_steal(state->result, sock);
410 15578 : state->result->port = port;
411 15578 : state->result->hostname = talloc_steal(sock, state->host_name);
412 :
413 15578 : state->result->event.ctx = state->ctx->event_ctx;
414 15578 : if (composite_nomem(state->result->event.ctx, state->ctx)) return;
415 :
416 15578 : composite_done(state->ctx);
417 : }
418 :
419 : /*
420 : finish a smbcli_sock_connect_send() operation
421 : */
422 15579 : NTSTATUS smbcli_sock_connect_recv(struct composite_context *c,
423 : TALLOC_CTX *mem_ctx,
424 : struct smbcli_socket **result)
425 : {
426 15579 : NTSTATUS status = composite_wait(c);
427 15579 : if (NT_STATUS_IS_OK(status)) {
428 842 : struct sock_connect_state *state =
429 15578 : talloc_get_type(c->private_data,
430 : struct sock_connect_state);
431 15578 : *result = talloc_steal(mem_ctx, state->result);
432 : }
433 15579 : talloc_free(c);
434 15579 : return status;
435 : }
436 :
437 : /*
438 : connect a smbcli_socket context to an IP/port pair
439 : if port is 0 then choose the ports listed in smb.conf (normally 445 then 139)
440 :
441 : sync version of the function
442 : */
443 6 : NTSTATUS smbcli_sock_connect(TALLOC_CTX *mem_ctx,
444 : const char *host_addr, const char **ports,
445 : const char *host_name,
446 : struct resolve_context *resolve_ctx,
447 : struct tevent_context *event_ctx,
448 : const char *socket_options,
449 : struct nbt_name *calling,
450 : struct nbt_name *called,
451 : struct smbcli_socket **result)
452 : {
453 0 : struct composite_context *c =
454 6 : smbcli_sock_connect_send(mem_ctx, host_addr, ports, host_name,
455 : resolve_ctx,
456 : event_ctx, socket_options,
457 : calling, called);
458 6 : return smbcli_sock_connect_recv(c, mem_ctx, result);
459 : }
|