1bbb10800b83d8ea05ddca33aef04f69dc8ab56c
[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    Copyright (C) Jeremy Allison 2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../libcli/smb/smb_common.h"
26 #include "../lib/tsocket/tsocket.h"
27 #include "../lib/util/tevent_ntstatus.h"
28 #include "smbprofile.h"
29
30 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
31
32 static const char *smb2_names[] = {
33         "SMB2_NEGPROT",
34         "SMB2_SESSSETUP",
35         "SMB2_LOGOFF",
36         "SMB2_TCON",
37         "SMB2_TDIS",
38         "SMB2_CREATE",
39         "SMB2_CLOSE",
40         "SMB2_FLUSH",
41         "SMB2_READ",
42         "SMB2_WRITE",
43         "SMB2_LOCK",
44         "SMB2_IOCTL",
45         "SMB2_CANCEL",
46         "SMB2_KEEPALIVE",
47         "SMB2_FIND",
48         "SMB2_NOTIFY",
49         "SMB2_GETINFO",
50         "SMB2_SETINFO",
51         "SMB2_BREAK"
52 };
53
54 const char *smb2_opcode_name(uint16_t opcode)
55 {
56         if (opcode > 0x12) {
57                 return "Bad SMB2 opcode";
58         }
59         return smb2_names[opcode];
60 }
61
62 static void print_req_vectors(struct smbd_smb2_request *req)
63 {
64         int i;
65
66         for (i = 0; i < req->in.vector_count; i++) {
67                 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
68                         (unsigned int)i,
69                         (unsigned int)req->in.vector[i].iov_len);
70         }
71         for (i = 0; i < req->out.vector_count; i++) {
72                 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
73                         (unsigned int)i,
74                         (unsigned int)req->out.vector[i].iov_len);
75         }
76 }
77
78 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
79 {
80         if (size < (4 + SMB2_HDR_BODY)) {
81                 return false;
82         }
83
84         if (IVAL(inbuf, 4) != SMB2_MAGIC) {
85                 return false;
86         }
87
88         return true;
89 }
90
91 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
92 {
93         NTSTATUS status;
94         int ret;
95
96         TALLOC_FREE(sconn->smb1.fde);
97
98         sconn->smb2.event_ctx = server_event_context();
99
100         sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
101         if (sconn->smb2.recv_queue == NULL) {
102                 return NT_STATUS_NO_MEMORY;
103         }
104
105         sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
106         if (sconn->smb2.send_queue == NULL) {
107                 return NT_STATUS_NO_MEMORY;
108         }
109
110         sconn->smb2.sessions.idtree = idr_init(sconn);
111         if (sconn->smb2.sessions.idtree == NULL) {
112                 return NT_STATUS_NO_MEMORY;
113         }
114         sconn->smb2.sessions.limit = 0x0000FFFE;
115         sconn->smb2.sessions.list = NULL;
116         sconn->smb2.seqnum_low = 0;
117         sconn->smb2.credits_granted = 0;
118         sconn->smb2.max_credits = lp_smb2_max_credits();
119         sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
120                         DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR*sconn->smb2.max_credits);
121         if (sconn->smb2.credits_bitmap == NULL) {
122                 return NT_STATUS_NO_MEMORY;
123         }
124
125         ret = tstream_bsd_existing_socket(sconn, sconn->sock,
126                                           &sconn->smb2.stream);
127         if (ret == -1) {
128                 status = map_nt_error_from_unix(errno);
129                 return status;
130         }
131
132         /* Ensure child is set to non-blocking mode */
133         set_blocking(sconn->sock, false);
134         return NT_STATUS_OK;
135 }
136
137 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
138 #define _smb2_setlen(_buf,len) do { \
139         uint8_t *buf = (uint8_t *)_buf; \
140         buf[0] = 0; \
141         buf[1] = ((len)&0xFF0000)>>16; \
142         buf[2] = ((len)&0xFF00)>>8; \
143         buf[3] = (len)&0xFF; \
144 } while (0)
145
146 static void smb2_setup_nbt_length(struct iovec *vector, int count)
147 {
148         size_t len = 0;
149         int i;
150
151         for (i=1; i < count; i++) {
152                 len += vector[i].iov_len;
153         }
154
155         _smb2_setlen(vector[0].iov_base, len);
156 }
157
158 static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request **req)
159 {
160         if (*req) {
161                 (*req)->parent = NULL;
162                 (*req)->mem_pool = NULL;
163         }
164
165         return 0;
166 }
167
168 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
169 {
170         if (req->parent) {
171                 *req->parent = NULL;
172                 talloc_free(req->mem_pool);
173         }
174
175         return 0;
176 }
177
178 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
179 {
180         TALLOC_CTX *mem_pool;
181         struct smbd_smb2_request **parent;
182         struct smbd_smb2_request *req;
183
184 #if 0
185         /* Enable this to find subtle valgrind errors. */
186         mem_pool = talloc_init("smbd_smb2_request_allocate");
187 #else
188         mem_pool = talloc_pool(mem_ctx, 8192);
189 #endif
190         if (mem_pool == NULL) {
191                 return NULL;
192         }
193
194         parent = talloc(mem_pool, struct smbd_smb2_request *);
195         if (parent == NULL) {
196                 talloc_free(mem_pool);
197                 return NULL;
198         }
199
200         req = talloc_zero(parent, struct smbd_smb2_request);
201         if (req == NULL) {
202                 talloc_free(mem_pool);
203                 return NULL;
204         }
205         *parent         = req;
206         req->mem_pool   = mem_pool;
207         req->parent     = parent;
208
209         talloc_set_destructor(parent, smbd_smb2_request_parent_destructor);
210         talloc_set_destructor(req, smbd_smb2_request_destructor);
211
212         return req;
213 }
214
215 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
216                                          const uint8_t *inbuf, size_t size,
217                                          struct smbd_smb2_request **_req)
218 {
219         struct smbd_smb2_request *req;
220         uint32_t protocol_version;
221         const uint8_t *inhdr = NULL;
222         off_t ofs = 0;
223         uint16_t cmd;
224         uint32_t next_command_ofs;
225
226         if (size < (4 + SMB2_HDR_BODY + 2)) {
227                 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
228                 return NT_STATUS_INVALID_PARAMETER;
229         }
230
231         inhdr = inbuf + 4;
232
233         protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
234         if (protocol_version != SMB2_MAGIC) {
235                 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
236                          protocol_version));
237                 return NT_STATUS_INVALID_PARAMETER;
238         }
239
240         cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
241         if (cmd != SMB2_OP_NEGPROT) {
242                 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
243                          cmd));
244                 return NT_STATUS_INVALID_PARAMETER;
245         }
246
247         next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
248         if (next_command_ofs != 0) {
249                 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
250                          next_command_ofs));
251                 return NT_STATUS_INVALID_PARAMETER;
252         }
253
254         req = smbd_smb2_request_allocate(sconn);
255         if (req == NULL) {
256                 return NT_STATUS_NO_MEMORY;
257         }
258         req->sconn = sconn;
259
260         talloc_steal(req, inbuf);
261
262         req->in.vector = talloc_array(req, struct iovec, 4);
263         if (req->in.vector == NULL) {
264                 TALLOC_FREE(req);
265                 return NT_STATUS_NO_MEMORY;
266         }
267         req->in.vector_count = 4;
268
269         memcpy(req->in.nbt_hdr, inbuf, 4);
270
271         ofs = 0;
272         req->in.vector[0].iov_base      = discard_const_p(void, req->in.nbt_hdr);
273         req->in.vector[0].iov_len       = 4;
274         ofs += req->in.vector[0].iov_len;
275
276         req->in.vector[1].iov_base      = discard_const_p(void, (inbuf + ofs));
277         req->in.vector[1].iov_len       = SMB2_HDR_BODY;
278         ofs += req->in.vector[1].iov_len;
279
280         req->in.vector[2].iov_base      = discard_const_p(void, (inbuf + ofs));
281         req->in.vector[2].iov_len       = SVAL(inbuf, ofs) & 0xFFFE;
282         ofs += req->in.vector[2].iov_len;
283
284         if (ofs > size) {
285                 return NT_STATUS_INVALID_PARAMETER;
286         }
287
288         req->in.vector[3].iov_base      = discard_const_p(void, (inbuf + ofs));
289         req->in.vector[3].iov_len       = size - ofs;
290         ofs += req->in.vector[3].iov_len;
291
292         req->current_idx = 1;
293
294         *_req = req;
295         return NT_STATUS_OK;
296 }
297
298 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
299                                 const uint8_t *inhdr)
300 {
301         uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
302         struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
303         uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
304         unsigned int bitmap_offset;
305
306         if (opcode == SMB2_OP_CANCEL) {
307                 /* SMB2_CANCEL requests by definition resend messageids. */
308                 return true;
309         }
310
311         if (message_id < sconn->smb2.seqnum_low ||
312                         message_id > (sconn->smb2.seqnum_low +
313                         (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR))) {
314                 DEBUG(0,("smb2_validate_message_id: bad message_id "
315                         "%llu (low = %llu, max = %lu)\n",
316                         (unsigned long long)message_id,
317                         (unsigned long long)sconn->smb2.seqnum_low,
318                         (unsigned long)sconn->smb2.max_credits ));
319                 return false;
320         }
321
322         /* client just used a credit. */
323         SMB_ASSERT(sconn->smb2.credits_granted > 0);
324         sconn->smb2.credits_granted -= 1;
325
326         /* Mark the message_id as seen in the bitmap. */
327         bitmap_offset = (unsigned int)(message_id %
328                         (uint64_t)(sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR));
329         if (bitmap_query(credits_bm, bitmap_offset)) {
330                 DEBUG(0,("smb2_validate_message_id: duplicate message_id "
331                         "%llu (bm offset %u)\n",
332                         (unsigned long long)message_id,
333                         bitmap_offset));
334                 return false;
335         }
336         bitmap_set(credits_bm, bitmap_offset);
337
338         if (message_id == sconn->smb2.seqnum_low + 1) {
339                 /* Move the window forward by all the message_id's
340                    already seen. */
341                 while (bitmap_query(credits_bm, bitmap_offset)) {
342                         DEBUG(10,("smb2_validate_message_id: clearing "
343                                 "id %llu (position %u) from bitmap\n",
344                                 (unsigned long long)(sconn->smb2.seqnum_low + 1),
345                                 bitmap_offset ));
346                         bitmap_clear(credits_bm, bitmap_offset);
347                         sconn->smb2.seqnum_low += 1;
348                         bitmap_offset = (bitmap_offset + 1) %
349                                 (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR);
350                 }
351         }
352
353         return true;
354 }
355
356 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
357 {
358         int count;
359         int idx;
360         bool compound_related = false;
361
362         count = req->in.vector_count;
363
364         if (count < 4) {
365                 /* It's not a SMB2 request */
366                 return NT_STATUS_INVALID_PARAMETER;
367         }
368
369         for (idx=1; idx < count; idx += 3) {
370                 const uint8_t *inhdr = NULL;
371                 uint32_t flags;
372
373                 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
374                         return NT_STATUS_INVALID_PARAMETER;
375                 }
376
377                 if (req->in.vector[idx+1].iov_len < 2) {
378                         return NT_STATUS_INVALID_PARAMETER;
379                 }
380
381                 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
382
383                 /* Check the SMB2 header */
384                 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
385                         return NT_STATUS_INVALID_PARAMETER;
386                 }
387
388                 if (!smb2_validate_message_id(req->sconn, inhdr)) {
389                         return NT_STATUS_INVALID_PARAMETER;
390                 }
391
392                 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
393                 if (idx == 1) {
394                         /*
395                          * the 1st request should never have the
396                          * SMB2_HDR_FLAG_CHAINED flag set
397                          */
398                         if (flags & SMB2_HDR_FLAG_CHAINED) {
399                                 req->next_status = NT_STATUS_INVALID_PARAMETER;
400                                 return NT_STATUS_OK;
401                         }
402                 } else if (idx == 4) {
403                         /*
404                          * the 2nd request triggers related vs. unrelated
405                          * compounded requests
406                          */
407                         if (flags & SMB2_HDR_FLAG_CHAINED) {
408                                 compound_related = true;
409                         }
410                 } else if (idx > 4) {
411 #if 0
412                         /*
413                          * It seems the this tests are wrong
414                          * see the SMB2-COMPOUND test
415                          */
416
417                         /*
418                          * all other requests should match the 2nd one
419                          */
420                         if (flags & SMB2_HDR_FLAG_CHAINED) {
421                                 if (!compound_related) {
422                                         req->next_status =
423                                                 NT_STATUS_INVALID_PARAMETER;
424                                         return NT_STATUS_OK;
425                                 }
426                         } else {
427                                 if (compound_related) {
428                                         req->next_status =
429                                                 NT_STATUS_INVALID_PARAMETER;
430                                         return NT_STATUS_OK;
431                                 }
432                         }
433 #endif
434                 }
435         }
436
437         return NT_STATUS_OK;
438 }
439
440 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
441                         const struct iovec *in_vector,
442                         struct iovec *out_vector)
443 {
444         uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
445         uint16_t credits_requested = 0;
446         uint16_t credits_granted = 0;
447
448         if (in_vector != NULL) {
449                 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
450                 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
451         }
452
453         SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
454
455         /* Remember what we gave out. */
456         credits_granted = MIN(credits_requested, (sconn->smb2.max_credits -
457                 sconn->smb2.credits_granted));
458
459         if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
460                 /* First negprot packet, or ensure the client credits can
461                    never drop to zero. */
462                 credits_granted = 1;
463         }
464
465         SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
466         sconn->smb2.credits_granted += credits_granted;
467
468         DEBUG(10,("smb2_set_operation_credit: requested %u, "
469                 "granted %u, total granted %u\n",
470                 (unsigned int)credits_requested,
471                 (unsigned int)credits_granted,
472                 (unsigned int)sconn->smb2.credits_granted ));
473 }
474
475 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
476                                 struct smbd_smb2_request *outreq)
477 {
478         int count, idx;
479
480         count = outreq->out.vector_count;
481
482         for (idx=1; idx < count; idx += 3) {
483                 smb2_set_operation_credit(outreq->sconn,
484                         &inreq->in.vector[idx],
485                         &outreq->out.vector[idx]);
486         }
487 }
488
489 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
490 {
491         struct iovec *vector;
492         int count;
493         int idx;
494
495         count = req->in.vector_count;
496         vector = talloc_zero_array(req, struct iovec, count);
497         if (vector == NULL) {
498                 return NT_STATUS_NO_MEMORY;
499         }
500
501         vector[0].iov_base      = req->out.nbt_hdr;
502         vector[0].iov_len       = 4;
503         SIVAL(req->out.nbt_hdr, 0, 0);
504
505         for (idx=1; idx < count; idx += 3) {
506                 const uint8_t *inhdr = NULL;
507                 uint32_t in_flags;
508                 uint8_t *outhdr = NULL;
509                 uint8_t *outbody = NULL;
510                 uint32_t next_command_ofs = 0;
511                 struct iovec *current = &vector[idx];
512
513                 if ((idx + 3) < count) {
514                         /* we have a next command -
515                          * setup for the error case. */
516                         next_command_ofs = SMB2_HDR_BODY + 9;
517                 }
518
519                 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
520                 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
521
522                 outhdr = talloc_zero_array(vector, uint8_t,
523                                       OUTVEC_ALLOC_SIZE);
524                 if (outhdr == NULL) {
525                         return NT_STATUS_NO_MEMORY;
526                 }
527
528                 outbody = outhdr + SMB2_HDR_BODY;
529
530                 current[0].iov_base     = (void *)outhdr;
531                 current[0].iov_len      = SMB2_HDR_BODY;
532
533                 current[1].iov_base     = (void *)outbody;
534                 current[1].iov_len      = 8;
535
536                 current[2].iov_base     = NULL;
537                 current[2].iov_len      = 0;
538
539                 /* setup the SMB2 header */
540                 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID,     SMB2_MAGIC);
541                 SSVAL(outhdr, SMB2_HDR_LENGTH,          SMB2_HDR_BODY);
542                 SSVAL(outhdr, SMB2_HDR_EPOCH,           0);
543                 SIVAL(outhdr, SMB2_HDR_STATUS,
544                       NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
545                 SSVAL(outhdr, SMB2_HDR_OPCODE,
546                       SVAL(inhdr, SMB2_HDR_OPCODE));
547                 SIVAL(outhdr, SMB2_HDR_FLAGS,
548                       IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
549                 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND,    next_command_ofs);
550                 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
551                       BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
552                 SIVAL(outhdr, SMB2_HDR_PID,
553                       IVAL(inhdr, SMB2_HDR_PID));
554                 SIVAL(outhdr, SMB2_HDR_TID,
555                       IVAL(inhdr, SMB2_HDR_TID));
556                 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
557                       BVAL(inhdr, SMB2_HDR_SESSION_ID));
558                 memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16);
559
560                 /* setup error body header */
561                 SSVAL(outbody, 0x00, 0x08 + 1);
562                 SSVAL(outbody, 0x02, 0);
563                 SIVAL(outbody, 0x04, 0);
564         }
565
566         req->out.vector = vector;
567         req->out.vector_count = count;
568
569         /* setup the length of the NBT packet */
570         smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
571
572         DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
573
574         return NT_STATUS_OK;
575 }
576
577 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
578                                          const char *reason,
579                                          const char *location)
580 {
581         DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
582                   reason, location));
583         exit_server_cleanly(reason);
584 }
585
586 static bool dup_smb2_vec3(TALLOC_CTX *ctx,
587                         struct iovec *outvec,
588                         const struct iovec *srcvec)
589 {
590         /* vec[0] is always boilerplate and must
591          * be allocated with size OUTVEC_ALLOC_SIZE. */
592
593         outvec[0].iov_base = talloc_memdup(ctx,
594                                 srcvec[0].iov_base,
595                                 OUTVEC_ALLOC_SIZE);
596         if (!outvec[0].iov_base) {
597                 return false;
598         }
599         outvec[0].iov_len = SMB2_HDR_BODY;
600
601         /*
602          * If this is a "standard" vec[1] of length 8,
603          * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
604          * then duplicate this. Else use talloc_memdup().
605          */
606
607         if (srcvec[1].iov_len == 8 &&
608                         srcvec[1].iov_base ==
609                                 ((uint8_t *)srcvec[0].iov_base) +
610                                         SMB2_HDR_BODY) {
611                 outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
612                                         SMB2_HDR_BODY;
613                 outvec[1].iov_len = 8;
614         } else {
615                 outvec[1].iov_base = talloc_memdup(ctx,
616                                 srcvec[1].iov_base,
617                                 srcvec[1].iov_len);
618                 if (!outvec[1].iov_base) {
619                         return false;
620                 }
621                 outvec[1].iov_len = srcvec[1].iov_len;
622         }
623
624         /*
625          * If this is a "standard" vec[2] of length 1,
626          * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
627          * then duplicate this. Else use talloc_memdup().
628          */
629
630         if (srcvec[2].iov_base &&
631                         srcvec[2].iov_len) {
632                 if (srcvec[2].iov_base ==
633                                 ((uint8_t *)srcvec[0].iov_base) +
634                                         (OUTVEC_ALLOC_SIZE - 1) &&
635                                 srcvec[2].iov_len == 1) {
636                         /* Common SMB2 error packet case. */
637                         outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
638                                 (OUTVEC_ALLOC_SIZE - 1);
639                 } else {
640                         outvec[2].iov_base = talloc_memdup(ctx,
641                                         srcvec[2].iov_base,
642                                         srcvec[2].iov_len);
643                         if (!outvec[2].iov_base) {
644                                 return false;
645                         }
646                 }
647                 outvec[2].iov_len = srcvec[2].iov_len;
648         } else {
649                 outvec[2].iov_base = NULL;
650                 outvec[2].iov_len = 0;
651         }
652         return true;
653 }
654
655 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
656 {
657         struct smbd_smb2_request *newreq = NULL;
658         struct iovec *outvec = NULL;
659         int count = req->out.vector_count;
660         int i;
661
662         newreq = smbd_smb2_request_allocate(req->sconn);
663         if (!newreq) {
664                 return NULL;
665         }
666
667         newreq->sconn = req->sconn;
668         newreq->session = req->session;
669         newreq->do_signing = req->do_signing;
670         newreq->current_idx = req->current_idx;
671         newreq->async = false;
672         newreq->cancelled = false;
673         /* Note we are leaving:
674                 ->tcon
675                 ->smb1req
676                 ->compat_chain_fsp
677            uninitialized as NULL here as
678            they're not used in the interim
679            response code. JRA. */
680
681         outvec = talloc_zero_array(newreq, struct iovec, count);
682         if (!outvec) {
683                 TALLOC_FREE(newreq);
684                 return NULL;
685         }
686         newreq->out.vector = outvec;
687         newreq->out.vector_count = count;
688
689         /* Setup the outvec's identically to req. */
690         outvec[0].iov_base = newreq->out.nbt_hdr;
691         outvec[0].iov_len = 4;
692         memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
693
694         /* Setup the vectors identically to the ones in req. */
695         for (i = 1; i < count; i += 3) {
696                 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
697                         break;
698                 }
699         }
700
701         if (i < count) {
702                 /* Alloc failed. */
703                 TALLOC_FREE(newreq);
704                 return NULL;
705         }
706
707         smb2_setup_nbt_length(newreq->out.vector,
708                 newreq->out.vector_count);
709
710         return newreq;
711 }
712
713 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
714
715 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
716 {
717         int i = 0;
718         uint8_t *outhdr = NULL;
719         struct smbd_smb2_request *nreq = NULL;
720
721         /* Create a new smb2 request we'll use
722            for the interim return. */
723         nreq = dup_smb2_req(req);
724         if (!nreq) {
725                 return NT_STATUS_NO_MEMORY;
726         }
727
728         /* Lose the last 3 out vectors. They're the
729            ones we'll be using for the async reply. */
730         nreq->out.vector_count -= 3;
731
732         smb2_setup_nbt_length(nreq->out.vector,
733                 nreq->out.vector_count);
734
735         /* Step back to the previous reply. */
736         i = nreq->current_idx - 3;
737         outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
738         /* And end the chain. */
739         SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
740
741         /* Calculate outgoing credits */
742         smb2_calculate_credits(req, nreq);
743
744         /* Re-sign if needed. */
745         if (nreq->do_signing) {
746                 NTSTATUS status;
747                 status = smb2_signing_sign_pdu(nreq->session->session_key,
748                                         &nreq->out.vector[i], 3);
749                 if (!NT_STATUS_IS_OK(status)) {
750                         return status;
751                 }
752         }
753         if (DEBUGLEVEL >= 10) {
754                 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
755                         (unsigned int)nreq->current_idx );
756                 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
757                         (unsigned int)nreq->out.vector_count );
758                 print_req_vectors(nreq);
759         }
760         nreq->subreq = tstream_writev_queue_send(nreq,
761                                         nreq->sconn->smb2.event_ctx,
762                                         nreq->sconn->smb2.stream,
763                                         nreq->sconn->smb2.send_queue,
764                                         nreq->out.vector,
765                                         nreq->out.vector_count);
766
767         if (nreq->subreq == NULL) {
768                 return NT_STATUS_NO_MEMORY;
769         }
770
771         tevent_req_set_callback(nreq->subreq,
772                         smbd_smb2_request_writev_done,
773                         nreq);
774
775         return NT_STATUS_OK;
776 }
777
778 struct smbd_smb2_request_pending_state {
779         struct smbd_server_connection *sconn;
780         uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
781         struct iovec vector[3];
782 };
783
784 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
785 {
786         struct smbd_smb2_request_pending_state *state =
787                 tevent_req_callback_data(subreq,
788                         struct smbd_smb2_request_pending_state);
789         struct smbd_server_connection *sconn = state->sconn;
790         int ret;
791         int sys_errno;
792
793         ret = tstream_writev_queue_recv(subreq, &sys_errno);
794         TALLOC_FREE(subreq);
795         if (ret == -1) {
796                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
797                 smbd_server_connection_terminate(sconn, nt_errstr(status));
798                 return;
799         }
800
801         TALLOC_FREE(state);
802 }
803
804 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
805                                          struct tevent_req *subreq)
806 {
807         NTSTATUS status;
808         struct smbd_smb2_request_pending_state *state = NULL;
809         int i = req->current_idx;
810         uint8_t *reqhdr = NULL;
811         uint8_t *hdr = NULL;
812         uint8_t *body = NULL;
813         uint32_t flags = 0;
814         uint64_t message_id = 0;
815         uint64_t async_id = 0;
816         struct iovec *outvec = NULL;
817
818         if (!tevent_req_is_in_progress(subreq)) {
819                 return NT_STATUS_OK;
820         }
821
822         req->subreq = subreq;
823         subreq = NULL;
824
825         if (req->async) {
826                 /* We're already async. */
827                 return NT_STATUS_OK;
828         }
829
830         if (req->in.vector_count > i + 3) {
831                 /*
832                  * We're trying to go async in a compound
833                  * request chain. This is not allowed.
834                  * Cancel the outstanding request.
835                  */
836                 tevent_req_cancel(req->subreq);
837                 return smbd_smb2_request_error(req,
838                         NT_STATUS_INSUFFICIENT_RESOURCES);
839         }
840
841         if (DEBUGLEVEL >= 10) {
842                 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
843                         (unsigned int)req->current_idx );
844                 print_req_vectors(req);
845         }
846
847         if (req->out.vector_count > 4) {
848                 /* This is a compound reply. We
849                  * must do an interim response
850                  * followed by the async response
851                  * to match W2K8R2.
852                  */
853                 status = smb2_send_async_interim_response(req);
854                 if (!NT_STATUS_IS_OK(status)) {
855                         return status;
856                 }
857         }
858
859         /* Don't return an intermediate packet on a pipe read/write. */
860         if (req->tcon && req->tcon->compat_conn && IS_IPC(req->tcon->compat_conn)) {
861                 return NT_STATUS_OK;
862         }
863
864         reqhdr = (uint8_t *)req->out.vector[i].iov_base;
865         flags = (IVAL(reqhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
866         message_id = BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
867         async_id = message_id; /* keep it simple for now... */
868
869         /*
870          * What we send is identical to a smbd_smb2_request_error
871          * packet with an error status of STATUS_PENDING. Make use
872          * of this fact sometime when refactoring. JRA.
873          */
874
875         state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
876         if (state == NULL) {
877                 return NT_STATUS_NO_MEMORY;
878         }
879         state->sconn = req->sconn;
880
881         state->vector[0].iov_base = (void *)state->buf;
882         state->vector[0].iov_len = 4;
883
884         state->vector[1].iov_base = state->buf + 4;
885         state->vector[1].iov_len = SMB2_HDR_BODY;
886
887         state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
888         state->vector[2].iov_len = 9;
889
890         smb2_setup_nbt_length(state->vector, 3);
891
892         hdr = (uint8_t *)state->vector[1].iov_base;
893         body = (uint8_t *)state->vector[2].iov_base;
894
895         SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
896         SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
897         SSVAL(hdr, SMB2_HDR_EPOCH, 0);
898         SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
899         SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE));
900
901         SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
902         SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
903         SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
904         SBVAL(hdr, SMB2_HDR_PID, async_id);
905         SBVAL(hdr, SMB2_HDR_SESSION_ID,
906                 BVAL(reqhdr, SMB2_HDR_SESSION_ID));
907         memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
908
909         SSVAL(body, 0x00, 0x08 + 1);
910
911         SCVAL(body, 0x02, 0);
912         SCVAL(body, 0x03, 0);
913         SIVAL(body, 0x04, 0);
914         /* Match W2K8R2... */
915         SCVAL(body, 0x08, 0x21);
916
917         /* Ensure we correctly go through crediting. Grant
918            the credits now, and zero credits on the final
919            response. */
920         smb2_set_operation_credit(req->sconn,
921                         &req->in.vector[i],
922                         &state->vector[1]);
923
924         if (req->do_signing) {
925                 status = smb2_signing_sign_pdu(req->session->session_key,
926                                         &state->vector[1], 2);
927                 if (!NT_STATUS_IS_OK(status)) {
928                         return status;
929                 }
930         }
931
932         subreq = tstream_writev_queue_send(state,
933                                         req->sconn->smb2.event_ctx,
934                                         req->sconn->smb2.stream,
935                                         req->sconn->smb2.send_queue,
936                                         state->vector,
937                                         3);
938
939         if (subreq == NULL) {
940                 return NT_STATUS_NO_MEMORY;
941         }
942
943         tevent_req_set_callback(subreq,
944                         smbd_smb2_request_pending_writev_done,
945                         state);
946
947         /* Note we're going async with this request. */
948         req->async = true;
949
950         /*
951          * Now manipulate req so that the outstanding async request
952          * is the only one left in the struct smbd_smb2_request.
953          */
954
955         if (req->current_idx == 1) {
956                 /* There was only one. */
957                 goto out;
958         }
959
960         /* Re-arrange the in.vectors. */
961         req->in.vector[1] = req->in.vector[i];
962         req->in.vector[2] = req->in.vector[i+1];
963         req->in.vector[3] = req->in.vector[i+2];
964         req->in.vector_count = 4;
965         /* Reset the new in size. */
966         smb2_setup_nbt_length(req->in.vector, 4);
967
968         /* Now recreate the out.vectors. */
969         outvec = talloc_zero_array(req, struct iovec, 4);
970         if (!outvec) {
971                 return NT_STATUS_NO_MEMORY;
972         }
973
974         /* 0 is always boilerplate and must
975          * be of size 4 for the length field. */
976
977         outvec[0].iov_base = req->out.nbt_hdr;
978         outvec[0].iov_len = 4;
979         SIVAL(req->out.nbt_hdr, 0, 0);
980
981         if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
982                 return NT_STATUS_NO_MEMORY;
983         }
984
985         TALLOC_FREE(req->out.vector);
986
987         req->out.vector = outvec;
988
989         req->current_idx = 1;
990         req->out.vector_count = 4;
991
992   out:
993
994         smb2_setup_nbt_length(req->out.vector,
995                 req->out.vector_count);
996
997         /* Ensure our final reply matches the interim one. */
998         reqhdr = (uint8_t *)req->out.vector[1].iov_base;
999         SIVAL(reqhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1000         SBVAL(reqhdr, SMB2_HDR_PID, async_id);
1001
1002         {
1003                 const uint8_t *inhdr =
1004                         (const uint8_t *)req->in.vector[1].iov_base;
1005                 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1006                         "going async\n",
1007                         smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1008                         (unsigned long long)async_id ));
1009         }
1010         return NT_STATUS_OK;
1011 }
1012
1013 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1014 {
1015         struct smbd_server_connection *sconn = req->sconn;
1016         struct smbd_smb2_request *cur;
1017         const uint8_t *inhdr;
1018         int i = req->current_idx;
1019         uint32_t flags;
1020         uint64_t search_message_id;
1021         uint64_t search_async_id;
1022         uint64_t found_id;
1023
1024         inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1025
1026         flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1027         search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1028         search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1029
1030         /*
1031          * we don't need the request anymore
1032          * cancel requests never have a response
1033          */
1034         DLIST_REMOVE(req->sconn->smb2.requests, req);
1035         TALLOC_FREE(req);
1036
1037         for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1038                 const uint8_t *outhdr;
1039                 uint64_t message_id;
1040                 uint64_t async_id;
1041
1042                 i = cur->current_idx;
1043
1044                 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
1045
1046                 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1047                 async_id = BVAL(outhdr, SMB2_HDR_PID);
1048
1049                 if (flags & SMB2_HDR_FLAG_ASYNC) {
1050                         if (search_async_id == async_id) {
1051                                 found_id = async_id;
1052                                 break;
1053                         }
1054                 } else {
1055                         if (search_message_id == message_id) {
1056                                 found_id = message_id;
1057                                 break;
1058                         }
1059                 }
1060         }
1061
1062         if (cur && cur->subreq) {
1063                 inhdr = (const uint8_t *)cur->in.vector[i].iov_base;
1064                 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1065                         "cancel opcode[%s] mid %llu\n",
1066                         smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1067                         (unsigned long long)found_id ));
1068                 tevent_req_cancel(cur->subreq);
1069         }
1070
1071         return NT_STATUS_OK;
1072 }
1073
1074 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1075 {
1076         const uint8_t *inhdr;
1077         int i = req->current_idx;
1078         uint16_t opcode;
1079         uint32_t flags;
1080         uint64_t mid;
1081         NTSTATUS status;
1082         NTSTATUS session_status;
1083         uint32_t allowed_flags;
1084         NTSTATUS return_value;
1085
1086         inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1087
1088         /* TODO: verify more things */
1089
1090         flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1091         opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1092         mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1093         DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1094                 smb2_opcode_name(opcode),
1095                 (unsigned long long)mid));
1096
1097         allowed_flags = SMB2_HDR_FLAG_CHAINED |
1098                         SMB2_HDR_FLAG_SIGNED |
1099                         SMB2_HDR_FLAG_DFS;
1100         if (opcode == SMB2_OP_CANCEL) {
1101                 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1102         }
1103         if ((flags & ~allowed_flags) != 0) {
1104                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1105         }
1106
1107         session_status = smbd_smb2_request_check_session(req);
1108
1109         req->do_signing = false;
1110         if (flags & SMB2_HDR_FLAG_SIGNED) {
1111                 if (!NT_STATUS_IS_OK(session_status)) {
1112                         return smbd_smb2_request_error(req, session_status);
1113                 }
1114
1115                 req->do_signing = true;
1116                 status = smb2_signing_check_pdu(req->session->session_key,
1117                                                 &req->in.vector[i], 3);
1118                 if (!NT_STATUS_IS_OK(status)) {
1119                         return smbd_smb2_request_error(req, status);
1120                 }
1121         } else if (req->session && req->session->do_signing) {
1122                 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1123         }
1124
1125         if (flags & SMB2_HDR_FLAG_CHAINED) {
1126                 /*
1127                  * This check is mostly for giving the correct error code
1128                  * for compounded requests.
1129                  *
1130                  * TODO: we may need to move this after the session
1131                  *       and tcon checks.
1132                  */
1133                 if (!NT_STATUS_IS_OK(req->next_status)) {
1134                         return smbd_smb2_request_error(req, req->next_status);
1135                 }
1136         } else {
1137                 req->compat_chain_fsp = NULL;
1138         }
1139
1140         switch (opcode) {
1141         case SMB2_OP_NEGPROT:
1142                 {
1143                         START_PROFILE(smb2_negprot);
1144                         return_value = smbd_smb2_request_process_negprot(req);
1145                         END_PROFILE(smb2_negprot);
1146                 }
1147                 break;
1148
1149         case SMB2_OP_SESSSETUP:
1150                 {
1151                         START_PROFILE(smb2_sesssetup);
1152                         return_value = smbd_smb2_request_process_sesssetup(req);
1153                         END_PROFILE(smb2_sesssetup);
1154                 }
1155                 break;
1156
1157         case SMB2_OP_LOGOFF:
1158                 if (!NT_STATUS_IS_OK(session_status)) {
1159                         return_value = smbd_smb2_request_error(req, session_status);
1160                         break;
1161                 }
1162
1163                 {
1164                         START_PROFILE(smb2_logoff);
1165                         return_value = smbd_smb2_request_process_logoff(req);
1166                         END_PROFILE(smb2_logoff);
1167                 }
1168                 break;
1169
1170         case SMB2_OP_TCON:
1171                 if (!NT_STATUS_IS_OK(session_status)) {
1172                         return_value = smbd_smb2_request_error(req, session_status);
1173                         break;
1174                 }
1175
1176                 {
1177                         START_PROFILE(smb2_tcon);
1178                         return_value = smbd_smb2_request_process_tcon(req);
1179                         END_PROFILE(smb2_tcon);
1180                 }
1181                 break;
1182
1183         case SMB2_OP_TDIS:
1184                 if (!NT_STATUS_IS_OK(session_status)) {
1185                         return_value = smbd_smb2_request_error(req, session_status);
1186                         break;
1187                 }
1188                 status = smbd_smb2_request_check_tcon(req);
1189                 if (!NT_STATUS_IS_OK(status)) {
1190                         return_value = smbd_smb2_request_error(req, status);
1191                         break;
1192                 }
1193
1194                 {
1195                         START_PROFILE(smb2_tdis);
1196                         return_value = smbd_smb2_request_process_tdis(req);
1197                         END_PROFILE(smb2_tdis);
1198                 }
1199                 break;
1200
1201         case SMB2_OP_CREATE:
1202                 if (!NT_STATUS_IS_OK(session_status)) {
1203                         return_value = smbd_smb2_request_error(req, session_status);
1204                         break;
1205                 }
1206                 status = smbd_smb2_request_check_tcon(req);
1207                 if (!NT_STATUS_IS_OK(status)) {
1208                         return_value = smbd_smb2_request_error(req, status);
1209                         break;
1210                 }
1211
1212                 {
1213                         START_PROFILE(smb2_create);
1214                         return_value = smbd_smb2_request_process_create(req);
1215                         END_PROFILE(smb2_create);
1216                 }
1217                 break;
1218
1219         case SMB2_OP_CLOSE:
1220                 if (!NT_STATUS_IS_OK(session_status)) {
1221                         return_value = smbd_smb2_request_error(req, session_status);
1222                         break;
1223                 }
1224                 status = smbd_smb2_request_check_tcon(req);
1225                 if (!NT_STATUS_IS_OK(status)) {
1226                         return_value = smbd_smb2_request_error(req, status);
1227                         break;
1228                 }
1229
1230                 {
1231                         START_PROFILE(smb2_close);
1232                         return_value = smbd_smb2_request_process_close(req);
1233                         END_PROFILE(smb2_close);
1234                 }
1235                 break;
1236
1237         case SMB2_OP_FLUSH:
1238                 if (!NT_STATUS_IS_OK(session_status)) {
1239                         return_value = smbd_smb2_request_error(req, session_status);
1240                         break;
1241                 }
1242                 status = smbd_smb2_request_check_tcon(req);
1243                 if (!NT_STATUS_IS_OK(status)) {
1244                         return_value = smbd_smb2_request_error(req, status);
1245                         break;
1246                 }
1247
1248                 {
1249                         START_PROFILE(smb2_flush);
1250                         return_value = smbd_smb2_request_process_flush(req);
1251                         END_PROFILE(smb2_flush);
1252                 }
1253                 break;
1254
1255         case SMB2_OP_READ:
1256                 if (!NT_STATUS_IS_OK(session_status)) {
1257                         return_value = smbd_smb2_request_error(req, session_status);
1258                         break;
1259                 }
1260                 status = smbd_smb2_request_check_tcon(req);
1261                 if (!NT_STATUS_IS_OK(status)) {
1262                         return_value = smbd_smb2_request_error(req, status);
1263                         break;
1264                 }
1265
1266                 {
1267                         START_PROFILE(smb2_read);
1268                         return_value = smbd_smb2_request_process_read(req);
1269                         END_PROFILE(smb2_read);
1270                 }
1271                 break;
1272
1273         case SMB2_OP_WRITE:
1274                 if (!NT_STATUS_IS_OK(session_status)) {
1275                         return_value = smbd_smb2_request_error(req, session_status);
1276                         break;
1277                 }
1278                 status = smbd_smb2_request_check_tcon(req);
1279                 if (!NT_STATUS_IS_OK(status)) {
1280                         return_value = smbd_smb2_request_error(req, status);
1281                         break;
1282                 }
1283
1284                 {
1285                         START_PROFILE(smb2_write);
1286                         return_value = smbd_smb2_request_process_write(req);
1287                         END_PROFILE(smb2_write);
1288                 }
1289                 break;
1290
1291         case SMB2_OP_LOCK:
1292                 if (!NT_STATUS_IS_OK(session_status)) {
1293                         /* Too ugly to live ? JRA. */
1294                         if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
1295                                 session_status = NT_STATUS_FILE_CLOSED;
1296                         }
1297                         return_value = smbd_smb2_request_error(req, session_status);
1298                         break;
1299                 }
1300                 status = smbd_smb2_request_check_tcon(req);
1301                 if (!NT_STATUS_IS_OK(status)) {
1302                         /* Too ugly to live ? JRA. */
1303                         if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
1304                                 status = NT_STATUS_FILE_CLOSED;
1305                         }
1306                         return_value = smbd_smb2_request_error(req, status);
1307                         break;
1308                 }
1309
1310                 {
1311                         START_PROFILE(smb2_lock);
1312                         return_value = smbd_smb2_request_process_lock(req);
1313                         END_PROFILE(smb2_lock);
1314                 }
1315                 break;
1316
1317         case SMB2_OP_IOCTL:
1318                 if (!NT_STATUS_IS_OK(session_status)) {
1319                         return_value = smbd_smb2_request_error(req, session_status);
1320                         break;
1321                 }
1322                 status = smbd_smb2_request_check_tcon(req);
1323                 if (!NT_STATUS_IS_OK(status)) {
1324                         return_value = smbd_smb2_request_error(req, status);
1325                         break;
1326                 }
1327
1328                 {
1329                         START_PROFILE(smb2_ioctl);
1330                         return_value = smbd_smb2_request_process_ioctl(req);
1331                         END_PROFILE(smb2_ioctl);
1332                 }
1333                 break;
1334
1335         case SMB2_OP_CANCEL:
1336                 {
1337                         START_PROFILE(smb2_cancel);
1338                         return_value = smbd_smb2_request_process_cancel(req);
1339                         END_PROFILE(smb2_cancel);
1340                 }
1341                 break;
1342
1343         case SMB2_OP_KEEPALIVE:
1344                 {START_PROFILE(smb2_keepalive);
1345                 return_value = smbd_smb2_request_process_keepalive(req);
1346                 END_PROFILE(smb2_keepalive);}
1347                 break;
1348
1349         case SMB2_OP_FIND:
1350                 if (!NT_STATUS_IS_OK(session_status)) {
1351                         return_value = smbd_smb2_request_error(req, session_status);
1352                         break;
1353                 }
1354                 status = smbd_smb2_request_check_tcon(req);
1355                 if (!NT_STATUS_IS_OK(status)) {
1356                         return_value = smbd_smb2_request_error(req, status);
1357                         break;
1358                 }
1359
1360                 {
1361                         START_PROFILE(smb2_find);
1362                         return_value = smbd_smb2_request_process_find(req);
1363                         END_PROFILE(smb2_find);
1364                 }
1365                 break;
1366
1367         case SMB2_OP_NOTIFY:
1368                 if (!NT_STATUS_IS_OK(session_status)) {
1369                         return_value = smbd_smb2_request_error(req, session_status);
1370                         break;
1371                 }
1372                 status = smbd_smb2_request_check_tcon(req);
1373                 if (!NT_STATUS_IS_OK(status)) {
1374                         return_value = smbd_smb2_request_error(req, status);
1375                         break;
1376                 }
1377
1378                 {
1379                         START_PROFILE(smb2_notify);
1380                         return_value = smbd_smb2_request_process_notify(req);
1381                         END_PROFILE(smb2_notify);
1382                 }
1383                 break;
1384
1385         case SMB2_OP_GETINFO:
1386                 if (!NT_STATUS_IS_OK(session_status)) {
1387                         return_value = smbd_smb2_request_error(req, session_status);
1388                         break;
1389                 }
1390                 status = smbd_smb2_request_check_tcon(req);
1391                 if (!NT_STATUS_IS_OK(status)) {
1392                         return_value = smbd_smb2_request_error(req, status);
1393                         break;
1394                 }
1395
1396                 {
1397                         START_PROFILE(smb2_getinfo);
1398                         return_value = smbd_smb2_request_process_getinfo(req);
1399                         END_PROFILE(smb2_getinfo);
1400                 }
1401                 break;
1402
1403         case SMB2_OP_SETINFO:
1404                 if (!NT_STATUS_IS_OK(session_status)) {
1405                         return_value = smbd_smb2_request_error(req, session_status);
1406                         break;
1407                 }
1408                 status = smbd_smb2_request_check_tcon(req);
1409                 if (!NT_STATUS_IS_OK(status)) {
1410                         return_value = smbd_smb2_request_error(req, status);
1411                         break;
1412                 }
1413
1414                 {
1415                         START_PROFILE(smb2_setinfo);
1416                         return_value = smbd_smb2_request_process_setinfo(req);
1417                         END_PROFILE(smb2_setinfo);
1418                 }
1419                 break;
1420
1421         case SMB2_OP_BREAK:
1422                 if (!NT_STATUS_IS_OK(session_status)) {
1423                         return_value = smbd_smb2_request_error(req, session_status);
1424                         break;
1425                 }
1426                 status = smbd_smb2_request_check_tcon(req);
1427                 if (!NT_STATUS_IS_OK(status)) {
1428                         return_value = smbd_smb2_request_error(req, status);
1429                         break;
1430                 }
1431
1432                 {
1433                         START_PROFILE(smb2_break);
1434                         return_value = smbd_smb2_request_process_break(req);
1435                         END_PROFILE(smb2_break);
1436                 }
1437                 break;
1438
1439         default:
1440                 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1441                 break;
1442         }
1443         return return_value;
1444 }
1445
1446 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
1447 {
1448         struct tevent_req *subreq;
1449         int i = req->current_idx;
1450
1451         req->subreq = NULL;
1452
1453         req->current_idx += 3;
1454
1455         if (req->current_idx < req->out.vector_count) {
1456                 /*
1457                  * We must process the remaining compound
1458                  * SMB2 requests before any new incoming SMB2
1459                  * requests. This is because incoming SMB2
1460                  * requests may include a cancel for a
1461                  * compound request we haven't processed
1462                  * yet.
1463                  */
1464                 struct tevent_immediate *im = tevent_create_immediate(req);
1465                 if (!im) {
1466                         return NT_STATUS_NO_MEMORY;
1467                 }
1468                 tevent_schedule_immediate(im,
1469                                         req->sconn->smb2.event_ctx,
1470                                         smbd_smb2_request_dispatch_immediate,
1471                                         req);
1472                 return NT_STATUS_OK;
1473         }
1474
1475         smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
1476
1477         /* Set credit for this operation (zero credits if this
1478            is a final reply for an async operation). */
1479         smb2_set_operation_credit(req->sconn,
1480                         req->async ? NULL : &req->in.vector[i],
1481                         &req->out.vector[i]);
1482
1483         if (req->do_signing) {
1484                 NTSTATUS status;
1485                 status = smb2_signing_sign_pdu(req->session->session_key,
1486                                                &req->out.vector[i], 3);
1487                 if (!NT_STATUS_IS_OK(status)) {
1488                         return status;
1489                 }
1490         }
1491
1492         if (DEBUGLEVEL >= 10) {
1493                 dbgtext("smbd_smb2_request_reply: sending...\n");
1494                 print_req_vectors(req);
1495         }
1496
1497         /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
1498         if (req->out.vector_count == 4 &&
1499                         req->out.vector[3].iov_base == NULL &&
1500                         req->out.vector[3].iov_len != 0) {
1501                 /* Dynamic part is NULL. Chop it off,
1502                    We're going to send it via sendfile. */
1503                 req->out.vector_count -= 1;
1504         }
1505
1506         subreq = tstream_writev_queue_send(req,
1507                                            req->sconn->smb2.event_ctx,
1508                                            req->sconn->smb2.stream,
1509                                            req->sconn->smb2.send_queue,
1510                                            req->out.vector,
1511                                            req->out.vector_count);
1512         if (subreq == NULL) {
1513                 return NT_STATUS_NO_MEMORY;
1514         }
1515         tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
1516         /*
1517          * We're done with this request -
1518          * move it off the "being processed" queue.
1519          */
1520         DLIST_REMOVE(req->sconn->smb2.requests, req);
1521
1522         return NT_STATUS_OK;
1523 }
1524
1525 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
1526                                         struct tevent_immediate *im,
1527                                         void *private_data)
1528 {
1529         struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
1530                                         struct smbd_smb2_request);
1531         struct smbd_server_connection *sconn = req->sconn;
1532         NTSTATUS status;
1533
1534         TALLOC_FREE(im);
1535
1536         if (DEBUGLEVEL >= 10) {
1537                 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
1538                         req->current_idx, req->in.vector_count));
1539                 print_req_vectors(req);
1540         }
1541
1542         status = smbd_smb2_request_dispatch(req);
1543         if (!NT_STATUS_IS_OK(status)) {
1544                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1545                 return;
1546         }
1547 }
1548
1549 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
1550 {
1551         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
1552                                         struct smbd_smb2_request);
1553         struct smbd_server_connection *sconn = req->sconn;
1554         int ret;
1555         int sys_errno;
1556
1557         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1558         TALLOC_FREE(subreq);
1559         TALLOC_FREE(req);
1560         if (ret == -1) {
1561                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1562                 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
1563                         nt_errstr(status)));
1564                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1565                 return;
1566         }
1567 }
1568
1569 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
1570                                    NTSTATUS status,
1571                                    DATA_BLOB body, DATA_BLOB *dyn,
1572                                    const char *location)
1573 {
1574         uint8_t *outhdr;
1575         int i = req->current_idx;
1576         uint32_t next_command_ofs;
1577
1578         DEBUG(10,("smbd_smb2_request_done_ex: "
1579                   "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
1580                   i, nt_errstr(status), (unsigned int)body.length,
1581                   dyn ? "yes": "no",
1582                   (unsigned int)(dyn ? dyn->length : 0),
1583                   location));
1584
1585         if (body.length < 2) {
1586                 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1587         }
1588
1589         if ((body.length % 2) != 0) {
1590                 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1591         }
1592
1593         outhdr = (uint8_t *)req->out.vector[i].iov_base;
1594
1595         next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
1596         SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
1597
1598         req->out.vector[i+1].iov_base = (void *)body.data;
1599         req->out.vector[i+1].iov_len = body.length;
1600
1601         if (dyn) {
1602                 req->out.vector[i+2].iov_base   = (void *)dyn->data;
1603                 req->out.vector[i+2].iov_len    = dyn->length;
1604         } else {
1605                 req->out.vector[i+2].iov_base = NULL;
1606                 req->out.vector[i+2].iov_len = 0;
1607         }
1608
1609         /* see if we need to recalculate the offset to the next response */
1610         if (next_command_ofs > 0) {
1611                 next_command_ofs  = SMB2_HDR_BODY;
1612                 next_command_ofs += req->out.vector[i+1].iov_len;
1613                 next_command_ofs += req->out.vector[i+2].iov_len;
1614         }
1615
1616         if ((next_command_ofs % 8) != 0) {
1617                 size_t pad_size = 8 - (next_command_ofs % 8);
1618                 if (req->out.vector[i+2].iov_len == 0) {
1619                         /*
1620                          * if the dyn buffer is empty
1621                          * we can use it to add padding
1622                          */
1623                         uint8_t *pad;
1624
1625                         pad = talloc_zero_array(req->out.vector,
1626                                                 uint8_t, pad_size);
1627                         if (pad == NULL) {
1628                                 return smbd_smb2_request_error(req,
1629                                                 NT_STATUS_NO_MEMORY);
1630                         }
1631
1632                         req->out.vector[i+2].iov_base = (void *)pad;
1633                         req->out.vector[i+2].iov_len = pad_size;
1634                 } else {
1635                         /*
1636                          * For now we copy the dynamic buffer
1637                          * and add the padding to the new buffer
1638                          */
1639                         size_t old_size;
1640                         uint8_t *old_dyn;
1641                         size_t new_size;
1642                         uint8_t *new_dyn;
1643
1644                         old_size = req->out.vector[i+2].iov_len;
1645                         old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
1646
1647                         new_size = old_size + pad_size;
1648                         new_dyn = talloc_zero_array(req->out.vector,
1649                                                uint8_t, new_size);
1650                         if (new_dyn == NULL) {
1651                                 return smbd_smb2_request_error(req,
1652                                                 NT_STATUS_NO_MEMORY);
1653                         }
1654
1655                         memcpy(new_dyn, old_dyn, old_size);
1656                         memset(new_dyn + old_size, 0, pad_size);
1657
1658                         req->out.vector[i+2].iov_base = (void *)new_dyn;
1659                         req->out.vector[i+2].iov_len = new_size;
1660                 }
1661                 next_command_ofs += pad_size;
1662         }
1663
1664         SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
1665
1666         return smbd_smb2_request_reply(req);
1667 }
1668
1669 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
1670                                     NTSTATUS status,
1671                                     DATA_BLOB *info,
1672                                     const char *location)
1673 {
1674         DATA_BLOB body;
1675         int i = req->current_idx;
1676         uint8_t *outhdr = (uint8_t *)req->out.vector[i].iov_base;
1677
1678         DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
1679                   i, nt_errstr(status), info ? " +info" : "",
1680                   location));
1681
1682         body.data = outhdr + SMB2_HDR_BODY;
1683         body.length = 8;
1684         SSVAL(body.data, 0, 9);
1685
1686         if (info) {
1687                 SIVAL(body.data, 0x04, info->length);
1688         } else {
1689                 /* Allocated size of req->out.vector[i].iov_base
1690                  * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
1691                  * 1 byte without having to do an alloc.
1692                  */
1693                 info = talloc_zero_array(req->out.vector,
1694                                         DATA_BLOB,
1695                                         1);
1696                 if (!info) {
1697                         return NT_STATUS_NO_MEMORY;
1698                 }
1699                 info->data = ((uint8_t *)outhdr) +
1700                         OUTVEC_ALLOC_SIZE - 1;
1701                 info->length = 1;
1702                 SCVAL(info->data, 0, 0);
1703         }
1704
1705         /*
1706          * if a request fails, all other remaining
1707          * compounded requests should fail too
1708          */
1709         req->next_status = NT_STATUS_INVALID_PARAMETER;
1710
1711         return smbd_smb2_request_done_ex(req, status, body, info, __location__);
1712 }
1713
1714
1715 struct smbd_smb2_send_oplock_break_state {
1716         struct smbd_server_connection *sconn;
1717         uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
1718         struct iovec vector;
1719 };
1720
1721 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
1722
1723 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
1724                                      uint64_t file_id_persistent,
1725                                      uint64_t file_id_volatile,
1726                                      uint8_t oplock_level)
1727 {
1728         struct smbd_smb2_send_oplock_break_state *state;
1729         struct tevent_req *subreq;
1730         uint8_t *hdr;
1731         uint8_t *body;
1732
1733         state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
1734         if (state == NULL) {
1735                 return NT_STATUS_NO_MEMORY;
1736         }
1737         state->sconn = sconn;
1738
1739         state->vector.iov_base = (void *)state->buf;
1740         state->vector.iov_len = sizeof(state->buf);
1741
1742         _smb2_setlen(state->buf, sizeof(state->buf) - 4);
1743         hdr = state->buf + 4;
1744         body = hdr + SMB2_HDR_BODY;
1745
1746         SIVAL(hdr, 0,                           SMB2_MAGIC);
1747         SSVAL(hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
1748         SSVAL(hdr, SMB2_HDR_EPOCH,              0);
1749         SIVAL(hdr, SMB2_HDR_STATUS,             0);
1750         SSVAL(hdr, SMB2_HDR_OPCODE,             SMB2_OP_BREAK);
1751         SSVAL(hdr, SMB2_HDR_CREDIT,             0);
1752         SIVAL(hdr, SMB2_HDR_FLAGS,              SMB2_HDR_FLAG_REDIRECT);
1753         SIVAL(hdr, SMB2_HDR_NEXT_COMMAND,       0);
1754         SBVAL(hdr, SMB2_HDR_MESSAGE_ID,         UINT64_MAX);
1755         SIVAL(hdr, SMB2_HDR_PID,                0);
1756         SIVAL(hdr, SMB2_HDR_TID,                0);
1757         SBVAL(hdr, SMB2_HDR_SESSION_ID,         0);
1758         memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
1759
1760         SSVAL(body, 0x00, 0x18);
1761
1762         SCVAL(body, 0x02, oplock_level);
1763         SCVAL(body, 0x03, 0);           /* reserved */
1764         SIVAL(body, 0x04, 0);           /* reserved */
1765         SBVAL(body, 0x08, file_id_persistent);
1766         SBVAL(body, 0x10, file_id_volatile);
1767
1768         subreq = tstream_writev_queue_send(state,
1769                                            sconn->smb2.event_ctx,
1770                                            sconn->smb2.stream,
1771                                            sconn->smb2.send_queue,
1772                                            &state->vector, 1);
1773         if (subreq == NULL) {
1774                 return NT_STATUS_NO_MEMORY;
1775         }
1776         tevent_req_set_callback(subreq,
1777                                 smbd_smb2_oplock_break_writev_done,
1778                                 state);
1779
1780         return NT_STATUS_OK;
1781 }
1782
1783 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
1784 {
1785         struct smbd_smb2_send_oplock_break_state *state =
1786                 tevent_req_callback_data(subreq,
1787                 struct smbd_smb2_send_oplock_break_state);
1788         struct smbd_server_connection *sconn = state->sconn;
1789         int ret;
1790         int sys_errno;
1791
1792         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1793         TALLOC_FREE(subreq);
1794         if (ret == -1) {
1795                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1796                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1797                 return;
1798         }
1799
1800         TALLOC_FREE(state);
1801 }
1802
1803 struct smbd_smb2_request_read_state {
1804         size_t missing;
1805         bool asked_for_header;
1806         struct smbd_smb2_request *smb2_req;
1807 };
1808
1809 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
1810                                          void *private_data,
1811                                          TALLOC_CTX *mem_ctx,
1812                                          struct iovec **_vector,
1813                                          size_t *_count);
1814 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
1815
1816 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
1817                                         struct tevent_context *ev,
1818                                         struct smbd_server_connection *sconn)
1819 {
1820         struct tevent_req *req;
1821         struct smbd_smb2_request_read_state *state;
1822         struct tevent_req *subreq;
1823
1824         req = tevent_req_create(mem_ctx, &state,
1825                                 struct smbd_smb2_request_read_state);
1826         if (req == NULL) {
1827                 return NULL;
1828         }
1829         state->missing = 0;
1830         state->asked_for_header = false;
1831
1832         state->smb2_req = smbd_smb2_request_allocate(state);
1833         if (tevent_req_nomem(state->smb2_req, req)) {
1834                 return tevent_req_post(req, ev);
1835         }
1836         state->smb2_req->sconn = sconn;
1837
1838         subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
1839                                               sconn->smb2.recv_queue,
1840                                               smbd_smb2_request_next_vector,
1841                                               state);
1842         if (tevent_req_nomem(subreq, req)) {
1843                 return tevent_req_post(req, ev);
1844         }
1845         tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
1846
1847         return req;
1848 }
1849
1850 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
1851                                          void *private_data,
1852                                          TALLOC_CTX *mem_ctx,
1853                                          struct iovec **_vector,
1854                                          size_t *_count)
1855 {
1856         struct smbd_smb2_request_read_state *state =
1857                 talloc_get_type_abort(private_data,
1858                 struct smbd_smb2_request_read_state);
1859         struct smbd_smb2_request *req = state->smb2_req;
1860         struct iovec *vector;
1861         int idx = req->in.vector_count;
1862         size_t len = 0;
1863         uint8_t *buf = NULL;
1864
1865         if (req->in.vector_count == 0) {
1866                 /*
1867                  * first we need to get the NBT header
1868                  */
1869                 req->in.vector = talloc_array(req, struct iovec,
1870                                               req->in.vector_count + 1);
1871                 if (req->in.vector == NULL) {
1872                         return -1;
1873                 }
1874                 req->in.vector_count += 1;
1875
1876                 req->in.vector[idx].iov_base    = (void *)req->in.nbt_hdr;
1877                 req->in.vector[idx].iov_len     = 4;
1878
1879                 vector = talloc_array(mem_ctx, struct iovec, 1);
1880                 if (vector == NULL) {
1881                         return -1;
1882                 }
1883
1884                 vector[0] = req->in.vector[idx];
1885
1886                 *_vector = vector;
1887                 *_count = 1;
1888                 return 0;
1889         }
1890
1891         if (req->in.vector_count == 1) {
1892                 /*
1893                  * Now we analyze the NBT header
1894                  */
1895                 state->missing = smb2_len(req->in.vector[0].iov_base);
1896
1897                 if (state->missing == 0) {
1898                         /* if there're no remaining bytes, we're done */
1899                         *_vector = NULL;
1900                         *_count = 0;
1901                         return 0;
1902                 }
1903
1904                 req->in.vector = talloc_realloc(req, req->in.vector,
1905                                                 struct iovec,
1906                                                 req->in.vector_count + 1);
1907                 if (req->in.vector == NULL) {
1908                         return -1;
1909                 }
1910                 req->in.vector_count += 1;
1911
1912                 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
1913                         /*
1914                          * it's a special NBT message,
1915                          * so get all remaining bytes
1916                          */
1917                         len = state->missing;
1918                 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
1919                         /*
1920                          * it's an invalid message, just read what we can get
1921                          * and let the caller handle the error
1922                          */
1923                         len = state->missing;
1924                 } else {
1925                         /*
1926                          * We assume it's a SMB2 request,
1927                          * and we first get the header and the
1928                          * first 2 bytes (the struct size) of the body
1929                          */
1930                         len = SMB2_HDR_BODY + 2;
1931
1932                         state->asked_for_header = true;
1933                 }
1934
1935                 state->missing -= len;
1936
1937                 buf = talloc_array(req->in.vector, uint8_t, len);
1938                 if (buf == NULL) {
1939                         return -1;
1940                 }
1941
1942                 req->in.vector[idx].iov_base    = (void *)buf;
1943                 req->in.vector[idx].iov_len     = len;
1944
1945                 vector = talloc_array(mem_ctx, struct iovec, 1);
1946                 if (vector == NULL) {
1947                         return -1;
1948                 }
1949
1950                 vector[0] = req->in.vector[idx];
1951
1952                 *_vector = vector;
1953                 *_count = 1;
1954                 return 0;
1955         }
1956
1957         if (state->missing == 0) {
1958                 /* if there're no remaining bytes, we're done */
1959                 *_vector = NULL;
1960                 *_count = 0;
1961                 return 0;
1962         }
1963
1964         if (state->asked_for_header) {
1965                 const uint8_t *hdr;
1966                 size_t full_size;
1967                 size_t next_command_ofs;
1968                 size_t body_size;
1969                 uint8_t *body;
1970                 size_t dyn_size;
1971                 uint8_t *dyn;
1972                 bool invalid = false;
1973
1974                 state->asked_for_header = false;
1975
1976                 /*
1977                  * We got the SMB2 header and the first 2 bytes
1978                  * of the body. We fix the size to just the header
1979                  * and manually copy the 2 first bytes to the body section
1980                  */
1981                 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
1982                 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
1983
1984                 /* allocate vectors for body and dynamic areas */
1985                 req->in.vector = talloc_realloc(req, req->in.vector,
1986                                                 struct iovec,
1987                                                 req->in.vector_count + 2);
1988                 if (req->in.vector == NULL) {
1989                         return -1;
1990                 }
1991                 req->in.vector_count += 2;
1992
1993                 full_size = state->missing + SMB2_HDR_BODY + 2;
1994                 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
1995                 body_size = SVAL(hdr, SMB2_HDR_BODY);
1996
1997                 if (next_command_ofs != 0) {
1998                         if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
1999                                 /*
2000                                  * this is invalid, just return a zero
2001                                  * body and let the caller deal with the error
2002                                  */
2003                                 invalid = true;
2004                         } else if (next_command_ofs > full_size) {
2005                                 /*
2006                                  * this is invalid, just return a zero
2007                                  * body and let the caller deal with the error
2008                                  */
2009                                 invalid = true;
2010                         } else {
2011                                 full_size = next_command_ofs;
2012                         }
2013                 }
2014
2015                 if (!invalid) {
2016                         if (body_size < 2) {
2017                                 /*
2018                                  * this is invalid, just return a zero
2019                                  * body and let the caller deal with the error
2020                                  */
2021                                 invalid = true;
2022                         }
2023
2024                         /*
2025                          * Mask out the lowest bit, the "dynamic" part
2026                          * of body_size.
2027                          */
2028                         body_size &= ~1;
2029
2030                         if (body_size > (full_size - SMB2_HDR_BODY)) {
2031                                 /*
2032                                  * this is invalid, just return a zero
2033                                  * body and let the caller deal with the error
2034                                  */
2035                                 invalid = true;
2036                         }
2037                 }
2038
2039                 if (invalid) {
2040                         /* the caller should check this */
2041                         body_size = 2;
2042                 }
2043
2044                 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
2045
2046                 state->missing -= (body_size - 2) + dyn_size;
2047
2048                 body = talloc_array(req->in.vector, uint8_t, body_size);
2049                 if (body == NULL) {
2050                         return -1;
2051                 }
2052
2053                 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
2054                 if (dyn == NULL) {
2055                         return -1;
2056                 }
2057
2058                 req->in.vector[idx].iov_base    = (void *)body;
2059                 req->in.vector[idx].iov_len     = body_size;
2060                 req->in.vector[idx+1].iov_base  = (void *)dyn;
2061                 req->in.vector[idx+1].iov_len   = dyn_size;
2062
2063                 vector = talloc_array(mem_ctx, struct iovec, 2);
2064                 if (vector == NULL) {
2065                         return -1;
2066                 }
2067
2068                 /*
2069                  * the first 2 bytes of the body were already fetched
2070                  * together with the header
2071                  */
2072                 memcpy(body, hdr + SMB2_HDR_BODY, 2);
2073                 vector[0].iov_base = body + 2;
2074                 vector[0].iov_len = body_size - 2;
2075
2076                 vector[1] = req->in.vector[idx+1];
2077
2078                 *_vector = vector;
2079                 *_count = 2;
2080                 return 0;
2081         }
2082
2083         /*
2084          * when we endup here, we're looking for a new SMB2 request
2085          * next. And we ask for its header and the first 2 bytes of
2086          * the body (like we did for the first SMB2 request).
2087          */
2088
2089         req->in.vector = talloc_realloc(req, req->in.vector,
2090                                         struct iovec,
2091                                         req->in.vector_count + 1);
2092         if (req->in.vector == NULL) {
2093                 return -1;
2094         }
2095         req->in.vector_count += 1;
2096
2097         /*
2098          * We assume it's a SMB2 request,
2099          * and we first get the header and the
2100          * first 2 bytes (the struct size) of the body
2101          */
2102         len = SMB2_HDR_BODY + 2;
2103
2104         if (len > state->missing) {
2105                 /* let the caller handle the error */
2106                 len = state->missing;
2107         }
2108
2109         state->missing -= len;
2110         state->asked_for_header = true;
2111
2112         buf = talloc_array(req->in.vector, uint8_t, len);
2113         if (buf == NULL) {
2114                 return -1;
2115         }
2116
2117         req->in.vector[idx].iov_base    = (void *)buf;
2118         req->in.vector[idx].iov_len     = len;
2119
2120         vector = talloc_array(mem_ctx, struct iovec, 1);
2121         if (vector == NULL) {
2122                 return -1;
2123         }
2124
2125         vector[0] = req->in.vector[idx];
2126
2127         *_vector = vector;
2128         *_count = 1;
2129         return 0;
2130 }
2131
2132 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2133 {
2134         struct tevent_req *req =
2135                 tevent_req_callback_data(subreq,
2136                 struct tevent_req);
2137         int ret;
2138         int sys_errno;
2139         NTSTATUS status;
2140
2141         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2142         if (ret == -1) {
2143                 status = map_nt_error_from_unix(sys_errno);
2144                 tevent_req_nterror(req, status);
2145                 return;
2146         }
2147
2148         tevent_req_done(req);
2149 }
2150
2151 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2152                                             TALLOC_CTX *mem_ctx,
2153                                             struct smbd_smb2_request **_smb2_req)
2154 {
2155         struct smbd_smb2_request_read_state *state =
2156                 tevent_req_data(req,
2157                 struct smbd_smb2_request_read_state);
2158         NTSTATUS status;
2159
2160         if (tevent_req_is_nterror(req, &status)) {
2161                 tevent_req_received(req);
2162                 return status;
2163         }
2164
2165         talloc_steal(mem_ctx, state->smb2_req->mem_pool);
2166         *_smb2_req = state->smb2_req;
2167         tevent_req_received(req);
2168         return NT_STATUS_OK;
2169 }
2170
2171 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2172
2173 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2174                              const uint8_t *inbuf, size_t size)
2175 {
2176         NTSTATUS status;
2177         struct smbd_smb2_request *req = NULL;
2178         struct tevent_req *subreq;
2179
2180         DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2181                  (unsigned int)size));
2182
2183         status = smbd_initialize_smb2(sconn);
2184         if (!NT_STATUS_IS_OK(status)) {
2185                 smbd_server_connection_terminate(sconn, nt_errstr(status));
2186                 return;
2187         }
2188
2189         status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2190         if (!NT_STATUS_IS_OK(status)) {
2191                 smbd_server_connection_terminate(sconn, nt_errstr(status));
2192                 return;
2193         }
2194
2195         status = smbd_smb2_request_setup_out(req);
2196         if (!NT_STATUS_IS_OK(status)) {
2197                 smbd_server_connection_terminate(sconn, nt_errstr(status));
2198                 return;
2199         }
2200
2201         status = smbd_smb2_request_dispatch(req);
2202         if (!NT_STATUS_IS_OK(status)) {
2203                 smbd_server_connection_terminate(sconn, nt_errstr(status));
2204                 return;
2205         }
2206
2207         /* ask for the next request */
2208         subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
2209         if (subreq == NULL) {
2210                 smbd_server_connection_terminate(sconn, "no memory for reading");
2211                 return;
2212         }
2213         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2214 }
2215
2216 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2217 {
2218         struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2219                                                struct smbd_server_connection);
2220         NTSTATUS status;
2221         struct smbd_smb2_request *req = NULL;
2222
2223         status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2224         TALLOC_FREE(subreq);
2225         if (!NT_STATUS_IS_OK(status)) {
2226                 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2227                         nt_errstr(status)));
2228                 smbd_server_connection_terminate(sconn, nt_errstr(status));
2229                 return;
2230         }
2231
2232         if (req->in.nbt_hdr[0] != 0x00) {
2233                 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
2234                          req->in.nbt_hdr[0]));
2235                 TALLOC_FREE(req);
2236                 goto next;
2237         }
2238
2239         req->current_idx = 1;
2240
2241         DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2242                  req->current_idx, req->in.vector_count));
2243
2244         status = smbd_smb2_request_validate(req);
2245         if (!NT_STATUS_IS_OK(status)) {
2246                 smbd_server_connection_terminate(sconn, nt_errstr(status));
2247                 return;
2248         }
2249
2250         status = smbd_smb2_request_setup_out(req);
2251         if (!NT_STATUS_IS_OK(status)) {
2252                 smbd_server_connection_terminate(sconn, nt_errstr(status));
2253                 return;
2254         }
2255
2256         status = smbd_smb2_request_dispatch(req);
2257         if (!NT_STATUS_IS_OK(status)) {
2258                 smbd_server_connection_terminate(sconn, nt_errstr(status));
2259                 return;
2260         }
2261
2262 next:
2263         /* ask for the next request (this constructs the main loop) */
2264         subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
2265         if (subreq == NULL) {
2266                 smbd_server_connection_terminate(sconn, "no memory for reading");
2267                 return;
2268         }
2269         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2270 }