Make smbd_lock_socket/smbd_unlock_socket recursive with a ref_count.
[metze/samba/wip.git] / source3 / smbd / smb2_server.c
1 /*
2    Unix SMB/CIFS implementation.
3    Core SMB2 server
4
5    Copyright (C) Stefan Metzmacher 2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "smbd/globals.h"
23 #include "../libcli/smb/smb_common.h"
24 #include "../lib/tsocket/tsocket.h"
25
26 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
27 {
28         if (size < (4 + SMB2_HDR_BODY)) {
29                 return false;
30         }
31
32         if (IVAL(inbuf, 4) != SMB2_MAGIC) {
33                 return false;
34         }
35
36         return true;
37 }
38
39 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
40 {
41         NTSTATUS status;
42         int ret;
43
44         TALLOC_FREE(sconn->smb1.fde);
45
46         sconn->smb2.event_ctx = smbd_event_context();
47
48         sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
49         if (sconn->smb2.recv_queue == NULL) {
50                 return NT_STATUS_NO_MEMORY;
51         }
52
53         sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
54         if (sconn->smb2.send_queue == NULL) {
55                 return NT_STATUS_NO_MEMORY;
56         }
57
58         sconn->smb2.sessions.idtree = idr_init(sconn);
59         if (sconn->smb2.sessions.idtree == NULL) {
60                 return NT_STATUS_NO_MEMORY;
61         }
62         sconn->smb2.sessions.limit = 0x0000FFFE;
63         sconn->smb2.sessions.list = NULL;
64
65         ret = tstream_bsd_existing_socket(sconn, smbd_server_fd(),
66                                           &sconn->smb2.stream);
67         if (ret == -1) {
68                 status = map_nt_error_from_unix(errno);
69                 return status;
70         }
71
72         /* Ensure child is set to non-blocking mode */
73         set_blocking(smbd_server_fd(),false);
74         return NT_STATUS_OK;
75 }
76
77 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
78 #define _smb2_setlen(_buf,len) do { \
79         uint8_t *buf = (uint8_t *)_buf; \
80         buf[0] = 0; \
81         buf[1] = ((len)&0xFF0000)>>16; \
82         buf[2] = ((len)&0xFF00)>>8; \
83         buf[3] = (len)&0xFF; \
84 } while (0)
85
86 static void smb2_setup_nbt_length(struct iovec *vector, int count)
87 {
88         size_t len = 0;
89         int i;
90
91         for (i=1; i < count; i++) {
92                 len += vector[i].iov_len;
93         }
94
95         _smb2_setlen(vector[0].iov_base, len);
96 }
97
98 static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request **req)
99 {
100         if (*req) {
101                 (*req)->parent = NULL;
102                 (*req)->mem_pool = NULL;
103         }
104
105         return 0;
106 }
107
108 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
109 {
110         if (req->out.vector) {
111                 DLIST_REMOVE(req->sconn->smb2.requests, req);
112         }
113
114         if (req->parent) {
115                 *req->parent = NULL;
116                 talloc_free(req->mem_pool);
117         }
118
119         return 0;
120 }
121
122 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
123 {
124         TALLOC_CTX *mem_pool;
125         struct smbd_smb2_request **parent;
126         struct smbd_smb2_request *req;
127
128         mem_pool = talloc_pool(mem_ctx, 8192);
129         if (mem_pool == NULL) {
130                 return NULL;
131         }
132
133         parent = talloc(mem_pool, struct smbd_smb2_request *);
134         if (parent == NULL) {
135                 talloc_free(mem_pool);
136                 return NULL;
137         }
138
139         req = talloc_zero(parent, struct smbd_smb2_request);
140         if (req == NULL) {
141                 talloc_free(mem_pool);
142                 return NULL;
143         }
144         *parent         = req;
145         req->mem_pool   = mem_pool;
146         req->parent     = parent;
147
148         talloc_set_destructor(parent, smbd_smb2_request_parent_destructor);
149         talloc_set_destructor(req, smbd_smb2_request_destructor);
150
151         return req;
152 }
153
154 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
155                                          const uint8_t *inbuf, size_t size,
156                                          struct smbd_smb2_request **_req)
157 {
158         struct smbd_smb2_request *req;
159         uint32_t protocol_version;
160         const uint8_t *inhdr = NULL;
161         off_t ofs = 0;
162         uint16_t cmd;
163         uint32_t next_command_ofs;
164
165         if (size < (4 + SMB2_HDR_BODY + 2)) {
166                 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
167                 return NT_STATUS_INVALID_PARAMETER;
168         }
169
170         inhdr = inbuf + 4;
171
172         protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
173         if (protocol_version != SMB2_MAGIC) {
174                 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
175                          protocol_version));
176                 return NT_STATUS_INVALID_PARAMETER;
177         }
178
179         cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
180         if (cmd != SMB2_OP_NEGPROT) {
181                 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
182                          cmd));
183                 return NT_STATUS_INVALID_PARAMETER;
184         }
185
186         next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
187         if (next_command_ofs != 0) {
188                 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
189                          next_command_ofs));
190                 return NT_STATUS_INVALID_PARAMETER;
191         }
192
193         req = smbd_smb2_request_allocate(sconn);
194         if (req == NULL) {
195                 return NT_STATUS_NO_MEMORY;
196         }
197         req->sconn = sconn;
198
199         talloc_steal(req, inbuf);
200
201         req->in.vector = talloc_array(req, struct iovec, 4);
202         if (req->in.vector == NULL) {
203                 TALLOC_FREE(req);
204                 return NT_STATUS_NO_MEMORY;
205         }
206         req->in.vector_count = 4;
207
208         memcpy(req->in.nbt_hdr, inbuf, 4);
209
210         ofs = 0;
211         req->in.vector[0].iov_base      = (void *)req->in.nbt_hdr;
212         req->in.vector[0].iov_len       = 4;
213         ofs += req->in.vector[0].iov_len;
214
215         req->in.vector[1].iov_base      = (void *)(inbuf + ofs);
216         req->in.vector[1].iov_len       = SMB2_HDR_BODY;
217         ofs += req->in.vector[1].iov_len;
218
219         req->in.vector[2].iov_base      = (void *)(inbuf + ofs);
220         req->in.vector[2].iov_len       = SVAL(inbuf, ofs) & 0xFFFE;
221         ofs += req->in.vector[2].iov_len;
222
223         if (ofs > size) {
224                 return NT_STATUS_INVALID_PARAMETER;
225         }
226
227         req->in.vector[3].iov_base      = (void *)(inbuf + ofs);
228         req->in.vector[3].iov_len       = size - ofs;
229         ofs += req->in.vector[3].iov_len;
230
231         req->current_idx = 1;
232
233         *_req = req;
234         return NT_STATUS_OK;
235 }
236
237 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req,
238                                 uint16_t *p_creds_requested)
239 {
240         int count;
241         int idx;
242         bool compound_related = false;
243
244         count = req->in.vector_count;
245
246         if (count < 4) {
247                 /* It's not a SMB2 request */
248                 return NT_STATUS_INVALID_PARAMETER;
249         }
250
251         for (idx=1; idx < count; idx += 3) {
252                 const uint8_t *inhdr = NULL;
253                 uint32_t flags;
254
255                 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
256                         return NT_STATUS_INVALID_PARAMETER;
257                 }
258
259                 if (req->in.vector[idx+1].iov_len < 2) {
260                         return NT_STATUS_INVALID_PARAMETER;
261                 }
262
263                 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
264
265                 /* setup the SMB2 header */
266                 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
267                         return NT_STATUS_INVALID_PARAMETER;
268                 }
269
270                 *p_creds_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
271
272                 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
273                 if (idx == 1) {
274                         /*
275                          * the 1st request should never have the
276                          * SMB2_HDR_FLAG_CHAINED flag set
277                          */
278                         if (flags & SMB2_HDR_FLAG_CHAINED) {
279                                 req->next_status = NT_STATUS_INVALID_PARAMETER;
280                                 return NT_STATUS_OK;
281                         }
282                 } else if (idx == 4) {
283                         /*
284                          * the 2nd request triggers related vs. unrelated
285                          * compounded requests
286                          */
287                         if (flags & SMB2_HDR_FLAG_CHAINED) {
288                                 compound_related = true;
289                         }
290                 } else if (idx > 4) {
291 #if 0
292                         /*
293                          * It seems the this tests are wrong
294                          * see the SMB2-COMPOUND test
295                          */
296
297                         /*
298                          * all other requests should match the 2nd one
299                          */
300                         if (flags & SMB2_HDR_FLAG_CHAINED) {
301                                 if (!compound_related) {
302                                         req->next_status =
303                                                 NT_STATUS_INVALID_PARAMETER;
304                                         return NT_STATUS_OK;
305                                 }
306                         } else {
307                                 if (compound_related) {
308                                         req->next_status =
309                                                 NT_STATUS_INVALID_PARAMETER;
310                                         return NT_STATUS_OK;
311                                 }
312                         }
313 #endif
314                 }
315         }
316
317         return NT_STATUS_OK;
318 }
319
320 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req, uint16_t creds)
321 {
322         struct iovec *vector;
323         int count;
324         int idx;
325
326         count = req->in.vector_count;
327         vector = talloc_array(req, struct iovec, count);
328         if (vector == NULL) {
329                 return NT_STATUS_NO_MEMORY;
330         }
331
332         vector[0].iov_base      = req->out.nbt_hdr;
333         vector[0].iov_len       = 4;
334         SIVAL(req->out.nbt_hdr, 0, 0);
335
336         for (idx=1; idx < count; idx += 3) {
337                 const uint8_t *inhdr = NULL;
338                 uint32_t in_flags;
339                 uint8_t *outhdr = NULL;
340                 uint8_t *outbody = NULL;
341                 uint32_t next_command_ofs = 0;
342                 struct iovec *current = &vector[idx];
343
344                 if ((idx + 3) < count) {
345                         /* we have a next command */
346                         next_command_ofs = SMB2_HDR_BODY + 8;
347                 }
348
349                 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
350                 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
351
352                 outhdr = talloc_array(vector, uint8_t,
353                                       SMB2_HDR_BODY + 8);
354                 if (outhdr == NULL) {
355                         return NT_STATUS_NO_MEMORY;
356                 }
357
358                 outbody = outhdr + SMB2_HDR_BODY;
359
360                 current[0].iov_base     = (void *)outhdr;
361                 current[0].iov_len      = SMB2_HDR_BODY;
362
363                 current[1].iov_base     = (void *)outbody;
364                 current[1].iov_len      = 8;
365
366                 current[2].iov_base     = NULL;
367                 current[2].iov_len      = 0;
368
369                 /* setup the SMB2 header */
370                 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID,     SMB2_MAGIC);
371                 SSVAL(outhdr, SMB2_HDR_LENGTH,          SMB2_HDR_BODY);
372                 SSVAL(outhdr, SMB2_HDR_EPOCH,           0);
373                 SIVAL(outhdr, SMB2_HDR_STATUS,
374                       NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
375                 SSVAL(outhdr, SMB2_HDR_OPCODE,
376                       SVAL(inhdr, SMB2_HDR_OPCODE));
377                 SSVAL(outhdr, SMB2_HDR_CREDIT,          creds);
378                 SIVAL(outhdr, SMB2_HDR_FLAGS,
379                       IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
380                 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND,    next_command_ofs);
381                 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
382                       BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
383                 SIVAL(outhdr, SMB2_HDR_PID,
384                       IVAL(inhdr, SMB2_HDR_PID));
385                 SIVAL(outhdr, SMB2_HDR_TID,
386                       IVAL(inhdr, SMB2_HDR_TID));
387                 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
388                       BVAL(inhdr, SMB2_HDR_SESSION_ID));
389                 memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16);
390
391                 /* setup error body header */
392                 SSVAL(outbody, 0x00, 0x08 + 1);
393                 SSVAL(outbody, 0x02, 0);
394                 SIVAL(outbody, 0x04, 0);
395         }
396
397         req->out.vector = vector;
398         req->out.vector_count = count;
399
400         /* setup the length of the NBT packet */
401         smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
402
403         DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
404
405         return NT_STATUS_OK;
406 }
407
408 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
409                                          const char *reason,
410                                          const char *location)
411 {
412         DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
413                   reason, location));
414         exit_server_cleanly(reason);
415 }
416
417 struct smbd_smb2_request_pending_state {
418         struct smbd_server_connection *sconn;
419         uint8_t buf[4 + SMB2_HDR_BODY + 0x08];
420         struct iovec vector;
421 };
422
423 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq);
424
425 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
426                                          struct tevent_req *subreq)
427 {
428         struct smbd_smb2_request_pending_state *state;
429         uint8_t *outhdr;
430         int i = req->current_idx;
431         uint32_t flags;
432         uint64_t message_id;
433         uint64_t async_id;
434         uint8_t *hdr;
435         uint8_t *body;
436
437         if (!tevent_req_is_in_progress(subreq)) {
438                 return NT_STATUS_OK;
439         }
440
441         req->subreq = subreq;
442         subreq = NULL;
443
444         outhdr = (uint8_t *)req->out.vector[i].iov_base;
445
446         flags = IVAL(outhdr, SMB2_HDR_FLAGS);
447         message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
448
449         async_id = message_id; /* keep it simple for now... */
450         SIVAL(outhdr, SMB2_HDR_FLAGS,   flags | SMB2_HDR_FLAG_ASYNC);
451         SBVAL(outhdr, SMB2_HDR_PID,     async_id);
452
453         /* TODO: add a paramter to delay this */
454         state = talloc(req->sconn, struct smbd_smb2_request_pending_state);
455         if (state == NULL) {
456                 return NT_STATUS_NO_MEMORY;
457         }
458         state->sconn = req->sconn;
459
460         state->vector.iov_base = (void *)state->buf;
461         state->vector.iov_len = sizeof(state->buf);
462
463         _smb2_setlen(state->buf, sizeof(state->buf) - 4);
464         hdr = state->buf + 4;
465         body = hdr + SMB2_HDR_BODY;
466
467         SIVAL(hdr, SMB2_HDR_PROTOCOL_ID,        SMB2_MAGIC);
468         SSVAL(hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
469         SSVAL(hdr, SMB2_HDR_EPOCH,              0);
470         SIVAL(hdr, SMB2_HDR_STATUS,             NT_STATUS_V(STATUS_PENDING));
471         SSVAL(hdr, SMB2_HDR_OPCODE,
472               SVAL(outhdr, SMB2_HDR_OPCODE));
473         SSVAL(hdr, SMB2_HDR_CREDIT,             1);
474         SIVAL(hdr, SMB2_HDR_FLAGS,
475               IVAL(outhdr, SMB2_HDR_FLAGS));
476         SIVAL(hdr, SMB2_HDR_NEXT_COMMAND,       0);
477         SBVAL(hdr, SMB2_HDR_MESSAGE_ID,
478               BVAL(outhdr, SMB2_HDR_MESSAGE_ID));
479         SBVAL(hdr, SMB2_HDR_PID,
480               BVAL(outhdr, SMB2_HDR_PID));
481         SBVAL(hdr, SMB2_HDR_SESSION_ID,
482               BVAL(outhdr, SMB2_HDR_SESSION_ID));
483         memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
484
485         SSVAL(body, 0x00, 0x08 + 1);
486
487         SCVAL(body, 0x02, 0);
488         SCVAL(body, 0x03, 0);
489         SIVAL(body, 0x04, 0);
490
491         subreq = tstream_writev_queue_send(state,
492                                            req->sconn->smb2.event_ctx,
493                                            req->sconn->smb2.stream,
494                                            req->sconn->smb2.send_queue,
495                                            &state->vector, 1);
496         if (subreq == NULL) {
497                 return NT_STATUS_NO_MEMORY;
498         }
499         tevent_req_set_callback(subreq,
500                                 smbd_smb2_request_pending_writev_done,
501                                 state);
502
503         return NT_STATUS_OK;
504 }
505
506 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
507 {
508         struct smbd_smb2_request_pending_state *state =
509                 tevent_req_callback_data(subreq,
510                 struct smbd_smb2_request_pending_state);
511         struct smbd_server_connection *sconn = state->sconn;
512         int ret;
513         int sys_errno;
514
515         ret = tstream_writev_queue_recv(subreq, &sys_errno);
516         TALLOC_FREE(subreq);
517         if (ret == -1) {
518                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
519                 smbd_server_connection_terminate(sconn, nt_errstr(status));
520                 return;
521         }
522
523         TALLOC_FREE(state);
524 }
525
526 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
527 {
528         struct smbd_server_connection *sconn = req->sconn;
529         struct smbd_smb2_request *cur;
530         const uint8_t *inhdr;
531         int i = req->current_idx;
532         uint32_t flags;
533         uint64_t search_message_id;
534         uint64_t search_async_id;
535
536         inhdr = (const uint8_t *)req->in.vector[i].iov_base;
537
538         flags = IVAL(inhdr, SMB2_HDR_FLAGS);
539         search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
540         search_async_id = BVAL(inhdr, SMB2_HDR_PID);
541
542         /*
543          * we don't need the request anymore
544          * cancel requests never have a response
545          */
546         TALLOC_FREE(req);
547
548         for (cur = sconn->smb2.requests; cur; cur = cur->next) {
549                 const uint8_t *outhdr;
550                 uint64_t message_id;
551                 uint64_t async_id;
552
553                 i = cur->current_idx;
554
555                 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
556
557                 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
558                 async_id = BVAL(outhdr, SMB2_HDR_PID);
559
560                 if (flags & SMB2_HDR_FLAG_ASYNC) {
561                         if (search_async_id == async_id) {
562                                 break;
563                         }
564                 } else {
565                         if (search_message_id == message_id) {
566                                 break;
567                         }
568                 }
569         }
570
571         if (cur && cur->subreq) {
572                 tevent_req_cancel(cur->subreq);
573         }
574
575         return NT_STATUS_OK;
576 }
577
578 static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
579 {
580         const uint8_t *inhdr;
581         int i = req->current_idx;
582         uint16_t opcode;
583         uint32_t flags;
584         NTSTATUS status;
585         NTSTATUS session_status;
586         uint32_t allowed_flags;
587
588         inhdr = (const uint8_t *)req->in.vector[i].iov_base;
589
590         /* TODO: verify more things */
591
592         flags = IVAL(inhdr, SMB2_HDR_FLAGS);
593         opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
594         DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode));
595
596         allowed_flags = SMB2_HDR_FLAG_CHAINED |
597                         SMB2_HDR_FLAG_SIGNED |
598                         SMB2_HDR_FLAG_DFS;
599         if (opcode == SMB2_OP_CANCEL) {
600                 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
601         }
602         if ((flags & ~allowed_flags) != 0) {
603                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
604         }
605
606         session_status = smbd_smb2_request_check_session(req);
607
608         req->do_signing = false;
609         if (flags & SMB2_HDR_FLAG_SIGNED) {
610                 if (!NT_STATUS_IS_OK(session_status)) {
611                         return smbd_smb2_request_error(req, session_status);
612                 }
613
614                 req->do_signing = true;
615                 status = smb2_signing_check_pdu(req->session->session_key,
616                                                 &req->in.vector[i], 3);
617                 if (!NT_STATUS_IS_OK(status)) {
618                         return smbd_smb2_request_error(req, status);
619                 }
620         } else if (req->session && req->session->do_signing) {
621                 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
622         }
623
624         if (flags & SMB2_HDR_FLAG_CHAINED) {
625                 /*
626                  * This check is mostly for giving the correct error code
627                  * for compounded requests.
628                  *
629                  * TODO: we may need to move this after the session
630                  *       and tcon checks.
631                  */
632                 if (!NT_STATUS_IS_OK(req->next_status)) {
633                         return smbd_smb2_request_error(req, req->next_status);
634                 }
635         } else {
636                 req->compat_chain_fsp = NULL;
637         }
638
639         switch (opcode) {
640         case SMB2_OP_NEGPROT:
641                 return smbd_smb2_request_process_negprot(req);
642
643         case SMB2_OP_SESSSETUP:
644                 return smbd_smb2_request_process_sesssetup(req);
645
646         case SMB2_OP_LOGOFF:
647                 if (!NT_STATUS_IS_OK(session_status)) {
648                         return smbd_smb2_request_error(req, session_status);
649                 }
650                 return smbd_smb2_request_process_logoff(req);
651
652         case SMB2_OP_TCON:
653                 if (!NT_STATUS_IS_OK(session_status)) {
654                         return smbd_smb2_request_error(req, session_status);
655                 }
656                 status = smbd_smb2_request_check_session(req);
657                 if (!NT_STATUS_IS_OK(status)) {
658                         return smbd_smb2_request_error(req, status);
659                 }
660                 return smbd_smb2_request_process_tcon(req);
661
662         case SMB2_OP_TDIS:
663                 if (!NT_STATUS_IS_OK(session_status)) {
664                         return smbd_smb2_request_error(req, session_status);
665                 }
666                 status = smbd_smb2_request_check_tcon(req);
667                 if (!NT_STATUS_IS_OK(status)) {
668                         return smbd_smb2_request_error(req, status);
669                 }
670                 return smbd_smb2_request_process_tdis(req);
671
672         case SMB2_OP_CREATE:
673                 if (!NT_STATUS_IS_OK(session_status)) {
674                         return smbd_smb2_request_error(req, session_status);
675                 }
676                 status = smbd_smb2_request_check_tcon(req);
677                 if (!NT_STATUS_IS_OK(status)) {
678                         return smbd_smb2_request_error(req, status);
679                 }
680                 return smbd_smb2_request_process_create(req);
681
682         case SMB2_OP_CLOSE:
683                 if (!NT_STATUS_IS_OK(session_status)) {
684                         return smbd_smb2_request_error(req, session_status);
685                 }
686                 status = smbd_smb2_request_check_tcon(req);
687                 if (!NT_STATUS_IS_OK(status)) {
688                         return smbd_smb2_request_error(req, status);
689                 }
690                 return smbd_smb2_request_process_close(req);
691
692         case SMB2_OP_FLUSH:
693                 if (!NT_STATUS_IS_OK(session_status)) {
694                         return smbd_smb2_request_error(req, session_status);
695                 }
696                 status = smbd_smb2_request_check_tcon(req);
697                 if (!NT_STATUS_IS_OK(status)) {
698                         return smbd_smb2_request_error(req, status);
699                 }
700                 return smbd_smb2_request_process_flush(req);
701
702         case SMB2_OP_READ:
703                 if (!NT_STATUS_IS_OK(session_status)) {
704                         return smbd_smb2_request_error(req, session_status);
705                 }
706                 status = smbd_smb2_request_check_tcon(req);
707                 if (!NT_STATUS_IS_OK(status)) {
708                         return smbd_smb2_request_error(req, status);
709                 }
710                 return smbd_smb2_request_process_read(req);
711
712         case SMB2_OP_WRITE:
713                 if (!NT_STATUS_IS_OK(session_status)) {
714                         return smbd_smb2_request_error(req, session_status);
715                 }
716                 status = smbd_smb2_request_check_tcon(req);
717                 if (!NT_STATUS_IS_OK(status)) {
718                         return smbd_smb2_request_error(req, status);
719                 }
720                 return smbd_smb2_request_process_write(req);
721
722         case SMB2_OP_LOCK:
723                 if (!NT_STATUS_IS_OK(session_status)) {
724                         return smbd_smb2_request_error(req, session_status);
725                 }
726                 status = smbd_smb2_request_check_tcon(req);
727                 if (!NT_STATUS_IS_OK(status)) {
728                         return smbd_smb2_request_error(req, status);
729                 }
730                 return smbd_smb2_request_process_lock(req);
731
732         case SMB2_OP_IOCTL:
733                 if (!NT_STATUS_IS_OK(session_status)) {
734                         return smbd_smb2_request_error(req, session_status);
735                 }
736                 status = smbd_smb2_request_check_tcon(req);
737                 if (!NT_STATUS_IS_OK(status)) {
738                         return smbd_smb2_request_error(req, status);
739                 }
740                 return smbd_smb2_request_process_ioctl(req);
741
742         case SMB2_OP_CANCEL:
743                 return smbd_smb2_request_process_cancel(req);
744
745         case SMB2_OP_KEEPALIVE:
746                 return smbd_smb2_request_process_keepalive(req);
747
748         case SMB2_OP_FIND:
749                 if (!NT_STATUS_IS_OK(session_status)) {
750                         return smbd_smb2_request_error(req, session_status);
751                 }
752                 status = smbd_smb2_request_check_tcon(req);
753                 if (!NT_STATUS_IS_OK(status)) {
754                         return smbd_smb2_request_error(req, status);
755                 }
756                 return smbd_smb2_request_process_find(req);
757
758         case SMB2_OP_NOTIFY:
759                 if (!NT_STATUS_IS_OK(session_status)) {
760                         return smbd_smb2_request_error(req, session_status);
761                 }
762                 status = smbd_smb2_request_check_tcon(req);
763                 if (!NT_STATUS_IS_OK(status)) {
764                         return smbd_smb2_request_error(req, status);
765                 }
766                 return smbd_smb2_request_process_notify(req);
767
768         case SMB2_OP_GETINFO:
769                 if (!NT_STATUS_IS_OK(session_status)) {
770                         return smbd_smb2_request_error(req, session_status);
771                 }
772                 status = smbd_smb2_request_check_tcon(req);
773                 if (!NT_STATUS_IS_OK(status)) {
774                         return smbd_smb2_request_error(req, status);
775                 }
776                 return smbd_smb2_request_process_getinfo(req);
777
778         case SMB2_OP_SETINFO:
779                 if (!NT_STATUS_IS_OK(session_status)) {
780                         return smbd_smb2_request_error(req, session_status);
781                 }
782                 status = smbd_smb2_request_check_tcon(req);
783                 if (!NT_STATUS_IS_OK(status)) {
784                         return smbd_smb2_request_error(req, status);
785                 }
786                 return smbd_smb2_request_process_setinfo(req);
787
788         case SMB2_OP_BREAK:
789                 if (!NT_STATUS_IS_OK(session_status)) {
790                         return smbd_smb2_request_error(req, session_status);
791                 }
792                 status = smbd_smb2_request_check_tcon(req);
793                 if (!NT_STATUS_IS_OK(status)) {
794                         return smbd_smb2_request_error(req, status);
795                 }
796                 return smbd_smb2_request_process_break(req);
797         }
798
799         return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
800 }
801
802 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq);
803 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
804
805 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
806 {
807         struct tevent_req *subreq;
808
809         req->subreq = NULL;
810
811         smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
812
813         if (req->do_signing) {
814                 int i = req->current_idx;
815                 NTSTATUS status;
816                 status = smb2_signing_sign_pdu(req->session->session_key,
817                                                &req->out.vector[i], 3);
818                 if (!NT_STATUS_IS_OK(status)) {
819                         return status;
820                 }
821         }
822
823         req->current_idx += 3;
824
825         if (req->current_idx < req->out.vector_count) {
826                 struct timeval zero = timeval_zero();
827                 subreq = tevent_wakeup_send(req,
828                                             req->sconn->smb2.event_ctx,
829                                             zero);
830                 if (subreq == NULL) {
831                         return NT_STATUS_NO_MEMORY;
832                 }
833                 tevent_req_set_callback(subreq,
834                                         smbd_smb2_request_dispatch_compound,
835                                         req);
836
837                 return NT_STATUS_OK;
838         }
839
840         subreq = tstream_writev_queue_send(req,
841                                            req->sconn->smb2.event_ctx,
842                                            req->sconn->smb2.stream,
843                                            req->sconn->smb2.send_queue,
844                                            req->out.vector,
845                                            req->out.vector_count);
846         if (subreq == NULL) {
847                 return NT_STATUS_NO_MEMORY;
848         }
849         tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
850
851         return NT_STATUS_OK;
852 }
853
854 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq)
855 {
856         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
857                                         struct smbd_smb2_request);
858         struct smbd_server_connection *sconn = req->sconn;
859         NTSTATUS status;
860
861         tevent_wakeup_recv(subreq);
862         TALLOC_FREE(subreq);
863
864         DEBUG(10,("smbd_smb2_request_dispatch_compound: idx[%d] of %d vectors\n",
865                   req->current_idx, req->in.vector_count));
866
867         status = smbd_smb2_request_dispatch(req);
868         if (!NT_STATUS_IS_OK(status)) {
869                 smbd_server_connection_terminate(sconn, nt_errstr(status));
870                 return;
871         }
872 }
873
874 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
875 {
876         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
877                                         struct smbd_smb2_request);
878         struct smbd_server_connection *sconn = req->sconn;
879         int ret;
880         int sys_errno;
881
882         ret = tstream_writev_queue_recv(subreq, &sys_errno);
883         TALLOC_FREE(subreq);
884         TALLOC_FREE(req);
885         if (ret == -1) {
886                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
887                 smbd_server_connection_terminate(sconn, nt_errstr(status));
888                 return;
889         }
890 }
891
892 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
893                                     NTSTATUS status,
894                                     DATA_BLOB *info,
895                                     const char *location)
896 {
897         uint8_t *outhdr;
898         uint8_t *outbody;
899         int i = req->current_idx;
900
901         DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
902                   i, nt_errstr(status), info ? " +info" : "",
903                   location));
904
905         outhdr = (uint8_t *)req->out.vector[i].iov_base;
906
907         SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
908
909         outbody = outhdr + SMB2_HDR_BODY;
910
911         req->out.vector[i+1].iov_base = (void *)outbody;
912         req->out.vector[i+1].iov_len = 8;
913
914         if (info) {
915                 SIVAL(outbody, 0x04, info->length);
916                 req->out.vector[i+2].iov_base   = (void *)info->data;
917                 req->out.vector[i+2].iov_len    = info->length;
918         } else {
919                 req->out.vector[i+2].iov_base = NULL;
920                 req->out.vector[i+2].iov_len = 0;
921         }
922
923         /*
924          * if a request fails, all other remaining
925          * compounded requests should fail too
926          */
927         req->next_status = NT_STATUS_INVALID_PARAMETER;
928
929         return smbd_smb2_request_reply(req);
930 }
931
932 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
933                                    NTSTATUS status,
934                                    DATA_BLOB body, DATA_BLOB *dyn,
935                                    const char *location)
936 {
937         uint8_t *outhdr;
938         uint8_t *outdyn;
939         int i = req->current_idx;
940         uint32_t next_command_ofs;
941
942         DEBUG(10,("smbd_smb2_request_done_ex: "
943                   "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
944                   i, nt_errstr(status), (unsigned int)body.length,
945                   dyn ? "yes": "no",
946                   (unsigned int)(dyn ? dyn->length : 0),
947                   location));
948
949         if (body.length < 2) {
950                 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
951         }
952
953         if ((body.length % 2) != 0) {
954                 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
955         }
956
957         outhdr = (uint8_t *)req->out.vector[i].iov_base;
958         /* the fallback dynamic buffer */
959         outdyn = outhdr + SMB2_HDR_BODY + 8;
960
961         next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
962         SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
963
964         req->out.vector[i+1].iov_base = (void *)body.data;
965         req->out.vector[i+1].iov_len = body.length;
966
967         if (dyn) {
968                 req->out.vector[i+2].iov_base   = (void *)dyn->data;
969                 req->out.vector[i+2].iov_len    = dyn->length;
970         } else {
971                 req->out.vector[i+2].iov_base = NULL;
972                 req->out.vector[i+2].iov_len = 0;
973         }
974
975         /* see if we need to recalculate the offset to the next response */
976         if (next_command_ofs > 0) {
977                 next_command_ofs  = SMB2_HDR_BODY;
978                 next_command_ofs += req->out.vector[i+1].iov_len;
979                 next_command_ofs += req->out.vector[i+2].iov_len;
980         }
981
982         if ((next_command_ofs % 8) != 0) {
983                 size_t pad_size = 8 - (next_command_ofs % 8);
984                 if (req->out.vector[i+2].iov_len == 0) {
985                         /*
986                          * if the dyn buffer is empty
987                          * we can use it to add padding
988                          */
989                         uint8_t *pad;
990
991                         pad = talloc_zero_array(req->out.vector,
992                                                 uint8_t, pad_size);
993                         if (pad == NULL) {
994                                 return smbd_smb2_request_error(req,
995                                                 NT_STATUS_NO_MEMORY);
996                         }
997
998                         req->out.vector[i+2].iov_base = (void *)pad;
999                         req->out.vector[i+2].iov_len = pad_size;
1000                 } else {
1001                         /*
1002                          * For now we copy the dynamic buffer
1003                          * and add the padding to the new buffer
1004                          */
1005                         size_t old_size;
1006                         uint8_t *old_dyn;
1007                         size_t new_size;
1008                         uint8_t *new_dyn;
1009
1010                         old_size = req->out.vector[i+2].iov_len;
1011                         old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
1012
1013                         new_size = old_size + pad_size;
1014                         new_dyn = talloc_array(req->out.vector,
1015                                                uint8_t, new_size);
1016                         if (new_dyn == NULL) {
1017                                 return smbd_smb2_request_error(req,
1018                                                 NT_STATUS_NO_MEMORY);
1019                         }
1020
1021                         memcpy(new_dyn, old_dyn, old_size);
1022                         memset(new_dyn + old_size, 0, pad_size);
1023
1024                         req->out.vector[i+2].iov_base = (void *)new_dyn;
1025                         req->out.vector[i+2].iov_len = new_size;
1026
1027                         TALLOC_FREE(old_dyn);
1028                 }
1029                 next_command_ofs += pad_size;
1030         }
1031
1032         SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
1033
1034         return smbd_smb2_request_reply(req);
1035 }
1036
1037 struct smbd_smb2_send_oplock_break_state {
1038         struct smbd_server_connection *sconn;
1039         uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
1040         struct iovec vector;
1041 };
1042
1043 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
1044
1045 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
1046                                      uint64_t file_id_persistent,
1047                                      uint64_t file_id_volatile,
1048                                      uint8_t oplock_level)
1049 {
1050         struct smbd_smb2_send_oplock_break_state *state;
1051         struct tevent_req *subreq;
1052         uint8_t *hdr;
1053         uint8_t *body;
1054
1055         state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
1056         if (state == NULL) {
1057                 return NT_STATUS_NO_MEMORY;
1058         }
1059         state->sconn = sconn;
1060
1061         state->vector.iov_base = (void *)state->buf;
1062         state->vector.iov_len = sizeof(state->buf);
1063
1064         _smb2_setlen(state->buf, sizeof(state->buf) - 4);
1065         hdr = state->buf + 4;
1066         body = hdr + SMB2_HDR_BODY;
1067
1068         SIVAL(hdr, 0,                           SMB2_MAGIC);
1069         SSVAL(hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
1070         SSVAL(hdr, SMB2_HDR_EPOCH,              0);
1071         SIVAL(hdr, SMB2_HDR_STATUS,             0);
1072         SSVAL(hdr, SMB2_HDR_OPCODE,             SMB2_OP_BREAK);
1073         SSVAL(hdr, SMB2_HDR_CREDIT,             0);
1074         SIVAL(hdr, SMB2_HDR_FLAGS,              SMB2_HDR_FLAG_REDIRECT);
1075         SIVAL(hdr, SMB2_HDR_NEXT_COMMAND,       0);
1076         SBVAL(hdr, SMB2_HDR_MESSAGE_ID,         UINT64_MAX);
1077         SIVAL(hdr, SMB2_HDR_PID,                0);
1078         SIVAL(hdr, SMB2_HDR_TID,                0);
1079         SBVAL(hdr, SMB2_HDR_SESSION_ID,         0);
1080         memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
1081
1082         SSVAL(body, 0x00, 0x18);
1083
1084         SCVAL(body, 0x02, oplock_level);
1085         SCVAL(body, 0x03, 0);           /* reserved */
1086         SIVAL(body, 0x04, 0);           /* reserved */
1087         SBVAL(body, 0x08, file_id_persistent);
1088         SBVAL(body, 0x10, file_id_volatile);
1089
1090         subreq = tstream_writev_queue_send(state,
1091                                            sconn->smb2.event_ctx,
1092                                            sconn->smb2.stream,
1093                                            sconn->smb2.send_queue,
1094                                            &state->vector, 1);
1095         if (subreq == NULL) {
1096                 return NT_STATUS_NO_MEMORY;
1097         }
1098         tevent_req_set_callback(subreq,
1099                                 smbd_smb2_oplock_break_writev_done,
1100                                 state);
1101
1102         return NT_STATUS_OK;
1103 }
1104
1105 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
1106 {
1107         struct smbd_smb2_send_oplock_break_state *state =
1108                 tevent_req_callback_data(subreq,
1109                 struct smbd_smb2_send_oplock_break_state);
1110         struct smbd_server_connection *sconn = state->sconn;
1111         int ret;
1112         int sys_errno;
1113
1114         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1115         TALLOC_FREE(subreq);
1116         if (ret == -1) {
1117                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1118                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1119                 return;
1120         }
1121
1122         TALLOC_FREE(state);
1123 }
1124
1125 struct smbd_smb2_request_read_state {
1126         size_t missing;
1127         bool asked_for_header;
1128         struct smbd_smb2_request *smb2_req;
1129 };
1130
1131 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
1132                                          void *private_data,
1133                                          TALLOC_CTX *mem_ctx,
1134                                          struct iovec **_vector,
1135                                          size_t *_count);
1136 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
1137
1138 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
1139                                         struct tevent_context *ev,
1140                                         struct smbd_server_connection *sconn)
1141 {
1142         struct tevent_req *req;
1143         struct smbd_smb2_request_read_state *state;
1144         struct tevent_req *subreq;
1145
1146         req = tevent_req_create(mem_ctx, &state,
1147                                 struct smbd_smb2_request_read_state);
1148         if (req == NULL) {
1149                 return NULL;
1150         }
1151         state->missing = 0;
1152         state->asked_for_header = false;
1153
1154         state->smb2_req = smbd_smb2_request_allocate(state);
1155         if (tevent_req_nomem(state->smb2_req, req)) {
1156                 return tevent_req_post(req, ev);
1157         }
1158         state->smb2_req->sconn = sconn;
1159
1160         subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
1161                                               sconn->smb2.recv_queue,
1162                                               smbd_smb2_request_next_vector,
1163                                               state);
1164         if (tevent_req_nomem(subreq, req)) {
1165                 return tevent_req_post(req, ev);
1166         }
1167         tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
1168
1169         return req;
1170 }
1171
1172 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
1173                                          void *private_data,
1174                                          TALLOC_CTX *mem_ctx,
1175                                          struct iovec **_vector,
1176                                          size_t *_count)
1177 {
1178         struct smbd_smb2_request_read_state *state =
1179                 talloc_get_type_abort(private_data,
1180                 struct smbd_smb2_request_read_state);
1181         struct smbd_smb2_request *req = state->smb2_req;
1182         struct iovec *vector;
1183         int idx = req->in.vector_count;
1184         size_t len = 0;
1185         uint8_t *buf = NULL;
1186
1187         if (req->in.vector_count == 0) {
1188                 /*
1189                  * first we need to get the NBT header
1190                  */
1191                 req->in.vector = talloc_array(req, struct iovec,
1192                                               req->in.vector_count + 1);
1193                 if (req->in.vector == NULL) {
1194                         return -1;
1195                 }
1196                 req->in.vector_count += 1;
1197
1198                 req->in.vector[idx].iov_base    = (void *)req->in.nbt_hdr;
1199                 req->in.vector[idx].iov_len     = 4;
1200
1201                 vector = talloc_array(mem_ctx, struct iovec, 1);
1202                 if (vector == NULL) {
1203                         return -1;
1204                 }
1205
1206                 vector[0] = req->in.vector[idx];
1207
1208                 *_vector = vector;
1209                 *_count = 1;
1210                 return 0;
1211         }
1212
1213         if (req->in.vector_count == 1) {
1214                 /*
1215                  * Now we analyze the NBT header
1216                  */
1217                 state->missing = smb2_len(req->in.vector[0].iov_base);
1218
1219                 if (state->missing == 0) {
1220                         /* if there're no remaining bytes, we're done */
1221                         *_vector = NULL;
1222                         *_count = 0;
1223                         return 0;
1224                 }
1225
1226                 req->in.vector = talloc_realloc(req, req->in.vector,
1227                                                 struct iovec,
1228                                                 req->in.vector_count + 1);
1229                 if (req->in.vector == NULL) {
1230                         return -1;
1231                 }
1232                 req->in.vector_count += 1;
1233
1234                 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
1235                         /*
1236                          * it's a special NBT message,
1237                          * so get all remaining bytes
1238                          */
1239                         len = state->missing;
1240                 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
1241                         /*
1242                          * it's an invalid message, just read what we can get
1243                          * and let the caller handle the error
1244                          */
1245                         len = state->missing;
1246                 } else {
1247                         /*
1248                          * We assume it's a SMB2 request,
1249                          * and we first get the header and the
1250                          * first 2 bytes (the struct size) of the body
1251                          */
1252                         len = SMB2_HDR_BODY + 2;
1253
1254                         state->asked_for_header = true;
1255                 }
1256
1257                 state->missing -= len;
1258
1259                 buf = talloc_array(req->in.vector, uint8_t, len);
1260                 if (buf == NULL) {
1261                         return -1;
1262                 }
1263
1264                 req->in.vector[idx].iov_base    = (void *)buf;
1265                 req->in.vector[idx].iov_len     = len;
1266
1267                 vector = talloc_array(mem_ctx, struct iovec, 1);
1268                 if (vector == NULL) {
1269                         return -1;
1270                 }
1271
1272                 vector[0] = req->in.vector[idx];
1273
1274                 *_vector = vector;
1275                 *_count = 1;
1276                 return 0;
1277         }
1278
1279         if (state->missing == 0) {
1280                 /* if there're no remaining bytes, we're done */
1281                 *_vector = NULL;
1282                 *_count = 0;
1283                 return 0;
1284         }
1285
1286         if (state->asked_for_header) {
1287                 const uint8_t *hdr;
1288                 size_t full_size;
1289                 size_t next_command_ofs;
1290                 size_t body_size;
1291                 uint8_t *body;
1292                 size_t dyn_size;
1293                 uint8_t *dyn;
1294                 bool invalid = false;
1295
1296                 state->asked_for_header = false;
1297
1298                 /*
1299                  * We got the SMB2 header and the first 2 bytes
1300                  * of the body. We fix the size to just the header
1301                  * and manually copy the 2 first bytes to the body section
1302                  */
1303                 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
1304                 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
1305
1306                 /* allocate vectors for body and dynamic areas */
1307                 req->in.vector = talloc_realloc(req, req->in.vector,
1308                                                 struct iovec,
1309                                                 req->in.vector_count + 2);
1310                 if (req->in.vector == NULL) {
1311                         return -1;
1312                 }
1313                 req->in.vector_count += 2;
1314
1315                 full_size = state->missing + SMB2_HDR_BODY + 2;
1316                 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
1317                 body_size = SVAL(hdr, SMB2_HDR_BODY);
1318
1319                 if (next_command_ofs != 0) {
1320                         if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
1321                                 /*
1322                                  * this is invalid, just return a zero
1323                                  * body and let the caller deal with the error
1324                                  */
1325                                 invalid = true;
1326                         } else if (next_command_ofs > full_size) {
1327                                 /*
1328                                  * this is invalid, just return a zero
1329                                  * body and let the caller deal with the error
1330                                  */
1331                                 invalid = true;
1332                         } else {
1333                                 full_size = next_command_ofs;
1334                         }
1335                 }
1336
1337                 if (!invalid) {
1338                         if (body_size < 2) {
1339                                 /*
1340                                  * this is invalid, just return a zero
1341                                  * body and let the caller deal with the error
1342                                  */
1343                                 invalid = true;
1344                         }
1345
1346                         if ((body_size % 2) != 0) {
1347                                 body_size -= 1;
1348                         }
1349
1350                         if (body_size > (full_size - SMB2_HDR_BODY)) {
1351                                 /*
1352                                  * this is invalid, just return a zero
1353                                  * body and let the caller deal with the error
1354                                  */
1355                                 invalid = true;
1356                         }
1357                 }
1358
1359                 if (invalid) {
1360                         /* the caller should check this */
1361                         body_size = 2;
1362                 }
1363
1364                 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
1365
1366                 state->missing -= (body_size - 2) + dyn_size;
1367
1368                 body = talloc_array(req->in.vector, uint8_t, body_size);
1369                 if (body == NULL) {
1370                         return -1;
1371                 }
1372
1373                 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
1374                 if (dyn == NULL) {
1375                         return -1;
1376                 }
1377
1378                 req->in.vector[idx].iov_base    = (void *)body;
1379                 req->in.vector[idx].iov_len     = body_size;
1380                 req->in.vector[idx+1].iov_base  = (void *)dyn;
1381                 req->in.vector[idx+1].iov_len   = dyn_size;
1382
1383                 vector = talloc_array(mem_ctx, struct iovec, 2);
1384                 if (vector == NULL) {
1385                         return -1;
1386                 }
1387
1388                 /*
1389                  * the first 2 bytes of the body were already fetched
1390                  * together with the header
1391                  */
1392                 memcpy(body, hdr + SMB2_HDR_BODY, 2);
1393                 vector[0].iov_base = body + 2;
1394                 vector[0].iov_len = body_size - 2;
1395
1396                 vector[1] = req->in.vector[idx+1];
1397
1398                 *_vector = vector;
1399                 *_count = 2;
1400                 return 0;
1401         }
1402
1403         /*
1404          * when we endup here, we're looking for a new SMB2 request
1405          * next. And we ask for its header and the first 2 bytes of
1406          * the body (like we did for the first SMB2 request).
1407          */
1408
1409         req->in.vector = talloc_realloc(req, req->in.vector,
1410                                         struct iovec,
1411                                         req->in.vector_count + 1);
1412         if (req->in.vector == NULL) {
1413                 return -1;
1414         }
1415         req->in.vector_count += 1;
1416
1417         /*
1418          * We assume it's a SMB2 request,
1419          * and we first get the header and the
1420          * first 2 bytes (the struct size) of the body
1421          */
1422         len = SMB2_HDR_BODY + 2;
1423
1424         if (len > state->missing) {
1425                 /* let the caller handle the error */
1426                 len = state->missing;
1427         }
1428
1429         state->missing -= len;
1430         state->asked_for_header = true;
1431
1432         buf = talloc_array(req->in.vector, uint8_t, len);
1433         if (buf == NULL) {
1434                 return -1;
1435         }
1436
1437         req->in.vector[idx].iov_base    = (void *)buf;
1438         req->in.vector[idx].iov_len     = len;
1439
1440         vector = talloc_array(mem_ctx, struct iovec, 1);
1441         if (vector == NULL) {
1442                 return -1;
1443         }
1444
1445         vector[0] = req->in.vector[idx];
1446
1447         *_vector = vector;
1448         *_count = 1;
1449         return 0;
1450 }
1451
1452 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
1453 {
1454         struct tevent_req *req =
1455                 tevent_req_callback_data(subreq,
1456                 struct tevent_req);
1457         int ret;
1458         int sys_errno;
1459         NTSTATUS status;
1460
1461         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1462         if (ret == -1) {
1463                 status = map_nt_error_from_unix(sys_errno);
1464                 tevent_req_nterror(req, status);
1465                 return;
1466         }
1467
1468         tevent_req_done(req);
1469 }
1470
1471 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
1472                                             TALLOC_CTX *mem_ctx,
1473                                             struct smbd_smb2_request **_smb2_req)
1474 {
1475         struct smbd_smb2_request_read_state *state =
1476                 tevent_req_data(req,
1477                 struct smbd_smb2_request_read_state);
1478         NTSTATUS status;
1479
1480         if (tevent_req_is_nterror(req, &status)) {
1481                 tevent_req_received(req);
1482                 return status;
1483         }
1484
1485         talloc_steal(mem_ctx, state->smb2_req->mem_pool);
1486         *_smb2_req = state->smb2_req;
1487         tevent_req_received(req);
1488         return NT_STATUS_OK;
1489 }
1490
1491 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
1492
1493 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
1494                              const uint8_t *inbuf, size_t size)
1495 {
1496         NTSTATUS status;
1497         struct smbd_smb2_request *req;
1498         struct tevent_req *subreq;
1499
1500         DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
1501                  (unsigned int)size));
1502
1503         status = smbd_initialize_smb2(sconn);
1504         if (!NT_STATUS_IS_OK(status)) {
1505                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1506                 return;
1507         }
1508
1509         status = smbd_smb2_request_create(sconn, inbuf, size, &req);
1510         if (!NT_STATUS_IS_OK(status)) {
1511                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1512                 return;
1513         }
1514
1515         status = smbd_smb2_request_setup_out(req, (uint16_t)lp_maxmux());
1516         if (!NT_STATUS_IS_OK(status)) {
1517                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1518                 return;
1519         }
1520
1521         status = smbd_smb2_request_dispatch(req);
1522         if (!NT_STATUS_IS_OK(status)) {
1523                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1524                 return;
1525         }
1526
1527         /* ask for the next request */
1528         subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
1529         if (subreq == NULL) {
1530                 smbd_server_connection_terminate(sconn, "no memory for reading");
1531                 return;
1532         }
1533         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
1534 }
1535
1536 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
1537 {
1538         uint16_t creds_requested = 0;
1539         struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
1540                                                struct smbd_server_connection);
1541         NTSTATUS status;
1542         struct smbd_smb2_request *req = NULL;
1543
1544         status = smbd_smb2_request_read_recv(subreq, sconn, &req);
1545         TALLOC_FREE(subreq);
1546         if (!NT_STATUS_IS_OK(status)) {
1547                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1548                 return;
1549         }
1550
1551         if (req->in.nbt_hdr[0] != 0x00) {
1552                 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
1553                          req->in.nbt_hdr[0]));
1554                 TALLOC_FREE(req);
1555                 goto next;
1556         }
1557
1558         req->current_idx = 1;
1559
1560         DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
1561                  req->current_idx, req->in.vector_count));
1562
1563         status = smbd_smb2_request_validate(req, &creds_requested);
1564         if (!NT_STATUS_IS_OK(status)) {
1565                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1566                 return;
1567         }
1568
1569         status = smbd_smb2_request_setup_out(req, 5);
1570         if (!NT_STATUS_IS_OK(status)) {
1571                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1572                 return;
1573         }
1574
1575         status = smbd_smb2_request_dispatch(req);
1576         if (!NT_STATUS_IS_OK(status)) {
1577                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1578                 return;
1579         }
1580
1581 next:
1582         /* ask for the next request (this constructs the main loop) */
1583         subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
1584         if (subreq == NULL) {
1585                 smbd_server_connection_terminate(sconn, "no memory for reading");
1586                 return;
1587         }
1588         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
1589 }