s4:torture: send the TCONX_FLAG_EXTENDED_RESPONSE flag
[Samba/gebeck_regimport.git] / source4 / libcli / raw / clisocket.c
blobdd3ea3971c1510ea49a974c83cb00f36357843a1
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 uint8_t *request;
40 struct iovec iov;
41 uint8_t *response;
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,
50 uint16_t port,
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;
59 uint8_t *p;
60 NTSTATUS status;
62 req = tevent_req_create(mem_ctx, &state,
63 struct smbcli_transport_connect_state);
64 if (req == NULL) {
65 return NULL;
67 state->ev = ev;
68 state->sock = sock;
70 if (port != 139) {
71 tevent_req_done(req);
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,
86 NBT_HDR_SIZE +
87 called_blob.length +
88 calling_blob.length);
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,
109 sock->fd,
110 true, /* err_on_readability */
111 &state->iov, 1);
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,
117 req);
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);
128 return req;
131 static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
133 struct tevent_req *req =
134 tevent_req_callback_data(subreq,
135 struct tevent_req);
136 struct smbcli_transport_connect_state *state =
137 tevent_req_data(req,
138 struct smbcli_transport_connect_state);
139 ssize_t ret;
140 int err;
142 ret = writev_recv(subreq, &err);
143 TALLOC_FREE(subreq);
144 if (ret == -1) {
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);
151 return;
154 subreq = read_smb_send(state, state->ev,
155 state->sock->fd);
156 if (tevent_req_nomem(subreq, req)) {
157 return;
159 tevent_req_set_callback(subreq,
160 smbcli_transport_connect_read_smb_done,
161 req);
164 static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
166 struct tevent_req *req =
167 tevent_req_callback_data(subreq,
168 struct tevent_req);
169 struct smbcli_transport_connect_state *state =
170 tevent_req_data(req,
171 struct smbcli_transport_connect_state);
172 ssize_t ret;
173 int err;
174 NTSTATUS status;
175 uint8_t error;
177 ret = read_smb_recv(subreq, state,
178 &state->response, &err);
179 if (ret == -1) {
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);
186 return;
189 if (ret < 4) {
190 close(state->sock->fd);
191 state->sock->fd = -1;
193 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
194 return;
197 switch (CVAL(state->response, 0)) {
198 case NBSSpositive:
199 tevent_req_done(req);
200 return;
202 case NBSSnegative:
203 if (ret < 5) {
204 close(state->sock->fd);
205 state->sock->fd = -1;
207 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
208 return;
211 error = CVAL(state->response, 4);
212 switch (error) {
213 case 0x80:
214 case 0x81:
215 status = NT_STATUS_REMOTE_NOT_LISTENING;
216 break;
217 case 0x82:
218 status = NT_STATUS_RESOURCE_NAME_NOT_FOUND;
219 break;
220 case 0x83:
221 status = NT_STATUS_REMOTE_RESOURCES;
222 break;
223 default:
224 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
225 break;
227 break;
229 case NBSSretarget:
230 DEBUG(1,("Warning: session retarget not supported\n"));
231 status = NT_STATUS_NOT_SUPPORTED;
232 break;
234 default:
235 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
236 break;
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;
253 int num_ports;
254 uint16_t *ports;
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,
271 void *private_data)
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,
280 sock,
281 addr->port,
282 timeout_msec,
283 &state->calling,
284 &state->called);
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,
296 const char **ports,
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;
306 NTSTATUS status;
307 int i;
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;
318 state->ctx = result;
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);
332 if (!host_addr) {
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)) {
342 goto failed;
344 status = nbt_name_dup(state, called, &state->called);
345 if (!NT_STATUS_IS_OK(status)) {
346 goto failed;
349 ctx = socket_connect_multi_ex_send(state, host_addr,
350 state->num_ports, state->ports,
351 resolve_ctx,
352 state->ctx->event_ctx,
353 &state->multi_ex);
354 if (ctx == NULL) goto failed;
355 ctx->async.fn = smbcli_sock_connect_recv_conn;
356 ctx->async.private_data = state;
357 return result;
359 failed:
360 talloc_free(result);
361 return NULL;
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;
370 uint16_t port;
372 state->ctx->status = socket_connect_multi_ex_recv(ctx, state, &sock,
373 &port);
374 if (!composite_is_ok(state->ctx)) return;
376 state->ctx->status =
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,
398 TALLOC_CTX *mem_ctx,
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);
408 talloc_free(c);
409 return status;
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,
430 resolve_ctx,
431 event_ctx, socket_options,
432 calling, called);
433 return smbcli_sock_connect_recv(c, mem_ctx, result);