python:tests: Store keys as bytes rather than as lists of ints
[samba.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                                               NULL); /* smb3_ciphers */
104         if (transport->conn == NULL) {
105                 TALLOC_FREE(sock);
106                 TALLOC_FREE(transport);
107                 return NULL;
108         }
109         sock->sock->fd = -1;
110         TALLOC_FREE(sock);
111
112         talloc_set_destructor(transport, transport_destructor);
113
114         return transport;
115 }
116
117 /*
118   create a transport structure based on an established socket
119 */
120 NTSTATUS smbcli_transport_raw_init(TALLOC_CTX *mem_ctx,
121                                    struct tevent_context *ev,
122                                    struct smbXcli_conn **_conn,
123                                    const struct smbcli_options *options,
124                                    struct smbcli_transport **_transport)
125 {
126         struct smbcli_transport *transport = NULL;
127         NTSTATUS status;
128
129         if (*_conn == NULL) {
130                 return NT_STATUS_INVALID_PARAMETER;
131         }
132
133         transport = talloc_zero(mem_ctx, struct smbcli_transport);
134         if (transport == NULL) {
135                 return NT_STATUS_NO_MEMORY;
136         }
137
138         transport->ev = ev;
139         transport->options = *options;
140
141         /*
142          * First only set the pointer without move.
143          */
144         transport->conn = *_conn;
145         status = smb_raw_negotiate_fill_transport(transport);
146         if (!NT_STATUS_IS_OK(status)) {
147                 TALLOC_FREE(transport);
148                 return status;
149         }
150
151         talloc_set_destructor(transport, transport_destructor);
152
153         /*
154          * Now move it away from the caller...
155          */
156         transport->conn = talloc_move(transport, _conn);
157         *_transport = transport;
158         return NT_STATUS_OK;
159 }
160
161 /*
162   mark the transport as dead
163 */
164 void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status)
165 {
166         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
167                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
168         }
169         if (NT_STATUS_IS_OK(status)) {
170                 status = NT_STATUS_LOCAL_DISCONNECT;
171         }
172
173         smbXcli_conn_disconnect(transport->conn, status);
174 }
175
176 static void idle_handler(struct tevent_context *ev,
177                          struct tevent_timer *te, struct timeval t, void *private_data)
178 {
179         struct smbcli_transport *transport = talloc_get_type(private_data,
180                                                              struct smbcli_transport);
181         struct timeval next;
182
183         transport->idle.func(transport, transport->idle.private_data);
184
185         if (transport->idle.func == NULL) {
186                 return;
187         }
188
189         if (!smbXcli_conn_is_connected(transport->conn)) {
190                 return;
191         }
192
193         next = timeval_current_ofs_usec(transport->idle.period);
194
195         transport->idle.te = tevent_add_timer(transport->ev,
196                                               transport,
197                                               next,
198                                               idle_handler,
199                                               transport);
200 }
201
202 /*
203   setup the idle handler for a transport
204   the period is in microseconds
205 */
206 _PUBLIC_ void smbcli_transport_idle_handler(struct smbcli_transport *transport,
207                                    void (*idle_func)(struct smbcli_transport *, void *),
208                                    uint64_t period,
209                                    void *private_data)
210 {
211         TALLOC_FREE(transport->idle.te);
212         ZERO_STRUCT(transport->idle);
213
214         if (idle_func == NULL) {
215                 return;
216         }
217
218         if (!smbXcli_conn_is_connected(transport->conn)) {
219                 return;
220         }
221
222         transport->idle.func = idle_func;
223         transport->idle.private_data = private_data;
224         transport->idle.period = period;
225
226         transport->idle.te = tevent_add_timer(transport->ev,
227                                               transport,
228                                               timeval_current_ofs_usec(period),
229                                               idle_handler,
230                                               transport);
231 }
232
233 /*
234   process some read/write requests that are pending
235   return false if the socket is dead
236 */
237 _PUBLIC_ bool smbcli_transport_process(struct smbcli_transport *transport)
238 {
239         struct tevent_req *subreq = NULL;
240         int ret;
241
242         if (!smbXcli_conn_is_connected(transport->conn)) {
243                 return false;
244         }
245
246         if (!smbXcli_conn_has_async_calls(transport->conn)) {
247                 return true;
248         }
249
250         /*
251          * do not block for more than 500 micro seconds
252          */
253         subreq = tevent_wakeup_send(transport,
254                                     transport->ev,
255                                     timeval_current_ofs_usec(500));
256         if (subreq == NULL) {
257                 return false;
258         }
259
260         ret = tevent_loop_once(transport->ev);
261         if (ret != 0) {
262                 return false;
263         }
264
265         TALLOC_FREE(subreq);
266
267         if (!smbXcli_conn_is_connected(transport->conn)) {
268                 return false;
269         }
270
271         return true;
272 }
273
274 static void smbcli_transport_break_handler(struct tevent_req *subreq);
275 static void smbcli_request_done(struct tevent_req *subreq);
276
277 struct tevent_req *smbcli_transport_setup_subreq(struct smbcli_request *req)
278 {
279         struct smbcli_transport *transport = req->transport;
280         uint8_t smb_command;
281         uint8_t additional_flags;
282         uint8_t clear_flags;
283         uint16_t additional_flags2;
284         uint16_t clear_flags2;
285         uint32_t pid;
286         struct smbXcli_tcon *tcon = NULL;
287         struct smbXcli_session *session = NULL;
288         uint32_t timeout_msec = transport->options.request_timeout * 1000;
289         struct iovec *bytes_iov = NULL;
290         struct tevent_req *subreq = NULL;
291
292         smb_command = SVAL(req->out.hdr, HDR_COM);
293         additional_flags = CVAL(req->out.hdr, HDR_FLG);
294         additional_flags2 = SVAL(req->out.hdr, HDR_FLG2);
295         pid  = SVAL(req->out.hdr, HDR_PID);
296         pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16;
297
298         clear_flags = ~additional_flags;
299         clear_flags2 = ~additional_flags2;
300
301         if (req->session) {
302                 session = req->session->smbXcli;
303         }
304
305         if (req->tree) {
306                 tcon = req->tree->smbXcli;
307         }
308
309         bytes_iov = talloc(req, struct iovec);
310         if (bytes_iov == NULL) {
311                 return NULL;
312         }
313         bytes_iov->iov_base = (void *)req->out.data;
314         bytes_iov->iov_len = req->out.data_size;
315
316         subreq = smb1cli_req_create(req,
317                                     transport->ev,
318                                     transport->conn,
319                                     smb_command,
320                                     additional_flags,
321                                     clear_flags,
322                                     additional_flags2,
323                                     clear_flags2,
324                                     timeout_msec,
325                                     pid,
326                                     tcon,
327                                     session,
328                                     req->out.wct,
329                                     (uint16_t *)req->out.vwv,
330                                     1, bytes_iov);
331         if (subreq == NULL) {
332                 return NULL;
333         }
334
335         ZERO_STRUCT(req->out);
336
337         return subreq;
338 }
339
340 /*
341   put a request into the send queue
342 */
343 void smbcli_transport_send(struct smbcli_request *req)
344 {
345         struct smbcli_transport *transport = req->transport;
346         NTSTATUS status;
347         bool need_pending_break = false;
348         struct tevent_req *subreq = NULL;
349         size_t i;
350         size_t num_subreqs = 0;
351
352         if (transport->oplock.handler) {
353                 need_pending_break = true;
354         }
355
356         if (transport->break_subreq) {
357                 need_pending_break = false;
358         }
359
360         if (need_pending_break) {
361                 subreq = smb1cli_req_create(transport,
362                                             transport->ev,
363                                             transport->conn,
364                                             0, /* smb_command */
365                                             0, /* additional_flags */
366                                             0, /* clear_flags */
367                                             0, /* additional_flags2 */
368                                             0, /* clear_flags2 */
369                                             0, /* timeout_msec */
370                                             0, /* pid */
371                                             NULL, /* tcon */
372                                             NULL, /* session */
373                                             0, /* wct */
374                                             NULL, /* vwv */
375                                             0, /* iov_count */
376                                             NULL); /* bytes_iov */
377                 if (subreq != NULL) {
378                         smb1cli_req_set_mid(subreq, 0xFFFF);
379                         smbXcli_req_set_pending(subreq);
380                         tevent_req_set_callback(subreq,
381                                                 smbcli_transport_break_handler,
382                                                 transport);
383                         transport->break_subreq = subreq;
384                         subreq = NULL;
385                 }
386         }
387
388         subreq = smbcli_transport_setup_subreq(req);
389         if (subreq == NULL) {
390                 req->state = SMBCLI_REQUEST_ERROR;
391                 req->status = NT_STATUS_NO_MEMORY;
392                 return;
393         }
394
395         for (i = 0; i < ARRAY_SIZE(req->subreqs); i++) {
396                 if (req->subreqs[i] == NULL) {
397                         req->subreqs[i] = subreq;
398                         subreq = NULL;
399                 }
400                 if (req->subreqs[i] == NULL) {
401                         break;
402                 }
403
404                 if (!tevent_req_is_in_progress(req->subreqs[i])) {
405                         req->state = SMBCLI_REQUEST_ERROR;
406                         req->status = NT_STATUS_INTERNAL_ERROR;
407                         return;
408                 }
409         }
410         num_subreqs = i;
411
412         req->state = SMBCLI_REQUEST_RECV;
413         tevent_req_set_callback(req->subreqs[0], smbcli_request_done, req);
414
415         status = smb1cli_req_chain_submit(req->subreqs, num_subreqs);
416         if (!NT_STATUS_IS_OK(status)) {
417                 req->status = status;
418                 req->state = SMBCLI_REQUEST_ERROR;
419                 smbXcli_conn_disconnect(transport->conn, status);
420         }
421 }
422
423 static void smbcli_request_done(struct tevent_req *subreq)
424 {
425         struct smbcli_request *req =
426                 tevent_req_callback_data(subreq,
427                 struct smbcli_request);
428         struct smbcli_transport *transport = req->transport;
429         ssize_t len;
430         size_t i;
431         uint8_t *hdr = NULL;
432         uint8_t wct = 0;
433         uint16_t *vwv = NULL;
434         uint32_t num_bytes = 0;
435         uint8_t *bytes = NULL;
436         struct iovec *recv_iov = NULL;
437         uint8_t *inbuf = NULL;
438
439         req->status = smb1cli_req_recv(req->subreqs[0], req,
440                                        &recv_iov,
441                                        &hdr,
442                                        &wct,
443                                        &vwv,
444                                        NULL, /* pvwv_offset */
445                                        &num_bytes,
446                                        &bytes,
447                                        NULL, /* pbytes_offset */
448                                        &inbuf,
449                                        NULL, 0); /* expected */
450         TALLOC_FREE(req->subreqs[0]);
451         if (!NT_STATUS_IS_OK(req->status)) {
452                 if (recv_iov == NULL) {
453                         req->state = SMBCLI_REQUEST_ERROR;
454                         transport->error.e.nt_status = req->status;
455                         transport->error.etype = ETYPE_SOCKET;
456                         if (req->async.fn) {
457                                 req->async.fn(req);
458                         }
459                         return;
460                 }
461         }
462
463         /*
464          * For SMBreadBraw hdr is NULL
465          */
466         len = recv_iov[0].iov_len;
467         for (i=1; hdr != NULL && i < 3; i++) {
468                 uint8_t *p = recv_iov[i-1].iov_base;
469                 uint8_t *c1 = recv_iov[i].iov_base;
470                 uint8_t *c2 = p + recv_iov[i-1].iov_len;
471
472                 len += recv_iov[i].iov_len;
473
474                 c2 += i;
475                 len += i;
476
477                 if (recv_iov[i].iov_len == 0) {
478                         continue;
479                 }
480
481                 if (c1 != c2) {
482                         req->state = SMBCLI_REQUEST_ERROR;
483                         req->status = NT_STATUS_INTERNAL_ERROR;
484                         transport->error.e.nt_status = req->status;
485                         transport->error.etype = ETYPE_SMB;
486                         if (req->async.fn) {
487                                 req->async.fn(req);
488                         }
489                         return;
490                 }
491         }
492
493         /* fill in the 'in' portion of the matching request */
494         req->in.buffer = inbuf;
495         req->in.size = NBT_HDR_SIZE + len;
496         req->in.allocated = req->in.size;
497
498         req->in.hdr = hdr;
499         req->in.vwv = (uint8_t *)vwv;
500         req->in.wct = wct;
501         req->in.data = bytes;
502         req->in.data_size = num_bytes;
503         req->in.ptr = req->in.data;
504         if (hdr != NULL) {
505                 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
506         }
507
508         smb_setup_bufinfo(req);
509
510         transport->error.e.nt_status = req->status;
511         if (NT_STATUS_IS_OK(req->status)) {
512                 transport->error.etype = ETYPE_NONE;
513         } else {
514                 transport->error.etype = ETYPE_SMB;
515         }
516
517         req->state = SMBCLI_REQUEST_DONE;
518         if (req->async.fn) {
519                 req->async.fn(req);
520         }
521 }
522
523 static void smbcli_transport_break_handler(struct tevent_req *subreq)
524 {
525         struct smbcli_transport *transport =
526                 tevent_req_callback_data(subreq,
527                 struct smbcli_transport);
528         NTSTATUS status;
529         struct iovec *recv_iov = NULL;
530         uint8_t *hdr = NULL;
531         uint16_t *vwv = NULL;
532         const struct smb1cli_req_expected_response expected[] = {
533         {
534                 .status = NT_STATUS_OK,
535                 .wct = 8,
536         }
537         };
538         uint16_t tid;
539         uint16_t fnum;
540         uint8_t level;
541
542         transport->break_subreq = NULL;
543
544         status = smb1cli_req_recv(subreq, transport,
545                                   &recv_iov,
546                                   &hdr,
547                                   NULL, /* pwct */
548                                   &vwv,
549                                   NULL, /* pvwv_offset */
550                                   NULL, /* pnum_bytes */
551                                   NULL, /* pbytes */
552                                   NULL, /* pbytes_offset */
553                                   NULL, /* pinbuf */
554                                   expected,
555                                   ARRAY_SIZE(expected));
556         TALLOC_FREE(subreq);
557         if (!NT_STATUS_IS_OK(status)) {
558                 TALLOC_FREE(recv_iov);
559                 smbcli_transport_dead(transport, status);
560                 return;
561         }
562
563         /*
564          * Setup the subreq to handle the
565          * next incoming SMB2 Break.
566          */
567         subreq = smb1cli_req_create(transport,
568                                     transport->ev,
569                                     transport->conn,
570                                     0, /* smb_command */
571                                     0, /* additional_flags */
572                                     0, /* clear_flags */
573                                     0, /* additional_flags2 */
574                                     0, /* clear_flags2 */
575                                     0, /* timeout_msec */
576                                     0, /* pid */
577                                     NULL, /* tcon */
578                                     NULL, /* session */
579                                     0, /* wct */
580                                     NULL, /* vwv */
581                                     0, /* iov_count */
582                                     NULL); /* bytes_iov */
583         if (subreq != NULL) {
584                 smb1cli_req_set_mid(subreq, 0xFFFF);
585                 smbXcli_req_set_pending(subreq);
586                 tevent_req_set_callback(subreq,
587                                         smbcli_transport_break_handler,
588                                         transport);
589                 transport->break_subreq = subreq;
590         }
591
592         tid = SVAL(hdr, HDR_TID);
593         fnum = SVAL(vwv+2, 0);
594         level = CVAL(vwv+3, 1);
595
596         TALLOC_FREE(recv_iov);
597
598         if (transport->oplock.handler) {
599                 transport->oplock.handler(transport, tid, fnum, level,
600                                           transport->oplock.private_data);
601         } else {
602                 DEBUG(5,("Got SMB oplock break with no handler\n"));
603         }
604
605 }
606
607
608 /****************************************************************************
609  Send an SMBecho (async send)
610 *****************************************************************************/
611 _PUBLIC_ struct smbcli_request *smb_raw_echo_send(struct smbcli_transport *transport,
612                                          struct smb_echo *p)
613 {
614         struct smbcli_request *req;
615
616         req = smbcli_request_setup_transport(transport, SMBecho, 1, p->in.size);
617         if (!req) return NULL;
618
619         SSVAL(req->out.vwv, VWV(0), p->in.repeat_count);
620
621         memcpy(req->out.data, p->in.data, p->in.size);
622
623         ZERO_STRUCT(p->out);
624
625         if (!smbcli_request_send(req)) {
626                 smbcli_request_destroy(req);
627                 return NULL;
628         }
629
630         return req;
631 }
632
633 /****************************************************************************
634  raw echo interface (async recv)
635 ****************************************************************************/
636 NTSTATUS smb_raw_echo_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
637                            struct smb_echo *p)
638 {
639         if (!smbcli_request_receive(req) ||
640             smbcli_request_is_error(req)) {
641                 goto failed;
642         }
643
644         SMBCLI_CHECK_WCT(req, 1);
645         p->out.count++;
646         p->out.sequence_number = SVAL(req->in.vwv, VWV(0));
647         p->out.size = req->in.data_size;
648         talloc_free(p->out.data);
649         p->out.data = talloc_array(mem_ctx, uint8_t, p->out.size);
650         NT_STATUS_HAVE_NO_MEMORY(p->out.data);
651
652         if (!smbcli_raw_pull_data(&req->in.bufinfo, req->in.data, p->out.size, p->out.data)) {
653                 req->status = NT_STATUS_BUFFER_TOO_SMALL;
654         }
655
656         if (p->out.count == p->in.repeat_count) {
657                 return smbcli_request_destroy(req);
658         }
659
660         return NT_STATUS_OK;
661
662 failed:
663         return smbcli_request_destroy(req);
664 }
665
666 /****************************************************************************
667  Send a echo (sync interface)
668 *****************************************************************************/
669 NTSTATUS smb_raw_echo(struct smbcli_transport *transport, struct smb_echo *p)
670 {
671         struct smbcli_request *req = smb_raw_echo_send(transport, p);
672         return smbcli_request_simple_recv(req);
673 }