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