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
;
44 static void smbcli_transport_connect_writev_done(struct tevent_req
*subreq
);
45 static void smbcli_transport_connect_read_smb_done(struct tevent_req
*subreq
);
47 static struct tevent_req
*smbcli_transport_connect_send(TALLOC_CTX
*mem_ctx
,
48 struct tevent_context
*ev
,
49 struct socket_context
*sock
,
51 uint32_t timeout_msec
,
52 struct nbt_name
*calling
,
53 struct nbt_name
*called
)
55 struct tevent_req
*req
;
56 struct smbcli_transport_connect_state
*state
;
57 struct tevent_req
*subreq
;
58 DATA_BLOB calling_blob
, called_blob
;
62 req
= tevent_req_create(mem_ctx
, &state
,
63 struct smbcli_transport_connect_state
);
72 return tevent_req_post(req
, ev
);
75 status
= nbt_name_to_blob(state
, &calling_blob
, calling
);
76 if (tevent_req_nterror(req
, status
)) {
77 return tevent_req_post(req
, ev
);
80 status
= nbt_name_to_blob(state
, &called_blob
, called
);
81 if (tevent_req_nterror(req
, status
)) {
82 return tevent_req_post(req
, ev
);
85 state
->request
= talloc_array(state
, uint8_t,
89 if (tevent_req_nomem(state
->request
, req
)) {
90 return tevent_req_post(req
, ev
);
93 /* put in the destination name */
94 p
= state
->request
+ NBT_HDR_SIZE
;
95 memcpy(p
, called_blob
.data
, called_blob
.length
);
96 p
+= called_blob
.length
;
98 memcpy(p
, calling_blob
.data
, calling_blob
.length
);
99 p
+= calling_blob
.length
;
101 _smb_setlen_nbt(state
->request
,
102 PTR_DIFF(p
, state
->request
) - NBT_HDR_SIZE
);
103 SCVAL(state
->request
, 0, NBSSrequest
);
105 state
->iov
.iov_len
= talloc_array_length(state
->request
);
106 state
->iov
.iov_base
= (void *)state
->request
;
108 subreq
= writev_send(state
, ev
, NULL
,
110 true, /* err_on_readability */
112 if (tevent_req_nomem(subreq
, req
)) {
113 return tevent_req_post(req
, ev
);
115 tevent_req_set_callback(subreq
,
116 smbcli_transport_connect_writev_done
,
119 if (timeout_msec
> 0) {
120 struct timeval endtime
;
122 endtime
= timeval_current_ofs_msec(timeout_msec
);
123 if (!tevent_req_set_endtime(req
, ev
, endtime
)) {
124 return tevent_req_post(req
, ev
);
131 static void smbcli_transport_connect_writev_done(struct tevent_req
*subreq
)
133 struct tevent_req
*req
=
134 tevent_req_callback_data(subreq
,
136 struct smbcli_transport_connect_state
*state
=
138 struct smbcli_transport_connect_state
);
142 ret
= writev_recv(subreq
, &err
);
145 NTSTATUS status
= map_nt_error_from_unix_common(err
);
147 close(state
->sock
->fd
);
148 state
->sock
->fd
= -1;
150 tevent_req_nterror(req
, status
);
154 subreq
= read_smb_send(state
, state
->ev
,
156 if (tevent_req_nomem(subreq
, req
)) {
159 tevent_req_set_callback(subreq
,
160 smbcli_transport_connect_read_smb_done
,
164 static void smbcli_transport_connect_read_smb_done(struct tevent_req
*subreq
)
166 struct tevent_req
*req
=
167 tevent_req_callback_data(subreq
,
169 struct smbcli_transport_connect_state
*state
=
171 struct smbcli_transport_connect_state
);
177 ret
= read_smb_recv(subreq
, state
,
178 &state
->response
, &err
);
180 status
= map_nt_error_from_unix_common(err
);
182 close(state
->sock
->fd
);
183 state
->sock
->fd
= -1;
185 tevent_req_nterror(req
, status
);
190 close(state
->sock
->fd
);
191 state
->sock
->fd
= -1;
193 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
197 switch (CVAL(state
->response
, 0)) {
199 tevent_req_done(req
);
204 close(state
->sock
->fd
);
205 state
->sock
->fd
= -1;
207 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
211 error
= CVAL(state
->response
, 4);
215 status
= NT_STATUS_REMOTE_NOT_LISTENING
;
218 status
= NT_STATUS_RESOURCE_NAME_NOT_FOUND
;
221 status
= NT_STATUS_REMOTE_RESOURCES
;
224 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
230 DEBUG(1,("Warning: session retarget not supported\n"));
231 status
= NT_STATUS_NOT_SUPPORTED
;
235 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
239 close(state
->sock
->fd
);
240 state
->sock
->fd
= -1;
242 tevent_req_nterror(req
, status
);
245 static NTSTATUS
smbcli_transport_connect_recv(struct tevent_req
*req
)
247 return tevent_req_simple_recv_ntstatus(req
);
250 struct sock_connect_state
{
251 struct composite_context
*ctx
;
252 const char *host_name
;
255 const char *socket_options
;
256 struct smbcli_socket
*result
;
257 struct socket_connect_multi_ex multi_ex
;
258 struct nbt_name calling
;
259 struct nbt_name called
;
263 connect a smbcli_socket context to an IP/port pair
264 if port is 0 then choose 445 then 139
267 static struct tevent_req
*smbcli_sock_establish_send(TALLOC_CTX
*mem_ctx
,
268 struct tevent_context
*ev
,
269 struct socket_context
*sock
,
270 struct socket_address
*addr
,
273 struct sock_connect_state
*state
=
274 talloc_get_type_abort(private_data
,
275 struct sock_connect_state
);
276 uint32_t timeout_msec
= 15 * 1000;
278 return smbcli_transport_connect_send(state
,
287 static NTSTATUS
smbcli_sock_establish_recv(struct tevent_req
*req
)
289 return smbcli_transport_connect_recv(req
);
292 static void smbcli_sock_connect_recv_conn(struct composite_context
*ctx
);
294 struct composite_context
*smbcli_sock_connect_send(TALLOC_CTX
*mem_ctx
,
295 const char *host_addr
,
297 const char *host_name
,
298 struct resolve_context
*resolve_ctx
,
299 struct tevent_context
*event_ctx
,
300 const char *socket_options
,
301 struct nbt_name
*calling
,
302 struct nbt_name
*called
)
304 struct composite_context
*result
, *ctx
;
305 struct sock_connect_state
*state
;
309 result
= talloc_zero(mem_ctx
, struct composite_context
);
310 if (result
== NULL
) goto failed
;
311 result
->state
= COMPOSITE_STATE_IN_PROGRESS
;
313 result
->event_ctx
= event_ctx
;
314 if (result
->event_ctx
== NULL
) goto failed
;
316 state
= talloc(result
, struct sock_connect_state
);
317 if (state
== NULL
) goto failed
;
319 result
->private_data
= state
;
321 state
->host_name
= talloc_strdup(state
, host_name
);
322 if (state
->host_name
== NULL
) goto failed
;
324 state
->num_ports
= str_list_length(ports
);
325 state
->ports
= talloc_array(state
, uint16_t, state
->num_ports
);
326 if (state
->ports
== NULL
) goto failed
;
327 for (i
=0;ports
[i
];i
++) {
328 state
->ports
[i
] = atoi(ports
[i
]);
330 state
->socket_options
= talloc_reference(state
, socket_options
);
333 host_addr
= host_name
;
336 state
->multi_ex
.private_data
= state
;
337 state
->multi_ex
.establish_send
= smbcli_sock_establish_send
;
338 state
->multi_ex
.establish_recv
= smbcli_sock_establish_recv
;
340 status
= nbt_name_dup(state
, calling
, &state
->calling
);
341 if (!NT_STATUS_IS_OK(status
)) {
344 status
= nbt_name_dup(state
, called
, &state
->called
);
345 if (!NT_STATUS_IS_OK(status
)) {
349 ctx
= socket_connect_multi_ex_send(state
, host_addr
,
350 state
->num_ports
, state
->ports
,
352 state
->ctx
->event_ctx
,
354 if (ctx
== NULL
) goto failed
;
355 ctx
->async
.fn
= smbcli_sock_connect_recv_conn
;
356 ctx
->async
.private_data
= state
;
364 static void smbcli_sock_connect_recv_conn(struct composite_context
*ctx
)
366 struct sock_connect_state
*state
=
367 talloc_get_type(ctx
->async
.private_data
,
368 struct sock_connect_state
);
369 struct socket_context
*sock
;
372 state
->ctx
->status
= socket_connect_multi_ex_recv(ctx
, state
, &sock
,
374 if (!composite_is_ok(state
->ctx
)) return;
377 socket_set_option(sock
, state
->socket_options
, NULL
);
378 if (!composite_is_ok(state
->ctx
)) return;
381 state
->result
= talloc_zero(state
, struct smbcli_socket
);
382 if (composite_nomem(state
->result
, state
->ctx
)) return;
384 state
->result
->sock
= talloc_steal(state
->result
, sock
);
385 state
->result
->port
= port
;
386 state
->result
->hostname
= talloc_steal(sock
, state
->host_name
);
388 state
->result
->event
.ctx
= state
->ctx
->event_ctx
;
389 if (composite_nomem(state
->result
->event
.ctx
, state
->ctx
)) return;
391 composite_done(state
->ctx
);
395 finish a smbcli_sock_connect_send() operation
397 NTSTATUS
smbcli_sock_connect_recv(struct composite_context
*c
,
399 struct smbcli_socket
**result
)
401 NTSTATUS status
= composite_wait(c
);
402 if (NT_STATUS_IS_OK(status
)) {
403 struct sock_connect_state
*state
=
404 talloc_get_type(c
->private_data
,
405 struct sock_connect_state
);
406 *result
= talloc_steal(mem_ctx
, state
->result
);
413 connect a smbcli_socket context to an IP/port pair
414 if port is 0 then choose the ports listed in smb.conf (normally 445 then 139)
416 sync version of the function
418 NTSTATUS
smbcli_sock_connect(TALLOC_CTX
*mem_ctx
,
419 const char *host_addr
, const char **ports
,
420 const char *host_name
,
421 struct resolve_context
*resolve_ctx
,
422 struct tevent_context
*event_ctx
,
423 const char *socket_options
,
424 struct nbt_name
*calling
,
425 struct nbt_name
*called
,
426 struct smbcli_socket
**result
)
428 struct composite_context
*c
=
429 smbcli_sock_connect_send(mem_ctx
, host_addr
, ports
, host_name
,
431 event_ctx
, socket_options
,
433 return smbcli_sock_connect_recv(c
, mem_ctx
, result
);