s4:libcli:smb2: set SMB2_CAP_ALL in the negprot
[metze/samba/wip.git] / source4 / libcli / smb2 / transport.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    SMB2 client transport context management functions
5
6    Copyright (C) Andrew Tridgell 2005
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 "libcli/raw/libcliraw.h"
25 #include "libcli/raw/raw_proto.h"
26 #include "libcli/smb2/smb2.h"
27 #include "libcli/smb2/smb2_calls.h"
28 #include "lib/socket/socket.h"
29 #include "lib/events/events.h"
30 #include "lib/stream/packet.h"
31 #include "../lib/util/dlinklist.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "librpc/ndr/libndr.h"
34
35 /*
36   destroy a transport
37  */
38 static int transport_destructor(struct smb2_transport *transport)
39 {
40         smb2_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 smb2_transport *smb2_transport_init(struct smbcli_socket *sock,
48                                            TALLOC_CTX *parent_ctx,
49                                            struct smbcli_options *options)
50 {
51         struct smb2_transport *transport;
52         struct GUID client_guid;
53         uint32_t smb2_capabilities = 0;
54
55         transport = talloc_zero(parent_ctx, struct smb2_transport);
56         if (!transport) return NULL;
57
58         transport->ev = sock->event.ctx;
59         transport->options = *options;
60
61         TALLOC_FREE(sock->event.fde);
62         TALLOC_FREE(sock->event.te);
63
64         client_guid = GUID_random();
65
66         /* TODO: hand this in via the options? */
67         smb2_capabilities = SMB2_CAP_ALL;
68
69         transport->conn = smbXcli_conn_create(transport,
70                                               sock->sock->fd,
71                                               sock->hostname,
72                                               options->signing,
73                                               0, /* smb1_capabilities */
74                                               &client_guid,
75                                               smb2_capabilities);
76         if (transport->conn == NULL) {
77                 talloc_free(transport);
78                 return NULL;
79         }
80         sock->sock->fd = -1;
81         TALLOC_FREE(sock);
82
83         talloc_set_destructor(transport, transport_destructor);
84
85         return transport;
86 }
87
88 /*
89   mark the transport as dead
90 */
91 void smb2_transport_dead(struct smb2_transport *transport, NTSTATUS status)
92 {
93         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
94                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
95         }
96         if (NT_STATUS_IS_OK(status)) {
97                 status = NT_STATUS_LOCAL_DISCONNECT;
98         }
99
100         smbXcli_conn_disconnect(transport->conn, status);
101 }
102
103 static void smb2_request_done(struct tevent_req *subreq);
104 static void smb2_transport_break_handler(struct tevent_req *subreq);
105
106 /*
107   put a request into the send queue
108 */
109 void smb2_transport_send(struct smb2_request *req)
110 {
111         NTSTATUS status;
112         struct smb2_transport *transport = req->transport;
113         struct tevent_req **reqs = transport->compound.reqs;
114         size_t num_reqs = talloc_array_length(reqs);
115         size_t i;
116         uint16_t cmd = SVAL(req->out.hdr, SMB2_HDR_OPCODE);
117         uint32_t additional_flags = IVAL(req->out.hdr, SMB2_HDR_FLAGS);
118         uint32_t clear_flags = 0;
119         uint32_t pid = IVAL(req->out.hdr, SMB2_HDR_PID);
120         uint32_t tid = IVAL(req->out.hdr, SMB2_HDR_TID);
121         struct smbXcli_session *session = NULL;
122         bool need_pending_break = false;
123         size_t hdr_ofs;
124         size_t pdu_len;
125         DATA_BLOB body = data_blob_null;
126         DATA_BLOB dyn = data_blob_null;
127         uint32_t timeout_msec = transport->options.request_timeout * 1000;
128
129         if (transport->oplock.handler) {
130                 need_pending_break = true;
131         }
132
133         if (transport->lease.handler) {
134                 need_pending_break = true;
135         }
136
137         if (transport->break_subreq) {
138                 need_pending_break = false;
139         }
140
141         if (need_pending_break) {
142                 struct tevent_req *subreq;
143
144                 subreq = smb2cli_req_create(transport,
145                                             transport->ev,
146                                             transport->conn,
147                                             SMB2_OP_BREAK,
148                                             0, /* additional_flags */
149                                             0, /*clear_flags */
150                                             0, /* timeout_msec */
151                                             0, /* pid */
152                                             0, /* tid */
153                                             NULL, /* session */
154                                             NULL, /* body */
155                                             0, /* body_fixed */
156                                             NULL, /* dyn */
157                                             0); /* dyn_len */
158                 if (subreq != NULL) {
159                         smbXcli_req_set_pending(subreq);
160                         tevent_req_set_callback(subreq,
161                                                 smb2_transport_break_handler,
162                                                 transport);
163                         transport->break_subreq = subreq;
164                 }
165         }
166
167         if (req->session) {
168                 session = req->session->smbXcli;
169         }
170
171         if (transport->compound.related) {
172                 additional_flags |= SMB2_HDR_FLAG_CHAINED;
173         }
174
175         hdr_ofs = PTR_DIFF(req->out.hdr, req->out.buffer);
176         pdu_len = req->out.size - hdr_ofs;
177         body.data = req->out.body;
178         body.length = req->out.body_fixed;
179         dyn.data = req->out.body + req->out.body_fixed;
180         dyn.length = pdu_len - (SMB2_HDR_BODY + req->out.body_fixed);
181
182         req->subreq = smb2cli_req_create(req,
183                                          transport->ev,
184                                          transport->conn,
185                                          cmd,
186                                          additional_flags,
187                                          clear_flags,
188                                          timeout_msec,
189                                          pid,
190                                          tid,
191                                          session,
192                                          body.data, body.length,
193                                          dyn.data, dyn.length);
194         if (req->subreq == NULL) {
195                 req->state = SMB2_REQUEST_ERROR;
196                 req->status = NT_STATUS_NO_MEMORY;
197                 return;
198         }
199
200         if (!tevent_req_is_in_progress(req->subreq)) {
201                 req->state = SMB2_REQUEST_ERROR;
202                 req->status = NT_STATUS_INTERNAL_ERROR;/* TODO */
203                 return;
204         }
205
206         tevent_req_set_callback(req->subreq, smb2_request_done, req);
207
208         smb2cli_req_set_notify_async(req->subreq);
209         if (req->credit_charge) {
210                 smb2cli_req_set_credit_charge(req->subreq, req->credit_charge);
211         }
212
213         ZERO_STRUCT(req->out);
214         req->state = SMB2_REQUEST_RECV;
215
216         if (num_reqs > 0) {
217                 for (i=0; i < num_reqs; i++) {
218                         if (reqs[i] != NULL) {
219                                 continue;
220                         }
221
222                         reqs[i] = req->subreq;
223                         i++;
224                         break;
225                 }
226
227                 if (i < num_reqs) {
228                         return;
229                 }
230         } else {
231                 reqs = &req->subreq;
232                 num_reqs = 1;
233         }
234         status = smb2cli_req_compound_submit(reqs, num_reqs);
235
236         TALLOC_FREE(transport->compound.reqs);
237
238         if (!NT_STATUS_IS_OK(status)) {
239                 req->status = status;
240                 req->state = SMB2_REQUEST_ERROR;
241                 smbXcli_conn_disconnect(transport->conn, status);
242         }
243 }
244
245 static void smb2_request_done(struct tevent_req *subreq)
246 {
247         struct smb2_request *req =
248                 tevent_req_callback_data(subreq,
249                 struct smb2_request);
250         ssize_t len;
251         size_t i;
252
253         req->recv_iov = NULL;
254
255         req->status = smb2cli_req_recv(req->subreq, req, &req->recv_iov, NULL, 0);
256         if (NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
257                 req->cancel.can_cancel = true;
258                 return;
259         }
260         TALLOC_FREE(req->subreq);
261         if (!NT_STATUS_IS_OK(req->status)) {
262                 if (req->recv_iov == NULL) {
263                         req->state = SMB2_REQUEST_ERROR;
264                         if (req->async.fn) {
265                                 req->async.fn(req);
266                         }
267                         return;
268                 }
269         }
270
271         len = req->recv_iov[0].iov_len;
272         for (i=1; i < 3; i++) {
273                 uint8_t *p = req->recv_iov[i-1].iov_base;
274                 uint8_t *c1 = req->recv_iov[i].iov_base;
275                 uint8_t *c2 = p + req->recv_iov[i-1].iov_len;
276
277                 len += req->recv_iov[i].iov_len;
278
279                 if (req->recv_iov[i].iov_len == 0) {
280                         continue;
281                 }
282
283                 if (c1 != c2) {
284                         req->status = NT_STATUS_INTERNAL_ERROR;
285                         req->state = SMB2_REQUEST_ERROR;
286                         if (req->async.fn) {
287                                 req->async.fn(req);
288                         }
289                         return;
290                 }
291         }
292
293         req->in.buffer = req->recv_iov[0].iov_base;
294         req->in.size = len;
295         req->in.allocated = req->in.size;
296
297         req->in.hdr        =  req->recv_iov[0].iov_base;
298         req->in.body       =  req->recv_iov[1].iov_base;
299         req->in.dynamic    =  req->recv_iov[2].iov_base;
300         req->in.body_fixed =  req->recv_iov[1].iov_len;
301         req->in.body_size  =  req->in.body_fixed;
302         req->in.body_size  += req->recv_iov[2].iov_len;
303
304         smb2_setup_bufinfo(req);
305
306         req->state = SMB2_REQUEST_DONE;
307         if (req->async.fn) {
308                 req->async.fn(req);
309         }
310 }
311
312 static void smb2_transport_break_handler(struct tevent_req *subreq)
313 {
314         struct smb2_transport *transport =
315                 tevent_req_callback_data(subreq,
316                 struct smb2_transport);
317         NTSTATUS status;
318         uint8_t *hdr;
319         uint8_t *body;
320         uint16_t len = 0;
321         bool lease;
322         struct iovec *recv_iov = NULL;
323
324         transport->break_subreq = NULL;
325
326         status = smb2cli_req_recv(subreq, transport, &recv_iov, NULL, 0);
327         TALLOC_FREE(subreq);
328         if (!NT_STATUS_IS_OK(status)) {
329                 TALLOC_FREE(recv_iov);
330                 smb2_transport_dead(transport, status);
331                 return;
332         }
333
334         /*
335          * Setup the subreq to handle the
336          * next incoming SMB2 Break.
337          */
338         subreq = smb2cli_req_create(transport,
339                                     transport->ev,
340                                     transport->conn,
341                                     SMB2_OP_BREAK,
342                                     0, /* additional_flags */
343                                     0, /*clear_flags */
344                                     0, /* timeout_msec */
345                                     0, /* pid */
346                                     0, /* tid */
347                                     NULL, /* session */
348                                     NULL, /* body */
349                                     0, /* body_fixed */
350                                     NULL, /* dyn */
351                                     0); /* dyn_len */
352         if (subreq != NULL) {
353                 smbXcli_req_set_pending(subreq);
354                 tevent_req_set_callback(subreq,
355                                         smb2_transport_break_handler,
356                                         transport);
357                 transport->break_subreq = subreq;
358         }
359
360         hdr = recv_iov[0].iov_base;
361         body = recv_iov[1].iov_base;
362
363         len = recv_iov[1].iov_len;
364         if (recv_iov[1].iov_len >= 2) {
365                 len = CVAL(body, 0x00);
366                 if (len != recv_iov[1].iov_len) {
367                         len = recv_iov[1].iov_len;
368                 }
369         }
370
371         if (len == 24) {
372                 lease = false;
373         } else if (len == 44) {
374                 lease = true;
375         } else {
376                 DEBUG(1,("Discarding smb2 oplock reply of invalid size %u\n",
377                         (unsigned)len));
378                 TALLOC_FREE(recv_iov);
379                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
380                 smb2_transport_dead(transport, status);
381                 return;
382         }
383
384         if (!lease && transport->oplock.handler) {
385                 struct smb2_handle h;
386                 uint8_t level;
387
388                 level = CVAL(body, 0x02);
389                 smb2_pull_handle(body+0x08, &h);
390
391                 TALLOC_FREE(recv_iov);
392
393                 transport->oplock.handler(transport, &h, level,
394                                           transport->oplock.private_data);
395         } else if (lease && transport->lease.handler) {
396                 struct smb2_lease_break lb;
397
398                 ZERO_STRUCT(lb);
399                 lb.break_flags =                SVAL(body, 0x4);
400                 memcpy(&lb.current_lease.lease_key, body+0x8,
401                     sizeof(struct smb2_lease_key));
402                 lb.current_lease.lease_state =  SVAL(body, 0x18);
403                 lb.new_lease_state =            SVAL(body, 0x1C);
404                 lb.break_reason =               SVAL(body, 0x20);
405                 lb.access_mask_hint =           SVAL(body, 0x24);
406                 lb.share_mask_hint =            SVAL(body, 0x28);
407
408                 TALLOC_FREE(recv_iov);
409
410                 transport->lease.handler(transport, &lb,
411                     transport->lease.private_data);
412         } else {
413                 DEBUG(5,("Got SMB2 %s break with no handler\n",
414                         lease ? "lease" : "oplock"));
415         }
416         TALLOC_FREE(recv_iov);
417 }
418
419 NTSTATUS smb2_transport_compound_start(struct smb2_transport *transport,
420                                        uint32_t num)
421 {
422         TALLOC_FREE(transport->compound.reqs);
423         ZERO_STRUCT(transport->compound);
424
425         transport->compound.reqs = talloc_zero_array(transport,
426                                                      struct tevent_req *,
427                                                      num);
428         if (transport->compound.reqs == NULL) {
429                 return NT_STATUS_NO_MEMORY;
430         }
431
432         return NT_STATUS_OK;
433 }
434
435 void smb2_transport_compound_set_related(struct smb2_transport *transport,
436                                          bool related)
437 {
438         transport->compound.related = related;
439 }
440
441 void smb2_transport_credits_ask_num(struct smb2_transport *transport,
442                                     uint16_t ask_num)
443 {
444         smb2cli_conn_set_max_credits(transport->conn, ask_num);
445 }
446
447 static void idle_handler(struct tevent_context *ev, 
448                          struct tevent_timer *te, struct timeval t, void *private_data)
449 {
450         struct smb2_transport *transport = talloc_get_type(private_data,
451                                                            struct smb2_transport);
452         struct timeval next;
453
454         transport->idle.func(transport, transport->idle.private_data);
455
456         next = timeval_current_ofs_usec(transport->idle.period);
457         transport->idle.te = tevent_add_timer(transport->ev,
458                                               transport,
459                                               next,
460                                               idle_handler,
461                                               transport);
462 }
463
464 /*
465   setup the idle handler for a transport
466   the period is in microseconds
467 */
468 void smb2_transport_idle_handler(struct smb2_transport *transport, 
469                                  void (*idle_func)(struct smb2_transport *, void *),
470                                  uint64_t period,
471                                  void *private_data)
472 {
473         TALLOC_FREE(transport->idle.te);
474
475         transport->idle.func = idle_func;
476         transport->idle.private_data = private_data;
477         transport->idle.period = period;
478
479         transport->idle.te = tevent_add_timer(transport->ev,
480                                               transport,
481                                               timeval_current_ofs_usec(period),
482                                               idle_handler,
483                                               transport);
484 }