s3:smb2_server: try to sign an error response if we have a signing key
[Samba.git] / source3 / smbd / smb2_server.c
blobff4ee60e95c518011f7a2e5c57f2ae67b5b30b52
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
5 Copyright (C) Stefan Metzmacher 2009
6 Copyright (C) Jeremy Allison 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../libcli/smb/smb_common.h"
26 #include "../lib/tsocket/tsocket.h"
27 #include "../lib/util/tevent_ntstatus.h"
28 #include "smbprofile.h"
29 #include "../lib/util/bitmap.h"
30 #include "../librpc/gen_ndr/krb5pac.h"
31 #include "auth.h"
33 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
35 static const struct smbd_smb2_dispatch_table {
36 uint16_t opcode;
37 const char *name;
38 bool need_session;
39 bool need_tcon;
40 bool as_root;
41 uint16_t fileid_ofs;
42 bool allow_invalid_fileid;
43 } smbd_smb2_table[] = {
44 #define _OP(o) .opcode = o, .name = #o
46 _OP(SMB2_OP_NEGPROT),
47 .as_root = true,
48 },{
49 _OP(SMB2_OP_SESSSETUP),
50 .as_root = true,
51 },{
52 _OP(SMB2_OP_LOGOFF),
53 .need_session = true,
54 .as_root = true,
55 },{
56 _OP(SMB2_OP_TCON),
57 .need_session = true,
59 * This call needs to be run as root.
61 * smbd_smb2_request_process_tcon()
62 * calls make_connection_snum(), which will call
63 * change_to_user(), when needed.
65 .as_root = true,
66 },{
67 _OP(SMB2_OP_TDIS),
68 .need_session = true,
69 .need_tcon = true,
70 .as_root = true,
71 },{
72 _OP(SMB2_OP_CREATE),
73 .need_session = true,
74 .need_tcon = true,
75 },{
76 _OP(SMB2_OP_CLOSE),
77 .need_session = true,
78 .need_tcon = true,
79 .fileid_ofs = 0x08,
80 },{
81 _OP(SMB2_OP_FLUSH),
82 .need_session = true,
83 .need_tcon = true,
84 .fileid_ofs = 0x08,
85 },{
86 _OP(SMB2_OP_READ),
87 .need_session = true,
88 .need_tcon = true,
89 .fileid_ofs = 0x10,
90 },{
91 _OP(SMB2_OP_WRITE),
92 .need_session = true,
93 .need_tcon = true,
94 .fileid_ofs = 0x10,
95 },{
96 _OP(SMB2_OP_LOCK),
97 .need_session = true,
98 .need_tcon = true,
99 .fileid_ofs = 0x08,
101 _OP(SMB2_OP_IOCTL),
102 .need_session = true,
103 .need_tcon = true,
104 .fileid_ofs = 0x08,
105 .allow_invalid_fileid = true,
107 _OP(SMB2_OP_CANCEL),
108 .as_root = true,
110 _OP(SMB2_OP_KEEPALIVE),
111 .as_root = true,
113 _OP(SMB2_OP_FIND),
114 .need_session = true,
115 .need_tcon = true,
116 .fileid_ofs = 0x08,
118 _OP(SMB2_OP_NOTIFY),
119 .need_session = true,
120 .need_tcon = true,
121 .fileid_ofs = 0x08,
123 _OP(SMB2_OP_GETINFO),
124 .need_session = true,
125 .need_tcon = true,
126 .fileid_ofs = 0x18,
128 _OP(SMB2_OP_SETINFO),
129 .need_session = true,
130 .need_tcon = true,
131 .fileid_ofs = 0x10,
133 _OP(SMB2_OP_BREAK),
134 .need_session = true,
135 .need_tcon = true,
137 * we do not set
138 * .fileid_ofs here
139 * as LEASE breaks does not
140 * have a file id
145 const char *smb2_opcode_name(uint16_t opcode)
147 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
148 return "Bad SMB2 opcode";
150 return smbd_smb2_table[opcode].name;
153 static const struct smbd_smb2_dispatch_table *smbd_smb2_call(uint16_t opcode)
155 const struct smbd_smb2_dispatch_table *ret = NULL;
157 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
158 return NULL;
161 ret = &smbd_smb2_table[opcode];
163 SMB_ASSERT(ret->opcode == opcode);
165 return ret;
168 static void print_req_vectors(const struct smbd_smb2_request *req)
170 int i;
172 for (i = 0; i < req->in.vector_count; i++) {
173 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
174 (unsigned int)i,
175 (unsigned int)req->in.vector[i].iov_len);
177 for (i = 0; i < req->out.vector_count; i++) {
178 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
179 (unsigned int)i,
180 (unsigned int)req->out.vector[i].iov_len);
184 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
186 if (size < (4 + SMB2_HDR_BODY)) {
187 return false;
190 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
191 return false;
194 return true;
197 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
199 NTSTATUS status;
200 int ret;
202 TALLOC_FREE(sconn->smb1.fde);
204 sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
205 if (sconn->smb2.recv_queue == NULL) {
206 return NT_STATUS_NO_MEMORY;
209 sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
210 if (sconn->smb2.send_queue == NULL) {
211 return NT_STATUS_NO_MEMORY;
214 sconn->smb2.seqnum_low = 0;
215 sconn->smb2.seqnum_range = 1;
216 sconn->smb2.credits_granted = 1;
217 sconn->smb2.max_credits = lp_smb2_max_credits();
218 sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
219 sconn->smb2.max_credits);
220 if (sconn->smb2.credits_bitmap == NULL) {
221 return NT_STATUS_NO_MEMORY;
224 ret = tstream_bsd_existing_socket(sconn, sconn->sock,
225 &sconn->smb2.stream);
226 if (ret == -1) {
227 status = map_nt_error_from_unix(errno);
228 return status;
231 /* Ensure child is set to non-blocking mode */
232 set_blocking(sconn->sock, false);
233 return NT_STATUS_OK;
236 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
237 #define _smb2_setlen(_buf,len) do { \
238 uint8_t *buf = (uint8_t *)_buf; \
239 buf[0] = 0; \
240 buf[1] = ((len)&0xFF0000)>>16; \
241 buf[2] = ((len)&0xFF00)>>8; \
242 buf[3] = (len)&0xFF; \
243 } while (0)
245 static void smb2_setup_nbt_length(struct iovec *vector, int count)
247 size_t len = 0;
248 int i;
250 for (i=1; i < count; i++) {
251 len += vector[i].iov_len;
254 _smb2_setlen(vector[0].iov_base, len);
257 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
259 data_blob_clear_free(&req->last_key);
260 return 0;
263 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
265 TALLOC_CTX *mem_pool;
266 struct smbd_smb2_request *req;
268 #if 0
269 /* Enable this to find subtle valgrind errors. */
270 mem_pool = talloc_init("smbd_smb2_request_allocate");
271 #else
272 mem_pool = talloc_pool(mem_ctx, 8192);
273 #endif
274 if (mem_pool == NULL) {
275 return NULL;
278 req = talloc_zero(mem_pool, struct smbd_smb2_request);
279 if (req == NULL) {
280 talloc_free(mem_pool);
281 return NULL;
283 talloc_reparent(mem_pool, mem_ctx, req);
284 TALLOC_FREE(mem_pool);
286 req->last_session_id = UINT64_MAX;
287 req->last_tid = UINT32_MAX;
289 talloc_set_destructor(req, smbd_smb2_request_destructor);
291 return req;
294 static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
295 NTTIME now,
296 uint8_t *buf,
297 size_t buflen,
298 TALLOC_CTX *mem_ctx,
299 struct iovec **piov,
300 int *pnum_iov)
302 struct iovec *iov;
303 int num_iov = 1;
304 size_t taken = 0;
305 uint8_t *first_hdr = buf;
308 * Note: index '0' is reserved for the transport protocol
310 iov = talloc_zero_array(mem_ctx, struct iovec, num_iov);
311 if (iov == NULL) {
312 return NT_STATUS_NO_MEMORY;
315 while (taken < buflen) {
316 size_t len = buflen - taken;
317 uint8_t *hdr = first_hdr + taken;
318 struct iovec *cur;
319 size_t full_size;
320 size_t next_command_ofs;
321 uint16_t body_size;
322 uint8_t *body = NULL;
323 uint32_t dyn_size;
324 uint8_t *dyn = NULL;
325 struct iovec *iov_tmp;
328 * We need the header plus the body length field
331 if (len < SMB2_HDR_BODY + 2) {
332 DEBUG(10, ("%d bytes left, expected at least %d\n",
333 (int)len, SMB2_HDR_BODY));
334 goto inval;
336 if (IVAL(hdr, 0) != SMB2_MAGIC) {
337 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
338 IVAL(hdr, 0)));
339 goto inval;
341 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
342 DEBUG(10, ("Got HDR len %d, expected %d\n",
343 SVAL(hdr, 4), SMB2_HDR_BODY));
344 goto inval;
347 full_size = len;
348 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
349 body_size = SVAL(hdr, SMB2_HDR_BODY);
351 if (next_command_ofs != 0) {
352 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
353 goto inval;
355 if (next_command_ofs > full_size) {
356 goto inval;
358 full_size = next_command_ofs;
360 if (body_size < 2) {
361 goto inval;
363 body_size &= 0xfffe;
365 if (body_size > (full_size - SMB2_HDR_BODY)) {
367 * let the caller handle the error
369 body_size = full_size - SMB2_HDR_BODY;
371 body = hdr + SMB2_HDR_BODY;
372 dyn = body + body_size;
373 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
375 iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
376 num_iov + SMBD_SMB2_NUM_IOV_PER_REQ);
377 if (iov_tmp == NULL) {
378 TALLOC_FREE(iov);
379 return NT_STATUS_NO_MEMORY;
381 iov = iov_tmp;
382 cur = &iov[num_iov];
383 num_iov += SMBD_SMB2_NUM_IOV_PER_REQ;
385 cur[SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
386 cur[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
387 cur[SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
388 cur[SMBD_SMB2_BODY_IOV_OFS].iov_len = body_size;
389 cur[SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
390 cur[SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_size;
392 taken += full_size;
395 *piov = iov;
396 *pnum_iov = num_iov;
397 return NT_STATUS_OK;
399 inval:
400 TALLOC_FREE(iov);
401 return NT_STATUS_INVALID_PARAMETER;
404 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
405 uint8_t *inbuf, size_t size,
406 struct smbd_smb2_request **_req)
408 struct smbd_smb2_request *req;
409 uint32_t protocol_version;
410 const uint8_t *inhdr = NULL;
411 uint16_t cmd;
412 uint32_t next_command_ofs;
413 NTSTATUS status;
414 NTTIME now;
416 if (size < (4 + SMB2_HDR_BODY + 2)) {
417 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
418 return NT_STATUS_INVALID_PARAMETER;
421 inhdr = inbuf + 4;
423 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
424 if (protocol_version != SMB2_MAGIC) {
425 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
426 protocol_version));
427 return NT_STATUS_INVALID_PARAMETER;
430 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
431 if (cmd != SMB2_OP_NEGPROT) {
432 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
433 cmd));
434 return NT_STATUS_INVALID_PARAMETER;
437 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
438 if (next_command_ofs != 0) {
439 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
440 next_command_ofs));
441 return NT_STATUS_INVALID_PARAMETER;
444 req = smbd_smb2_request_allocate(sconn);
445 if (req == NULL) {
446 return NT_STATUS_NO_MEMORY;
448 req->sconn = sconn;
450 talloc_steal(req, inbuf);
452 req->request_time = timeval_current();
453 now = timeval_to_nttime(&req->request_time);
455 status = smbd_smb2_inbuf_parse_compound(sconn->conn,
456 now,
457 inbuf + NBT_HDR_SIZE,
458 size - NBT_HDR_SIZE,
459 req, &req->in.vector,
460 &req->in.vector_count);
461 if (!NT_STATUS_IS_OK(status)) {
462 TALLOC_FREE(req);
463 return status;
466 req->current_idx = 1;
468 *_req = req;
469 return NT_STATUS_OK;
472 static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
473 uint64_t message_id, uint64_t seq_id)
475 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
476 unsigned int offset;
478 if (seq_id < sconn->smb2.seqnum_low) {
479 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
480 "%llu (sequence id %llu) "
481 "(granted = %u, low = %llu, range = %u)\n",
482 (unsigned long long)message_id,
483 (unsigned long long)seq_id,
484 (unsigned int)sconn->smb2.credits_granted,
485 (unsigned long long)sconn->smb2.seqnum_low,
486 (unsigned int)sconn->smb2.seqnum_range));
487 return false;
490 if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
491 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
492 "%llu (sequence id %llu) "
493 "(granted = %u, low = %llu, range = %u)\n",
494 (unsigned long long)message_id,
495 (unsigned long long)seq_id,
496 (unsigned int)sconn->smb2.credits_granted,
497 (unsigned long long)sconn->smb2.seqnum_low,
498 (unsigned int)sconn->smb2.seqnum_range));
499 return false;
502 offset = seq_id % sconn->smb2.max_credits;
504 if (bitmap_query(credits_bm, offset)) {
505 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
506 "%llu (sequence id %llu) "
507 "(granted = %u, low = %llu, range = %u) "
508 "(bm offset %u)\n",
509 (unsigned long long)message_id,
510 (unsigned long long)seq_id,
511 (unsigned int)sconn->smb2.credits_granted,
512 (unsigned long long)sconn->smb2.seqnum_low,
513 (unsigned int)sconn->smb2.seqnum_range,
514 offset));
515 return false;
518 /* Mark the message_ids as seen in the bitmap. */
519 bitmap_set(credits_bm, offset);
521 if (seq_id != sconn->smb2.seqnum_low) {
522 return true;
526 * Move the window forward by all the message_id's
527 * already seen.
529 while (bitmap_query(credits_bm, offset)) {
530 DEBUG(10,("smb2_validate_sequence_number: clearing "
531 "id %llu (position %u) from bitmap\n",
532 (unsigned long long)(sconn->smb2.seqnum_low),
533 offset));
534 bitmap_clear(credits_bm, offset);
536 sconn->smb2.seqnum_low += 1;
537 sconn->smb2.seqnum_range -= 1;
538 offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
541 return true;
544 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
545 const uint8_t *inhdr)
547 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
548 uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
549 uint16_t credit_charge = 1;
550 uint64_t i;
552 if (opcode == SMB2_OP_CANCEL) {
553 /* SMB2_CANCEL requests by definition resend messageids. */
554 return true;
557 if (sconn->smb2.supports_multicredit) {
558 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
559 credit_charge = MAX(credit_charge, 1);
562 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
563 "credits_granted %llu, "
564 "seqnum low/range: %llu/%llu\n",
565 (unsigned long long) message_id,
566 (unsigned long long) credit_charge,
567 (unsigned long long) sconn->smb2.credits_granted,
568 (unsigned long long) sconn->smb2.seqnum_low,
569 (unsigned long long) sconn->smb2.seqnum_range));
571 if (sconn->smb2.credits_granted < credit_charge) {
572 DEBUG(0, ("smb2_validate_message_id: client used more "
573 "credits than granted, mid %llu, charge %llu, "
574 "credits_granted %llu, "
575 "seqnum low/range: %llu/%llu\n",
576 (unsigned long long) message_id,
577 (unsigned long long) credit_charge,
578 (unsigned long long) sconn->smb2.credits_granted,
579 (unsigned long long) sconn->smb2.seqnum_low,
580 (unsigned long long) sconn->smb2.seqnum_range));
581 return false;
585 * now check the message ids
587 * for multi-credit requests we need to check all current mid plus
588 * the implicit mids caused by the credit charge
589 * e.g. current mid = 15, charge 5 => mark 15-19 as used
592 for (i = 0; i <= (credit_charge-1); i++) {
593 uint64_t id = message_id + i;
594 bool ok;
596 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
597 (unsigned long long)message_id,
598 credit_charge,
599 (unsigned long long)id));
601 ok = smb2_validate_sequence_number(sconn, message_id, id);
602 if (!ok) {
603 return false;
607 /* substract used credits */
608 sconn->smb2.credits_granted -= credit_charge;
610 return true;
613 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
615 int count;
616 int idx;
618 count = req->in.vector_count;
620 if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
621 /* It's not a SMB2 request */
622 return NT_STATUS_INVALID_PARAMETER;
625 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
626 struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
627 struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx);
628 const uint8_t *inhdr = NULL;
629 uint32_t flags;
631 if (hdr->iov_len != SMB2_HDR_BODY) {
632 return NT_STATUS_INVALID_PARAMETER;
635 if (body->iov_len < 2) {
636 return NT_STATUS_INVALID_PARAMETER;
639 inhdr = (const uint8_t *)hdr->iov_base;
641 /* Check the SMB2 header */
642 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
643 return NT_STATUS_INVALID_PARAMETER;
646 if (!smb2_validate_message_id(req->sconn, inhdr)) {
647 return NT_STATUS_INVALID_PARAMETER;
650 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
651 if (idx < SMBD_SMB2_NUM_IOV_PER_REQ) {
653 * the 1st request should never have the
654 * SMB2_HDR_FLAG_CHAINED flag set
656 if (flags & SMB2_HDR_FLAG_CHAINED) {
657 req->next_status = NT_STATUS_INVALID_PARAMETER;
658 return NT_STATUS_OK;
660 } else if (idx < 2*SMBD_SMB2_NUM_IOV_PER_REQ) {
662 * the 2nd request triggers related vs. unrelated
663 * compounded requests
665 if (flags & SMB2_HDR_FLAG_CHAINED) {
666 req->compound_related = true;
668 } else {
669 #if 0
671 * It seems the this tests are wrong
672 * see the SMB2-COMPOUND test
676 * all other requests should match the 2nd one
678 if (flags & SMB2_HDR_FLAG_CHAINED) {
679 if (!req->compound_related) {
680 req->next_status =
681 NT_STATUS_INVALID_PARAMETER;
682 return NT_STATUS_OK;
684 } else {
685 if (req->compound_related) {
686 req->next_status =
687 NT_STATUS_INVALID_PARAMETER;
688 return NT_STATUS_OK;
691 #endif
695 return NT_STATUS_OK;
698 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
699 const struct iovec *in_vector,
700 struct iovec *out_vector)
702 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
703 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
704 uint16_t credit_charge = 1;
705 uint16_t credits_requested;
706 uint32_t out_flags;
707 uint16_t cmd;
708 NTSTATUS out_status;
709 uint16_t credits_granted = 0;
710 uint64_t credits_possible;
711 uint16_t current_max_credits;
714 * first we grant only 1/16th of the max range.
716 * Windows also starts with the 1/16th and then grants
717 * more later. I was only able to trigger higher
718 * values, when using a verify high credit charge.
720 * TODO: scale up depending one load, free memory
721 * or other stuff.
722 * Maybe also on the relationship between number
723 * of requests and the used sequence number.
724 * Which means we would grant more credits
725 * for client which use multi credit requests.
727 current_max_credits = sconn->smb2.max_credits / 16;
728 current_max_credits = MAX(current_max_credits, 1);
730 if (sconn->smb2.supports_multicredit) {
731 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
732 credit_charge = MAX(credit_charge, 1);
735 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
736 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
737 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
738 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
740 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
741 SMB_ASSERT(sconn->smb2.max_credits >= credit_charge);
743 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
745 * In case we already send an async interim
746 * response, we should not grant
747 * credits on the final response.
749 credits_granted = 0;
750 } else if (credits_requested > 0) {
751 uint16_t additional_max = 0;
752 uint16_t additional_credits = credits_requested - 1;
754 switch (cmd) {
755 case SMB2_OP_NEGPROT:
756 break;
757 case SMB2_OP_SESSSETUP:
759 * Windows 2012 RC1 starts to grant
760 * additional credits
761 * with a successful session setup
763 if (NT_STATUS_IS_OK(out_status)) {
764 additional_max = 32;
766 break;
767 default:
769 * We match windows and only grant additional credits
770 * in chunks of 32.
772 additional_max = 32;
773 break;
776 additional_credits = MIN(additional_credits, additional_max);
778 credits_granted = credit_charge + additional_credits;
779 } else if (sconn->smb2.credits_granted == 0) {
781 * Make sure the client has always at least one credit
783 credits_granted = 1;
787 * sequence numbers should not wrap
789 * 1. calculate the possible credits until
790 * the sequence numbers start to wrap on 64-bit.
792 * 2. UINT64_MAX is used for Break Notifications.
794 * 2. truncate the possible credits to the maximum
795 * credits we want to grant to the client in total.
797 * 3. remove the range we'll already granted to the client
798 * this makes sure the client consumes the lowest sequence
799 * number, before we can grant additional credits.
801 credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
802 if (credits_possible > 0) {
803 /* remove UINT64_MAX */
804 credits_possible -= 1;
806 credits_possible = MIN(credits_possible, current_max_credits);
807 credits_possible -= sconn->smb2.seqnum_range;
809 credits_granted = MIN(credits_granted, credits_possible);
811 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
812 sconn->smb2.credits_granted += credits_granted;
813 sconn->smb2.seqnum_range += credits_granted;
815 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
816 "granted %u, current possible/max %u/%u, "
817 "total granted/max/low/range %u/%u/%llu/%u\n",
818 (unsigned int)credits_requested,
819 (unsigned int)credit_charge,
820 (unsigned int)credits_granted,
821 (unsigned int)credits_possible,
822 (unsigned int)current_max_credits,
823 (unsigned int)sconn->smb2.credits_granted,
824 (unsigned int)sconn->smb2.max_credits,
825 (unsigned long long)sconn->smb2.seqnum_low,
826 (unsigned int)sconn->smb2.seqnum_range));
829 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
830 struct smbd_smb2_request *outreq)
832 int count, idx;
833 uint16_t total_credits = 0;
835 count = outreq->out.vector_count;
837 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
838 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(inreq,in,idx);
839 struct iovec *outhdr_v = SMBD_SMB2_IDX_HDR_IOV(outreq,out,idx);
840 uint8_t *outhdr = (uint8_t *)outhdr_v->iov_base;
842 smb2_set_operation_credit(outreq->sconn, inhdr_v, outhdr_v);
844 /* To match Windows, count up what we
845 just granted. */
846 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
847 /* Set to zero in all but the last reply. */
848 if (idx + SMBD_SMB2_NUM_IOV_PER_REQ < count) {
849 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
850 } else {
851 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
856 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
858 struct iovec *vector;
859 int count;
860 int idx;
862 count = req->in.vector_count;
863 vector = talloc_zero_array(req, struct iovec, count);
864 if (vector == NULL) {
865 return NT_STATUS_NO_MEMORY;
868 vector[0].iov_base = req->out.nbt_hdr;
869 vector[0].iov_len = 4;
870 SIVAL(req->out.nbt_hdr, 0, 0);
872 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
873 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
874 const uint8_t *inhdr = (const uint8_t *)inhdr_v->iov_base;
875 uint8_t *outhdr = NULL;
876 uint8_t *outbody = NULL;
877 uint32_t next_command_ofs = 0;
878 struct iovec *current = &vector[idx];
880 if ((idx + SMBD_SMB2_NUM_IOV_PER_REQ) < count) {
881 /* we have a next command -
882 * setup for the error case. */
883 next_command_ofs = SMB2_HDR_BODY + 9;
886 outhdr = talloc_zero_array(vector, uint8_t,
887 OUTVEC_ALLOC_SIZE);
888 if (outhdr == NULL) {
889 return NT_STATUS_NO_MEMORY;
892 outbody = outhdr + SMB2_HDR_BODY;
894 current[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)outhdr;
895 current[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
897 current[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)outbody;
898 current[SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
900 current[SMBD_SMB2_DYN_IOV_OFS].iov_base = NULL;
901 current[SMBD_SMB2_DYN_IOV_OFS].iov_len = 0;
903 /* setup the SMB2 header */
904 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
905 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
906 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
907 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
908 SIVAL(outhdr, SMB2_HDR_STATUS,
909 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
910 SSVAL(outhdr, SMB2_HDR_OPCODE,
911 SVAL(inhdr, SMB2_HDR_OPCODE));
912 SIVAL(outhdr, SMB2_HDR_FLAGS,
913 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
914 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
915 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
916 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
917 SIVAL(outhdr, SMB2_HDR_PID,
918 IVAL(inhdr, SMB2_HDR_PID));
919 SIVAL(outhdr, SMB2_HDR_TID,
920 IVAL(inhdr, SMB2_HDR_TID));
921 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
922 BVAL(inhdr, SMB2_HDR_SESSION_ID));
923 memcpy(outhdr + SMB2_HDR_SIGNATURE,
924 inhdr + SMB2_HDR_SIGNATURE, 16);
926 /* setup error body header */
927 SSVAL(outbody, 0x00, 0x08 + 1);
928 SSVAL(outbody, 0x02, 0);
929 SIVAL(outbody, 0x04, 0);
932 req->out.vector = vector;
933 req->out.vector_count = count;
935 /* setup the length of the NBT packet */
936 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
938 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
940 return NT_STATUS_OK;
943 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
944 const char *reason,
945 const char *location)
947 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
948 reason, location));
949 exit_server_cleanly(reason);
952 static bool dup_smb2_vec3(TALLOC_CTX *ctx,
953 struct iovec *outvec,
954 const struct iovec *srcvec)
956 const uint8_t *srchdr;
957 size_t srchdr_len;
958 const uint8_t *srcbody;
959 size_t srcbody_len;
960 const uint8_t *expected_srcbody;
961 const uint8_t *srcdyn;
962 size_t srcdyn_len;
963 const uint8_t *expected_srcdyn;
964 uint8_t *dsthdr;
965 uint8_t *dstbody;
966 uint8_t *dstdyn;
968 srchdr = (const uint8_t *)srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base;
969 srchdr_len = srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_len;
970 srcbody = (const uint8_t *)srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_base;
971 srcbody_len = srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_len;
972 expected_srcbody = srchdr + SMB2_HDR_BODY;
973 srcdyn = (const uint8_t *)srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_base;
974 srcdyn_len = srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_len;
975 expected_srcdyn = srcbody + 8;
977 if (srchdr_len != SMB2_HDR_BODY) {
978 return false;
981 /* vec[SMBD_SMB2_HDR_IOV_OFS] is always boilerplate and must
982 * be allocated with size OUTVEC_ALLOC_SIZE. */
984 dsthdr = talloc_memdup(ctx, srchdr, OUTVEC_ALLOC_SIZE);
985 if (dsthdr == NULL) {
986 return false;
988 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)dsthdr;
989 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
992 * If this is a "standard" vec[SMBD_SMB2_BOFY_IOV_OFS] of length 8,
993 * pointing to srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + SMB2_HDR_BODY,
994 * then duplicate this. Else use talloc_memdup().
997 if ((srcbody == expected_srcbody) && (srcbody_len == 8)) {
998 dstbody = dsthdr + SMB2_HDR_BODY;
999 } else {
1000 dstbody = talloc_memdup(ctx, srcbody, srcbody_len);
1001 if (dstbody == NULL) {
1002 return false;
1005 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)dstbody;
1006 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_len = srcbody_len;
1009 * If this is a "standard" vec[SMBD_SMB2_DYN_IOV_OFS] of length 1,
1010 * pointing to
1011 * srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + 8
1012 * then duplicate this. Else use talloc_memdup().
1015 if ((srcdyn == expected_srcdyn) && (srcdyn_len == 1)) {
1016 dstdyn = dsthdr + SMB2_HDR_BODY + 8;
1017 } else if (srcdyn == NULL) {
1018 dstdyn = NULL;
1019 } else {
1020 dstdyn = talloc_memdup(ctx, srcdyn, srcdyn_len);
1021 if (dstdyn == NULL) {
1022 return false;
1025 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_base = (void *)dstdyn;
1026 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_len = srcdyn_len;
1028 return true;
1031 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
1033 struct smbd_smb2_request *newreq = NULL;
1034 struct iovec *outvec = NULL;
1035 int count = req->out.vector_count;
1036 int i;
1038 newreq = smbd_smb2_request_allocate(req->sconn);
1039 if (!newreq) {
1040 return NULL;
1043 newreq->sconn = req->sconn;
1044 newreq->session = req->session;
1045 newreq->do_encryption = req->do_encryption;
1046 newreq->do_signing = req->do_signing;
1047 newreq->current_idx = req->current_idx;
1049 outvec = talloc_zero_array(newreq, struct iovec, count);
1050 if (!outvec) {
1051 TALLOC_FREE(newreq);
1052 return NULL;
1054 newreq->out.vector = outvec;
1055 newreq->out.vector_count = count;
1057 /* Setup the outvec's identically to req. */
1058 outvec[0].iov_base = newreq->out.nbt_hdr;
1059 outvec[0].iov_len = 4;
1060 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
1062 /* Setup the vectors identically to the ones in req. */
1063 for (i = 1; i < count; i += SMBD_SMB2_NUM_IOV_PER_REQ) {
1064 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
1065 break;
1069 if (i < count) {
1070 /* Alloc failed. */
1071 TALLOC_FREE(newreq);
1072 return NULL;
1075 smb2_setup_nbt_length(newreq->out.vector,
1076 newreq->out.vector_count);
1078 return newreq;
1081 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
1083 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1085 struct smbXsrv_connection *conn = req->sconn->conn;
1086 struct iovec *outhdr_v = NULL;
1087 uint8_t *outhdr = NULL;
1088 struct smbd_smb2_request *nreq = NULL;
1089 NTSTATUS status;
1091 /* Create a new smb2 request we'll use
1092 for the interim return. */
1093 nreq = dup_smb2_req(req);
1094 if (!nreq) {
1095 return NT_STATUS_NO_MEMORY;
1098 /* Lose the last X out vectors. They're the
1099 ones we'll be using for the async reply. */
1100 nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ;
1102 smb2_setup_nbt_length(nreq->out.vector,
1103 nreq->out.vector_count);
1105 /* Step back to the previous reply. */
1106 nreq->current_idx -= SMBD_SMB2_NUM_IOV_PER_REQ;
1107 outhdr_v = SMBD_SMB2_OUT_HDR_IOV(nreq);
1108 outhdr = SMBD_SMB2_OUT_HDR_PTR(nreq);
1109 /* And end the chain. */
1110 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1112 /* Calculate outgoing credits */
1113 smb2_calculate_credits(req, nreq);
1116 * As we have changed the header (SMB2_HDR_NEXT_COMMAND),
1117 * we need to sign here with the last signing key we remembered
1119 if (req->last_key.length > 0) {
1120 status = smb2_signing_sign_pdu(req->last_key,
1121 conn->protocol,
1122 outhdr_v,
1123 SMBD_SMB2_NUM_IOV_PER_REQ);
1124 if (!NT_STATUS_IS_OK(status)) {
1125 return status;
1129 if (DEBUGLEVEL >= 10) {
1130 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1131 (unsigned int)nreq->current_idx );
1132 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1133 (unsigned int)nreq->out.vector_count );
1134 print_req_vectors(nreq);
1136 nreq->subreq = tstream_writev_queue_send(nreq,
1137 nreq->sconn->ev_ctx,
1138 nreq->sconn->smb2.stream,
1139 nreq->sconn->smb2.send_queue,
1140 nreq->out.vector,
1141 nreq->out.vector_count);
1143 if (nreq->subreq == NULL) {
1144 return NT_STATUS_NO_MEMORY;
1147 tevent_req_set_callback(nreq->subreq,
1148 smbd_smb2_request_writev_done,
1149 nreq);
1151 return NT_STATUS_OK;
1154 struct smbd_smb2_request_pending_state {
1155 struct smbd_server_connection *sconn;
1156 uint8_t buf[NBT_HDR_SIZE + SMB2_HDR_BODY + 0x08 + 1];
1157 struct iovec vector[1 + SMBD_SMB2_NUM_IOV_PER_REQ];
1160 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
1162 struct smbd_smb2_request_pending_state *state =
1163 tevent_req_callback_data(subreq,
1164 struct smbd_smb2_request_pending_state);
1165 struct smbd_server_connection *sconn = state->sconn;
1166 int ret;
1167 int sys_errno;
1169 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1170 TALLOC_FREE(subreq);
1171 if (ret == -1) {
1172 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1173 smbd_server_connection_terminate(sconn, nt_errstr(status));
1174 return;
1177 TALLOC_FREE(state);
1180 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1181 struct tevent_timer *te,
1182 struct timeval current_time,
1183 void *private_data);
1185 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1186 struct tevent_req *subreq,
1187 uint32_t defer_time)
1189 NTSTATUS status;
1190 int idx = req->current_idx;
1191 struct timeval defer_endtime;
1192 uint8_t *outhdr = NULL;
1193 uint32_t flags;
1195 if (!tevent_req_is_in_progress(subreq)) {
1196 return NT_STATUS_OK;
1199 req->subreq = subreq;
1200 subreq = NULL;
1202 if (req->async_te) {
1203 /* We're already async. */
1204 return NT_STATUS_OK;
1207 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1208 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1209 if (flags & SMB2_HDR_FLAG_ASYNC) {
1210 /* We're already async. */
1211 return NT_STATUS_OK;
1214 if (req->in.vector_count > idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
1216 * We're trying to go async in a compound
1217 * request chain. This is not allowed.
1218 * Cancel the outstanding request.
1220 tevent_req_cancel(req->subreq);
1221 return smbd_smb2_request_error(req,
1222 NT_STATUS_INSUFFICIENT_RESOURCES);
1225 if (DEBUGLEVEL >= 10) {
1226 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1227 (unsigned int)req->current_idx );
1228 print_req_vectors(req);
1231 if (req->out.vector_count >= (2*SMBD_SMB2_NUM_IOV_PER_REQ)) {
1233 * This is a compound reply. We
1234 * must do an interim response
1235 * followed by the async response
1236 * to match W2K8R2.
1238 status = smb2_send_async_interim_response(req);
1239 if (!NT_STATUS_IS_OK(status)) {
1240 return status;
1244 * We're splitting off the last SMB2
1245 * request in a compound set, and the
1246 * smb2_send_async_interim_response()
1247 * call above just sent all the replies
1248 * for the previous SMB2 requests in
1249 * this compound set. So we're no longer
1250 * in the "compound_related_in_progress"
1251 * state, and this is no longer a compound
1252 * request.
1254 req->compound_related = false;
1255 req->sconn->smb2.compound_related_in_progress = false;
1257 req->current_idx = 1;
1259 /* Re-arrange the in.vectors. */
1260 memmove(&req->in.vector[req->current_idx],
1261 &req->in.vector[idx],
1262 sizeof(req->in.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
1263 req->in.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
1265 /* Re-arrange the out.vectors. */
1266 memmove(&req->out.vector[req->current_idx],
1267 &req->out.vector[idx],
1268 sizeof(req->out.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
1269 req->out.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
1271 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1272 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1273 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1275 data_blob_clear_free(&req->last_key);
1277 defer_endtime = timeval_current_ofs_usec(defer_time);
1278 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1279 req, defer_endtime,
1280 smbd_smb2_request_pending_timer,
1281 req);
1282 if (req->async_te == NULL) {
1283 return NT_STATUS_NO_MEMORY;
1286 return NT_STATUS_OK;
1289 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1290 struct tevent_timer *te,
1291 struct timeval current_time,
1292 void *private_data)
1294 struct smbd_smb2_request *req =
1295 talloc_get_type_abort(private_data,
1296 struct smbd_smb2_request);
1297 struct smbd_smb2_request_pending_state *state = NULL;
1298 uint8_t *outhdr = NULL;
1299 const uint8_t *inhdr = NULL;
1300 uint8_t *hdr = NULL;
1301 uint8_t *body = NULL;
1302 uint8_t *dyn = NULL;
1303 uint32_t flags = 0;
1304 uint64_t message_id = 0;
1305 uint64_t async_id = 0;
1306 struct tevent_req *subreq = NULL;
1308 TALLOC_FREE(req->async_te);
1310 /* Ensure our final reply matches the interim one. */
1311 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1312 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1313 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1314 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1316 async_id = message_id; /* keep it simple for now... */
1318 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1319 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1321 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1322 "going async\n",
1323 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1324 (unsigned long long)async_id ));
1327 * What we send is identical to a smbd_smb2_request_error
1328 * packet with an error status of STATUS_PENDING. Make use
1329 * of this fact sometime when refactoring. JRA.
1332 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1333 if (state == NULL) {
1334 smbd_server_connection_terminate(req->sconn,
1335 nt_errstr(NT_STATUS_NO_MEMORY));
1336 return;
1338 state->sconn = req->sconn;
1341 hdr = state->buf + NBT_HDR_SIZE;
1342 body = hdr + SMB2_HDR_BODY;
1343 dyn = body + 8;
1348 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1349 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1350 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1351 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1352 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1354 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1355 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1356 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1357 SBVAL(hdr, SMB2_HDR_PID, async_id);
1358 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1359 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1360 memcpy(hdr+SMB2_HDR_SIGNATURE,
1361 outhdr+SMB2_HDR_SIGNATURE, 16);
1363 SSVAL(body, 0x00, 0x08 + 1);
1365 SCVAL(body, 0x02, 0);
1366 SCVAL(body, 0x03, 0);
1367 SIVAL(body, 0x04, 0);
1368 /* Match W2K8R2... */
1369 SCVAL(dyn, 0x00, 0x21);
1371 state->vector[0].iov_base = (void *)state->buf;
1372 state->vector[0].iov_len = NBT_HDR_SIZE;
1374 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1375 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1377 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1378 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1380 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1381 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1383 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1385 /* Ensure we correctly go through crediting. Grant
1386 the credits now, and zero credits on the final
1387 response. */
1388 smb2_set_operation_credit(req->sconn,
1389 SMBD_SMB2_IN_HDR_IOV(req),
1390 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1392 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1394 if (req->do_signing) {
1395 NTSTATUS status;
1396 struct smbXsrv_session *x = req->session;
1397 struct smbXsrv_connection *conn = x->connection;
1398 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1400 status = smb2_signing_sign_pdu(signing_key,
1401 conn->protocol,
1402 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1403 SMBD_SMB2_NUM_IOV_PER_REQ);
1404 if (!NT_STATUS_IS_OK(status)) {
1405 smbd_server_connection_terminate(req->sconn,
1406 nt_errstr(status));
1407 return;
1411 subreq = tstream_writev_queue_send(state,
1412 state->sconn->ev_ctx,
1413 state->sconn->smb2.stream,
1414 state->sconn->smb2.send_queue,
1415 state->vector,
1416 ARRAY_SIZE(state->vector));
1417 if (subreq == NULL) {
1418 smbd_server_connection_terminate(state->sconn,
1419 nt_errstr(NT_STATUS_NO_MEMORY));
1420 return;
1422 tevent_req_set_callback(subreq,
1423 smbd_smb2_request_pending_writev_done,
1424 state);
1427 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1429 struct smbd_server_connection *sconn = req->sconn;
1430 struct smbd_smb2_request *cur;
1431 const uint8_t *inhdr;
1432 uint32_t flags;
1433 uint64_t search_message_id;
1434 uint64_t search_async_id;
1435 uint64_t found_id;
1437 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1439 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1440 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1441 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1444 * we don't need the request anymore
1445 * cancel requests never have a response
1447 DLIST_REMOVE(req->sconn->smb2.requests, req);
1448 TALLOC_FREE(req);
1450 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1451 const uint8_t *outhdr;
1452 uint64_t message_id;
1453 uint64_t async_id;
1455 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1457 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1458 async_id = BVAL(outhdr, SMB2_HDR_PID);
1460 if (flags & SMB2_HDR_FLAG_ASYNC) {
1461 if (search_async_id == async_id) {
1462 found_id = async_id;
1463 break;
1465 } else {
1466 if (search_message_id == message_id) {
1467 found_id = message_id;
1468 break;
1473 if (cur && cur->subreq) {
1474 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1475 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1476 "cancel opcode[%s] mid %llu\n",
1477 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1478 (unsigned long long)found_id ));
1479 tevent_req_cancel(cur->subreq);
1482 return NT_STATUS_OK;
1485 /*************************************************************
1486 Ensure an incoming tid is a valid one for us to access.
1487 Change to the associated uid credentials and chdir to the
1488 valid tid directory.
1489 *************************************************************/
1491 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1493 const uint8_t *inhdr;
1494 uint32_t in_flags;
1495 uint32_t in_tid;
1496 struct smbXsrv_tcon *tcon;
1497 NTSTATUS status;
1498 NTTIME now = timeval_to_nttime(&req->request_time);
1500 req->tcon = NULL;
1502 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1504 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1505 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1507 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1508 in_tid = req->last_tid;
1511 status = smb2srv_tcon_lookup(req->session,
1512 in_tid, now, &tcon);
1513 if (!NT_STATUS_IS_OK(status)) {
1514 return status;
1517 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1518 return NT_STATUS_ACCESS_DENIED;
1521 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1522 if (!set_current_service(tcon->compat, 0, true)) {
1523 return NT_STATUS_ACCESS_DENIED;
1526 req->tcon = tcon;
1527 req->last_tid = in_tid;
1529 return NT_STATUS_OK;
1532 /*************************************************************
1533 Ensure an incoming session_id is a valid one for us to access.
1534 *************************************************************/
1536 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1538 const uint8_t *inhdr;
1539 uint32_t in_flags;
1540 uint16_t in_opcode;
1541 uint64_t in_session_id;
1542 struct smbXsrv_session *session = NULL;
1543 struct auth_session_info *session_info;
1544 NTSTATUS status;
1545 NTTIME now = timeval_to_nttime(&req->request_time);
1547 req->session = NULL;
1548 req->tcon = NULL;
1550 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1552 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1553 in_opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1554 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1556 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1557 in_session_id = req->last_session_id;
1560 /* lookup an existing session */
1561 status = smb2srv_session_lookup(req->sconn->conn,
1562 in_session_id, now,
1563 &session);
1564 if (session) {
1565 req->session = session;
1566 req->last_session_id = in_session_id;
1568 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1569 switch (in_opcode) {
1570 case SMB2_OP_SESSSETUP:
1571 status = NT_STATUS_OK;
1572 break;
1573 default:
1574 break;
1577 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1578 switch (in_opcode) {
1579 case SMB2_OP_TCON:
1580 case SMB2_OP_CREATE:
1581 case SMB2_OP_GETINFO:
1582 case SMB2_OP_SETINFO:
1583 return NT_STATUS_INVALID_HANDLE;
1584 default:
1586 * Notice the check for
1587 * (session_info == NULL)
1588 * below.
1590 status = NT_STATUS_OK;
1591 break;
1594 if (!NT_STATUS_IS_OK(status)) {
1595 return status;
1598 session_info = session->global->auth_session_info;
1599 if (session_info == NULL) {
1600 return NT_STATUS_INVALID_HANDLE;
1603 set_current_user_info(session_info->unix_info->sanitized_username,
1604 session_info->unix_info->unix_name,
1605 session_info->info->domain_name);
1607 return NT_STATUS_OK;
1610 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1611 uint32_t data_length)
1613 uint16_t needed_charge;
1614 uint16_t credit_charge = 1;
1615 const uint8_t *inhdr;
1617 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1619 if (req->sconn->smb2.supports_multicredit) {
1620 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1621 credit_charge = MAX(credit_charge, 1);
1624 needed_charge = (data_length - 1)/ 65536 + 1;
1626 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1627 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1628 credit_charge, needed_charge));
1630 if (needed_charge > credit_charge) {
1631 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1632 credit_charge, needed_charge));
1633 return NT_STATUS_INVALID_PARAMETER;
1636 return NT_STATUS_OK;
1639 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1640 size_t expected_body_size)
1642 struct iovec *inhdr_v;
1643 const uint8_t *inhdr;
1644 uint16_t opcode;
1645 const uint8_t *inbody;
1646 size_t body_size;
1647 size_t min_dyn_size = expected_body_size & 0x00000001;
1648 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1651 * The following should be checked already.
1653 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1654 return NT_STATUS_INTERNAL_ERROR;
1656 if (req->current_idx > max_idx) {
1657 return NT_STATUS_INTERNAL_ERROR;
1660 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1661 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1662 return NT_STATUS_INTERNAL_ERROR;
1664 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1665 return NT_STATUS_INTERNAL_ERROR;
1668 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1669 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1671 switch (opcode) {
1672 case SMB2_OP_IOCTL:
1673 case SMB2_OP_GETINFO:
1674 min_dyn_size = 0;
1675 break;
1679 * Now check the expected body size,
1680 * where the last byte might be in the
1681 * dynamic section..
1683 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1684 return NT_STATUS_INVALID_PARAMETER;
1686 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1687 return NT_STATUS_INVALID_PARAMETER;
1690 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1692 body_size = SVAL(inbody, 0x00);
1693 if (body_size != expected_body_size) {
1694 return NT_STATUS_INVALID_PARAMETER;
1697 return NT_STATUS_OK;
1700 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1702 struct smbXsrv_connection *conn = req->sconn->conn;
1703 const struct smbd_smb2_dispatch_table *call = NULL;
1704 const uint8_t *inhdr;
1705 uint16_t opcode;
1706 uint32_t flags;
1707 uint64_t mid;
1708 NTSTATUS status;
1709 NTSTATUS session_status;
1710 uint32_t allowed_flags;
1711 NTSTATUS return_value;
1712 struct smbXsrv_session *x = NULL;
1713 bool signing_required = false;
1715 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1717 /* TODO: verify more things */
1719 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1720 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1721 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1722 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1723 smb2_opcode_name(opcode),
1724 (unsigned long long)mid));
1726 if (conn->protocol >= PROTOCOL_SMB2_02) {
1728 * once the protocol is negotiated
1729 * SMB2_OP_NEGPROT is not allowed anymore
1731 if (opcode == SMB2_OP_NEGPROT) {
1732 /* drop the connection */
1733 return NT_STATUS_INVALID_PARAMETER;
1735 } else {
1737 * if the protocol is not negotiated yet
1738 * only SMB2_OP_NEGPROT is allowed.
1740 if (opcode != SMB2_OP_NEGPROT) {
1741 /* drop the connection */
1742 return NT_STATUS_INVALID_PARAMETER;
1747 * Check if the client provided a valid session id,
1748 * if so smbd_smb2_request_check_session() calls
1749 * set_current_user_info().
1751 * As some command don't require a valid session id
1752 * we defer the check of the session_status
1754 session_status = smbd_smb2_request_check_session(req);
1755 x = req->session;
1757 if (x != NULL) {
1758 signing_required = x->global->signing_required;
1760 if (opcode == SMB2_OP_SESSSETUP &&
1761 x->global->channels[0].signing_key.length) {
1762 signing_required = true;
1766 call = smbd_smb2_call(opcode);
1767 if (call == NULL) {
1768 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1771 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1772 SMB2_HDR_FLAG_SIGNED |
1773 SMB2_HDR_FLAG_DFS;
1774 if (opcode == SMB2_OP_CANCEL) {
1775 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1777 if ((flags & ~allowed_flags) != 0) {
1778 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1781 req->do_signing = false;
1782 if (flags & SMB2_HDR_FLAG_SIGNED) {
1783 DATA_BLOB signing_key;
1785 if (x == NULL) {
1786 return smbd_smb2_request_error(
1787 req, NT_STATUS_ACCESS_DENIED);
1790 signing_key = x->global->channels[0].signing_key;
1793 * If we have a signing key, we should
1794 * sign the response
1796 if (signing_key.length > 0) {
1797 req->do_signing = true;
1800 status = smb2_signing_check_pdu(signing_key,
1801 conn->protocol,
1802 SMBD_SMB2_IN_HDR_IOV(req),
1803 SMBD_SMB2_NUM_IOV_PER_REQ);
1804 if (!NT_STATUS_IS_OK(status)) {
1805 return smbd_smb2_request_error(req, status);
1809 * Now that we know the request was correctly signed
1810 * we have to sign the response too.
1812 req->do_signing = true;
1814 if (!NT_STATUS_IS_OK(session_status)) {
1815 return smbd_smb2_request_error(req, session_status);
1817 } else if (opcode == SMB2_OP_CANCEL) {
1818 /* Cancel requests are allowed to skip the signing */
1819 } else if (signing_required) {
1821 * If signing is required we try to sign
1822 * a possible error response
1824 req->do_signing = true;
1825 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1828 if (flags & SMB2_HDR_FLAG_CHAINED) {
1830 * This check is mostly for giving the correct error code
1831 * for compounded requests.
1833 * TODO: we may need to move this after the session
1834 * and tcon checks.
1836 if (!NT_STATUS_IS_OK(req->next_status)) {
1837 return smbd_smb2_request_error(req, req->next_status);
1839 } else {
1840 req->compat_chain_fsp = NULL;
1843 if (req->compound_related) {
1844 req->sconn->smb2.compound_related_in_progress = true;
1847 if (call->need_session) {
1848 if (!NT_STATUS_IS_OK(session_status)) {
1849 return smbd_smb2_request_error(req, session_status);
1853 if (call->need_tcon) {
1854 SMB_ASSERT(call->need_session);
1857 * This call needs to be run as user.
1859 * smbd_smb2_request_check_tcon()
1860 * calls change_to_user() on success.
1862 status = smbd_smb2_request_check_tcon(req);
1863 if (!NT_STATUS_IS_OK(status)) {
1864 return smbd_smb2_request_error(req, status);
1868 if (call->fileid_ofs != 0) {
1869 size_t needed = call->fileid_ofs + 16;
1870 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
1871 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
1872 uint64_t file_id_persistent;
1873 uint64_t file_id_volatile;
1874 struct files_struct *fsp;
1876 SMB_ASSERT(call->need_tcon);
1878 if (needed > body_size) {
1879 return smbd_smb2_request_error(req,
1880 NT_STATUS_INVALID_PARAMETER);
1883 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
1884 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
1886 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
1887 if (fsp == NULL) {
1888 if (!call->allow_invalid_fileid) {
1889 return smbd_smb2_request_error(req,
1890 NT_STATUS_FILE_CLOSED);
1893 if (file_id_persistent != UINT64_MAX) {
1894 return smbd_smb2_request_error(req,
1895 NT_STATUS_FILE_CLOSED);
1897 if (file_id_volatile != UINT64_MAX) {
1898 return smbd_smb2_request_error(req,
1899 NT_STATUS_FILE_CLOSED);
1904 if (call->as_root) {
1905 SMB_ASSERT(call->fileid_ofs == 0);
1906 /* This call needs to be run as root */
1907 change_to_root_user();
1908 } else {
1909 SMB_ASSERT(call->need_tcon);
1912 switch (opcode) {
1913 case SMB2_OP_NEGPROT:
1915 START_PROFILE(smb2_negprot);
1916 return_value = smbd_smb2_request_process_negprot(req);
1917 END_PROFILE(smb2_negprot);
1919 break;
1921 case SMB2_OP_SESSSETUP:
1923 START_PROFILE(smb2_sesssetup);
1924 return_value = smbd_smb2_request_process_sesssetup(req);
1925 END_PROFILE(smb2_sesssetup);
1927 break;
1929 case SMB2_OP_LOGOFF:
1931 START_PROFILE(smb2_logoff);
1932 return_value = smbd_smb2_request_process_logoff(req);
1933 END_PROFILE(smb2_logoff);
1935 break;
1937 case SMB2_OP_TCON:
1939 START_PROFILE(smb2_tcon);
1940 return_value = smbd_smb2_request_process_tcon(req);
1941 END_PROFILE(smb2_tcon);
1943 break;
1945 case SMB2_OP_TDIS:
1947 START_PROFILE(smb2_tdis);
1948 return_value = smbd_smb2_request_process_tdis(req);
1949 END_PROFILE(smb2_tdis);
1951 break;
1953 case SMB2_OP_CREATE:
1955 START_PROFILE(smb2_create);
1956 return_value = smbd_smb2_request_process_create(req);
1957 END_PROFILE(smb2_create);
1959 break;
1961 case SMB2_OP_CLOSE:
1963 START_PROFILE(smb2_close);
1964 return_value = smbd_smb2_request_process_close(req);
1965 END_PROFILE(smb2_close);
1967 break;
1969 case SMB2_OP_FLUSH:
1971 START_PROFILE(smb2_flush);
1972 return_value = smbd_smb2_request_process_flush(req);
1973 END_PROFILE(smb2_flush);
1975 break;
1977 case SMB2_OP_READ:
1979 START_PROFILE(smb2_read);
1980 return_value = smbd_smb2_request_process_read(req);
1981 END_PROFILE(smb2_read);
1983 break;
1985 case SMB2_OP_WRITE:
1987 START_PROFILE(smb2_write);
1988 return_value = smbd_smb2_request_process_write(req);
1989 END_PROFILE(smb2_write);
1991 break;
1993 case SMB2_OP_LOCK:
1995 START_PROFILE(smb2_lock);
1996 return_value = smbd_smb2_request_process_lock(req);
1997 END_PROFILE(smb2_lock);
1999 break;
2001 case SMB2_OP_IOCTL:
2003 START_PROFILE(smb2_ioctl);
2004 return_value = smbd_smb2_request_process_ioctl(req);
2005 END_PROFILE(smb2_ioctl);
2007 break;
2009 case SMB2_OP_CANCEL:
2011 START_PROFILE(smb2_cancel);
2012 return_value = smbd_smb2_request_process_cancel(req);
2013 END_PROFILE(smb2_cancel);
2015 break;
2017 case SMB2_OP_KEEPALIVE:
2019 START_PROFILE(smb2_keepalive);
2020 return_value = smbd_smb2_request_process_keepalive(req);
2021 END_PROFILE(smb2_keepalive);
2023 break;
2025 case SMB2_OP_FIND:
2027 START_PROFILE(smb2_find);
2028 return_value = smbd_smb2_request_process_find(req);
2029 END_PROFILE(smb2_find);
2031 break;
2033 case SMB2_OP_NOTIFY:
2035 START_PROFILE(smb2_notify);
2036 return_value = smbd_smb2_request_process_notify(req);
2037 END_PROFILE(smb2_notify);
2039 break;
2041 case SMB2_OP_GETINFO:
2043 START_PROFILE(smb2_getinfo);
2044 return_value = smbd_smb2_request_process_getinfo(req);
2045 END_PROFILE(smb2_getinfo);
2047 break;
2049 case SMB2_OP_SETINFO:
2051 START_PROFILE(smb2_setinfo);
2052 return_value = smbd_smb2_request_process_setinfo(req);
2053 END_PROFILE(smb2_setinfo);
2055 break;
2057 case SMB2_OP_BREAK:
2059 START_PROFILE(smb2_break);
2060 return_value = smbd_smb2_request_process_break(req);
2061 END_PROFILE(smb2_break);
2063 break;
2065 default:
2066 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2067 break;
2069 return return_value;
2072 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2074 struct smbXsrv_connection *conn = req->sconn->conn;
2075 struct tevent_req *subreq;
2076 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2077 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2079 req->subreq = NULL;
2080 TALLOC_FREE(req->async_te);
2082 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2083 (req->last_key.length > 0)) {
2084 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2085 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2086 NTSTATUS status;
2089 * As we are sure the header of the last request in the
2090 * compound chain will not change, we can to sign here
2091 * with the last signing key we remembered.
2094 status = smb2_signing_sign_pdu(req->last_key,
2095 conn->protocol,
2096 lasthdr,
2097 SMBD_SMB2_NUM_IOV_PER_REQ);
2098 if (!NT_STATUS_IS_OK(status)) {
2099 return status;
2102 data_blob_clear_free(&req->last_key);
2104 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2106 if (req->current_idx < req->out.vector_count) {
2108 * We must process the remaining compound
2109 * SMB2 requests before any new incoming SMB2
2110 * requests. This is because incoming SMB2
2111 * requests may include a cancel for a
2112 * compound request we haven't processed
2113 * yet.
2115 struct tevent_immediate *im = tevent_create_immediate(req);
2116 if (!im) {
2117 return NT_STATUS_NO_MEMORY;
2120 if (req->do_signing) {
2121 struct smbXsrv_session *x = req->session;
2122 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2125 * we need to remember the signing key
2126 * and defer the signing until
2127 * we are sure that we do not change
2128 * the header again.
2130 req->last_key = data_blob_dup_talloc(req, signing_key);
2131 if (req->last_key.data == NULL) {
2132 return NT_STATUS_NO_MEMORY;
2136 tevent_schedule_immediate(im,
2137 req->sconn->ev_ctx,
2138 smbd_smb2_request_dispatch_immediate,
2139 req);
2140 return NT_STATUS_OK;
2143 if (req->compound_related) {
2144 req->sconn->smb2.compound_related_in_progress = false;
2147 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2149 /* Set credit for these operations (zero credits if this
2150 is a final reply for an async operation). */
2151 smb2_calculate_credits(req, req);
2154 * now check if we need to sign the current response
2156 if (req->do_signing) {
2157 NTSTATUS status;
2158 struct smbXsrv_session *x = req->session;
2159 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2161 status = smb2_signing_sign_pdu(signing_key,
2162 conn->protocol,
2163 outhdr,
2164 SMBD_SMB2_NUM_IOV_PER_REQ);
2165 if (!NT_STATUS_IS_OK(status)) {
2166 return status;
2170 if (DEBUGLEVEL >= 10) {
2171 dbgtext("smbd_smb2_request_reply: sending...\n");
2172 print_req_vectors(req);
2175 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2176 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2177 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2178 /* Dynamic part is NULL. Chop it off,
2179 We're going to send it via sendfile. */
2180 req->out.vector_count -= 1;
2183 subreq = tstream_writev_queue_send(req,
2184 req->sconn->ev_ctx,
2185 req->sconn->smb2.stream,
2186 req->sconn->smb2.send_queue,
2187 req->out.vector,
2188 req->out.vector_count);
2189 if (subreq == NULL) {
2190 return NT_STATUS_NO_MEMORY;
2192 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
2194 * We're done with this request -
2195 * move it off the "being processed" queue.
2197 DLIST_REMOVE(req->sconn->smb2.requests, req);
2199 return NT_STATUS_OK;
2202 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2204 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2205 struct tevent_immediate *im,
2206 void *private_data)
2208 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2209 struct smbd_smb2_request);
2210 struct smbd_server_connection *sconn = req->sconn;
2211 NTSTATUS status;
2213 TALLOC_FREE(im);
2215 if (DEBUGLEVEL >= 10) {
2216 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2217 req->current_idx, req->in.vector_count));
2218 print_req_vectors(req);
2221 status = smbd_smb2_request_dispatch(req);
2222 if (!NT_STATUS_IS_OK(status)) {
2223 smbd_server_connection_terminate(sconn, nt_errstr(status));
2224 return;
2227 status = smbd_smb2_request_next_incoming(sconn);
2228 if (!NT_STATUS_IS_OK(status)) {
2229 smbd_server_connection_terminate(sconn, nt_errstr(status));
2230 return;
2234 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
2236 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
2237 struct smbd_smb2_request);
2238 struct smbd_server_connection *sconn = req->sconn;
2239 int ret;
2240 int sys_errno;
2241 NTSTATUS status;
2243 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2244 TALLOC_FREE(subreq);
2245 TALLOC_FREE(req);
2246 if (ret == -1) {
2247 status = map_nt_error_from_unix(sys_errno);
2248 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
2249 nt_errstr(status)));
2250 smbd_server_connection_terminate(sconn, nt_errstr(status));
2251 return;
2254 status = smbd_smb2_request_next_incoming(sconn);
2255 if (!NT_STATUS_IS_OK(status)) {
2256 smbd_server_connection_terminate(sconn, nt_errstr(status));
2257 return;
2261 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2262 NTSTATUS status,
2263 DATA_BLOB body, DATA_BLOB *dyn,
2264 const char *location)
2266 uint8_t *outhdr;
2267 struct iovec *outbody_v;
2268 struct iovec *outdyn_v;
2269 uint32_t next_command_ofs;
2271 DEBUG(10,("smbd_smb2_request_done_ex: "
2272 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2273 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2274 dyn ? "yes": "no",
2275 (unsigned int)(dyn ? dyn->length : 0),
2276 location));
2278 if (body.length < 2) {
2279 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2282 if ((body.length % 2) != 0) {
2283 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2286 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2287 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2288 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2290 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2291 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2293 outbody_v->iov_base = (void *)body.data;
2294 outbody_v->iov_len = body.length;
2296 if (dyn) {
2297 outdyn_v->iov_base = (void *)dyn->data;
2298 outdyn_v->iov_len = dyn->length;
2299 } else {
2300 outdyn_v->iov_base = NULL;
2301 outdyn_v->iov_len = 0;
2304 /* see if we need to recalculate the offset to the next response */
2305 if (next_command_ofs > 0) {
2306 next_command_ofs = SMB2_HDR_BODY;
2307 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2308 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2311 if ((next_command_ofs % 8) != 0) {
2312 size_t pad_size = 8 - (next_command_ofs % 8);
2313 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2315 * if the dyn buffer is empty
2316 * we can use it to add padding
2318 uint8_t *pad;
2320 pad = talloc_zero_array(req->out.vector,
2321 uint8_t, pad_size);
2322 if (pad == NULL) {
2323 return smbd_smb2_request_error(req,
2324 NT_STATUS_NO_MEMORY);
2327 outdyn_v->iov_base = (void *)pad;
2328 outdyn_v->iov_len = pad_size;
2329 } else {
2331 * For now we copy the dynamic buffer
2332 * and add the padding to the new buffer
2334 size_t old_size;
2335 uint8_t *old_dyn;
2336 size_t new_size;
2337 uint8_t *new_dyn;
2339 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2340 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2342 new_size = old_size + pad_size;
2343 new_dyn = talloc_zero_array(req->out.vector,
2344 uint8_t, new_size);
2345 if (new_dyn == NULL) {
2346 return smbd_smb2_request_error(req,
2347 NT_STATUS_NO_MEMORY);
2350 memcpy(new_dyn, old_dyn, old_size);
2351 memset(new_dyn + old_size, 0, pad_size);
2353 outdyn_v->iov_base = (void *)new_dyn;
2354 outdyn_v->iov_len = new_size;
2356 next_command_ofs += pad_size;
2359 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2361 return smbd_smb2_request_reply(req);
2364 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2365 NTSTATUS status,
2366 DATA_BLOB *info,
2367 const char *location)
2369 DATA_BLOB body;
2370 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2372 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2373 req->current_idx, nt_errstr(status), info ? " +info" : "",
2374 location));
2376 body.data = outhdr + SMB2_HDR_BODY;
2377 body.length = 8;
2378 SSVAL(body.data, 0, 9);
2380 if (info) {
2381 SIVAL(body.data, 0x04, info->length);
2382 } else {
2383 /* Allocated size of req->out.vector[i].iov_base
2384 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2385 * 1 byte without having to do an alloc.
2387 info = talloc_zero_array(req->out.vector,
2388 DATA_BLOB,
2390 if (!info) {
2391 return NT_STATUS_NO_MEMORY;
2393 info->data = ((uint8_t *)outhdr) +
2394 OUTVEC_ALLOC_SIZE - 1;
2395 info->length = 1;
2396 SCVAL(info->data, 0, 0);
2400 * if a request fails, all other remaining
2401 * compounded requests should fail too
2403 req->next_status = NT_STATUS_INVALID_PARAMETER;
2405 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2409 struct smbd_smb2_send_oplock_break_state {
2410 struct smbd_server_connection *sconn;
2411 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
2412 struct iovec vector;
2415 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2417 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2418 uint64_t file_id_persistent,
2419 uint64_t file_id_volatile,
2420 uint8_t oplock_level)
2422 struct smbd_smb2_send_oplock_break_state *state;
2423 struct tevent_req *subreq;
2424 uint8_t *hdr;
2425 uint8_t *body;
2427 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2428 if (state == NULL) {
2429 return NT_STATUS_NO_MEMORY;
2431 state->sconn = sconn;
2433 state->vector.iov_base = (void *)state->buf;
2434 state->vector.iov_len = sizeof(state->buf);
2436 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
2437 hdr = state->buf + 4;
2438 body = hdr + SMB2_HDR_BODY;
2440 SIVAL(hdr, 0, SMB2_MAGIC);
2441 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2442 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2443 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2444 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2445 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2446 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2447 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2448 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2449 SIVAL(hdr, SMB2_HDR_PID, 0);
2450 SIVAL(hdr, SMB2_HDR_TID, 0);
2451 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2452 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2454 SSVAL(body, 0x00, 0x18);
2456 SCVAL(body, 0x02, oplock_level);
2457 SCVAL(body, 0x03, 0); /* reserved */
2458 SIVAL(body, 0x04, 0); /* reserved */
2459 SBVAL(body, 0x08, file_id_persistent);
2460 SBVAL(body, 0x10, file_id_volatile);
2462 subreq = tstream_writev_queue_send(state,
2463 sconn->ev_ctx,
2464 sconn->smb2.stream,
2465 sconn->smb2.send_queue,
2466 &state->vector, 1);
2467 if (subreq == NULL) {
2468 return NT_STATUS_NO_MEMORY;
2470 tevent_req_set_callback(subreq,
2471 smbd_smb2_oplock_break_writev_done,
2472 state);
2474 return NT_STATUS_OK;
2477 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2479 struct smbd_smb2_send_oplock_break_state *state =
2480 tevent_req_callback_data(subreq,
2481 struct smbd_smb2_send_oplock_break_state);
2482 struct smbd_server_connection *sconn = state->sconn;
2483 int ret;
2484 int sys_errno;
2486 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2487 TALLOC_FREE(subreq);
2488 if (ret == -1) {
2489 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2490 smbd_server_connection_terminate(sconn, nt_errstr(status));
2491 return;
2494 TALLOC_FREE(state);
2497 struct smbd_smb2_request_read_state {
2498 struct tevent_context *ev;
2499 struct smbd_server_connection *sconn;
2500 struct smbd_smb2_request *smb2_req;
2501 struct {
2502 uint8_t nbt[NBT_HDR_SIZE];
2503 bool done;
2504 } hdr;
2505 size_t pktlen;
2506 uint8_t *pktbuf;
2509 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2510 void *private_data,
2511 TALLOC_CTX *mem_ctx,
2512 struct iovec **_vector,
2513 size_t *_count);
2514 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2516 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2517 struct tevent_context *ev,
2518 struct smbd_server_connection *sconn)
2520 struct tevent_req *req;
2521 struct smbd_smb2_request_read_state *state;
2522 struct tevent_req *subreq;
2524 req = tevent_req_create(mem_ctx, &state,
2525 struct smbd_smb2_request_read_state);
2526 if (req == NULL) {
2527 return NULL;
2529 state->ev = ev;
2530 state->sconn = sconn;
2532 state->smb2_req = smbd_smb2_request_allocate(state);
2533 if (tevent_req_nomem(state->smb2_req, req)) {
2534 return tevent_req_post(req, ev);
2536 state->smb2_req->sconn = sconn;
2538 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2539 state->ev,
2540 state->sconn->smb2.stream,
2541 state->sconn->smb2.recv_queue,
2542 smbd_smb2_request_next_vector,
2543 state);
2544 if (tevent_req_nomem(subreq, req)) {
2545 return tevent_req_post(req, ev);
2547 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2549 return req;
2552 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2553 void *private_data,
2554 TALLOC_CTX *mem_ctx,
2555 struct iovec **_vector,
2556 size_t *_count)
2558 struct smbd_smb2_request_read_state *state =
2559 talloc_get_type_abort(private_data,
2560 struct smbd_smb2_request_read_state);
2561 struct iovec *vector;
2563 if (state->pktlen > 0) {
2564 /* if there're no remaining bytes, we're done */
2565 *_vector = NULL;
2566 *_count = 0;
2567 return 0;
2570 if (!state->hdr.done) {
2572 * first we need to get the NBT header
2574 vector = talloc_array(mem_ctx, struct iovec, 1);
2575 if (vector == NULL) {
2576 return -1;
2579 vector[0].iov_base = (void *)state->hdr.nbt;
2580 vector[0].iov_len = NBT_HDR_SIZE;
2582 *_vector = vector;
2583 *_count = 1;
2585 state->hdr.done = true;
2586 return 0;
2590 * Now we analyze the NBT header
2592 state->pktlen = smb2_len(state->hdr.nbt);
2594 if (state->pktlen == 0) {
2595 /* if there're no remaining bytes, we're done */
2596 *_vector = NULL;
2597 *_count = 0;
2598 return 0;
2601 state->pktbuf = talloc_array(state->smb2_req, uint8_t, state->pktlen);
2602 if (state->pktbuf == NULL) {
2603 return -1;
2606 vector = talloc_array(mem_ctx, struct iovec, 1);
2607 if (vector == NULL) {
2608 return -1;
2611 vector[0].iov_base = (void *)state->pktbuf;
2612 vector[0].iov_len = state->pktlen;
2614 *_vector = vector;
2615 *_count = 1;
2616 return 0;
2619 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2621 struct tevent_req *req =
2622 tevent_req_callback_data(subreq,
2623 struct tevent_req);
2624 struct smbd_smb2_request_read_state *state =
2625 tevent_req_data(req,
2626 struct smbd_smb2_request_read_state);
2627 int ret;
2628 int sys_errno;
2629 NTSTATUS status;
2630 NTTIME now;
2632 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2633 TALLOC_FREE(subreq);
2634 if (ret == -1) {
2635 status = map_nt_error_from_unix(sys_errno);
2636 tevent_req_nterror(req, status);
2637 return;
2640 if (state->hdr.nbt[0] != 0x00) {
2641 DEBUG(1,("smbd_smb2_request_read_done: ignore NBT[0x%02X] msg\n",
2642 state->hdr.nbt[0]));
2644 ZERO_STRUCT(state->hdr);
2645 TALLOC_FREE(state->pktbuf);
2646 state->pktlen = 0;
2648 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2649 state->ev,
2650 state->sconn->smb2.stream,
2651 state->sconn->smb2.recv_queue,
2652 smbd_smb2_request_next_vector,
2653 state);
2654 if (tevent_req_nomem(subreq, req)) {
2655 return;
2657 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2658 return;
2661 state->smb2_req->request_time = timeval_current();
2662 now = timeval_to_nttime(&state->smb2_req->request_time);
2664 status = smbd_smb2_inbuf_parse_compound(state->smb2_req->sconn->conn,
2665 now,
2666 state->pktbuf,
2667 state->pktlen,
2668 state->smb2_req,
2669 &state->smb2_req->in.vector,
2670 &state->smb2_req->in.vector_count);
2671 if (tevent_req_nterror(req, status)) {
2672 return;
2675 state->smb2_req->current_idx = 1;
2677 tevent_req_done(req);
2680 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2681 TALLOC_CTX *mem_ctx,
2682 struct smbd_smb2_request **_smb2_req)
2684 struct smbd_smb2_request_read_state *state =
2685 tevent_req_data(req,
2686 struct smbd_smb2_request_read_state);
2687 NTSTATUS status;
2689 if (tevent_req_is_nterror(req, &status)) {
2690 tevent_req_received(req);
2691 return status;
2694 *_smb2_req = talloc_move(mem_ctx, &state->smb2_req);
2695 tevent_req_received(req);
2696 return NT_STATUS_OK;
2699 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2701 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2703 size_t max_send_queue_len;
2704 size_t cur_send_queue_len;
2705 struct tevent_req *subreq;
2707 if (sconn->smb2.compound_related_in_progress) {
2709 * Can't read another until the related
2710 * compound is done.
2712 return NT_STATUS_OK;
2715 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
2717 * if there is already a smbd_smb2_request_read
2718 * pending, we are done.
2720 return NT_STATUS_OK;
2723 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2724 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
2726 if (cur_send_queue_len > max_send_queue_len) {
2728 * if we have a lot of requests to send,
2729 * we wait until they are on the wire until we
2730 * ask for the next request.
2732 return NT_STATUS_OK;
2735 /* ask for the next request */
2736 subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn);
2737 if (subreq == NULL) {
2738 return NT_STATUS_NO_MEMORY;
2740 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2742 return NT_STATUS_OK;
2745 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2746 uint8_t *inbuf, size_t size)
2748 NTSTATUS status;
2749 struct smbd_smb2_request *req = NULL;
2751 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2752 (unsigned int)size));
2754 status = smbd_initialize_smb2(sconn);
2755 if (!NT_STATUS_IS_OK(status)) {
2756 smbd_server_connection_terminate(sconn, nt_errstr(status));
2757 return;
2760 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2761 if (!NT_STATUS_IS_OK(status)) {
2762 smbd_server_connection_terminate(sconn, nt_errstr(status));
2763 return;
2766 status = smbd_smb2_request_validate(req);
2767 if (!NT_STATUS_IS_OK(status)) {
2768 smbd_server_connection_terminate(sconn, nt_errstr(status));
2769 return;
2772 status = smbd_smb2_request_setup_out(req);
2773 if (!NT_STATUS_IS_OK(status)) {
2774 smbd_server_connection_terminate(sconn, nt_errstr(status));
2775 return;
2778 status = smbd_smb2_request_dispatch(req);
2779 if (!NT_STATUS_IS_OK(status)) {
2780 smbd_server_connection_terminate(sconn, nt_errstr(status));
2781 return;
2784 status = smbd_smb2_request_next_incoming(sconn);
2785 if (!NT_STATUS_IS_OK(status)) {
2786 smbd_server_connection_terminate(sconn, nt_errstr(status));
2787 return;
2790 sconn->num_requests++;
2793 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2795 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2796 struct smbd_server_connection);
2797 NTSTATUS status;
2798 struct smbd_smb2_request *req = NULL;
2800 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2801 TALLOC_FREE(subreq);
2802 if (!NT_STATUS_IS_OK(status)) {
2803 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2804 nt_errstr(status)));
2805 smbd_server_connection_terminate(sconn, nt_errstr(status));
2806 return;
2809 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2810 req->current_idx, req->in.vector_count));
2812 status = smbd_smb2_request_validate(req);
2813 if (!NT_STATUS_IS_OK(status)) {
2814 smbd_server_connection_terminate(sconn, nt_errstr(status));
2815 return;
2818 status = smbd_smb2_request_setup_out(req);
2819 if (!NT_STATUS_IS_OK(status)) {
2820 smbd_server_connection_terminate(sconn, nt_errstr(status));
2821 return;
2824 status = smbd_smb2_request_dispatch(req);
2825 if (!NT_STATUS_IS_OK(status)) {
2826 smbd_server_connection_terminate(sconn, nt_errstr(status));
2827 return;
2830 status = smbd_smb2_request_next_incoming(sconn);
2831 if (!NT_STATUS_IS_OK(status)) {
2832 smbd_server_connection_terminate(sconn, nt_errstr(status));
2833 return;
2836 sconn->num_requests++;
2838 /* The timeout_processing function isn't run nearly
2839 often enough to implement 'max log size' without
2840 overrunning the size of the file by many megabytes.
2841 This is especially true if we are running at debug
2842 level 10. Checking every 50 SMB2s is a nice
2843 tradeoff of performance vs log file size overrun. */
2845 if ((sconn->num_requests % 50) == 0 &&
2846 need_to_check_log_size()) {
2847 change_to_root_user();
2848 check_log_size();