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