s3:smbd: the SMB2-COMPOUND test shows that the related vs. unrelated flags isn't...
[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 NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *conn,
99                                          const uint8_t *inbuf, size_t size,
100                                          struct smbd_smb2_request **_req)
101 {
102         TALLOC_CTX *mem_pool;
103         struct smbd_smb2_request *req;
104         uint32_t protocol_version;
105         const uint8_t *inhdr = NULL;
106         off_t ofs = 0;
107         uint16_t cmd;
108         uint32_t next_command_ofs;
109
110         if (size < (4 + SMB2_HDR_BODY + 2)) {
111                 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
112                 return NT_STATUS_INVALID_PARAMETER;
113         }
114
115         inhdr = inbuf + 4;
116
117         protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
118         if (protocol_version != SMB2_MAGIC) {
119                 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
120                          protocol_version));
121                 return NT_STATUS_INVALID_PARAMETER;
122         }
123
124         cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
125         if (cmd != SMB2_OP_NEGPROT) {
126                 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
127                          cmd));
128                 return NT_STATUS_INVALID_PARAMETER;
129         }
130
131         next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
132         if (next_command_ofs != 0) {
133                 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
134                          next_command_ofs));
135                 return NT_STATUS_INVALID_PARAMETER;
136         }
137
138         mem_pool = talloc_pool(conn, 8192);
139         if (mem_pool == NULL) {
140                 return NT_STATUS_NO_MEMORY;
141         }
142
143         req = talloc_zero(mem_pool, struct smbd_smb2_request);
144         if (req == NULL) {
145                 talloc_free(mem_pool);
146                 return NT_STATUS_NO_MEMORY;
147         }
148         req->mem_pool   = mem_pool;
149         req->conn       = conn;
150
151         talloc_steal(req, inbuf);
152
153         req->in.vector = talloc_array(req, struct iovec, 4);
154         if (req->in.vector == NULL) {
155                 talloc_free(mem_pool);
156                 return NT_STATUS_NO_MEMORY;
157         }
158         req->in.vector_count = 4;
159
160         memcpy(req->in.nbt_hdr, inbuf, 4);
161
162         ofs = 0;
163         req->in.vector[0].iov_base      = (void *)req->in.nbt_hdr;
164         req->in.vector[0].iov_len       = 4;
165         ofs += req->in.vector[0].iov_len;
166
167         req->in.vector[1].iov_base      = (void *)(inbuf + ofs);
168         req->in.vector[1].iov_len       = SMB2_HDR_BODY;
169         ofs += req->in.vector[1].iov_len;
170
171         req->in.vector[2].iov_base      = (void *)(inbuf + ofs);
172         req->in.vector[2].iov_len       = SVAL(inbuf, ofs) & 0xFFFE;
173         ofs += req->in.vector[2].iov_len;
174
175         if (ofs > size) {
176                 return NT_STATUS_INVALID_PARAMETER;
177         }
178
179         req->in.vector[3].iov_base      = (void *)(inbuf + ofs);
180         req->in.vector[3].iov_len       = size - ofs;
181         ofs += req->in.vector[3].iov_len;
182
183         req->current_idx = 1;
184
185         *_req = req;
186         return NT_STATUS_OK;
187 }
188
189 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
190 {
191         int count;
192         int idx;
193         bool compound_related = false;
194
195         count = req->in.vector_count;
196
197         if (count < 4) {
198                 /* It's not a SMB2 request */
199                 return NT_STATUS_INVALID_PARAMETER;
200         }
201
202         for (idx=1; idx < count; idx += 3) {
203                 const uint8_t *inhdr = NULL;
204                 uint32_t flags;
205
206                 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
207                         return NT_STATUS_INVALID_PARAMETER;
208                 }
209
210                 if (req->in.vector[idx+1].iov_len < 2) {
211                         return NT_STATUS_INVALID_PARAMETER;
212                 }
213
214                 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
215
216                 /* setup the SMB2 header */
217                 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
218                         return NT_STATUS_INVALID_PARAMETER;
219                 }
220
221                 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
222                 if (idx == 1) {
223                         /*
224                          * the 1st request should never have the
225                          * SMB2_HDR_FLAG_CHAINED flag set
226                          */
227                         if (flags & SMB2_HDR_FLAG_CHAINED) {
228                                 req->next_status = NT_STATUS_INVALID_PARAMETER;
229                                 return NT_STATUS_OK;
230                         }
231                 } else if (idx == 4) {
232                         /*
233                          * the 2nd request triggers related vs. unrelated
234                          * compounded requests
235                          */
236                         if (flags & SMB2_HDR_FLAG_CHAINED) {
237                                 compound_related = true;
238                         }
239                 } else if (idx > 4) {
240 #if 0
241                         /*
242                          * It seems the this tests are wrong
243                          * see the SMB2-COMPOUND test
244                          */
245
246                         /*
247                          * all other requests should match the 2nd one
248                          */
249                         if (flags & SMB2_HDR_FLAG_CHAINED) {
250                                 if (!compound_related) {
251                                         req->next_status =
252                                                 NT_STATUS_INVALID_PARAMETER;
253                                         return NT_STATUS_OK;
254                                 }
255                         } else {
256                                 if (compound_related) {
257                                         req->next_status =
258                                                 NT_STATUS_INVALID_PARAMETER;
259                                         return NT_STATUS_OK;
260                                 }
261                         }
262 #endif
263                 }
264         }
265
266         return NT_STATUS_OK;
267 }
268
269 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
270 {
271         struct iovec *vector;
272         int count;
273         int idx;
274
275         count = req->in.vector_count;
276         vector = talloc_array(req, struct iovec, count);
277         if (vector == NULL) {
278                 return NT_STATUS_NO_MEMORY;
279         }
280
281         vector[0].iov_base      = req->out.nbt_hdr;
282         vector[0].iov_len       = 4;
283         SIVAL(req->out.nbt_hdr, 0, 0);
284
285         for (idx=1; idx < count; idx += 3) {
286                 const uint8_t *inhdr = NULL;
287                 uint32_t in_flags;
288                 uint8_t *outhdr = NULL;
289                 uint8_t *outbody = NULL;
290                 uint32_t next_command_ofs = 0;
291                 struct iovec *current = &vector[idx];
292
293                 if ((idx + 3) < count) {
294                         /* we have a next command */
295                         next_command_ofs = SMB2_HDR_BODY + 8;
296                 }
297
298                 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
299                 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
300
301                 outhdr = talloc_array(vector, uint8_t,
302                                       SMB2_HDR_BODY + 8);
303                 if (outhdr == NULL) {
304                         return NT_STATUS_NO_MEMORY;
305                 }
306
307                 outbody = outhdr + SMB2_HDR_BODY;
308
309                 current[0].iov_base     = (void *)outhdr;
310                 current[0].iov_len      = SMB2_HDR_BODY;
311
312                 current[1].iov_base     = (void *)outbody;
313                 current[1].iov_len      = 8;
314
315                 current[2].iov_base     = NULL;
316                 current[2].iov_len      = 0;
317
318                 /* setup the SMB2 header */
319                 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID,     SMB2_MAGIC);
320                 SSVAL(outhdr, SMB2_HDR_LENGTH,          SMB2_HDR_BODY);
321                 SSVAL(outhdr, SMB2_HDR_EPOCH,           0);
322                 SIVAL(outhdr, SMB2_HDR_STATUS,
323                       NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
324                 SSVAL(outhdr, SMB2_HDR_OPCODE,
325                       SVAL(inhdr, SMB2_HDR_OPCODE));
326                 /* Make up a number for now... JRA. FIXME ! FIXME !*/
327                 SSVAL(outhdr, SMB2_HDR_CREDIT,          20);
328                 SIVAL(outhdr, SMB2_HDR_FLAGS,
329                       IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
330                 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND,    next_command_ofs);
331                 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
332                       BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
333                 SIVAL(outhdr, SMB2_HDR_PID,
334                       IVAL(inhdr, SMB2_HDR_PID));
335                 SIVAL(outhdr, SMB2_HDR_TID,
336                       IVAL(inhdr, SMB2_HDR_TID));
337                 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
338                       BVAL(inhdr, SMB2_HDR_SESSION_ID));
339                 memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16);
340
341                 /* setup error body header */
342                 SSVAL(outbody, 0x00, 0x08 + 1);
343                 SSVAL(outbody, 0x02, 0);
344                 SIVAL(outbody, 0x04, 0);
345         }
346
347         req->out.vector = vector;
348         req->out.vector_count = count;
349
350         /* setup the length of the NBT packet */
351         smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
352
353         return NT_STATUS_OK;
354 }
355
356 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
357                                          const char *reason,
358                                          const char *location)
359 {
360         DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
361                   reason, location));
362         exit_server_cleanly(reason);
363 }
364
365 static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
366 {
367         const uint8_t *inhdr;
368         int i = req->current_idx;
369         uint16_t opcode;
370         uint32_t flags;
371         NTSTATUS status;
372         NTSTATUS session_status;
373
374         inhdr = (const uint8_t *)req->in.vector[i].iov_base;
375
376         /* TODO: verify more things */
377
378         flags = IVAL(inhdr, SMB2_HDR_FLAGS);
379         opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
380         DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode));
381
382 #define TMP_SMB2_ALLOWED_FLAGS ( \
383         SMB2_HDR_FLAG_CHAINED | \
384         SMB2_HDR_FLAG_SIGNED | \
385         SMB2_HDR_FLAG_DFS)
386         if ((flags & ~TMP_SMB2_ALLOWED_FLAGS) != 0) {
387                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
388         }
389 #undef TMP_SMB2_ALLOWED_FLAGS
390
391         session_status = smbd_smb2_request_check_session(req);
392
393         req->do_signing = false;
394         if (flags & SMB2_HDR_FLAG_SIGNED) {
395                 if (!NT_STATUS_IS_OK(session_status)) {
396                         return smbd_smb2_request_error(req, session_status);
397                 }
398
399                 req->do_signing = true;
400                 status = smb2_signing_check_pdu(req->session->session_key,
401                                                 &req->in.vector[i], 3);
402                 if (!NT_STATUS_IS_OK(status)) {
403                         return smbd_smb2_request_error(req, status);
404                 }
405         } else if (req->session && req->session->do_signing) {
406                 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
407         }
408
409         if (flags & SMB2_HDR_FLAG_CHAINED) {
410                 /*
411                  * This check is mostly for giving the correct error code
412                  * for compounded requests.
413                  *
414                  * TODO: we may need to move this after the session
415                  *       and tcon checks.
416                  */
417                 if (!NT_STATUS_IS_OK(req->next_status)) {
418                         return smbd_smb2_request_error(req, req->next_status);
419                 }
420         } else {
421                 req->compat_chain_fsp = NULL;
422         }
423
424         switch (opcode) {
425         case SMB2_OP_NEGPROT:
426                 return smbd_smb2_request_process_negprot(req);
427
428         case SMB2_OP_SESSSETUP:
429                 return smbd_smb2_request_process_sesssetup(req);
430
431         case SMB2_OP_LOGOFF:
432                 if (!NT_STATUS_IS_OK(session_status)) {
433                         return smbd_smb2_request_error(req, session_status);
434                 }
435                 return smbd_smb2_request_process_logoff(req);
436
437         case SMB2_OP_TCON:
438                 if (!NT_STATUS_IS_OK(session_status)) {
439                         return smbd_smb2_request_error(req, session_status);
440                 }
441                 status = smbd_smb2_request_check_session(req);
442                 if (!NT_STATUS_IS_OK(status)) {
443                         return smbd_smb2_request_error(req, status);
444                 }
445                 return smbd_smb2_request_process_tcon(req);
446
447         case SMB2_OP_TDIS:
448                 if (!NT_STATUS_IS_OK(session_status)) {
449                         return smbd_smb2_request_error(req, session_status);
450                 }
451                 status = smbd_smb2_request_check_tcon(req);
452                 if (!NT_STATUS_IS_OK(status)) {
453                         return smbd_smb2_request_error(req, status);
454                 }
455                 return smbd_smb2_request_process_tdis(req);
456
457         case SMB2_OP_CREATE:
458                 if (!NT_STATUS_IS_OK(session_status)) {
459                         return smbd_smb2_request_error(req, session_status);
460                 }
461                 status = smbd_smb2_request_check_tcon(req);
462                 if (!NT_STATUS_IS_OK(status)) {
463                         return smbd_smb2_request_error(req, status);
464                 }
465                 return smbd_smb2_request_process_create(req);
466
467         case SMB2_OP_CLOSE:
468                 if (!NT_STATUS_IS_OK(session_status)) {
469                         return smbd_smb2_request_error(req, session_status);
470                 }
471                 status = smbd_smb2_request_check_tcon(req);
472                 if (!NT_STATUS_IS_OK(status)) {
473                         return smbd_smb2_request_error(req, status);
474                 }
475                 return smbd_smb2_request_process_close(req);
476
477         case SMB2_OP_FLUSH:
478                 if (!NT_STATUS_IS_OK(session_status)) {
479                         return smbd_smb2_request_error(req, session_status);
480                 }
481                 status = smbd_smb2_request_check_tcon(req);
482                 if (!NT_STATUS_IS_OK(status)) {
483                         return smbd_smb2_request_error(req, status);
484                 }
485                 return smbd_smb2_request_process_flush(req);
486
487         case SMB2_OP_READ:
488                 if (!NT_STATUS_IS_OK(session_status)) {
489                         return smbd_smb2_request_error(req, session_status);
490                 }
491                 status = smbd_smb2_request_check_tcon(req);
492                 if (!NT_STATUS_IS_OK(status)) {
493                         return smbd_smb2_request_error(req, status);
494                 }
495                 return smbd_smb2_request_process_read(req);
496
497         case SMB2_OP_WRITE:
498                 if (!NT_STATUS_IS_OK(session_status)) {
499                         return smbd_smb2_request_error(req, session_status);
500                 }
501                 status = smbd_smb2_request_check_tcon(req);
502                 if (!NT_STATUS_IS_OK(status)) {
503                         return smbd_smb2_request_error(req, status);
504                 }
505                 return smbd_smb2_request_process_write(req);
506
507         case SMB2_OP_LOCK:
508                 if (!NT_STATUS_IS_OK(session_status)) {
509                         return smbd_smb2_request_error(req, session_status);
510                 }
511                 status = smbd_smb2_request_check_tcon(req);
512                 if (!NT_STATUS_IS_OK(status)) {
513                         return smbd_smb2_request_error(req, status);
514                 }
515                 return smbd_smb2_request_error(req, NT_STATUS_NOT_IMPLEMENTED);
516
517         case SMB2_OP_IOCTL:
518                 if (!NT_STATUS_IS_OK(session_status)) {
519                         return smbd_smb2_request_error(req, session_status);
520                 }
521                 status = smbd_smb2_request_check_tcon(req);
522                 if (!NT_STATUS_IS_OK(status)) {
523                         return smbd_smb2_request_error(req, status);
524                 }
525                 return smbd_smb2_request_process_ioctl(req);
526
527         case SMB2_OP_CANCEL:
528                 return smbd_smb2_request_error(req, NT_STATUS_NOT_IMPLEMENTED);
529
530         case SMB2_OP_KEEPALIVE:
531                 return smbd_smb2_request_process_keepalive(req);
532
533         case SMB2_OP_FIND:
534                 if (!NT_STATUS_IS_OK(session_status)) {
535                         return smbd_smb2_request_error(req, session_status);
536                 }
537                 status = smbd_smb2_request_check_tcon(req);
538                 if (!NT_STATUS_IS_OK(status)) {
539                         return smbd_smb2_request_error(req, status);
540                 }
541                 return smbd_smb2_request_error(req, NT_STATUS_NOT_IMPLEMENTED);
542
543         case SMB2_OP_NOTIFY:
544                 if (!NT_STATUS_IS_OK(session_status)) {
545                         return smbd_smb2_request_error(req, session_status);
546                 }
547                 status = smbd_smb2_request_check_tcon(req);
548                 if (!NT_STATUS_IS_OK(status)) {
549                         return smbd_smb2_request_error(req, status);
550                 }
551                 return smbd_smb2_request_error(req, NT_STATUS_NOT_IMPLEMENTED);
552
553         case SMB2_OP_GETINFO:
554                 if (!NT_STATUS_IS_OK(session_status)) {
555                         return smbd_smb2_request_error(req, session_status);
556                 }
557                 status = smbd_smb2_request_check_tcon(req);
558                 if (!NT_STATUS_IS_OK(status)) {
559                         return smbd_smb2_request_error(req, status);
560                 }
561                 return smbd_smb2_request_error(req, NT_STATUS_NOT_IMPLEMENTED);
562
563         case SMB2_OP_SETINFO:
564                 if (!NT_STATUS_IS_OK(session_status)) {
565                         return smbd_smb2_request_error(req, session_status);
566                 }
567                 status = smbd_smb2_request_check_tcon(req);
568                 if (!NT_STATUS_IS_OK(status)) {
569                         return smbd_smb2_request_error(req, status);
570                 }
571                 return smbd_smb2_request_error(req, NT_STATUS_NOT_IMPLEMENTED);
572
573         case SMB2_OP_BREAK:
574                 if (!NT_STATUS_IS_OK(session_status)) {
575                         return smbd_smb2_request_error(req, session_status);
576                 }
577                 status = smbd_smb2_request_check_tcon(req);
578                 if (!NT_STATUS_IS_OK(status)) {
579                         return smbd_smb2_request_error(req, status);
580                 }
581                 return smbd_smb2_request_error(req, NT_STATUS_NOT_IMPLEMENTED);
582         }
583
584         return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
585 }
586
587 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq);
588 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
589
590 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
591 {
592         struct tevent_req *subreq;
593
594         smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
595
596         if (req->do_signing) {
597                 int i = req->current_idx;
598                 NTSTATUS status;
599                 status = smb2_signing_sign_pdu(req->session->session_key,
600                                                &req->out.vector[i], 3);
601                 if (!NT_STATUS_IS_OK(status)) {
602                         return status;
603                 }
604         }
605
606         req->current_idx += 3;
607
608         if (req->current_idx < req->out.vector_count) {
609                 struct timeval zero = timeval_zero();
610                 subreq = tevent_wakeup_send(req,
611                                             req->conn->smb2.event_ctx,
612                                             zero);
613                 if (subreq == NULL) {
614                         return NT_STATUS_NO_MEMORY;
615                 }
616                 tevent_req_set_callback(subreq,
617                                         smbd_smb2_request_dispatch_compound,
618                                         req);
619
620                 return NT_STATUS_OK;
621         }
622
623         subreq = tstream_writev_queue_send(req,
624                                            req->conn->smb2.event_ctx,
625                                            req->conn->smb2.stream,
626                                            req->conn->smb2.send_queue,
627                                            req->out.vector,
628                                            req->out.vector_count);
629         if (subreq == NULL) {
630                 return NT_STATUS_NO_MEMORY;
631         }
632         tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
633
634         return NT_STATUS_OK;
635 }
636
637 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq)
638 {
639         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
640                                         struct smbd_smb2_request);
641         struct smbd_server_connection *conn = req->conn;
642         NTSTATUS status;
643
644         tevent_wakeup_recv(subreq);
645         TALLOC_FREE(subreq);
646
647         DEBUG(10,("smbd_smb2_request_dispatch_compound: idx[%d] of %d vectors\n",
648                   req->current_idx, req->in.vector_count));
649
650         status = smbd_smb2_request_dispatch(req);
651         if (!NT_STATUS_IS_OK(status)) {
652                 smbd_server_connection_terminate(conn, nt_errstr(status));
653                 return;
654         }
655 }
656
657 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
658 {
659         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
660                                         struct smbd_smb2_request);
661         struct smbd_server_connection *conn = req->conn;
662         int ret;
663         int sys_errno;
664         TALLOC_CTX *mem_pool;
665
666         ret = tstream_writev_queue_recv(subreq, &sys_errno);
667         TALLOC_FREE(subreq);
668         if (ret == -1) {
669                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
670                 smbd_server_connection_terminate(conn, nt_errstr(status));
671                 return;
672         }
673
674         mem_pool = req->mem_pool;
675         req = NULL;
676         talloc_free(mem_pool);
677 }
678
679 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
680                                     NTSTATUS status,
681                                     DATA_BLOB *info,
682                                     const char *location)
683 {
684         uint8_t *outhdr;
685         uint8_t *outbody;
686         int i = req->current_idx;
687
688         DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
689                   i, nt_errstr(status), info ? " +info" : "",
690                   location));
691
692         outhdr = (uint8_t *)req->out.vector[i].iov_base;
693
694         SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
695
696         outbody = outhdr + SMB2_HDR_BODY;
697
698         req->out.vector[i+1].iov_base = (void *)outbody;
699         req->out.vector[i+1].iov_len = 8;
700
701         if (info) {
702                 SIVAL(outbody, 0x04, info->length);
703                 req->out.vector[i+2].iov_base   = (void *)info->data;
704                 req->out.vector[i+2].iov_len    = info->length;
705         } else {
706                 req->out.vector[i+2].iov_base = NULL;
707                 req->out.vector[i+2].iov_len = 0;
708         }
709
710         /*
711          * if a request fails, all other remaining
712          * compounded requests should fail too
713          */
714         req->next_status = NT_STATUS_INVALID_PARAMETER;
715
716         return smbd_smb2_request_reply(req);
717 }
718
719 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
720                                    NTSTATUS status,
721                                    DATA_BLOB body, DATA_BLOB *dyn,
722                                    const char *location)
723 {
724         uint8_t *outhdr;
725         uint8_t *outdyn;
726         int i = req->current_idx;
727         uint32_t next_command_ofs;
728
729         DEBUG(10,("smbd_smb2_request_done_ex: "
730                   "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
731                   i, nt_errstr(status), (unsigned int)body.length,
732                   dyn ? "yes": "no",
733                   (unsigned int)(dyn ? dyn->length : 0),
734                   location));
735
736         if (body.length < 2) {
737                 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
738         }
739
740         if ((body.length % 2) != 0) {
741                 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
742         }
743
744         outhdr = (uint8_t *)req->out.vector[i].iov_base;
745         /* the fallback dynamic buffer */
746         outdyn = outhdr + SMB2_HDR_BODY + 8;
747
748         next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
749         SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
750
751         req->out.vector[i+1].iov_base = (void *)body.data;
752         req->out.vector[i+1].iov_len = body.length;
753
754         if (dyn) {
755                 req->out.vector[i+2].iov_base   = (void *)dyn->data;
756                 req->out.vector[i+2].iov_len    = dyn->length;
757         } else {
758                 req->out.vector[i+2].iov_base = NULL;
759                 req->out.vector[i+2].iov_len = 0;
760         }
761
762         /* see if we need to recalculate the offset to the next response */
763         if (next_command_ofs > 0) {
764                 next_command_ofs  = SMB2_HDR_BODY;
765                 next_command_ofs += req->out.vector[i+1].iov_len;
766                 next_command_ofs += req->out.vector[i+2].iov_len;
767         }
768
769         if ((next_command_ofs % 8) != 0) {
770                 size_t pad_size = 8 - (next_command_ofs % 8);
771                 if (req->out.vector[i+2].iov_len == 0) {
772                         /*
773                          * if the dyn buffer is empty
774                          * we can use it to add padding
775                          */
776                         uint8_t *pad;
777
778                         pad = talloc_zero_array(req->out.vector,
779                                                 uint8_t, pad_size);
780                         if (pad == NULL) {
781                                 return smbd_smb2_request_error(req,
782                                                 NT_STATUS_NO_MEMORY);
783                         }
784
785                         req->out.vector[i+2].iov_base = (void *)pad;
786                         req->out.vector[i+2].iov_len = pad_size;
787                 } else {
788                         /*
789                          * For now we copy the dynamic buffer
790                          * and add the padding to the new buffer
791                          */
792                         size_t old_size;
793                         uint8_t *old_dyn;
794                         size_t new_size;
795                         uint8_t *new_dyn;
796
797                         old_size = req->out.vector[i+2].iov_len;
798                         old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
799
800                         new_size = old_size + pad_size;
801                         new_dyn = talloc_array(req->out.vector,
802                                                uint8_t, new_size);
803                         if (new_dyn == NULL) {
804                                 return smbd_smb2_request_error(req,
805                                                 NT_STATUS_NO_MEMORY);
806                         }
807
808                         memcpy(new_dyn, old_dyn, old_size);
809                         memset(new_dyn + old_size, 0, pad_size);
810
811                         req->out.vector[i+2].iov_base = (void *)new_dyn;
812                         req->out.vector[i+2].iov_len = new_size;
813
814                         TALLOC_FREE(old_dyn);
815                 }
816                 next_command_ofs += pad_size;
817         }
818
819         SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
820
821         return smbd_smb2_request_reply(req);
822 }
823
824 struct smbd_smb2_request_read_state {
825         size_t missing;
826         bool asked_for_header;
827         struct smbd_smb2_request *smb2_req;
828 };
829
830 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
831                                          void *private_data,
832                                          TALLOC_CTX *mem_ctx,
833                                          struct iovec **_vector,
834                                          size_t *_count);
835 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
836
837 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
838                                         struct tevent_context *ev,
839                                         struct smbd_server_connection *conn)
840 {
841         struct tevent_req *req;
842         struct smbd_smb2_request_read_state *state;
843         struct tevent_req *subreq;
844         TALLOC_CTX *mem_pool;
845
846         req = tevent_req_create(mem_ctx, &state,
847                                 struct smbd_smb2_request_read_state);
848         if (req == NULL) {
849                 return NULL;
850         }
851         state->missing = 0;
852         state->asked_for_header = false;
853
854         mem_pool = talloc_pool(state, 8192);
855         if (tevent_req_nomem(mem_pool, req)) {
856                 return tevent_req_post(req, ev);
857         }
858
859         state->smb2_req = talloc_zero(mem_pool, struct smbd_smb2_request);
860         if (tevent_req_nomem(state->smb2_req, req)) {
861                 return tevent_req_post(req, ev);
862         }
863
864         state->smb2_req->mem_pool       = mem_pool;
865         state->smb2_req->conn           = conn;
866
867         subreq = tstream_readv_pdu_queue_send(state, ev, conn->smb2.stream,
868                                               conn->smb2.recv_queue,
869                                               smbd_smb2_request_next_vector,
870                                               state);
871         if (tevent_req_nomem(subreq, req)) {
872                 return tevent_req_post(req, ev);
873         }
874         tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
875
876         return req;
877 }
878
879 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
880                                          void *private_data,
881                                          TALLOC_CTX *mem_ctx,
882                                          struct iovec **_vector,
883                                          size_t *_count)
884 {
885         struct smbd_smb2_request_read_state *state =
886                 talloc_get_type_abort(private_data,
887                 struct smbd_smb2_request_read_state);
888         struct smbd_smb2_request *req = state->smb2_req;
889         struct iovec *vector;
890         int idx = req->in.vector_count;
891         size_t len = 0;
892         uint8_t *buf = NULL;
893
894         if (req->in.vector_count == 0) {
895                 /*
896                  * first we need to get the NBT header
897                  */
898                 req->in.vector = talloc_array(req, struct iovec,
899                                               req->in.vector_count + 1);
900                 if (req->in.vector == NULL) {
901                         return -1;
902                 }
903                 req->in.vector_count += 1;
904
905                 req->in.vector[idx].iov_base    = (void *)req->in.nbt_hdr;
906                 req->in.vector[idx].iov_len     = 4;
907
908                 vector = talloc_array(mem_ctx, struct iovec, 1);
909                 if (vector == NULL) {
910                         return -1;
911                 }
912
913                 vector[0] = req->in.vector[idx];
914
915                 *_vector = vector;
916                 *_count = 1;
917                 return 0;
918         }
919
920         if (req->in.vector_count == 1) {
921                 /*
922                  * Now we analyze the NBT header
923                  */
924                 state->missing = smb2_len(req->in.vector[0].iov_base);
925
926                 if (state->missing == 0) {
927                         /* if there're no remaining bytes, we're done */
928                         *_vector = NULL;
929                         *_count = 0;
930                         return 0;
931                 }
932
933                 req->in.vector = talloc_realloc(req, req->in.vector,
934                                                 struct iovec,
935                                                 req->in.vector_count + 1);
936                 if (req->in.vector == NULL) {
937                         return -1;
938                 }
939                 req->in.vector_count += 1;
940
941                 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
942                         /*
943                          * it's a special NBT message,
944                          * so get all remaining bytes
945                          */
946                         len = state->missing;
947                 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
948                         /*
949                          * it's an invalid message, just read what we can get
950                          * and let the caller handle the error
951                          */
952                         len = state->missing;
953                 } else {
954                         /*
955                          * We assume it's a SMB2 request,
956                          * and we first get the header and the
957                          * first 2 bytes (the struct size) of the body
958                          */
959                         len = SMB2_HDR_BODY + 2;
960
961                         state->asked_for_header = true;
962                 }
963
964                 state->missing -= len;
965
966                 buf = talloc_array(req->in.vector, uint8_t, len);
967                 if (buf == NULL) {
968                         return -1;
969                 }
970
971                 req->in.vector[idx].iov_base    = (void *)buf;
972                 req->in.vector[idx].iov_len     = len;
973
974                 vector = talloc_array(mem_ctx, struct iovec, 1);
975                 if (vector == NULL) {
976                         return -1;
977                 }
978
979                 vector[0] = req->in.vector[idx];
980
981                 *_vector = vector;
982                 *_count = 1;
983                 return 0;
984         }
985
986         if (state->missing == 0) {
987                 /* if there're no remaining bytes, we're done */
988                 *_vector = NULL;
989                 *_count = 0;
990                 return 0;
991         }
992
993         if (state->asked_for_header) {
994                 const uint8_t *hdr;
995                 size_t full_size;
996                 size_t next_command_ofs;
997                 size_t body_size;
998                 uint8_t *body;
999                 size_t dyn_size;
1000                 uint8_t *dyn;
1001                 bool invalid = false;
1002
1003                 state->asked_for_header = false;
1004
1005                 /*
1006                  * We got the SMB2 header and the first 2 bytes
1007                  * of the body. We fix the size to just the header
1008                  * and manually copy the 2 first bytes to the body section
1009                  */
1010                 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
1011                 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
1012
1013                 /* allocate vectors for body and dynamic areas */
1014                 req->in.vector = talloc_realloc(req, req->in.vector,
1015                                                 struct iovec,
1016                                                 req->in.vector_count + 2);
1017                 if (req->in.vector == NULL) {
1018                         return -1;
1019                 }
1020                 req->in.vector_count += 2;
1021
1022                 full_size = state->missing + SMB2_HDR_BODY + 2;
1023                 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
1024                 body_size = SVAL(hdr, SMB2_HDR_BODY);
1025
1026                 if (next_command_ofs != 0) {
1027                         if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
1028                                 /*
1029                                  * this is invalid, just return a zero
1030                                  * body and let the caller deal with the error
1031                                  */
1032                                 invalid = true;
1033                         } else if (next_command_ofs > full_size) {
1034                                 /*
1035                                  * this is invalid, just return a zero
1036                                  * body and let the caller deal with the error
1037                                  */
1038                                 invalid = true;
1039                         } else {
1040                                 full_size = next_command_ofs;
1041                         }
1042                 }
1043
1044                 if (!invalid) {
1045                         if (body_size < 2) {
1046                                 /*
1047                                  * this is invalid, just return a zero
1048                                  * body and let the caller deal with the error
1049                                  */
1050                                 invalid = true;
1051                         } else if (body_size > (full_size - SMB2_HDR_BODY)) {
1052                                 /*
1053                                  * this is invalid, just return a zero
1054                                  * body and let the caller deal with the error
1055                                  */
1056                                 invalid = true;
1057                         }
1058                 }
1059
1060                 if (invalid) {
1061                         /* the caller should check this */
1062                         body_size = 0;
1063                 }
1064
1065                 if ((body_size % 2) != 0) {
1066                         body_size -= 1;
1067                 }
1068
1069                 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
1070
1071                 state->missing -= (body_size - 2) + dyn_size;
1072
1073                 body = talloc_array(req->in.vector, uint8_t, body_size);
1074                 if (body == NULL) {
1075                         return -1;
1076                 }
1077
1078                 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
1079                 if (dyn == NULL) {
1080                         return -1;
1081                 }
1082
1083                 req->in.vector[idx].iov_base    = (void *)body;
1084                 req->in.vector[idx].iov_len     = body_size;
1085                 req->in.vector[idx+1].iov_base  = (void *)dyn;
1086                 req->in.vector[idx+1].iov_len   = dyn_size;
1087
1088                 vector = talloc_array(mem_ctx, struct iovec, 2);
1089                 if (vector == NULL) {
1090                         return -1;
1091                 }
1092
1093                 /*
1094                  * the first 2 bytes of the body were already fetched
1095                  * together with the header
1096                  */
1097                 memcpy(body, hdr + SMB2_HDR_BODY, 2);
1098                 vector[0].iov_base = body + 2;
1099                 vector[0].iov_len = req->in.vector[idx].iov_len - 2;
1100
1101                 vector[1] = req->in.vector[idx+1];
1102
1103                 *_vector = vector;
1104                 *_count = 2;
1105                 return 0;
1106         }
1107
1108         /*
1109          * when we endup here, we're looking for a new SMB2 request
1110          * next. And we ask for its header and the first 2 bytes of
1111          * the body (like we did for the first SMB2 request).
1112          */
1113
1114         req->in.vector = talloc_realloc(req, req->in.vector,
1115                                         struct iovec,
1116                                         req->in.vector_count + 1);
1117         if (req->in.vector == NULL) {
1118                 return -1;
1119         }
1120         req->in.vector_count += 1;
1121
1122         /*
1123          * We assume it's a SMB2 request,
1124          * and we first get the header and the
1125          * first 2 bytes (the struct size) of the body
1126          */
1127         len = SMB2_HDR_BODY + 2;
1128
1129         if (len > state->missing) {
1130                 /* let the caller handle the error */
1131                 len = state->missing;
1132         }
1133
1134         state->missing -= len;
1135         state->asked_for_header = true;
1136
1137         buf = talloc_array(req->in.vector, uint8_t, len);
1138         if (buf == NULL) {
1139                 return -1;
1140         }
1141
1142         req->in.vector[idx].iov_base    = (void *)buf;
1143         req->in.vector[idx].iov_len     = len;
1144
1145         vector = talloc_array(mem_ctx, struct iovec, 1);
1146         if (vector == NULL) {
1147                 return -1;
1148         }
1149
1150         vector[0] = req->in.vector[idx];
1151
1152         *_vector = vector;
1153         *_count = 1;
1154         return 0;
1155 }
1156
1157 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
1158 {
1159         struct tevent_req *req =
1160                 tevent_req_callback_data(subreq,
1161                 struct tevent_req);
1162         int ret;
1163         int sys_errno;
1164         NTSTATUS status;
1165
1166         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1167         if (ret == -1) {
1168                 status = map_nt_error_from_unix(sys_errno);
1169                 tevent_req_nterror(req, status);
1170                 return;
1171         }
1172
1173         tevent_req_done(req);
1174 }
1175
1176 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
1177                                             TALLOC_CTX *mem_ctx,
1178                                             struct smbd_smb2_request **_smb2_req)
1179 {
1180         struct smbd_smb2_request_read_state *state =
1181                 tevent_req_data(req,
1182                 struct smbd_smb2_request_read_state);
1183         NTSTATUS status;
1184
1185         if (tevent_req_is_nterror(req, &status)) {
1186                 tevent_req_received(req);
1187                 return status;
1188         }
1189
1190         talloc_steal(mem_ctx, state->smb2_req->mem_pool);
1191         *_smb2_req = state->smb2_req;
1192         tevent_req_received(req);
1193         return NT_STATUS_OK;
1194 }
1195
1196 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
1197
1198 void smbd_smb2_first_negprot(struct smbd_server_connection *conn,
1199                              const uint8_t *inbuf, size_t size)
1200 {
1201         NTSTATUS status;
1202         struct smbd_smb2_request *req;
1203         struct tevent_req *subreq;
1204
1205         DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
1206                  (unsigned int)size));
1207
1208         status = smbd_initialize_smb2(conn);
1209         if (!NT_STATUS_IS_OK(status)) {
1210                 smbd_server_connection_terminate(conn, nt_errstr(status));
1211                 return;
1212         }
1213
1214         status = smbd_smb2_request_create(conn, inbuf, size, &req);
1215         if (!NT_STATUS_IS_OK(status)) {
1216                 smbd_server_connection_terminate(conn, nt_errstr(status));
1217                 return;
1218         }
1219
1220         status = smbd_smb2_request_setup_out(req);
1221         if (!NT_STATUS_IS_OK(status)) {
1222                 smbd_server_connection_terminate(conn, nt_errstr(status));
1223                 return;
1224         }
1225
1226         status = smbd_smb2_request_dispatch(req);
1227         if (!NT_STATUS_IS_OK(status)) {
1228                 smbd_server_connection_terminate(conn, nt_errstr(status));
1229                 return;
1230         }
1231
1232         /* ask for the next request */
1233         subreq = smbd_smb2_request_read_send(conn,conn->smb2.event_ctx, conn);
1234         if (subreq == NULL) {
1235                 smbd_server_connection_terminate(conn, "no memory for reading");
1236                 return;
1237         }
1238         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, conn);
1239 }
1240
1241 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
1242 {
1243         struct smbd_server_connection *conn = tevent_req_callback_data(subreq,
1244                                               struct smbd_server_connection);
1245         NTSTATUS status;
1246         struct smbd_smb2_request *req;
1247
1248         status = smbd_smb2_request_read_recv(subreq, conn, &req);
1249         TALLOC_FREE(subreq);
1250         if (!NT_STATUS_IS_OK(status)) {
1251                 smbd_server_connection_terminate(conn, nt_errstr(status));
1252                 return;
1253         }
1254
1255         if (req->in.nbt_hdr[0] != 0x00) {
1256                 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
1257                          req->in.nbt_hdr[0]));
1258                 talloc_free(req->mem_pool);
1259                 req = NULL;
1260                 goto next;
1261         }
1262
1263         req->current_idx = 1;
1264
1265         DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
1266                  req->current_idx, req->in.vector_count));
1267
1268         status = smbd_smb2_request_validate(req);
1269         if (!NT_STATUS_IS_OK(status)) {
1270                 smbd_server_connection_terminate(conn, nt_errstr(status));
1271                 return;
1272         }
1273
1274         status = smbd_smb2_request_setup_out(req);
1275         if (!NT_STATUS_IS_OK(status)) {
1276                 smbd_server_connection_terminate(conn, nt_errstr(status));
1277                 return;
1278         }
1279
1280         status = smbd_smb2_request_dispatch(req);
1281         if (!NT_STATUS_IS_OK(status)) {
1282                 smbd_server_connection_terminate(conn, nt_errstr(status));
1283                 return;
1284         }
1285
1286 next:
1287         /* ask for the next request (this constructs the main loop) */
1288         subreq = smbd_smb2_request_read_send(conn,conn->smb2.event_ctx, conn);
1289         if (subreq == NULL) {
1290                 smbd_server_connection_terminate(conn, "no memory for reading");
1291                 return;
1292         }
1293         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, conn);
1294 }