s4:libcli/raw: remove unused functions
[kai/samba.git] / source4 / libcli / raw / clisocket.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    SMB client socket context management functions
5
6    Copyright (C) Andrew Tridgell 1994-2005
7    Copyright (C) James Myers 2003 <myersjj@samba.org>
8    
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.
13    
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.
18    
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/>.
21 */
22
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"
35
36 struct smbcli_transport_connect_state {
37         struct tevent_context *ev;
38         struct smbcli_socket *sock;
39         uint8_t *request;
40         struct iovec iov;
41         uint8_t *response;
42 };
43
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);
46
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)
53 {
54         struct tevent_req *req;
55         struct smbcli_transport_connect_state *state;
56         struct tevent_req *subreq;
57         DATA_BLOB calling_blob, called_blob;
58         uint8_t *p;
59         NTSTATUS status;
60
61         req = tevent_req_create(mem_ctx, &state,
62                                 struct smbcli_transport_connect_state);
63         if (req == NULL) {
64                 return NULL;
65         }
66         state->ev = ev;
67         state->sock = sock;
68
69         if (sock->port != 139) {
70                 tevent_req_done(req);
71                 return tevent_req_post(req, ev);
72         }
73
74         status = nbt_name_to_blob(state, &calling_blob, calling);
75         if (tevent_req_nterror(req, status)) {
76                 return tevent_req_post(req, ev);
77         }
78
79         status = nbt_name_to_blob(state, &called_blob, called);
80         if (tevent_req_nterror(req, status)) {
81                 return tevent_req_post(req, ev);
82         }
83
84         state->request = talloc_array(state, uint8_t,
85                                       NBT_HDR_SIZE +
86                                       called_blob.length +
87                                       calling_blob.length);
88         if (tevent_req_nomem(state->request, req)) {
89                 return tevent_req_post(req, ev);
90         }
91
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;
96
97         memcpy(p, calling_blob.data, calling_blob.length);
98         p += calling_blob.length;
99
100         _smb_setlen_nbt(state->request,
101                         PTR_DIFF(p, state->request) - NBT_HDR_SIZE);
102         SCVAL(state->request, 0, NBSSrequest);
103
104         state->iov.iov_len = talloc_array_length(state->request);
105         state->iov.iov_base = (void *)state->request;
106
107         subreq = writev_send(state, ev, NULL,
108                              sock->sock->fd,
109                              true, /* err_on_readability */
110                              &state->iov, 1);
111         if (tevent_req_nomem(subreq, req)) {
112                 return tevent_req_post(req, ev);
113         }
114         tevent_req_set_callback(subreq,
115                                 smbcli_transport_connect_writev_done,
116                                 req);
117
118         if (timeout_msec > 0) {
119                 struct timeval endtime;
120
121                 endtime = timeval_current_ofs_msec(timeout_msec);
122                 if (!tevent_req_set_endtime(req, ev, endtime)) {
123                         return tevent_req_post(req, ev);
124                 }
125         }
126
127         return req;
128 }
129
130 static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
131 {
132         struct tevent_req *req =
133                 tevent_req_callback_data(subreq,
134                 struct tevent_req);
135         struct smbcli_transport_connect_state *state =
136                 tevent_req_data(req,
137                 struct smbcli_transport_connect_state);
138         ssize_t ret;
139         int err;
140
141         ret = writev_recv(subreq, &err);
142         TALLOC_FREE(subreq);
143         if (ret == -1) {
144                 NTSTATUS status = map_nt_error_from_unix_common(err);
145
146                 close(state->sock->sock->fd);
147                 state->sock->sock->fd = -1;
148
149                 tevent_req_nterror(req, status);
150                 return;
151         }
152
153         subreq = read_smb_send(state, state->ev,
154                                state->sock->sock->fd);
155         if (tevent_req_nomem(subreq, req)) {
156                 return;
157         }
158         tevent_req_set_callback(subreq,
159                                 smbcli_transport_connect_read_smb_done,
160                                 req);
161 }
162
163 static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
164 {
165         struct tevent_req *req =
166                 tevent_req_callback_data(subreq,
167                 struct tevent_req);
168         struct smbcli_transport_connect_state *state =
169                 tevent_req_data(req,
170                 struct smbcli_transport_connect_state);
171         ssize_t ret;
172         int err;
173         NTSTATUS status;
174         uint8_t error;
175
176         ret = read_smb_recv(subreq, state,
177                             &state->response, &err);
178         if (ret == -1) {
179                 status = map_nt_error_from_unix_common(err);
180
181                 close(state->sock->sock->fd);
182                 state->sock->sock->fd = -1;
183
184                 tevent_req_nterror(req, status);
185                 return;
186         }
187
188         if (ret < 4) {
189                 close(state->sock->sock->fd);
190                 state->sock->sock->fd = -1;
191
192                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
193                 return;
194         }
195
196         switch (CVAL(state->response, 0)) {
197         case NBSSpositive:
198                 tevent_req_done(req);
199                 return;
200
201         case NBSSnegative:
202                 if (ret < 5) {
203                         close(state->sock->sock->fd);
204                         state->sock->sock->fd = -1;
205
206                         tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
207                         return;
208                 }
209
210                 error = CVAL(state->response, 4);
211                 switch (error) {
212                 case 0x80:
213                 case 0x81:
214                         status = NT_STATUS_REMOTE_NOT_LISTENING;
215                         break;
216                 case 0x82:
217                         status = NT_STATUS_RESOURCE_NAME_NOT_FOUND;
218                         break;
219                 case 0x83:
220                         status = NT_STATUS_REMOTE_RESOURCES;
221                         break;
222                 default:
223                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
224                         break;
225                 }
226                 break;
227
228         case NBSSretarget:
229                 DEBUG(1,("Warning: session retarget not supported\n"));
230                 status = NT_STATUS_NOT_SUPPORTED;
231                 break;
232
233         default:
234                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
235                 break;
236         }
237
238         close(state->sock->sock->fd);
239         state->sock->sock->fd = -1;
240
241         tevent_req_nterror(req, status);
242 }
243
244 NTSTATUS smbcli_transport_connect_recv(struct tevent_req *req)
245 {
246         return tevent_req_simple_recv_ntstatus(req);
247 }
248
249 NTSTATUS smbcli_transport_connect(struct smbcli_socket *sock,
250                                   uint32_t timeout_msec,
251                                   struct nbt_name *calling,
252                                   struct nbt_name *called)
253 {
254         TALLOC_CTX *frame = talloc_stackframe();
255         struct tevent_context *ev;
256         struct tevent_req *req;
257         NTSTATUS status = NT_STATUS_NO_MEMORY;
258         bool ok;
259
260         ev = tevent_context_init(frame);
261         if (ev == NULL) {
262                 goto fail;
263         }
264         req = smbcli_transport_connect_send(frame, ev, sock,
265                                             timeout_msec,
266                                             calling, called);
267         if (req == NULL) {
268                 goto fail;
269         }
270         ok = tevent_req_poll(req, ev);
271         if (!ok) {
272                 status = map_nt_error_from_unix_common(errno);
273                 goto fail;
274         }
275         status = smbcli_transport_connect_recv(req);
276  fail:
277         TALLOC_FREE(frame);
278         return status;
279 }
280
281 struct sock_connect_state {
282         struct composite_context *ctx;
283         const char *host_name;
284         int num_ports;
285         uint16_t *ports;
286         const char *socket_options;
287         struct smbcli_socket *result;
288 };
289
290 /*
291   connect a smbcli_socket context to an IP/port pair
292   if port is 0 then choose 445 then 139
293 */
294
295 static void smbcli_sock_connect_recv_conn(struct composite_context *ctx);
296
297 struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx,
298                                                    const char *host_addr,
299                                                    const char **ports,
300                                                    const char *host_name,
301                                                    struct resolve_context *resolve_ctx,
302                                                    struct tevent_context *event_ctx,
303                                                    const char *socket_options)
304 {
305         struct composite_context *result, *ctx;
306         struct sock_connect_state *state;
307         int i;
308
309         result = talloc_zero(mem_ctx, struct composite_context);
310         if (result == NULL) goto failed;
311         result->state = COMPOSITE_STATE_IN_PROGRESS;
312
313         result->event_ctx = event_ctx;
314         if (result->event_ctx == NULL) goto failed;
315
316         state = talloc(result, struct sock_connect_state);
317         if (state == NULL) goto failed;
318         state->ctx = result;
319         result->private_data = state;
320
321         state->host_name = talloc_strdup(state, host_name);
322         if (state->host_name == NULL) goto failed;
323
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]);
329         }
330         state->socket_options = talloc_reference(state, socket_options);
331
332         if (!host_addr) {
333                 host_addr = host_name;
334         }
335
336         ctx = socket_connect_multi_send(state, host_addr,
337                                         state->num_ports, state->ports,
338                                         resolve_ctx,
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;
343         return result;
344
345 failed:
346         talloc_free(result);
347         return NULL;
348 }
349
350 static void smbcli_sock_connect_recv_conn(struct composite_context *ctx)
351 {
352         struct sock_connect_state *state =
353                 talloc_get_type(ctx->async.private_data,
354                                 struct sock_connect_state);
355         struct socket_context *sock;
356         uint16_t port;
357
358         state->ctx->status = socket_connect_multi_recv(ctx, state, &sock,
359                                                        &port);
360         if (!composite_is_ok(state->ctx)) return;
361
362         state->ctx->status =
363                 socket_set_option(sock, state->socket_options, NULL);
364         if (!composite_is_ok(state->ctx)) return;
365
366
367         state->result = talloc_zero(state, struct smbcli_socket);
368         if (composite_nomem(state->result, state->ctx)) return;
369
370         state->result->sock = talloc_steal(state->result, sock);
371         state->result->port = port;
372         state->result->hostname = talloc_steal(sock, state->host_name);
373
374         state->result->event.ctx = state->ctx->event_ctx;
375         if (composite_nomem(state->result->event.ctx, state->ctx)) return;
376
377         composite_done(state->ctx);
378 }
379
380 /*
381   finish a smbcli_sock_connect_send() operation
382 */
383 NTSTATUS smbcli_sock_connect_recv(struct composite_context *c,
384                                   TALLOC_CTX *mem_ctx,
385                                   struct smbcli_socket **result)
386 {
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);
393         }
394         talloc_free(c);
395         return status;
396 }
397
398 /*
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)
401
402   sync version of the function
403 */
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)
411 {
412         struct composite_context *c =
413                 smbcli_sock_connect_send(mem_ctx, host_addr, ports, host_name,
414                                          resolve_ctx,
415                                          event_ctx, socket_options);
416         return smbcli_sock_connect_recv(c, mem_ctx, result);
417 }
418
419
420 /****************************************************************************
421  mark the socket as dead
422 ****************************************************************************/
423 _PUBLIC_ void smbcli_sock_dead(struct smbcli_socket *sock)
424 {
425         talloc_free(sock->event.fde);
426         sock->event.fde = NULL;
427         talloc_free(sock->sock);
428         sock->sock = NULL;
429 }
430