2 Unix SMB/CIFS implementation.
4 SMB client socket context management functions
6 Copyright (C) Andrew Tridgell 1994-2005
7 Copyright (C) James Myers 2003 <myersjj@samba.org>
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.
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.
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/>.
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"
36 struct smbcli_transport_connect_state
{
37 struct tevent_context
*ev
;
38 struct socket_context
*sock
;
39 struct tevent_req
*io_req
;
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
);
50 static struct tevent_req
*smbcli_transport_connect_send(TALLOC_CTX
*mem_ctx
,
51 struct tevent_context
*ev
,
52 struct socket_context
*sock
,
54 uint32_t timeout_msec
,
55 struct nbt_name
*calling
,
56 struct nbt_name
*called
)
58 struct tevent_req
*req
;
59 struct smbcli_transport_connect_state
*state
;
60 struct tevent_req
*subreq
;
61 DATA_BLOB calling_blob
, called_blob
;
65 req
= tevent_req_create(mem_ctx
, &state
,
66 struct smbcli_transport_connect_state
);
75 return tevent_req_post(req
, ev
);
78 tevent_req_set_cleanup_fn(req
, smbcli_transport_connect_cleanup
);
80 status
= nbt_name_to_blob(state
, &calling_blob
, calling
);
81 if (tevent_req_nterror(req
, status
)) {
82 return tevent_req_post(req
, ev
);
85 status
= nbt_name_to_blob(state
, &called_blob
, called
);
86 if (tevent_req_nterror(req
, status
)) {
87 return tevent_req_post(req
, ev
);
90 state
->request
= talloc_array(state
, uint8_t,
94 if (tevent_req_nomem(state
->request
, req
)) {
95 return tevent_req_post(req
, ev
);
98 /* put in the destination name */
99 p
= state
->request
+ NBT_HDR_SIZE
;
100 memcpy(p
, called_blob
.data
, called_blob
.length
);
101 p
+= called_blob
.length
;
103 memcpy(p
, calling_blob
.data
, calling_blob
.length
);
104 p
+= calling_blob
.length
;
106 _smb_setlen_nbt(state
->request
,
107 PTR_DIFF(p
, state
->request
) - NBT_HDR_SIZE
);
108 SCVAL(state
->request
, 0, NBSSrequest
);
110 state
->iov
.iov_len
= talloc_array_length(state
->request
);
111 state
->iov
.iov_base
= (void *)state
->request
;
113 subreq
= writev_send(state
, ev
, NULL
,
115 true, /* err_on_readability */
117 if (tevent_req_nomem(subreq
, req
)) {
118 return tevent_req_post(req
, ev
);
120 tevent_req_set_callback(subreq
,
121 smbcli_transport_connect_writev_done
,
123 state
->io_req
= subreq
;
125 if (timeout_msec
> 0) {
126 struct timeval endtime
;
128 endtime
= timeval_current_ofs_msec(timeout_msec
);
129 if (!tevent_req_set_endtime(req
, ev
, endtime
)) {
130 return tevent_req_post(req
, ev
);
137 static void smbcli_transport_connect_cleanup(struct tevent_req
*req
,
138 enum tevent_req_state req_state
)
140 struct smbcli_transport_connect_state
*state
=
142 struct smbcli_transport_connect_state
);
144 TALLOC_FREE(state
->io_req
);
146 if (state
->sock
== NULL
) {
150 if (state
->sock
->fd
== -1) {
154 if (req_state
== TEVENT_REQ_DONE
) {
156 * we keep the socket open for the caller to use
162 close(state
->sock
->fd
);
163 state
->sock
->fd
= -1;
167 static void smbcli_transport_connect_writev_done(struct tevent_req
*subreq
)
169 struct tevent_req
*req
=
170 tevent_req_callback_data(subreq
,
172 struct smbcli_transport_connect_state
*state
=
174 struct smbcli_transport_connect_state
);
178 state
->io_req
= NULL
;
180 ret
= writev_recv(subreq
, &err
);
183 NTSTATUS status
= map_nt_error_from_unix_common(err
);
184 tevent_req_nterror(req
, status
);
188 subreq
= read_smb_send(state
, state
->ev
,
190 if (tevent_req_nomem(subreq
, req
)) {
193 tevent_req_set_callback(subreq
,
194 smbcli_transport_connect_read_smb_done
,
196 state
->io_req
= subreq
;
199 static void smbcli_transport_connect_read_smb_done(struct tevent_req
*subreq
)
201 struct tevent_req
*req
=
202 tevent_req_callback_data(subreq
,
204 struct smbcli_transport_connect_state
*state
=
206 struct smbcli_transport_connect_state
);
212 state
->io_req
= NULL
;
214 ret
= read_smb_recv(subreq
, state
,
215 &state
->response
, &err
);
218 status
= map_nt_error_from_unix_common(err
);
219 tevent_req_nterror(req
, status
);
224 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
228 switch (CVAL(state
->response
, 0)) {
230 tevent_req_done(req
);
235 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
239 error
= CVAL(state
->response
, 4);
243 status
= NT_STATUS_REMOTE_NOT_LISTENING
;
246 status
= NT_STATUS_RESOURCE_NAME_NOT_FOUND
;
249 status
= NT_STATUS_REMOTE_RESOURCES
;
252 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
258 DEBUG(1,("Warning: session retarget not supported\n"));
259 status
= NT_STATUS_NOT_SUPPORTED
;
263 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
267 tevent_req_nterror(req
, status
);
270 static NTSTATUS
smbcli_transport_connect_recv(struct tevent_req
*req
)
272 return tevent_req_simple_recv_ntstatus(req
);
275 struct sock_connect_state
{
276 struct composite_context
*ctx
;
277 const char *host_name
;
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
;
288 connect a smbcli_socket context to an IP/port pair
289 if port is 0 then choose 445 then 139
292 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
,
298 struct sock_connect_state
*state
=
299 talloc_get_type_abort(private_data
,
300 struct sock_connect_state
);
301 uint32_t timeout_msec
= 15 * 1000;
303 return smbcli_transport_connect_send(state
,
312 static NTSTATUS
smbcli_sock_establish_recv(struct tevent_req
*req
)
314 return smbcli_transport_connect_recv(req
);
317 static void smbcli_sock_connect_recv_conn(struct composite_context
*ctx
);
319 struct composite_context
*smbcli_sock_connect_send(TALLOC_CTX
*mem_ctx
,
320 const char *host_addr
,
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
)
329 struct composite_context
*result
, *ctx
;
330 struct sock_connect_state
*state
;
334 result
= talloc_zero(mem_ctx
, struct composite_context
);
335 if (result
== NULL
) goto failed
;
336 result
->state
= COMPOSITE_STATE_IN_PROGRESS
;
338 result
->event_ctx
= event_ctx
;
339 if (result
->event_ctx
== NULL
) goto failed
;
341 state
= talloc(result
, struct sock_connect_state
);
342 if (state
== NULL
) goto failed
;
344 result
->private_data
= state
;
346 state
->host_name
= talloc_strdup(state
, host_name
);
347 if (state
->host_name
== NULL
) goto failed
;
349 state
->num_ports
= str_list_length(ports
);
350 state
->ports
= talloc_array(state
, uint16_t, state
->num_ports
);
351 if (state
->ports
== NULL
) goto failed
;
352 for (i
=0;ports
[i
];i
++) {
353 state
->ports
[i
] = atoi(ports
[i
]);
355 state
->socket_options
= talloc_reference(state
, socket_options
);
358 host_addr
= host_name
;
361 state
->multi_ex
.private_data
= state
;
362 state
->multi_ex
.establish_send
= smbcli_sock_establish_send
;
363 state
->multi_ex
.establish_recv
= smbcli_sock_establish_recv
;
365 status
= nbt_name_dup(state
, calling
, &state
->calling
);
366 if (!NT_STATUS_IS_OK(status
)) {
369 status
= nbt_name_dup(state
, called
, &state
->called
);
370 if (!NT_STATUS_IS_OK(status
)) {
374 ctx
= socket_connect_multi_ex_send(state
, host_addr
,
375 state
->num_ports
, state
->ports
,
377 state
->ctx
->event_ctx
,
379 if (ctx
== NULL
) goto failed
;
380 ctx
->async
.fn
= smbcli_sock_connect_recv_conn
;
381 ctx
->async
.private_data
= state
;
389 static void smbcli_sock_connect_recv_conn(struct composite_context
*ctx
)
391 struct sock_connect_state
*state
=
392 talloc_get_type(ctx
->async
.private_data
,
393 struct sock_connect_state
);
394 struct socket_context
*sock
;
397 state
->ctx
->status
= socket_connect_multi_ex_recv(ctx
, state
, &sock
,
399 if (!composite_is_ok(state
->ctx
)) return;
402 socket_set_option(sock
, state
->socket_options
, NULL
);
403 if (!composite_is_ok(state
->ctx
)) return;
406 state
->result
= talloc_zero(state
, struct smbcli_socket
);
407 if (composite_nomem(state
->result
, state
->ctx
)) return;
409 state
->result
->sock
= talloc_steal(state
->result
, sock
);
410 state
->result
->port
= port
;
411 state
->result
->hostname
= talloc_steal(sock
, state
->host_name
);
413 state
->result
->event
.ctx
= state
->ctx
->event_ctx
;
414 if (composite_nomem(state
->result
->event
.ctx
, state
->ctx
)) return;
416 composite_done(state
->ctx
);
420 finish a smbcli_sock_connect_send() operation
422 NTSTATUS
smbcli_sock_connect_recv(struct composite_context
*c
,
424 struct smbcli_socket
**result
)
426 NTSTATUS status
= composite_wait(c
);
427 if (NT_STATUS_IS_OK(status
)) {
428 struct sock_connect_state
*state
=
429 talloc_get_type(c
->private_data
,
430 struct sock_connect_state
);
431 *result
= talloc_steal(mem_ctx
, state
->result
);
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)
441 sync version of the function
443 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
)
453 struct composite_context
*c
=
454 smbcli_sock_connect_send(mem_ctx
, host_addr
, ports
, host_name
,
456 event_ctx
, socket_options
,
458 return smbcli_sock_connect_recv(c
, mem_ctx
, result
);