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