d0dd1f9dee6a987f9d545e7b7daf95f9902db948
[vlendec/samba-autobuild/.git] / source4 / libcli / raw / clitransport.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB client transport context management functions
4
5    Copyright (C) Andrew Tridgell 1994-2005
6    Copyright (C) James Myers 2003 <myersjj@samba.org>
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/network.h"
24 #include "../lib/async_req/async_sock.h"
25 #include "../lib/util/tevent_ntstatus.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/raw/raw_proto.h"
28 #include "lib/socket/socket.h"
29 #include "lib/events/events.h"
30 #include "librpc/gen_ndr/ndr_nbt.h"
31 #include "../libcli/nbt/libnbt.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "../libcli/smb/read_smb.h"
34
35 /*
36   destroy a transport
37  */
38 static int transport_destructor(struct smbcli_transport *transport)
39 {
40         smbcli_transport_dead(transport, NT_STATUS_LOCAL_DISCONNECT);
41         return 0;
42 }
43
44 /*
45   create a transport structure based on an established socket
46 */
47 struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock,
48                                                TALLOC_CTX *parent_ctx, 
49                                                bool primary, 
50                                                struct smbcli_options *options)
51 {
52         struct smbcli_transport *transport;
53         uint32_t smb1_capabilities;
54
55         transport = talloc_zero(parent_ctx, struct smbcli_transport);
56         if (!transport) return NULL;
57
58         transport->ev = sock->event.ctx;
59         transport->options = *options;
60
61         if (transport->options.max_protocol == PROTOCOL_DEFAULT) {
62                 transport->options.max_protocol = PROTOCOL_NT1;
63         }
64
65         if (transport->options.max_protocol > PROTOCOL_NT1) {
66                 transport->options.max_protocol = PROTOCOL_NT1;
67         }
68
69         TALLOC_FREE(sock->event.fde);
70         TALLOC_FREE(sock->event.te);
71
72         smb1_capabilities = 0;
73         smb1_capabilities |= CAP_LARGE_FILES;
74         smb1_capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
75         smb1_capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND;
76         smb1_capabilities |= CAP_DFS | CAP_W2K_SMBS;
77         smb1_capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX;
78         smb1_capabilities |= CAP_LWIO;
79
80         if (options->ntstatus_support) {
81                 smb1_capabilities |= CAP_STATUS32;
82         }
83
84         if (options->unicode) {
85                 smb1_capabilities |= CAP_UNICODE;
86         }
87
88         if (options->use_spnego) {
89                 smb1_capabilities |= CAP_EXTENDED_SECURITY;
90         }
91
92         if (options->use_level2_oplocks) {
93                 smb1_capabilities |= CAP_LEVEL_II_OPLOCKS;
94         }
95
96         transport->conn = smbXcli_conn_create(transport,
97                                               sock->sock->fd,
98                                               sock->hostname,
99                                               options->signing,
100                                               smb1_capabilities,
101                                               NULL, /* client_guid */
102                                               0); /* smb2_capabilities */
103         if (transport->conn == NULL) {
104                 TALLOC_FREE(sock);
105                 TALLOC_FREE(transport);
106                 return NULL;
107         }
108         sock->sock->fd = -1;
109         TALLOC_FREE(sock);
110
111         talloc_set_destructor(transport, transport_destructor);
112
113         return transport;
114 }
115
116 /*
117   mark the transport as dead
118 */
119 void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status)
120 {
121         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
122                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
123         }
124         if (NT_STATUS_IS_OK(status)) {
125                 status = NT_STATUS_LOCAL_DISCONNECT;
126         }
127
128         smbXcli_conn_disconnect(transport->conn, status);
129 }
130
131 static void idle_handler(struct tevent_context *ev, 
132                          struct tevent_timer *te, struct timeval t, void *private_data)
133 {
134         struct smbcli_transport *transport = talloc_get_type(private_data,
135                                                              struct smbcli_transport);
136         struct timeval next;
137
138         transport->idle.func(transport, transport->idle.private_data);
139
140         next = timeval_current_ofs_usec(transport->idle.period);
141
142         transport->idle.te = tevent_add_timer(transport->ev,
143                                               transport,
144                                               next,
145                                               idle_handler,
146                                               transport);
147 }
148
149 /*
150   setup the idle handler for a transport
151   the period is in microseconds
152 */
153 _PUBLIC_ void smbcli_transport_idle_handler(struct smbcli_transport *transport, 
154                                    void (*idle_func)(struct smbcli_transport *, void *),
155                                    uint64_t period,
156                                    void *private_data)
157 {
158         TALLOC_FREE(transport->idle.te);
159
160         transport->idle.func = idle_func;
161         transport->idle.private_data = private_data;
162         transport->idle.period = period;
163
164         transport->idle.te = tevent_add_timer(transport->ev,
165                                               transport,
166                                               timeval_current_ofs_usec(period),
167                                               idle_handler,
168                                               transport);
169 }
170
171 /*
172   process some read/write requests that are pending
173   return false if the socket is dead
174 */
175 _PUBLIC_ bool smbcli_transport_process(struct smbcli_transport *transport)
176 {
177         struct tevent_req *subreq = NULL;
178         int ret;
179
180         if (!smbXcli_conn_is_connected(transport->conn)) {
181                 return false;
182         }
183
184         if (!smbXcli_conn_has_async_calls(transport->conn)) {
185                 return true;
186         }
187
188         /*
189          * do not block for more than 500 micro seconds
190          */
191         subreq = tevent_wakeup_send(transport,
192                                     transport->ev,
193                                     timeval_current_ofs_usec(500));
194         if (subreq == NULL) {
195                 return false;
196         }
197
198         ret = tevent_loop_once(transport->ev);
199         if (ret != 0) {
200                 return false;
201         }
202
203         TALLOC_FREE(subreq);
204
205         if (!smbXcli_conn_is_connected(transport->conn)) {
206                 return false;
207         }
208
209         return true;
210 }
211
212 static void smbcli_transport_break_handler(struct tevent_req *subreq);
213 static void smbcli_request_done(struct tevent_req *subreq);
214
215 struct tevent_req *smbcli_transport_setup_subreq(struct smbcli_request *req)
216 {
217         struct smbcli_transport *transport = req->transport;
218         uint8_t smb_command;
219         uint8_t additional_flags;
220         uint8_t clear_flags;
221         uint16_t additional_flags2;
222         uint16_t clear_flags2;
223         uint32_t pid;
224         struct smbXcli_tcon *tcon = NULL;
225         struct smbXcli_session *session = NULL;
226         uint32_t timeout_msec = transport->options.request_timeout * 1000;
227         struct iovec *bytes_iov = NULL;
228         struct tevent_req *subreq = NULL;
229
230         smb_command = SVAL(req->out.hdr, HDR_COM);
231         additional_flags = CVAL(req->out.hdr, HDR_FLG);
232         additional_flags2 = SVAL(req->out.hdr, HDR_FLG2);
233         pid  = SVAL(req->out.hdr, HDR_PID);
234         pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16;
235
236         clear_flags = ~additional_flags;
237         clear_flags2 = ~additional_flags2;
238
239         if (req->session) {
240                 session = req->session->smbXcli;
241         }
242
243         if (req->tree) {
244                 tcon = req->tree->smbXcli;
245         }
246
247         bytes_iov = talloc(req, struct iovec);
248         if (bytes_iov == NULL) {
249                 return NULL;
250         }
251         bytes_iov->iov_base = (void *)req->out.data;
252         bytes_iov->iov_len = req->out.data_size;
253
254         subreq = smb1cli_req_create(req,
255                                     transport->ev,
256                                     transport->conn,
257                                     smb_command,
258                                     additional_flags,
259                                     clear_flags,
260                                     additional_flags2,
261                                     clear_flags2,
262                                     timeout_msec,
263                                     pid,
264                                     tcon,
265                                     session,
266                                     req->out.wct,
267                                     (uint16_t *)req->out.vwv,
268                                     1, bytes_iov);
269         if (subreq == NULL) {
270                 return NULL;
271         }
272
273         ZERO_STRUCT(req->out);
274
275         return subreq;
276 }
277
278 /*
279   put a request into the send queue
280 */
281 void smbcli_transport_send(struct smbcli_request *req)
282 {
283         struct smbcli_transport *transport = req->transport;
284         NTSTATUS status;
285         bool need_pending_break = false;
286         struct tevent_req *subreq = NULL;
287         size_t i;
288         size_t num_subreqs = 0;
289
290         if (transport->oplock.handler) {
291                 need_pending_break = true;
292         }
293
294         if (transport->break_subreq) {
295                 need_pending_break = false;
296         }
297
298         if (need_pending_break) {
299                 subreq = smb1cli_req_create(transport,
300                                             transport->ev,
301                                             transport->conn,
302                                             0, /* smb_command */
303                                             0, /* additional_flags */
304                                             0, /* clear_flags */
305                                             0, /* additional_flags2 */
306                                             0, /* clear_flags2 */
307                                             0, /* timeout_msec */
308                                             0, /* pid */
309                                             NULL, /* tcon */
310                                             NULL, /* session */
311                                             0, /* wct */
312                                             NULL, /* vwv */
313                                             0, /* iov_count */
314                                             NULL); /* bytes_iov */
315                 if (subreq != NULL) {
316                         smb1cli_req_set_mid(subreq, 0xFFFF);
317                         smbXcli_req_set_pending(subreq);
318                         tevent_req_set_callback(subreq,
319                                                 smbcli_transport_break_handler,
320                                                 transport);
321                         transport->break_subreq = subreq;
322                         subreq = NULL;
323                 }
324         }
325
326         subreq = smbcli_transport_setup_subreq(req);
327         if (subreq == NULL) {
328                 req->state = SMBCLI_REQUEST_ERROR;
329                 req->status = NT_STATUS_NO_MEMORY;
330                 return;
331         }
332
333         for (i = 0; i < ARRAY_SIZE(req->subreqs); i++) {
334                 if (req->subreqs[i] == NULL) {
335                         req->subreqs[i] = subreq;
336                         subreq = NULL;
337                 }
338                 if (req->subreqs[i] == NULL) {
339                         break;
340                 }
341
342                 if (!tevent_req_is_in_progress(req->subreqs[i])) {
343                         req->state = SMBCLI_REQUEST_ERROR;
344                         req->status = NT_STATUS_INTERNAL_ERROR;
345                         return;
346                 }
347         }
348         num_subreqs = i;
349
350         req->state = SMBCLI_REQUEST_RECV;
351         tevent_req_set_callback(req->subreqs[0], smbcli_request_done, req);
352
353         status = smb1cli_req_chain_submit(req->subreqs, num_subreqs);
354         if (!NT_STATUS_IS_OK(status)) {
355                 req->status = status;
356                 req->state = SMBCLI_REQUEST_ERROR;
357                 smbXcli_conn_disconnect(transport->conn, status);
358         }
359 }
360
361 static void smbcli_request_done(struct tevent_req *subreq)
362 {
363         struct smbcli_request *req =
364                 tevent_req_callback_data(subreq,
365                 struct smbcli_request);
366         struct smbcli_transport *transport = req->transport;
367         ssize_t len;
368         size_t i;
369         uint8_t *hdr = NULL;
370         uint8_t wct = 0;
371         uint16_t *vwv = NULL;
372         uint32_t num_bytes = 0;
373         uint8_t *bytes = NULL;
374         struct iovec *recv_iov = NULL;
375         uint8_t *inbuf = NULL;
376
377         req->status = smb1cli_req_recv(req->subreqs[0], req,
378                                        &recv_iov,
379                                        &hdr,
380                                        &wct,
381                                        &vwv,
382                                        NULL, /* pvwv_offset */
383                                        &num_bytes,
384                                        &bytes,
385                                        NULL, /* pbytes_offset */
386                                        &inbuf,
387                                        NULL, 0); /* expected */
388         TALLOC_FREE(req->subreqs[0]);
389         if (!NT_STATUS_IS_OK(req->status)) {
390                 if (recv_iov == NULL) {
391                         req->state = SMBCLI_REQUEST_ERROR;
392                         transport->error.e.nt_status = req->status;
393                         transport->error.etype = ETYPE_SOCKET;
394                         if (req->async.fn) {
395                                 req->async.fn(req);
396                         }
397                         return;
398                 }
399         }
400
401         /*
402          * For SMBreadBraw hdr is NULL
403          */
404         len = recv_iov[0].iov_len;
405         for (i=1; hdr != NULL && i < 3; i++) {
406                 uint8_t *p = recv_iov[i-1].iov_base;
407                 uint8_t *c1 = recv_iov[i].iov_base;
408                 uint8_t *c2 = p + recv_iov[i-1].iov_len;
409
410                 len += recv_iov[i].iov_len;
411
412                 c2 += i;
413                 len += i;
414
415                 if (recv_iov[i].iov_len == 0) {
416                         continue;
417                 }
418
419                 if (c1 != c2) {
420                         req->state = SMBCLI_REQUEST_ERROR;
421                         req->status = NT_STATUS_INTERNAL_ERROR;
422                         transport->error.e.nt_status = req->status;
423                         transport->error.etype = ETYPE_SMB;
424                         if (req->async.fn) {
425                                 req->async.fn(req);
426                         }
427                         return;
428                 }
429         }
430
431         /* fill in the 'in' portion of the matching request */
432         req->in.buffer = inbuf;
433         req->in.size = NBT_HDR_SIZE + len;
434         req->in.allocated = req->in.size;
435
436         req->in.hdr = hdr;
437         req->in.vwv = (uint8_t *)vwv;
438         req->in.wct = wct;
439         req->in.data = bytes;
440         req->in.data_size = num_bytes;
441         req->in.ptr = req->in.data;
442         if (hdr != NULL) {
443                 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
444         }
445
446         smb_setup_bufinfo(req);
447
448         transport->error.e.nt_status = req->status;
449         if (NT_STATUS_IS_OK(req->status)) {
450                 transport->error.etype = ETYPE_NONE;
451         } else {
452                 transport->error.etype = ETYPE_SMB;
453         }
454
455         req->state = SMBCLI_REQUEST_DONE;
456         if (req->async.fn) {
457                 req->async.fn(req);
458         }
459 }
460
461 static void smbcli_transport_break_handler(struct tevent_req *subreq)
462 {
463         struct smbcli_transport *transport =
464                 tevent_req_callback_data(subreq,
465                 struct smbcli_transport);
466         NTSTATUS status;
467         struct iovec *recv_iov = NULL;
468         uint8_t *hdr = NULL;
469         uint16_t *vwv = NULL;
470         const struct smb1cli_req_expected_response expected[] = {
471         {
472                 .status = NT_STATUS_OK,
473                 .wct = 8,
474         }
475         };
476         uint16_t tid;
477         uint16_t fnum;
478         uint8_t level;
479
480         transport->break_subreq = NULL;
481
482         status = smb1cli_req_recv(subreq, transport,
483                                   &recv_iov,
484                                   &hdr,
485                                   NULL, /* pwct */
486                                   &vwv,
487                                   NULL, /* pvwv_offset */
488                                   NULL, /* pnum_bytes */
489                                   NULL, /* pbytes */
490                                   NULL, /* pbytes_offset */
491                                   NULL, /* pinbuf */
492                                   expected,
493                                   ARRAY_SIZE(expected));
494         TALLOC_FREE(subreq);
495         if (!NT_STATUS_IS_OK(status)) {
496                 TALLOC_FREE(recv_iov);
497                 smbcli_transport_dead(transport, status);
498                 return;
499         }
500
501         /*
502          * Setup the subreq to handle the
503          * next incoming SMB2 Break.
504          */
505         subreq = smb1cli_req_create(transport,
506                                     transport->ev,
507                                     transport->conn,
508                                     0, /* smb_command */
509                                     0, /* additional_flags */
510                                     0, /* clear_flags */
511                                     0, /* additional_flags2 */
512                                     0, /* clear_flags2 */
513                                     0, /* timeout_msec */
514                                     0, /* pid */
515                                     NULL, /* tcon */
516                                     NULL, /* session */
517                                     0, /* wct */
518                                     NULL, /* vwv */
519                                     0, /* iov_count */
520                                     NULL); /* bytes_iov */
521         if (subreq != NULL) {
522                 smb1cli_req_set_mid(subreq, 0xFFFF);
523                 smbXcli_req_set_pending(subreq);
524                 tevent_req_set_callback(subreq,
525                                         smbcli_transport_break_handler,
526                                         transport);
527                 transport->break_subreq = subreq;
528         }
529
530         tid = SVAL(hdr, HDR_TID);
531         fnum = SVAL(vwv+2, 0);
532         level = CVAL(vwv+3, 1);
533
534         TALLOC_FREE(recv_iov);
535
536         if (transport->oplock.handler) {
537                 transport->oplock.handler(transport, tid, fnum, level,
538                                           transport->oplock.private_data);
539         } else {
540                 DEBUG(5,("Got SMB oplock break with no handler\n"));
541         }
542
543 }
544
545
546 /****************************************************************************
547  Send an SMBecho (async send)
548 *****************************************************************************/
549 _PUBLIC_ struct smbcli_request *smb_raw_echo_send(struct smbcli_transport *transport,
550                                          struct smb_echo *p)
551 {
552         struct smbcli_request *req;
553
554         req = smbcli_request_setup_transport(transport, SMBecho, 1, p->in.size);
555         if (!req) return NULL;
556
557         SSVAL(req->out.vwv, VWV(0), p->in.repeat_count);
558
559         memcpy(req->out.data, p->in.data, p->in.size);
560
561         ZERO_STRUCT(p->out);
562
563         if (!smbcli_request_send(req)) {
564                 smbcli_request_destroy(req);
565                 return NULL;
566         }
567
568         return req;
569 }
570
571 /****************************************************************************
572  raw echo interface (async recv)
573 ****************************************************************************/
574 NTSTATUS smb_raw_echo_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
575                            struct smb_echo *p)
576 {
577         if (!smbcli_request_receive(req) ||
578             smbcli_request_is_error(req)) {
579                 goto failed;
580         }
581
582         SMBCLI_CHECK_WCT(req, 1);
583         p->out.count++;
584         p->out.sequence_number = SVAL(req->in.vwv, VWV(0));
585         p->out.size = req->in.data_size;
586         talloc_free(p->out.data);
587         p->out.data = talloc_array(mem_ctx, uint8_t, p->out.size);
588         NT_STATUS_HAVE_NO_MEMORY(p->out.data);
589
590         if (!smbcli_raw_pull_data(&req->in.bufinfo, req->in.data, p->out.size, p->out.data)) {
591                 req->status = NT_STATUS_BUFFER_TOO_SMALL;
592         }
593
594         if (p->out.count == p->in.repeat_count) {
595                 return smbcli_request_destroy(req);
596         }
597
598         return NT_STATUS_OK;
599
600 failed:
601         return smbcli_request_destroy(req);
602 }
603
604 /****************************************************************************
605  Send a echo (sync interface)
606 *****************************************************************************/
607 NTSTATUS smb_raw_echo(struct smbcli_transport *transport, struct smb_echo *p)
608 {
609         struct smbcli_request *req = smb_raw_echo_send(transport, p);
610         return smbcli_request_simple_recv(req);
611 }