ldb: change the version to 2.11.0 for Samba 4.22
[Samba.git] / source4 / libcli / raw / clisocket.c
blob0c53014fc3b012c19c89b60a72b1b3d2748162af
1 /*
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/>.
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"
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;
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,
53 uint16_t port,
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;
62 uint8_t *p;
63 NTSTATUS status;
65 req = tevent_req_create(mem_ctx, &state,
66 struct smbcli_transport_connect_state);
67 if (req == NULL) {
68 return NULL;
70 state->ev = ev;
71 state->sock = sock;
73 if (port != 139) {
74 tevent_req_done(req);
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,
91 NBT_HDR_SIZE +
92 called_blob.length +
93 calling_blob.length);
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,
114 sock->fd,
115 true, /* err_on_readability */
116 &state->iov, 1);
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,
122 req);
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);
134 return req;
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 =
141 tevent_req_data(req,
142 struct smbcli_transport_connect_state);
144 TALLOC_FREE(state->io_req);
146 if (state->sock == NULL) {
147 return;
150 if (state->sock->fd == -1) {
151 return;
154 if (req_state == TEVENT_REQ_DONE) {
156 * we keep the socket open for the caller to use
158 state->sock = NULL;
159 return;
162 close(state->sock->fd);
163 state->sock->fd = -1;
164 state->sock = NULL;
167 static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
169 struct tevent_req *req =
170 tevent_req_callback_data(subreq,
171 struct tevent_req);
172 struct smbcli_transport_connect_state *state =
173 tevent_req_data(req,
174 struct smbcli_transport_connect_state);
175 ssize_t ret;
176 int err;
178 state->io_req = NULL;
180 ret = writev_recv(subreq, &err);
181 TALLOC_FREE(subreq);
182 if (ret == -1) {
183 NTSTATUS status = map_nt_error_from_unix_common(err);
184 tevent_req_nterror(req, status);
185 return;
188 subreq = read_smb_send(state, state->ev,
189 state->sock->fd);
190 if (tevent_req_nomem(subreq, req)) {
191 return;
193 tevent_req_set_callback(subreq,
194 smbcli_transport_connect_read_smb_done,
195 req);
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,
203 struct tevent_req);
204 struct smbcli_transport_connect_state *state =
205 tevent_req_data(req,
206 struct smbcli_transport_connect_state);
207 ssize_t ret;
208 int err;
209 NTSTATUS status;
210 uint8_t error;
212 state->io_req = NULL;
214 ret = read_smb_recv(subreq, state,
215 &state->response, &err);
216 TALLOC_FREE(subreq);
217 if (ret == -1) {
218 status = map_nt_error_from_unix_common(err);
219 tevent_req_nterror(req, status);
220 return;
223 if (ret < 4) {
224 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
225 return;
228 switch (CVAL(state->response, 0)) {
229 case NBSSpositive:
230 tevent_req_done(req);
231 return;
233 case NBSSnegative:
234 if (ret < 5) {
235 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
236 return;
239 error = CVAL(state->response, 4);
240 switch (error) {
241 case 0x80:
242 case 0x81:
243 status = NT_STATUS_REMOTE_NOT_LISTENING;
244 break;
245 case 0x82:
246 status = NT_STATUS_RESOURCE_NAME_NOT_FOUND;
247 break;
248 case 0x83:
249 status = NT_STATUS_REMOTE_RESOURCES;
250 break;
251 default:
252 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
253 break;
255 break;
257 case NBSSretarget:
258 DEBUG(1,("Warning: session retarget not supported\n"));
259 status = NT_STATUS_NOT_SUPPORTED;
260 break;
262 default:
263 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
264 break;
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;
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;
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,
296 void *private_data)
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,
305 sock,
306 addr->port,
307 timeout_msec,
308 &state->calling,
309 &state->called);
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,
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)
329 struct composite_context *result, *ctx;
330 struct sock_connect_state *state;
331 NTSTATUS status;
332 int i;
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;
343 state->ctx = result;
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);
357 if (!host_addr) {
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)) {
367 goto failed;
369 status = nbt_name_dup(state, called, &state->called);
370 if (!NT_STATUS_IS_OK(status)) {
371 goto failed;
374 ctx = socket_connect_multi_ex_send(state, host_addr,
375 state->num_ports, state->ports,
376 resolve_ctx,
377 state->ctx->event_ctx,
378 &state->multi_ex);
379 if (ctx == NULL) goto failed;
380 ctx->async.fn = smbcli_sock_connect_recv_conn;
381 ctx->async.private_data = state;
382 return result;
384 failed:
385 talloc_free(result);
386 return NULL;
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;
395 uint16_t port;
397 state->ctx->status = socket_connect_multi_ex_recv(ctx, state, &sock,
398 &port);
399 if (!composite_is_ok(state->ctx)) return;
401 state->ctx->status =
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,
423 TALLOC_CTX *mem_ctx,
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);
433 talloc_free(c);
434 return status;
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,
455 resolve_ctx,
456 event_ctx, socket_options,
457 calling, called);
458 return smbcli_sock_connect_recv(c, mem_ctx, result);