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 smbcli_socket *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 struct tevent_req *smbcli_transport_connect_send(TALLOC_CTX *mem_ctx,
48 struct tevent_context *ev,
49 struct smbcli_socket *sock,
50 uint32_t timeout_msec,
51 struct nbt_name *calling,
52 struct nbt_name *called)
54 struct tevent_req *req;
55 struct smbcli_transport_connect_state *state;
56 struct tevent_req *subreq;
57 DATA_BLOB calling_blob, called_blob;
61 req = tevent_req_create(mem_ctx, &state,
62 struct smbcli_transport_connect_state);
69 if (sock->port != 139) {
71 return tevent_req_post(req, ev);
74 status = nbt_name_to_blob(state, &calling_blob, calling);
75 if (tevent_req_nterror(req, status)) {
76 return tevent_req_post(req, ev);
79 status = nbt_name_to_blob(state, &called_blob, called);
80 if (tevent_req_nterror(req, status)) {
81 return tevent_req_post(req, ev);
84 state->request = talloc_array(state, uint8_t,
88 if (tevent_req_nomem(state->request, req)) {
89 return tevent_req_post(req, ev);
92 /* put in the destination name */
93 p = state->request + NBT_HDR_SIZE;
94 memcpy(p, called_blob.data, called_blob.length);
95 p += called_blob.length;
97 memcpy(p, calling_blob.data, calling_blob.length);
98 p += calling_blob.length;
100 _smb_setlen_nbt(state->request,
101 PTR_DIFF(p, state->request) - NBT_HDR_SIZE);
102 SCVAL(state->request, 0, NBSSrequest);
104 state->iov.iov_len = talloc_array_length(state->request);
105 state->iov.iov_base = (void *)state->request;
107 subreq = writev_send(state, ev, NULL,
109 true, /* err_on_readability */
111 if (tevent_req_nomem(subreq, req)) {
112 return tevent_req_post(req, ev);
114 tevent_req_set_callback(subreq,
115 smbcli_transport_connect_writev_done,
118 if (timeout_msec > 0) {
119 struct timeval endtime;
121 endtime = timeval_current_ofs_msec(timeout_msec);
122 if (!tevent_req_set_endtime(req, ev, endtime)) {
123 return tevent_req_post(req, ev);
130 static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
132 struct tevent_req *req =
133 tevent_req_callback_data(subreq,
135 struct smbcli_transport_connect_state *state =
137 struct smbcli_transport_connect_state);
141 ret = writev_recv(subreq, &err);
144 NTSTATUS status = map_nt_error_from_unix_common(err);
146 close(state->sock->sock->fd);
147 state->sock->sock->fd = -1;
149 tevent_req_nterror(req, status);
153 subreq = read_smb_send(state, state->ev,
154 state->sock->sock->fd);
155 if (tevent_req_nomem(subreq, req)) {
158 tevent_req_set_callback(subreq,
159 smbcli_transport_connect_read_smb_done,
163 static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
165 struct tevent_req *req =
166 tevent_req_callback_data(subreq,
168 struct smbcli_transport_connect_state *state =
170 struct smbcli_transport_connect_state);
176 ret = read_smb_recv(subreq, state,
177 &state->response, &err);
179 status = map_nt_error_from_unix_common(err);
181 close(state->sock->sock->fd);
182 state->sock->sock->fd = -1;
184 tevent_req_nterror(req, status);
189 close(state->sock->sock->fd);
190 state->sock->sock->fd = -1;
192 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
196 switch (CVAL(state->response, 0)) {
198 tevent_req_done(req);
203 close(state->sock->sock->fd);
204 state->sock->sock->fd = -1;
206 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
210 error = CVAL(state->response, 4);
214 status = NT_STATUS_REMOTE_NOT_LISTENING;
217 status = NT_STATUS_RESOURCE_NAME_NOT_FOUND;
220 status = NT_STATUS_REMOTE_RESOURCES;
223 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
229 DEBUG(1,("Warning: session retarget not supported\n"));
230 status = NT_STATUS_NOT_SUPPORTED;
234 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
238 close(state->sock->sock->fd);
239 state->sock->sock->fd = -1;
241 tevent_req_nterror(req, status);
244 NTSTATUS smbcli_transport_connect_recv(struct tevent_req *req)
246 return tevent_req_simple_recv_ntstatus(req);
249 NTSTATUS smbcli_transport_connect(struct smbcli_socket *sock,
250 uint32_t timeout_msec,
251 struct nbt_name *calling,
252 struct nbt_name *called)
254 TALLOC_CTX *frame = talloc_stackframe();
255 struct tevent_context *ev;
256 struct tevent_req *req;
257 NTSTATUS status = NT_STATUS_NO_MEMORY;
260 ev = tevent_context_init(frame);
264 req = smbcli_transport_connect_send(frame, ev, sock,
270 ok = tevent_req_poll(req, ev);
272 status = map_nt_error_from_unix_common(errno);
275 status = smbcli_transport_connect_recv(req);
281 struct sock_connect_state {
282 struct composite_context *ctx;
283 const char *host_name;
286 const char *socket_options;
287 struct smbcli_socket *result;
291 connect a smbcli_socket context to an IP/port pair
292 if port is 0 then choose 445 then 139
295 static void smbcli_sock_connect_recv_conn(struct composite_context *ctx);
297 struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx,
298 const char *host_addr,
300 const char *host_name,
301 struct resolve_context *resolve_ctx,
302 struct tevent_context *event_ctx,
303 const char *socket_options)
305 struct composite_context *result, *ctx;
306 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 ctx = socket_connect_multi_send(state, host_addr,
337 state->num_ports, state->ports,
339 state->ctx->event_ctx);
340 if (ctx == NULL) goto failed;
341 ctx->async.fn = smbcli_sock_connect_recv_conn;
342 ctx->async.private_data = state;
350 static void smbcli_sock_connect_recv_conn(struct composite_context *ctx)
352 struct sock_connect_state *state =
353 talloc_get_type(ctx->async.private_data,
354 struct sock_connect_state);
355 struct socket_context *sock;
358 state->ctx->status = socket_connect_multi_recv(ctx, state, &sock,
360 if (!composite_is_ok(state->ctx)) return;
363 socket_set_option(sock, state->socket_options, NULL);
364 if (!composite_is_ok(state->ctx)) return;
367 state->result = talloc_zero(state, struct smbcli_socket);
368 if (composite_nomem(state->result, state->ctx)) return;
370 state->result->sock = talloc_steal(state->result, sock);
371 state->result->port = port;
372 state->result->hostname = talloc_steal(sock, state->host_name);
374 state->result->event.ctx = state->ctx->event_ctx;
375 if (composite_nomem(state->result->event.ctx, state->ctx)) return;
377 composite_done(state->ctx);
381 finish a smbcli_sock_connect_send() operation
383 NTSTATUS smbcli_sock_connect_recv(struct composite_context *c,
385 struct smbcli_socket **result)
387 NTSTATUS status = composite_wait(c);
388 if (NT_STATUS_IS_OK(status)) {
389 struct sock_connect_state *state =
390 talloc_get_type(c->private_data,
391 struct sock_connect_state);
392 *result = talloc_steal(mem_ctx, state->result);
399 connect a smbcli_socket context to an IP/port pair
400 if port is 0 then choose the ports listed in smb.conf (normally 445 then 139)
402 sync version of the function
404 NTSTATUS smbcli_sock_connect(TALLOC_CTX *mem_ctx,
405 const char *host_addr, const char **ports,
406 const char *host_name,
407 struct resolve_context *resolve_ctx,
408 struct tevent_context *event_ctx,
409 const char *socket_options,
410 struct smbcli_socket **result)
412 struct composite_context *c =
413 smbcli_sock_connect_send(mem_ctx, host_addr, ports, host_name,
415 event_ctx, socket_options);
416 return smbcli_sock_connect_recv(c, mem_ctx, result);
420 /****************************************************************************
421 mark the socket as dead
422 ****************************************************************************/
423 _PUBLIC_ void smbcli_sock_dead(struct smbcli_socket *sock)
425 talloc_free(sock->event.fde);
426 sock->event.fde = NULL;
427 talloc_free(sock->sock);