s3:smb2_server: implement credit granting similar to windows
[Samba/gebeck_regimport.git] / source3 / smbd / smb2_server.c
blobe4b0277a070d70de96fc809d2de51cbf84198a5e
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 char *smb2_names[] = {
36 "SMB2_NEGPROT",
37 "SMB2_SESSSETUP",
38 "SMB2_LOGOFF",
39 "SMB2_TCON",
40 "SMB2_TDIS",
41 "SMB2_CREATE",
42 "SMB2_CLOSE",
43 "SMB2_FLUSH",
44 "SMB2_READ",
45 "SMB2_WRITE",
46 "SMB2_LOCK",
47 "SMB2_IOCTL",
48 "SMB2_CANCEL",
49 "SMB2_KEEPALIVE",
50 "SMB2_FIND",
51 "SMB2_NOTIFY",
52 "SMB2_GETINFO",
53 "SMB2_SETINFO",
54 "SMB2_BREAK"
57 const char *smb2_opcode_name(uint16_t opcode)
59 if (opcode > 0x12) {
60 return "Bad SMB2 opcode";
62 return smb2_names[opcode];
65 static void print_req_vectors(struct smbd_smb2_request *req)
67 int i;
69 for (i = 0; i < req->in.vector_count; i++) {
70 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
71 (unsigned int)i,
72 (unsigned int)req->in.vector[i].iov_len);
74 for (i = 0; i < req->out.vector_count; i++) {
75 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
76 (unsigned int)i,
77 (unsigned int)req->out.vector[i].iov_len);
81 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
83 if (size < (4 + SMB2_HDR_BODY)) {
84 return false;
87 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
88 return false;
91 return true;
94 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
96 NTSTATUS status;
97 int ret;
99 TALLOC_FREE(sconn->smb1.fde);
101 sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
102 if (sconn->smb2.recv_queue == NULL) {
103 return NT_STATUS_NO_MEMORY;
106 sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
107 if (sconn->smb2.send_queue == NULL) {
108 return NT_STATUS_NO_MEMORY;
111 sconn->smb2.seqnum_low = 0;
112 sconn->smb2.seqnum_range = 1;
113 sconn->smb2.credits_granted = 1;
114 sconn->smb2.max_credits = lp_smb2_max_credits();
115 sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
116 sconn->smb2.max_credits);
117 if (sconn->smb2.credits_bitmap == NULL) {
118 return NT_STATUS_NO_MEMORY;
121 ret = tstream_bsd_existing_socket(sconn, sconn->sock,
122 &sconn->smb2.stream);
123 if (ret == -1) {
124 status = map_nt_error_from_unix(errno);
125 return status;
128 /* Ensure child is set to non-blocking mode */
129 set_blocking(sconn->sock, false);
130 return NT_STATUS_OK;
133 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
134 #define _smb2_setlen(_buf,len) do { \
135 uint8_t *buf = (uint8_t *)_buf; \
136 buf[0] = 0; \
137 buf[1] = ((len)&0xFF0000)>>16; \
138 buf[2] = ((len)&0xFF00)>>8; \
139 buf[3] = (len)&0xFF; \
140 } while (0)
142 static void smb2_setup_nbt_length(struct iovec *vector, int count)
144 size_t len = 0;
145 int i;
147 for (i=1; i < count; i++) {
148 len += vector[i].iov_len;
151 _smb2_setlen(vector[0].iov_base, len);
154 static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request **req)
156 if (*req) {
157 (*req)->parent = NULL;
158 (*req)->mem_pool = NULL;
161 return 0;
164 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
166 if (req->parent) {
167 *req->parent = NULL;
168 talloc_free(req->mem_pool);
171 return 0;
174 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
176 TALLOC_CTX *mem_pool;
177 struct smbd_smb2_request **parent;
178 struct smbd_smb2_request *req;
180 #if 0
181 /* Enable this to find subtle valgrind errors. */
182 mem_pool = talloc_init("smbd_smb2_request_allocate");
183 #else
184 mem_pool = talloc_pool(mem_ctx, 8192);
185 #endif
186 if (mem_pool == NULL) {
187 return NULL;
190 parent = talloc(mem_pool, struct smbd_smb2_request *);
191 if (parent == NULL) {
192 talloc_free(mem_pool);
193 return NULL;
196 req = talloc_zero(parent, struct smbd_smb2_request);
197 if (req == NULL) {
198 talloc_free(mem_pool);
199 return NULL;
201 *parent = req;
202 req->mem_pool = mem_pool;
203 req->parent = parent;
205 req->last_session_id = UINT64_MAX;
206 req->last_tid = UINT32_MAX;
208 talloc_set_destructor(parent, smbd_smb2_request_parent_destructor);
209 talloc_set_destructor(req, smbd_smb2_request_destructor);
211 return req;
214 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
215 const uint8_t *inbuf, size_t size,
216 struct smbd_smb2_request **_req)
218 struct smbd_smb2_request *req;
219 uint32_t protocol_version;
220 const uint8_t *inhdr = NULL;
221 off_t ofs = 0;
222 uint16_t cmd;
223 uint32_t next_command_ofs;
225 if (size < (4 + SMB2_HDR_BODY + 2)) {
226 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
227 return NT_STATUS_INVALID_PARAMETER;
230 inhdr = inbuf + 4;
232 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
233 if (protocol_version != SMB2_MAGIC) {
234 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
235 protocol_version));
236 return NT_STATUS_INVALID_PARAMETER;
239 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
240 if (cmd != SMB2_OP_NEGPROT) {
241 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
242 cmd));
243 return NT_STATUS_INVALID_PARAMETER;
246 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
247 if (next_command_ofs != 0) {
248 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
249 next_command_ofs));
250 return NT_STATUS_INVALID_PARAMETER;
253 req = smbd_smb2_request_allocate(sconn);
254 if (req == NULL) {
255 return NT_STATUS_NO_MEMORY;
257 req->sconn = sconn;
259 talloc_steal(req, inbuf);
261 req->in.vector = talloc_array(req, struct iovec, 4);
262 if (req->in.vector == NULL) {
263 TALLOC_FREE(req);
264 return NT_STATUS_NO_MEMORY;
266 req->in.vector_count = 4;
268 memcpy(req->in.nbt_hdr, inbuf, 4);
270 ofs = 0;
271 req->in.vector[0].iov_base = discard_const_p(void, req->in.nbt_hdr);
272 req->in.vector[0].iov_len = 4;
273 ofs += req->in.vector[0].iov_len;
275 req->in.vector[1].iov_base = discard_const_p(void, (inbuf + ofs));
276 req->in.vector[1].iov_len = SMB2_HDR_BODY;
277 ofs += req->in.vector[1].iov_len;
279 req->in.vector[2].iov_base = discard_const_p(void, (inbuf + ofs));
280 req->in.vector[2].iov_len = SVAL(inbuf, ofs) & 0xFFFE;
281 ofs += req->in.vector[2].iov_len;
283 if (ofs > size) {
284 return NT_STATUS_INVALID_PARAMETER;
287 req->in.vector[3].iov_base = discard_const_p(void, (inbuf + ofs));
288 req->in.vector[3].iov_len = size - ofs;
289 ofs += req->in.vector[3].iov_len;
291 req->current_idx = 1;
293 *_req = req;
294 return NT_STATUS_OK;
297 static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
298 uint64_t message_id, uint64_t seq_id)
300 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
301 unsigned int offset;
303 if (seq_id < sconn->smb2.seqnum_low) {
304 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
305 "%llu (sequence id %llu) "
306 "(granted = %u, low = %llu, range = %u)\n",
307 (unsigned long long)message_id,
308 (unsigned long long)seq_id,
309 (unsigned int)sconn->smb2.credits_granted,
310 (unsigned long long)sconn->smb2.seqnum_low,
311 (unsigned int)sconn->smb2.seqnum_range));
312 return false;
315 if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
316 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
317 "%llu (sequence id %llu) "
318 "(granted = %u, low = %llu, range = %u)\n",
319 (unsigned long long)message_id,
320 (unsigned long long)seq_id,
321 (unsigned int)sconn->smb2.credits_granted,
322 (unsigned long long)sconn->smb2.seqnum_low,
323 (unsigned int)sconn->smb2.seqnum_range));
324 return false;
327 offset = seq_id % sconn->smb2.max_credits;
329 if (bitmap_query(credits_bm, offset)) {
330 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
331 "%llu (sequence id %llu) "
332 "(granted = %u, low = %llu, range = %u) "
333 "(bm offset %u)\n",
334 (unsigned long long)message_id,
335 (unsigned long long)seq_id,
336 (unsigned int)sconn->smb2.credits_granted,
337 (unsigned long long)sconn->smb2.seqnum_low,
338 (unsigned int)sconn->smb2.seqnum_range,
339 offset));
340 return false;
343 /* Mark the message_ids as seen in the bitmap. */
344 bitmap_set(credits_bm, offset);
346 if (seq_id != sconn->smb2.seqnum_low) {
347 return true;
351 * Move the window forward by all the message_id's
352 * already seen.
354 while (bitmap_query(credits_bm, offset)) {
355 DEBUG(10,("smb2_validate_sequence_number: clearing "
356 "id %llu (position %u) from bitmap\n",
357 (unsigned long long)(sconn->smb2.seqnum_low),
358 offset));
359 bitmap_clear(credits_bm, offset);
361 sconn->smb2.seqnum_low += 1;
362 sconn->smb2.seqnum_range -= 1;
363 offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
366 return true;
369 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
370 const uint8_t *inhdr)
372 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
373 uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
374 uint16_t credit_charge = 1;
375 uint64_t i;
377 if (opcode == SMB2_OP_CANCEL) {
378 /* SMB2_CANCEL requests by definition resend messageids. */
379 return true;
382 if (sconn->smb2.supports_multicredit) {
383 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
384 credit_charge = MAX(credit_charge, 1);
387 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
388 "credits_granted %llu, "
389 "seqnum low/range: %llu/%llu\n",
390 (unsigned long long) message_id,
391 (unsigned long long) credit_charge,
392 (unsigned long long) sconn->smb2.credits_granted,
393 (unsigned long long) sconn->smb2.seqnum_low,
394 (unsigned long long) sconn->smb2.seqnum_range));
396 if (sconn->smb2.credits_granted < credit_charge) {
397 DEBUG(0, ("smb2_validate_message_id: client used more "
398 "credits than granted, mid %llu, charge %llu, "
399 "credits_granted %llu, "
400 "seqnum low/range: %llu/%llu\n",
401 (unsigned long long) message_id,
402 (unsigned long long) credit_charge,
403 (unsigned long long) sconn->smb2.credits_granted,
404 (unsigned long long) sconn->smb2.seqnum_low,
405 (unsigned long long) sconn->smb2.seqnum_range));
406 return false;
410 * now check the message ids
412 * for multi-credit requests we need to check all current mid plus
413 * the implicit mids caused by the credit charge
414 * e.g. current mid = 15, charge 5 => mark 15-19 as used
417 for (i = 0; i <= (credit_charge-1); i++) {
418 uint64_t id = message_id + i;
419 bool ok;
421 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
422 (unsigned long long)message_id,
423 credit_charge,
424 (unsigned long long)id));
426 ok = smb2_validate_sequence_number(sconn, message_id, id);
427 if (!ok) {
428 return false;
432 /* substract used credits */
433 sconn->smb2.credits_granted -= credit_charge;
435 return true;
438 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
440 int count;
441 int idx;
443 count = req->in.vector_count;
445 if (count < 4) {
446 /* It's not a SMB2 request */
447 return NT_STATUS_INVALID_PARAMETER;
450 for (idx=1; idx < count; idx += 3) {
451 const uint8_t *inhdr = NULL;
452 uint32_t flags;
454 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
455 return NT_STATUS_INVALID_PARAMETER;
458 if (req->in.vector[idx+1].iov_len < 2) {
459 return NT_STATUS_INVALID_PARAMETER;
462 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
464 /* Check the SMB2 header */
465 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
466 return NT_STATUS_INVALID_PARAMETER;
469 if (!smb2_validate_message_id(req->sconn, inhdr)) {
470 return NT_STATUS_INVALID_PARAMETER;
473 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
474 if (idx == 1) {
476 * the 1st request should never have the
477 * SMB2_HDR_FLAG_CHAINED flag set
479 if (flags & SMB2_HDR_FLAG_CHAINED) {
480 req->next_status = NT_STATUS_INVALID_PARAMETER;
481 return NT_STATUS_OK;
483 } else if (idx == 4) {
485 * the 2nd request triggers related vs. unrelated
486 * compounded requests
488 if (flags & SMB2_HDR_FLAG_CHAINED) {
489 req->compound_related = true;
491 } else if (idx > 4) {
492 #if 0
494 * It seems the this tests are wrong
495 * see the SMB2-COMPOUND test
499 * all other requests should match the 2nd one
501 if (flags & SMB2_HDR_FLAG_CHAINED) {
502 if (!req->compound_related) {
503 req->next_status =
504 NT_STATUS_INVALID_PARAMETER;
505 return NT_STATUS_OK;
507 } else {
508 if (req->compound_related) {
509 req->next_status =
510 NT_STATUS_INVALID_PARAMETER;
511 return NT_STATUS_OK;
514 #endif
518 return NT_STATUS_OK;
521 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
522 const struct iovec *in_vector,
523 struct iovec *out_vector)
525 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
526 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
527 uint16_t credits_requested;
528 uint32_t out_flags;
529 uint16_t cmd;
530 NTSTATUS out_status;
531 uint16_t credits_granted = 0;
532 uint64_t credits_possible;
533 uint16_t current_max_credits;
536 * first we grant only 1/16th of the max range.
538 * Windows also starts with the 1/16th and then grants
539 * more later. I was only able to trigger higher
540 * values, when using a verify high credit charge.
542 * TODO: scale up depending one load, free memory
543 * or other stuff.
544 * Maybe also on the relationship between number
545 * of requests and the used sequence number.
546 * Which means we would grant more credits
547 * for client which use multi credit requests.
549 current_max_credits = sconn->smb2.max_credits / 16;
550 current_max_credits = MAX(current_max_credits, 1);
552 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
553 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
554 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
555 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
557 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
559 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
561 * In case we already send an async interim
562 * response, we should not grant
563 * credits on the final response.
565 credits_granted = 0;
566 } else if (credits_requested > 0) {
567 uint16_t additional_max = 0;
568 uint16_t additional_credits = credits_requested - 1;
570 switch (cmd) {
571 case SMB2_OP_NEGPROT:
572 break;
573 case SMB2_OP_SESSSETUP:
575 * Windows 2012 RC1 starts to grant
576 * additional credits
577 * with a successful session setup
579 if (NT_STATUS_IS_OK(out_status)) {
580 additional_max = 32;
582 break;
583 default:
585 * We match windows and only grant additional credits
586 * in chunks of 32.
588 additional_max = 32;
589 break;
592 additional_credits = MIN(additional_credits, additional_max);
594 credits_granted = 1 + additional_credits;
595 } else if (sconn->smb2.credits_granted == 0) {
597 * Make sure the client has always at least one credit
599 credits_granted = 1;
603 * sequence numbers should not wrap
605 * 1. calculate the possible credits until
606 * the sequence numbers start to wrap on 64-bit.
608 * 2. UINT64_MAX is used for Break Notifications.
610 * 2. truncate the possible credits to the maximum
611 * credits we want to grant to the client in total.
613 * 3. remove the range we'll already granted to the client
614 * this makes sure the client consumes the lowest sequence
615 * number, before we can grant additional credits.
617 credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
618 if (credits_possible > 0) {
619 /* remove UINT64_MAX */
620 credits_possible -= 1;
622 credits_possible = MIN(credits_possible, current_max_credits);
623 credits_possible -= sconn->smb2.seqnum_range;
625 credits_granted = MIN(credits_granted, credits_possible);
627 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
628 sconn->smb2.credits_granted += credits_granted;
629 sconn->smb2.seqnum_range += credits_granted;
631 DEBUG(10,("smb2_set_operation_credit: requested %u, "
632 "granted %u, current possible/max %u/%u, "
633 "total granted/max/low/range %u/%u/%llu/%u\n",
634 (unsigned int)credits_requested,
635 (unsigned int)credits_granted,
636 (unsigned int)credits_possible,
637 (unsigned int)current_max_credits,
638 (unsigned int)sconn->smb2.credits_granted,
639 (unsigned int)sconn->smb2.max_credits,
640 (unsigned long long)sconn->smb2.seqnum_low,
641 (unsigned int)sconn->smb2.seqnum_range));
644 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
645 struct smbd_smb2_request *outreq)
647 int count, idx;
648 uint16_t total_credits = 0;
650 count = outreq->out.vector_count;
652 for (idx=1; idx < count; idx += 3) {
653 uint8_t *outhdr = (uint8_t *)outreq->out.vector[idx].iov_base;
654 smb2_set_operation_credit(outreq->sconn,
655 &inreq->in.vector[idx],
656 &outreq->out.vector[idx]);
657 /* To match Windows, count up what we
658 just granted. */
659 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
660 /* Set to zero in all but the last reply. */
661 if (idx + 3 < count) {
662 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
663 } else {
664 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
669 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
671 struct iovec *vector;
672 int count;
673 int idx;
675 req->request_time = timeval_current();
677 count = req->in.vector_count;
678 vector = talloc_zero_array(req, struct iovec, count);
679 if (vector == NULL) {
680 return NT_STATUS_NO_MEMORY;
683 vector[0].iov_base = req->out.nbt_hdr;
684 vector[0].iov_len = 4;
685 SIVAL(req->out.nbt_hdr, 0, 0);
687 for (idx=1; idx < count; idx += 3) {
688 const uint8_t *inhdr = NULL;
689 uint8_t *outhdr = NULL;
690 uint8_t *outbody = NULL;
691 uint32_t next_command_ofs = 0;
692 struct iovec *current = &vector[idx];
694 if ((idx + 3) < count) {
695 /* we have a next command -
696 * setup for the error case. */
697 next_command_ofs = SMB2_HDR_BODY + 9;
700 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
702 outhdr = talloc_zero_array(vector, uint8_t,
703 OUTVEC_ALLOC_SIZE);
704 if (outhdr == NULL) {
705 return NT_STATUS_NO_MEMORY;
708 outbody = outhdr + SMB2_HDR_BODY;
710 current[0].iov_base = (void *)outhdr;
711 current[0].iov_len = SMB2_HDR_BODY;
713 current[1].iov_base = (void *)outbody;
714 current[1].iov_len = 8;
716 current[2].iov_base = NULL;
717 current[2].iov_len = 0;
719 /* setup the SMB2 header */
720 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
721 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
722 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
723 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
724 SIVAL(outhdr, SMB2_HDR_STATUS,
725 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
726 SSVAL(outhdr, SMB2_HDR_OPCODE,
727 SVAL(inhdr, SMB2_HDR_OPCODE));
728 SIVAL(outhdr, SMB2_HDR_FLAGS,
729 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
730 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
731 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
732 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
733 SIVAL(outhdr, SMB2_HDR_PID,
734 IVAL(inhdr, SMB2_HDR_PID));
735 SIVAL(outhdr, SMB2_HDR_TID,
736 IVAL(inhdr, SMB2_HDR_TID));
737 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
738 BVAL(inhdr, SMB2_HDR_SESSION_ID));
739 memcpy(outhdr + SMB2_HDR_SIGNATURE,
740 inhdr + SMB2_HDR_SIGNATURE, 16);
742 /* setup error body header */
743 SSVAL(outbody, 0x00, 0x08 + 1);
744 SSVAL(outbody, 0x02, 0);
745 SIVAL(outbody, 0x04, 0);
748 req->out.vector = vector;
749 req->out.vector_count = count;
751 /* setup the length of the NBT packet */
752 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
754 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
756 return NT_STATUS_OK;
759 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
760 const char *reason,
761 const char *location)
763 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
764 reason, location));
765 exit_server_cleanly(reason);
768 static bool dup_smb2_vec3(TALLOC_CTX *ctx,
769 struct iovec *outvec,
770 const struct iovec *srcvec)
772 /* vec[0] is always boilerplate and must
773 * be allocated with size OUTVEC_ALLOC_SIZE. */
775 outvec[0].iov_base = talloc_memdup(ctx,
776 srcvec[0].iov_base,
777 OUTVEC_ALLOC_SIZE);
778 if (!outvec[0].iov_base) {
779 return false;
781 outvec[0].iov_len = SMB2_HDR_BODY;
784 * If this is a "standard" vec[1] of length 8,
785 * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
786 * then duplicate this. Else use talloc_memdup().
789 if (srcvec[1].iov_len == 8 &&
790 srcvec[1].iov_base ==
791 ((uint8_t *)srcvec[0].iov_base) +
792 SMB2_HDR_BODY) {
793 outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
794 SMB2_HDR_BODY;
795 outvec[1].iov_len = 8;
796 } else {
797 outvec[1].iov_base = talloc_memdup(ctx,
798 srcvec[1].iov_base,
799 srcvec[1].iov_len);
800 if (!outvec[1].iov_base) {
801 return false;
803 outvec[1].iov_len = srcvec[1].iov_len;
807 * If this is a "standard" vec[2] of length 1,
808 * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
809 * then duplicate this. Else use talloc_memdup().
812 if (srcvec[2].iov_base &&
813 srcvec[2].iov_len) {
814 if (srcvec[2].iov_base ==
815 ((uint8_t *)srcvec[0].iov_base) +
816 (OUTVEC_ALLOC_SIZE - 1) &&
817 srcvec[2].iov_len == 1) {
818 /* Common SMB2 error packet case. */
819 outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
820 (OUTVEC_ALLOC_SIZE - 1);
821 } else {
822 outvec[2].iov_base = talloc_memdup(ctx,
823 srcvec[2].iov_base,
824 srcvec[2].iov_len);
825 if (!outvec[2].iov_base) {
826 return false;
829 outvec[2].iov_len = srcvec[2].iov_len;
830 } else {
831 outvec[2].iov_base = NULL;
832 outvec[2].iov_len = 0;
834 return true;
837 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
839 struct smbd_smb2_request *newreq = NULL;
840 struct iovec *outvec = NULL;
841 int count = req->out.vector_count;
842 int i;
844 newreq = smbd_smb2_request_allocate(req->sconn);
845 if (!newreq) {
846 return NULL;
849 newreq->sconn = req->sconn;
850 newreq->session = req->session;
851 newreq->do_signing = req->do_signing;
852 newreq->current_idx = req->current_idx;
854 outvec = talloc_zero_array(newreq, struct iovec, count);
855 if (!outvec) {
856 TALLOC_FREE(newreq);
857 return NULL;
859 newreq->out.vector = outvec;
860 newreq->out.vector_count = count;
862 /* Setup the outvec's identically to req. */
863 outvec[0].iov_base = newreq->out.nbt_hdr;
864 outvec[0].iov_len = 4;
865 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
867 /* Setup the vectors identically to the ones in req. */
868 for (i = 1; i < count; i += 3) {
869 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
870 break;
874 if (i < count) {
875 /* Alloc failed. */
876 TALLOC_FREE(newreq);
877 return NULL;
880 smb2_setup_nbt_length(newreq->out.vector,
881 newreq->out.vector_count);
883 return newreq;
886 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
888 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
890 int i = 0;
891 uint8_t *outhdr = NULL;
892 struct smbd_smb2_request *nreq = NULL;
894 /* Create a new smb2 request we'll use
895 for the interim return. */
896 nreq = dup_smb2_req(req);
897 if (!nreq) {
898 return NT_STATUS_NO_MEMORY;
901 /* Lose the last 3 out vectors. They're the
902 ones we'll be using for the async reply. */
903 nreq->out.vector_count -= 3;
905 smb2_setup_nbt_length(nreq->out.vector,
906 nreq->out.vector_count);
908 /* Step back to the previous reply. */
909 i = nreq->current_idx - 3;
910 outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
911 /* And end the chain. */
912 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
914 /* Calculate outgoing credits */
915 smb2_calculate_credits(req, nreq);
917 /* Re-sign if needed. */
918 if (nreq->do_signing) {
919 NTSTATUS status;
920 struct smbXsrv_session *x = nreq->session;
921 struct smbXsrv_connection *conn = x->connection;
922 DATA_BLOB signing_key = x->global->channels[0].signing_key;
924 status = smb2_signing_sign_pdu(signing_key,
925 conn->protocol,
926 &nreq->out.vector[i], 3);
927 if (!NT_STATUS_IS_OK(status)) {
928 return status;
931 if (DEBUGLEVEL >= 10) {
932 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
933 (unsigned int)nreq->current_idx );
934 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
935 (unsigned int)nreq->out.vector_count );
936 print_req_vectors(nreq);
938 nreq->subreq = tstream_writev_queue_send(nreq,
939 nreq->sconn->ev_ctx,
940 nreq->sconn->smb2.stream,
941 nreq->sconn->smb2.send_queue,
942 nreq->out.vector,
943 nreq->out.vector_count);
945 if (nreq->subreq == NULL) {
946 return NT_STATUS_NO_MEMORY;
949 tevent_req_set_callback(nreq->subreq,
950 smbd_smb2_request_writev_done,
951 nreq);
953 return NT_STATUS_OK;
956 struct smbd_smb2_request_pending_state {
957 struct smbd_server_connection *sconn;
958 uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
959 struct iovec vector[3];
962 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
964 struct smbd_smb2_request_pending_state *state =
965 tevent_req_callback_data(subreq,
966 struct smbd_smb2_request_pending_state);
967 struct smbd_server_connection *sconn = state->sconn;
968 int ret;
969 int sys_errno;
971 ret = tstream_writev_queue_recv(subreq, &sys_errno);
972 TALLOC_FREE(subreq);
973 if (ret == -1) {
974 NTSTATUS status = map_nt_error_from_unix(sys_errno);
975 smbd_server_connection_terminate(sconn, nt_errstr(status));
976 return;
979 TALLOC_FREE(state);
982 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
983 struct tevent_timer *te,
984 struct timeval current_time,
985 void *private_data);
987 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
988 struct tevent_req *subreq,
989 uint32_t defer_time)
991 NTSTATUS status;
992 int i = req->current_idx;
993 struct timeval defer_endtime;
994 uint8_t *outhdr = NULL;
995 uint32_t flags;
997 if (!tevent_req_is_in_progress(subreq)) {
998 return NT_STATUS_OK;
1001 req->subreq = subreq;
1002 subreq = NULL;
1004 if (req->async_te) {
1005 /* We're already async. */
1006 return NT_STATUS_OK;
1009 outhdr = (uint8_t *)req->out.vector[i].iov_base;
1010 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1011 if (flags & SMB2_HDR_FLAG_ASYNC) {
1012 /* We're already async. */
1013 return NT_STATUS_OK;
1016 if (req->in.vector_count > i + 3) {
1018 * We're trying to go async in a compound
1019 * request chain. This is not allowed.
1020 * Cancel the outstanding request.
1022 tevent_req_cancel(req->subreq);
1023 return smbd_smb2_request_error(req,
1024 NT_STATUS_INSUFFICIENT_RESOURCES);
1027 if (DEBUGLEVEL >= 10) {
1028 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1029 (unsigned int)req->current_idx );
1030 print_req_vectors(req);
1033 if (req->out.vector_count > 4) {
1034 struct iovec *outvec = NULL;
1036 /* This is a compound reply. We
1037 * must do an interim response
1038 * followed by the async response
1039 * to match W2K8R2.
1041 status = smb2_send_async_interim_response(req);
1042 if (!NT_STATUS_IS_OK(status)) {
1043 return status;
1047 * We're splitting off the last SMB2
1048 * request in a compound set, and the
1049 * smb2_send_async_interim_response()
1050 * call above just sent all the replies
1051 * for the previous SMB2 requests in
1052 * this compound set. So we're no longer
1053 * in the "compound_related_in_progress"
1054 * state, and this is no longer a compound
1055 * request.
1057 req->compound_related = false;
1058 req->sconn->smb2.compound_related_in_progress = false;
1060 /* Re-arrange the in.vectors. */
1061 req->in.vector[1] = req->in.vector[i];
1062 req->in.vector[2] = req->in.vector[i+1];
1063 req->in.vector[3] = req->in.vector[i+2];
1064 req->in.vector_count = 4;
1066 /* Reset the new in size. */
1067 smb2_setup_nbt_length(req->in.vector, 4);
1069 /* Now recreate the out.vectors. */
1070 outvec = talloc_zero_array(req, struct iovec, 4);
1071 if (!outvec) {
1072 return NT_STATUS_NO_MEMORY;
1075 /* 0 is always boilerplate and must
1076 * be of size 4 for the length field. */
1078 outvec[0].iov_base = req->out.nbt_hdr;
1079 outvec[0].iov_len = 4;
1080 SIVAL(req->out.nbt_hdr, 0, 0);
1082 if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
1083 return NT_STATUS_NO_MEMORY;
1086 TALLOC_FREE(req->out.vector);
1088 req->out.vector = outvec;
1090 req->current_idx = 1;
1091 req->out.vector_count = 4;
1093 outhdr = (uint8_t *)req->out.vector[1].iov_base;
1094 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1095 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1098 defer_endtime = timeval_current_ofs_usec(defer_time);
1099 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1100 req, defer_endtime,
1101 smbd_smb2_request_pending_timer,
1102 req);
1103 if (req->async_te == NULL) {
1104 return NT_STATUS_NO_MEMORY;
1107 return NT_STATUS_OK;
1110 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1111 struct tevent_timer *te,
1112 struct timeval current_time,
1113 void *private_data)
1115 struct smbd_smb2_request *req =
1116 talloc_get_type_abort(private_data,
1117 struct smbd_smb2_request);
1118 struct smbd_smb2_request_pending_state *state = NULL;
1119 int i = req->current_idx;
1120 uint8_t *outhdr = NULL;
1121 const uint8_t *inhdr = NULL;
1122 uint8_t *hdr = NULL;
1123 uint8_t *body = NULL;
1124 uint32_t flags = 0;
1125 uint64_t message_id = 0;
1126 uint64_t async_id = 0;
1127 struct tevent_req *subreq = NULL;
1129 TALLOC_FREE(req->async_te);
1131 /* Ensure our final reply matches the interim one. */
1132 inhdr = (const uint8_t *)req->in.vector[1].iov_base;
1133 outhdr = (uint8_t *)req->out.vector[1].iov_base;
1134 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1135 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1137 async_id = message_id; /* keep it simple for now... */
1139 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1140 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1142 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1143 "going async\n",
1144 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1145 (unsigned long long)async_id ));
1148 * What we send is identical to a smbd_smb2_request_error
1149 * packet with an error status of STATUS_PENDING. Make use
1150 * of this fact sometime when refactoring. JRA.
1153 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1154 if (state == NULL) {
1155 smbd_server_connection_terminate(req->sconn,
1156 nt_errstr(NT_STATUS_NO_MEMORY));
1157 return;
1159 state->sconn = req->sconn;
1161 state->vector[0].iov_base = (void *)state->buf;
1162 state->vector[0].iov_len = 4;
1164 state->vector[1].iov_base = state->buf + 4;
1165 state->vector[1].iov_len = SMB2_HDR_BODY;
1167 state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
1168 state->vector[2].iov_len = 9;
1170 smb2_setup_nbt_length(state->vector, 3);
1172 hdr = (uint8_t *)state->vector[1].iov_base;
1173 body = (uint8_t *)state->vector[2].iov_base;
1175 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1176 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1177 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1178 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1179 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1181 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1182 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1183 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1184 SBVAL(hdr, SMB2_HDR_PID, async_id);
1185 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1186 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1187 memcpy(hdr+SMB2_HDR_SIGNATURE,
1188 outhdr+SMB2_HDR_SIGNATURE, 16);
1190 SSVAL(body, 0x00, 0x08 + 1);
1192 SCVAL(body, 0x02, 0);
1193 SCVAL(body, 0x03, 0);
1194 SIVAL(body, 0x04, 0);
1195 /* Match W2K8R2... */
1196 SCVAL(body, 0x08, 0x21);
1198 /* Ensure we correctly go through crediting. Grant
1199 the credits now, and zero credits on the final
1200 response. */
1201 smb2_set_operation_credit(req->sconn,
1202 &req->in.vector[i],
1203 &state->vector[1]);
1205 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1207 if (req->do_signing) {
1208 NTSTATUS status;
1209 struct smbXsrv_session *x = req->session;
1210 struct smbXsrv_connection *conn = x->connection;
1211 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1213 status = smb2_signing_sign_pdu(signing_key,
1214 conn->protocol,
1215 &state->vector[1], 2);
1216 if (!NT_STATUS_IS_OK(status)) {
1217 smbd_server_connection_terminate(req->sconn,
1218 nt_errstr(status));
1219 return;
1223 subreq = tstream_writev_queue_send(state,
1224 state->sconn->ev_ctx,
1225 state->sconn->smb2.stream,
1226 state->sconn->smb2.send_queue,
1227 state->vector,
1229 if (subreq == NULL) {
1230 smbd_server_connection_terminate(state->sconn,
1231 nt_errstr(NT_STATUS_NO_MEMORY));
1232 return;
1234 tevent_req_set_callback(subreq,
1235 smbd_smb2_request_pending_writev_done,
1236 state);
1239 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1241 struct smbd_server_connection *sconn = req->sconn;
1242 struct smbd_smb2_request *cur;
1243 const uint8_t *inhdr;
1244 int i = req->current_idx;
1245 uint32_t flags;
1246 uint64_t search_message_id;
1247 uint64_t search_async_id;
1248 uint64_t found_id;
1250 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1252 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1253 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1254 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1257 * we don't need the request anymore
1258 * cancel requests never have a response
1260 DLIST_REMOVE(req->sconn->smb2.requests, req);
1261 TALLOC_FREE(req);
1263 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1264 const uint8_t *outhdr;
1265 uint64_t message_id;
1266 uint64_t async_id;
1268 i = cur->current_idx;
1270 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
1272 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1273 async_id = BVAL(outhdr, SMB2_HDR_PID);
1275 if (flags & SMB2_HDR_FLAG_ASYNC) {
1276 if (search_async_id == async_id) {
1277 found_id = async_id;
1278 break;
1280 } else {
1281 if (search_message_id == message_id) {
1282 found_id = message_id;
1283 break;
1288 if (cur && cur->subreq) {
1289 inhdr = (const uint8_t *)cur->in.vector[i].iov_base;
1290 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1291 "cancel opcode[%s] mid %llu\n",
1292 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1293 (unsigned long long)found_id ));
1294 tevent_req_cancel(cur->subreq);
1297 return NT_STATUS_OK;
1300 /*************************************************************
1301 Ensure an incoming tid is a valid one for us to access.
1302 Change to the associated uid credentials and chdir to the
1303 valid tid directory.
1304 *************************************************************/
1306 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1308 const uint8_t *inhdr;
1309 int i = req->current_idx;
1310 uint32_t in_flags;
1311 uint32_t in_tid;
1312 struct smbXsrv_tcon0 *tcon;
1313 NTSTATUS status;
1314 NTTIME now = timeval_to_nttime(&req->request_time);
1316 req->tcon = NULL;
1318 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1320 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1321 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1323 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1324 in_tid = req->last_tid;
1327 status = smb2srv_tcon_lookup(req->session,
1328 in_tid, now, &tcon);
1329 if (!NT_STATUS_IS_OK(status)) {
1330 return status;
1333 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1334 return NT_STATUS_ACCESS_DENIED;
1337 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1338 if (!set_current_service(tcon->compat, 0, true)) {
1339 return NT_STATUS_ACCESS_DENIED;
1342 req->tcon = tcon;
1343 req->last_tid = in_tid;
1345 return NT_STATUS_OK;
1348 /*************************************************************
1349 Ensure an incoming session_id is a valid one for us to access.
1350 *************************************************************/
1352 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1354 const uint8_t *inhdr;
1355 int i = req->current_idx;
1356 uint32_t in_flags;
1357 uint16_t in_opcode;
1358 uint64_t in_session_id;
1359 struct smbXsrv_session *session = NULL;
1360 struct auth_session_info *session_info;
1361 NTSTATUS status;
1362 NTTIME now = timeval_to_nttime(&req->request_time);
1364 req->session = NULL;
1365 req->tcon = NULL;
1367 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1369 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1370 in_opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1371 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1373 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1374 in_session_id = req->last_session_id;
1377 /* lookup an existing session */
1378 status = smb2srv_session_lookup(req->sconn->conn,
1379 in_session_id, now,
1380 &session);
1381 if (session) {
1382 req->session = session;
1383 req->last_session_id = in_session_id;
1385 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1386 switch (in_opcode) {
1387 case SMB2_OP_SESSSETUP:
1388 status = NT_STATUS_OK;
1389 break;
1390 default:
1391 break;
1394 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1395 switch (in_opcode) {
1396 case SMB2_OP_TCON:
1397 case SMB2_OP_CREATE:
1398 case SMB2_OP_GETINFO:
1399 case SMB2_OP_SETINFO:
1400 return NT_STATUS_INVALID_HANDLE;
1401 default:
1403 * Notice the check for
1404 * (session_info == NULL)
1405 * below.
1407 status = NT_STATUS_OK;
1408 break;
1411 if (!NT_STATUS_IS_OK(status)) {
1412 return status;
1415 session_info = session->global->auth_session_info;
1416 if (session_info == NULL) {
1417 return NT_STATUS_INVALID_HANDLE;
1420 set_current_user_info(session_info->unix_info->sanitized_username,
1421 session_info->unix_info->unix_name,
1422 session_info->info->domain_name);
1424 return NT_STATUS_OK;
1427 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1428 uint32_t data_length)
1430 uint16_t needed_charge;
1431 uint16_t credit_charge;
1432 const uint8_t *inhdr;
1433 int i = req->current_idx;
1435 if (!req->sconn->smb2.supports_multicredit) {
1436 if (data_length > 65536) {
1437 return NT_STATUS_INVALID_PARAMETER;
1439 return NT_STATUS_OK;
1442 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1443 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1445 /* requests larger than 64 KB need credit charge */
1446 if (credit_charge == 0 && data_length > 65536) {
1447 DEBUG(2, ("Request larger than 64KB w/o creditcharge\n"));
1448 return NT_STATUS_INVALID_PARAMETER;
1451 needed_charge = (data_length - 1)/ 65536 + 1;
1453 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1454 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1455 credit_charge, needed_charge));
1457 if (needed_charge > credit_charge) {
1458 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1459 credit_charge, needed_charge));
1460 return NT_STATUS_INVALID_PARAMETER;
1463 return NT_STATUS_OK;
1466 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1467 size_t expected_body_size)
1469 const uint8_t *inhdr;
1470 uint16_t opcode;
1471 const uint8_t *inbody;
1472 int i = req->current_idx;
1473 size_t body_size;
1474 size_t min_dyn_size = expected_body_size & 0x00000001;
1477 * The following should be checked already.
1479 if ((i+2) > req->in.vector_count) {
1480 return NT_STATUS_INTERNAL_ERROR;
1482 if (req->in.vector[i+0].iov_len != SMB2_HDR_BODY) {
1483 return NT_STATUS_INTERNAL_ERROR;
1485 if (req->in.vector[i+1].iov_len < 2) {
1486 return NT_STATUS_INTERNAL_ERROR;
1489 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1490 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1492 switch (opcode) {
1493 case SMB2_OP_IOCTL:
1494 case SMB2_OP_GETINFO:
1495 min_dyn_size = 0;
1496 break;
1500 * Now check the expected body size,
1501 * where the last byte might be in the
1502 * dynamic section..
1504 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1505 return NT_STATUS_INVALID_PARAMETER;
1507 if (req->in.vector[i+2].iov_len < min_dyn_size) {
1508 return NT_STATUS_INVALID_PARAMETER;
1511 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1513 body_size = SVAL(inbody, 0x00);
1514 if (body_size != expected_body_size) {
1515 return NT_STATUS_INVALID_PARAMETER;
1518 return NT_STATUS_OK;
1521 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1523 const uint8_t *inhdr;
1524 int i = req->current_idx;
1525 uint16_t opcode;
1526 uint32_t flags;
1527 uint64_t mid;
1528 NTSTATUS status;
1529 NTSTATUS session_status;
1530 uint32_t allowed_flags;
1531 NTSTATUS return_value;
1532 struct smbXsrv_session *x = NULL;
1533 bool signing_required = false;
1535 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1537 /* TODO: verify more things */
1539 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1540 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1541 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1542 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1543 smb2_opcode_name(opcode),
1544 (unsigned long long)mid));
1546 if (get_Protocol() >= PROTOCOL_SMB2_02) {
1548 * once the protocol is negotiated
1549 * SMB2_OP_NEGPROT is not allowed anymore
1551 if (opcode == SMB2_OP_NEGPROT) {
1552 /* drop the connection */
1553 return NT_STATUS_INVALID_PARAMETER;
1555 } else {
1557 * if the protocol is not negotiated yet
1558 * only SMB2_OP_NEGPROT is allowed.
1560 if (opcode != SMB2_OP_NEGPROT) {
1561 /* drop the connection */
1562 return NT_STATUS_INVALID_PARAMETER;
1566 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1567 SMB2_HDR_FLAG_SIGNED |
1568 SMB2_HDR_FLAG_DFS;
1569 if (opcode == SMB2_OP_CANCEL) {
1570 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1572 if ((flags & ~allowed_flags) != 0) {
1573 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1577 * Check if the client provided a valid session id,
1578 * if so smbd_smb2_request_check_session() calls
1579 * set_current_user_info().
1581 * As some command don't require a valid session id
1582 * we defer the check of the session_status
1584 session_status = smbd_smb2_request_check_session(req);
1585 x = req->session;
1587 if (x != NULL) {
1588 signing_required = x->global->signing_required;
1590 if (opcode == SMB2_OP_SESSSETUP &&
1591 x->global->channels[0].signing_key.length) {
1592 signing_required = true;
1596 req->do_signing = false;
1597 if (flags & SMB2_HDR_FLAG_SIGNED) {
1598 struct smbXsrv_connection *conn = x->connection;
1599 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1601 if (!NT_STATUS_IS_OK(session_status)) {
1602 return smbd_smb2_request_error(req, session_status);
1605 req->do_signing = true;
1606 status = smb2_signing_check_pdu(signing_key,
1607 conn->protocol,
1608 &req->in.vector[i], 3);
1609 if (!NT_STATUS_IS_OK(status)) {
1610 return smbd_smb2_request_error(req, status);
1612 } else if (opcode == SMB2_OP_CANCEL) {
1613 /* Cancel requests are allowed to skip the signing */
1614 } else if (signing_required) {
1615 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1618 if (flags & SMB2_HDR_FLAG_CHAINED) {
1620 * This check is mostly for giving the correct error code
1621 * for compounded requests.
1623 * TODO: we may need to move this after the session
1624 * and tcon checks.
1626 if (!NT_STATUS_IS_OK(req->next_status)) {
1627 return smbd_smb2_request_error(req, req->next_status);
1629 } else {
1630 req->compat_chain_fsp = NULL;
1633 if (req->compound_related) {
1634 req->sconn->smb2.compound_related_in_progress = true;
1637 switch (opcode) {
1638 case SMB2_OP_NEGPROT:
1639 /* This call needs to be run as root */
1640 change_to_root_user();
1643 START_PROFILE(smb2_negprot);
1644 return_value = smbd_smb2_request_process_negprot(req);
1645 END_PROFILE(smb2_negprot);
1647 break;
1649 case SMB2_OP_SESSSETUP:
1650 /* This call needs to be run as root */
1651 change_to_root_user();
1654 START_PROFILE(smb2_sesssetup);
1655 return_value = smbd_smb2_request_process_sesssetup(req);
1656 END_PROFILE(smb2_sesssetup);
1658 break;
1660 case SMB2_OP_LOGOFF:
1661 if (!NT_STATUS_IS_OK(session_status)) {
1662 return_value = smbd_smb2_request_error(req, session_status);
1663 break;
1666 /* This call needs to be run as root */
1667 change_to_root_user();
1670 START_PROFILE(smb2_logoff);
1671 return_value = smbd_smb2_request_process_logoff(req);
1672 END_PROFILE(smb2_logoff);
1674 break;
1676 case SMB2_OP_TCON:
1677 if (!NT_STATUS_IS_OK(session_status)) {
1678 return_value = smbd_smb2_request_error(req, session_status);
1679 break;
1683 * This call needs to be run as root.
1685 * smbd_smb2_request_process_tcon()
1686 * calls make_connection_snum(), which will call
1687 * change_to_user(), when needed.
1689 change_to_root_user();
1692 START_PROFILE(smb2_tcon);
1693 return_value = smbd_smb2_request_process_tcon(req);
1694 END_PROFILE(smb2_tcon);
1696 break;
1698 case SMB2_OP_TDIS:
1699 if (!NT_STATUS_IS_OK(session_status)) {
1700 return_value = smbd_smb2_request_error(req, session_status);
1701 break;
1704 * This call needs to be run as user.
1706 * smbd_smb2_request_check_tcon()
1707 * calls change_to_user() on success.
1709 status = smbd_smb2_request_check_tcon(req);
1710 if (!NT_STATUS_IS_OK(status)) {
1711 return_value = smbd_smb2_request_error(req, status);
1712 break;
1714 /* This call needs to be run as root */
1715 change_to_root_user();
1719 START_PROFILE(smb2_tdis);
1720 return_value = smbd_smb2_request_process_tdis(req);
1721 END_PROFILE(smb2_tdis);
1723 break;
1725 case SMB2_OP_CREATE:
1726 if (!NT_STATUS_IS_OK(session_status)) {
1727 return_value = smbd_smb2_request_error(req, session_status);
1728 break;
1731 * This call needs to be run as user.
1733 * smbd_smb2_request_check_tcon()
1734 * calls change_to_user() on success.
1736 status = smbd_smb2_request_check_tcon(req);
1737 if (!NT_STATUS_IS_OK(status)) {
1738 return_value = smbd_smb2_request_error(req, status);
1739 break;
1743 START_PROFILE(smb2_create);
1744 return_value = smbd_smb2_request_process_create(req);
1745 END_PROFILE(smb2_create);
1747 break;
1749 case SMB2_OP_CLOSE:
1750 if (!NT_STATUS_IS_OK(session_status)) {
1751 return_value = smbd_smb2_request_error(req, session_status);
1752 break;
1755 * This call needs to be run as user.
1757 * smbd_smb2_request_check_tcon()
1758 * calls change_to_user() on success.
1760 status = smbd_smb2_request_check_tcon(req);
1761 if (!NT_STATUS_IS_OK(status)) {
1762 return_value = smbd_smb2_request_error(req, status);
1763 break;
1767 START_PROFILE(smb2_close);
1768 return_value = smbd_smb2_request_process_close(req);
1769 END_PROFILE(smb2_close);
1771 break;
1773 case SMB2_OP_FLUSH:
1774 if (!NT_STATUS_IS_OK(session_status)) {
1775 return_value = smbd_smb2_request_error(req, session_status);
1776 break;
1779 * This call needs to be run as user.
1781 * smbd_smb2_request_check_tcon()
1782 * calls change_to_user() on success.
1784 status = smbd_smb2_request_check_tcon(req);
1785 if (!NT_STATUS_IS_OK(status)) {
1786 return_value = smbd_smb2_request_error(req, status);
1787 break;
1791 START_PROFILE(smb2_flush);
1792 return_value = smbd_smb2_request_process_flush(req);
1793 END_PROFILE(smb2_flush);
1795 break;
1797 case SMB2_OP_READ:
1798 if (!NT_STATUS_IS_OK(session_status)) {
1799 return_value = smbd_smb2_request_error(req, session_status);
1800 break;
1803 * This call needs to be run as user.
1805 * smbd_smb2_request_check_tcon()
1806 * calls change_to_user() on success.
1808 status = smbd_smb2_request_check_tcon(req);
1809 if (!NT_STATUS_IS_OK(status)) {
1810 return_value = smbd_smb2_request_error(req, status);
1811 break;
1815 START_PROFILE(smb2_read);
1816 return_value = smbd_smb2_request_process_read(req);
1817 END_PROFILE(smb2_read);
1819 break;
1821 case SMB2_OP_WRITE:
1822 if (!NT_STATUS_IS_OK(session_status)) {
1823 return_value = smbd_smb2_request_error(req, session_status);
1824 break;
1827 * This call needs to be run as user.
1829 * smbd_smb2_request_check_tcon()
1830 * calls change_to_user() on success.
1832 status = smbd_smb2_request_check_tcon(req);
1833 if (!NT_STATUS_IS_OK(status)) {
1834 return_value = smbd_smb2_request_error(req, status);
1835 break;
1839 START_PROFILE(smb2_write);
1840 return_value = smbd_smb2_request_process_write(req);
1841 END_PROFILE(smb2_write);
1843 break;
1845 case SMB2_OP_LOCK:
1846 if (!NT_STATUS_IS_OK(session_status)) {
1847 /* Too ugly to live ? JRA. */
1848 if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
1849 session_status = NT_STATUS_FILE_CLOSED;
1851 return_value = smbd_smb2_request_error(req, session_status);
1852 break;
1855 * This call needs to be run as user.
1857 * smbd_smb2_request_check_tcon()
1858 * calls change_to_user() on success.
1860 status = smbd_smb2_request_check_tcon(req);
1861 if (!NT_STATUS_IS_OK(status)) {
1862 /* Too ugly to live ? JRA. */
1863 if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
1864 status = NT_STATUS_FILE_CLOSED;
1866 return_value = smbd_smb2_request_error(req, status);
1867 break;
1871 START_PROFILE(smb2_lock);
1872 return_value = smbd_smb2_request_process_lock(req);
1873 END_PROFILE(smb2_lock);
1875 break;
1877 case SMB2_OP_IOCTL:
1878 if (!NT_STATUS_IS_OK(session_status)) {
1879 return_value = smbd_smb2_request_error(req, session_status);
1880 break;
1883 * This call needs to be run as user.
1885 * smbd_smb2_request_check_tcon()
1886 * calls change_to_user() on success.
1888 status = smbd_smb2_request_check_tcon(req);
1889 if (!NT_STATUS_IS_OK(status)) {
1890 return_value = smbd_smb2_request_error(req, status);
1891 break;
1895 START_PROFILE(smb2_ioctl);
1896 return_value = smbd_smb2_request_process_ioctl(req);
1897 END_PROFILE(smb2_ioctl);
1899 break;
1901 case SMB2_OP_CANCEL:
1903 * This call needs to be run as root
1905 * That is what we also do in the SMB1 case.
1907 change_to_root_user();
1910 START_PROFILE(smb2_cancel);
1911 return_value = smbd_smb2_request_process_cancel(req);
1912 END_PROFILE(smb2_cancel);
1914 break;
1916 case SMB2_OP_KEEPALIVE:
1917 /* This call needs to be run as root */
1918 change_to_root_user();
1921 START_PROFILE(smb2_keepalive);
1922 return_value = smbd_smb2_request_process_keepalive(req);
1923 END_PROFILE(smb2_keepalive);
1925 break;
1927 case SMB2_OP_FIND:
1928 if (!NT_STATUS_IS_OK(session_status)) {
1929 return_value = smbd_smb2_request_error(req, session_status);
1930 break;
1933 * This call needs to be run as user.
1935 * smbd_smb2_request_check_tcon()
1936 * calls change_to_user() on success.
1938 status = smbd_smb2_request_check_tcon(req);
1939 if (!NT_STATUS_IS_OK(status)) {
1940 return_value = smbd_smb2_request_error(req, status);
1941 break;
1945 START_PROFILE(smb2_find);
1946 return_value = smbd_smb2_request_process_find(req);
1947 END_PROFILE(smb2_find);
1949 break;
1951 case SMB2_OP_NOTIFY:
1952 if (!NT_STATUS_IS_OK(session_status)) {
1953 return_value = smbd_smb2_request_error(req, session_status);
1954 break;
1957 * This call needs to be run as user.
1959 * smbd_smb2_request_check_tcon()
1960 * calls change_to_user() on success.
1962 status = smbd_smb2_request_check_tcon(req);
1963 if (!NT_STATUS_IS_OK(status)) {
1964 return_value = smbd_smb2_request_error(req, status);
1965 break;
1969 START_PROFILE(smb2_notify);
1970 return_value = smbd_smb2_request_process_notify(req);
1971 END_PROFILE(smb2_notify);
1973 break;
1975 case SMB2_OP_GETINFO:
1976 if (!NT_STATUS_IS_OK(session_status)) {
1977 return_value = smbd_smb2_request_error(req, session_status);
1978 break;
1981 * This call needs to be run as user.
1983 * smbd_smb2_request_check_tcon()
1984 * calls change_to_user() on success.
1986 status = smbd_smb2_request_check_tcon(req);
1987 if (!NT_STATUS_IS_OK(status)) {
1988 return_value = smbd_smb2_request_error(req, status);
1989 break;
1993 START_PROFILE(smb2_getinfo);
1994 return_value = smbd_smb2_request_process_getinfo(req);
1995 END_PROFILE(smb2_getinfo);
1997 break;
1999 case SMB2_OP_SETINFO:
2000 if (!NT_STATUS_IS_OK(session_status)) {
2001 return_value = smbd_smb2_request_error(req, session_status);
2002 break;
2005 * This call needs to be run as user.
2007 * smbd_smb2_request_check_tcon()
2008 * calls change_to_user() on success.
2010 status = smbd_smb2_request_check_tcon(req);
2011 if (!NT_STATUS_IS_OK(status)) {
2012 return_value = smbd_smb2_request_error(req, status);
2013 break;
2017 START_PROFILE(smb2_setinfo);
2018 return_value = smbd_smb2_request_process_setinfo(req);
2019 END_PROFILE(smb2_setinfo);
2021 break;
2023 case SMB2_OP_BREAK:
2024 if (!NT_STATUS_IS_OK(session_status)) {
2025 return_value = smbd_smb2_request_error(req, session_status);
2026 break;
2029 * This call needs to be run as user.
2031 * smbd_smb2_request_check_tcon()
2032 * calls change_to_user() on success.
2034 status = smbd_smb2_request_check_tcon(req);
2035 if (!NT_STATUS_IS_OK(status)) {
2036 return_value = smbd_smb2_request_error(req, status);
2037 break;
2041 START_PROFILE(smb2_break);
2042 return_value = smbd_smb2_request_process_break(req);
2043 END_PROFILE(smb2_break);
2045 break;
2047 default:
2048 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2049 break;
2051 return return_value;
2054 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2056 struct tevent_req *subreq;
2057 int i = req->current_idx;
2059 req->subreq = NULL;
2060 TALLOC_FREE(req->async_te);
2062 req->current_idx += 3;
2064 if (req->current_idx < req->out.vector_count) {
2066 * We must process the remaining compound
2067 * SMB2 requests before any new incoming SMB2
2068 * requests. This is because incoming SMB2
2069 * requests may include a cancel for a
2070 * compound request we haven't processed
2071 * yet.
2073 struct tevent_immediate *im = tevent_create_immediate(req);
2074 if (!im) {
2075 return NT_STATUS_NO_MEMORY;
2077 tevent_schedule_immediate(im,
2078 req->sconn->ev_ctx,
2079 smbd_smb2_request_dispatch_immediate,
2080 req);
2081 return NT_STATUS_OK;
2084 if (req->compound_related) {
2085 req->sconn->smb2.compound_related_in_progress = false;
2088 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2090 /* Set credit for these operations (zero credits if this
2091 is a final reply for an async operation). */
2092 smb2_calculate_credits(req, req);
2094 if (req->do_signing) {
2095 NTSTATUS status;
2096 struct smbXsrv_session *x = req->session;
2097 struct smbXsrv_connection *conn = x->connection;
2098 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2100 status = smb2_signing_sign_pdu(signing_key,
2101 conn->protocol,
2102 &req->out.vector[i], 3);
2103 if (!NT_STATUS_IS_OK(status)) {
2104 return status;
2108 if (DEBUGLEVEL >= 10) {
2109 dbgtext("smbd_smb2_request_reply: sending...\n");
2110 print_req_vectors(req);
2113 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2114 if (req->out.vector_count == 4 &&
2115 req->out.vector[3].iov_base == NULL &&
2116 req->out.vector[3].iov_len != 0) {
2117 /* Dynamic part is NULL. Chop it off,
2118 We're going to send it via sendfile. */
2119 req->out.vector_count -= 1;
2122 subreq = tstream_writev_queue_send(req,
2123 req->sconn->ev_ctx,
2124 req->sconn->smb2.stream,
2125 req->sconn->smb2.send_queue,
2126 req->out.vector,
2127 req->out.vector_count);
2128 if (subreq == NULL) {
2129 return NT_STATUS_NO_MEMORY;
2131 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
2133 * We're done with this request -
2134 * move it off the "being processed" queue.
2136 DLIST_REMOVE(req->sconn->smb2.requests, req);
2138 return NT_STATUS_OK;
2141 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2143 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2144 struct tevent_immediate *im,
2145 void *private_data)
2147 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2148 struct smbd_smb2_request);
2149 struct smbd_server_connection *sconn = req->sconn;
2150 NTSTATUS status;
2152 TALLOC_FREE(im);
2154 if (DEBUGLEVEL >= 10) {
2155 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2156 req->current_idx, req->in.vector_count));
2157 print_req_vectors(req);
2160 status = smbd_smb2_request_dispatch(req);
2161 if (!NT_STATUS_IS_OK(status)) {
2162 smbd_server_connection_terminate(sconn, nt_errstr(status));
2163 return;
2166 status = smbd_smb2_request_next_incoming(sconn);
2167 if (!NT_STATUS_IS_OK(status)) {
2168 smbd_server_connection_terminate(sconn, nt_errstr(status));
2169 return;
2173 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
2175 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
2176 struct smbd_smb2_request);
2177 struct smbd_server_connection *sconn = req->sconn;
2178 int ret;
2179 int sys_errno;
2180 NTSTATUS status;
2182 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2183 TALLOC_FREE(subreq);
2184 TALLOC_FREE(req);
2185 if (ret == -1) {
2186 status = map_nt_error_from_unix(sys_errno);
2187 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
2188 nt_errstr(status)));
2189 smbd_server_connection_terminate(sconn, nt_errstr(status));
2190 return;
2193 status = smbd_smb2_request_next_incoming(sconn);
2194 if (!NT_STATUS_IS_OK(status)) {
2195 smbd_server_connection_terminate(sconn, nt_errstr(status));
2196 return;
2200 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2201 NTSTATUS status,
2202 DATA_BLOB body, DATA_BLOB *dyn,
2203 const char *location)
2205 uint8_t *outhdr;
2206 int i = req->current_idx;
2207 uint32_t next_command_ofs;
2209 DEBUG(10,("smbd_smb2_request_done_ex: "
2210 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2211 i, nt_errstr(status), (unsigned int)body.length,
2212 dyn ? "yes": "no",
2213 (unsigned int)(dyn ? dyn->length : 0),
2214 location));
2216 if (body.length < 2) {
2217 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2220 if ((body.length % 2) != 0) {
2221 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2224 outhdr = (uint8_t *)req->out.vector[i].iov_base;
2226 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2227 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2229 req->out.vector[i+1].iov_base = (void *)body.data;
2230 req->out.vector[i+1].iov_len = body.length;
2232 if (dyn) {
2233 req->out.vector[i+2].iov_base = (void *)dyn->data;
2234 req->out.vector[i+2].iov_len = dyn->length;
2235 } else {
2236 req->out.vector[i+2].iov_base = NULL;
2237 req->out.vector[i+2].iov_len = 0;
2240 /* see if we need to recalculate the offset to the next response */
2241 if (next_command_ofs > 0) {
2242 next_command_ofs = SMB2_HDR_BODY;
2243 next_command_ofs += req->out.vector[i+1].iov_len;
2244 next_command_ofs += req->out.vector[i+2].iov_len;
2247 if ((next_command_ofs % 8) != 0) {
2248 size_t pad_size = 8 - (next_command_ofs % 8);
2249 if (req->out.vector[i+2].iov_len == 0) {
2251 * if the dyn buffer is empty
2252 * we can use it to add padding
2254 uint8_t *pad;
2256 pad = talloc_zero_array(req->out.vector,
2257 uint8_t, pad_size);
2258 if (pad == NULL) {
2259 return smbd_smb2_request_error(req,
2260 NT_STATUS_NO_MEMORY);
2263 req->out.vector[i+2].iov_base = (void *)pad;
2264 req->out.vector[i+2].iov_len = pad_size;
2265 } else {
2267 * For now we copy the dynamic buffer
2268 * and add the padding to the new buffer
2270 size_t old_size;
2271 uint8_t *old_dyn;
2272 size_t new_size;
2273 uint8_t *new_dyn;
2275 old_size = req->out.vector[i+2].iov_len;
2276 old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
2278 new_size = old_size + pad_size;
2279 new_dyn = talloc_zero_array(req->out.vector,
2280 uint8_t, new_size);
2281 if (new_dyn == NULL) {
2282 return smbd_smb2_request_error(req,
2283 NT_STATUS_NO_MEMORY);
2286 memcpy(new_dyn, old_dyn, old_size);
2287 memset(new_dyn + old_size, 0, pad_size);
2289 req->out.vector[i+2].iov_base = (void *)new_dyn;
2290 req->out.vector[i+2].iov_len = new_size;
2292 next_command_ofs += pad_size;
2295 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2297 return smbd_smb2_request_reply(req);
2300 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2301 NTSTATUS status,
2302 DATA_BLOB *info,
2303 const char *location)
2305 DATA_BLOB body;
2306 int i = req->current_idx;
2307 uint8_t *outhdr = (uint8_t *)req->out.vector[i].iov_base;
2309 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2310 i, nt_errstr(status), info ? " +info" : "",
2311 location));
2313 body.data = outhdr + SMB2_HDR_BODY;
2314 body.length = 8;
2315 SSVAL(body.data, 0, 9);
2317 if (info) {
2318 SIVAL(body.data, 0x04, info->length);
2319 } else {
2320 /* Allocated size of req->out.vector[i].iov_base
2321 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2322 * 1 byte without having to do an alloc.
2324 info = talloc_zero_array(req->out.vector,
2325 DATA_BLOB,
2327 if (!info) {
2328 return NT_STATUS_NO_MEMORY;
2330 info->data = ((uint8_t *)outhdr) +
2331 OUTVEC_ALLOC_SIZE - 1;
2332 info->length = 1;
2333 SCVAL(info->data, 0, 0);
2337 * if a request fails, all other remaining
2338 * compounded requests should fail too
2340 req->next_status = NT_STATUS_INVALID_PARAMETER;
2342 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2346 struct smbd_smb2_send_oplock_break_state {
2347 struct smbd_server_connection *sconn;
2348 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
2349 struct iovec vector;
2352 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2354 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2355 uint64_t file_id_persistent,
2356 uint64_t file_id_volatile,
2357 uint8_t oplock_level)
2359 struct smbd_smb2_send_oplock_break_state *state;
2360 struct tevent_req *subreq;
2361 uint8_t *hdr;
2362 uint8_t *body;
2364 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2365 if (state == NULL) {
2366 return NT_STATUS_NO_MEMORY;
2368 state->sconn = sconn;
2370 state->vector.iov_base = (void *)state->buf;
2371 state->vector.iov_len = sizeof(state->buf);
2373 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
2374 hdr = state->buf + 4;
2375 body = hdr + SMB2_HDR_BODY;
2377 SIVAL(hdr, 0, SMB2_MAGIC);
2378 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2379 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2380 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2381 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2382 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2383 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2384 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2385 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2386 SIVAL(hdr, SMB2_HDR_PID, 0);
2387 SIVAL(hdr, SMB2_HDR_TID, 0);
2388 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2389 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2391 SSVAL(body, 0x00, 0x18);
2393 SCVAL(body, 0x02, oplock_level);
2394 SCVAL(body, 0x03, 0); /* reserved */
2395 SIVAL(body, 0x04, 0); /* reserved */
2396 SBVAL(body, 0x08, file_id_persistent);
2397 SBVAL(body, 0x10, file_id_volatile);
2399 subreq = tstream_writev_queue_send(state,
2400 sconn->ev_ctx,
2401 sconn->smb2.stream,
2402 sconn->smb2.send_queue,
2403 &state->vector, 1);
2404 if (subreq == NULL) {
2405 return NT_STATUS_NO_MEMORY;
2407 tevent_req_set_callback(subreq,
2408 smbd_smb2_oplock_break_writev_done,
2409 state);
2411 return NT_STATUS_OK;
2414 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2416 struct smbd_smb2_send_oplock_break_state *state =
2417 tevent_req_callback_data(subreq,
2418 struct smbd_smb2_send_oplock_break_state);
2419 struct smbd_server_connection *sconn = state->sconn;
2420 int ret;
2421 int sys_errno;
2423 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2424 TALLOC_FREE(subreq);
2425 if (ret == -1) {
2426 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2427 smbd_server_connection_terminate(sconn, nt_errstr(status));
2428 return;
2431 TALLOC_FREE(state);
2434 struct smbd_smb2_request_read_state {
2435 size_t missing;
2436 bool asked_for_header;
2437 struct smbd_smb2_request *smb2_req;
2440 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2441 void *private_data,
2442 TALLOC_CTX *mem_ctx,
2443 struct iovec **_vector,
2444 size_t *_count);
2445 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2447 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2448 struct tevent_context *ev,
2449 struct smbd_server_connection *sconn)
2451 struct tevent_req *req;
2452 struct smbd_smb2_request_read_state *state;
2453 struct tevent_req *subreq;
2455 req = tevent_req_create(mem_ctx, &state,
2456 struct smbd_smb2_request_read_state);
2457 if (req == NULL) {
2458 return NULL;
2460 state->missing = 0;
2461 state->asked_for_header = false;
2463 state->smb2_req = smbd_smb2_request_allocate(state);
2464 if (tevent_req_nomem(state->smb2_req, req)) {
2465 return tevent_req_post(req, ev);
2467 state->smb2_req->sconn = sconn;
2469 subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
2470 sconn->smb2.recv_queue,
2471 smbd_smb2_request_next_vector,
2472 state);
2473 if (tevent_req_nomem(subreq, req)) {
2474 return tevent_req_post(req, ev);
2476 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2478 return req;
2481 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2482 void *private_data,
2483 TALLOC_CTX *mem_ctx,
2484 struct iovec **_vector,
2485 size_t *_count)
2487 struct smbd_smb2_request_read_state *state =
2488 talloc_get_type_abort(private_data,
2489 struct smbd_smb2_request_read_state);
2490 struct smbd_smb2_request *req = state->smb2_req;
2491 struct iovec *vector;
2492 int idx = req->in.vector_count;
2493 size_t len = 0;
2494 uint8_t *buf = NULL;
2496 if (req->in.vector_count == 0) {
2498 * first we need to get the NBT header
2500 req->in.vector = talloc_array(req, struct iovec,
2501 req->in.vector_count + 1);
2502 if (req->in.vector == NULL) {
2503 return -1;
2505 req->in.vector_count += 1;
2507 req->in.vector[idx].iov_base = (void *)req->in.nbt_hdr;
2508 req->in.vector[idx].iov_len = 4;
2510 vector = talloc_array(mem_ctx, struct iovec, 1);
2511 if (vector == NULL) {
2512 return -1;
2515 vector[0] = req->in.vector[idx];
2517 *_vector = vector;
2518 *_count = 1;
2519 return 0;
2522 if (req->in.vector_count == 1) {
2524 * Now we analyze the NBT header
2526 state->missing = smb2_len(req->in.vector[0].iov_base);
2528 if (state->missing == 0) {
2529 /* if there're no remaining bytes, we're done */
2530 *_vector = NULL;
2531 *_count = 0;
2532 return 0;
2535 req->in.vector = talloc_realloc(req, req->in.vector,
2536 struct iovec,
2537 req->in.vector_count + 1);
2538 if (req->in.vector == NULL) {
2539 return -1;
2541 req->in.vector_count += 1;
2543 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
2545 * it's a special NBT message,
2546 * so get all remaining bytes
2548 len = state->missing;
2549 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
2551 * it's an invalid message, just read what we can get
2552 * and let the caller handle the error
2554 len = state->missing;
2555 } else {
2557 * We assume it's a SMB2 request,
2558 * and we first get the header and the
2559 * first 2 bytes (the struct size) of the body
2561 len = SMB2_HDR_BODY + 2;
2563 state->asked_for_header = true;
2566 state->missing -= len;
2568 buf = talloc_array(req->in.vector, uint8_t, len);
2569 if (buf == NULL) {
2570 return -1;
2573 req->in.vector[idx].iov_base = (void *)buf;
2574 req->in.vector[idx].iov_len = len;
2576 vector = talloc_array(mem_ctx, struct iovec, 1);
2577 if (vector == NULL) {
2578 return -1;
2581 vector[0] = req->in.vector[idx];
2583 *_vector = vector;
2584 *_count = 1;
2585 return 0;
2588 if (state->missing == 0) {
2589 /* if there're no remaining bytes, we're done */
2590 *_vector = NULL;
2591 *_count = 0;
2592 return 0;
2595 if (state->asked_for_header) {
2596 const uint8_t *hdr;
2597 size_t full_size;
2598 size_t next_command_ofs;
2599 size_t body_size;
2600 uint8_t *body;
2601 size_t dyn_size;
2602 uint8_t *dyn;
2603 bool invalid = false;
2605 state->asked_for_header = false;
2608 * We got the SMB2 header and the first 2 bytes
2609 * of the body. We fix the size to just the header
2610 * and manually copy the 2 first bytes to the body section
2612 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
2613 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
2615 /* allocate vectors for body and dynamic areas */
2616 req->in.vector = talloc_realloc(req, req->in.vector,
2617 struct iovec,
2618 req->in.vector_count + 2);
2619 if (req->in.vector == NULL) {
2620 return -1;
2622 req->in.vector_count += 2;
2624 full_size = state->missing + SMB2_HDR_BODY + 2;
2625 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
2626 body_size = SVAL(hdr, SMB2_HDR_BODY);
2628 if (next_command_ofs != 0) {
2629 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
2631 * this is invalid, just return a zero
2632 * body and let the caller deal with the error
2634 invalid = true;
2635 } else if (next_command_ofs > full_size) {
2637 * this is invalid, just return a zero
2638 * body and let the caller deal with the error
2640 invalid = true;
2641 } else {
2642 full_size = next_command_ofs;
2646 if (!invalid) {
2647 if (body_size < 2) {
2649 * this is invalid, just return a zero
2650 * body and let the caller deal with the error
2652 invalid = true;
2656 * Mask out the lowest bit, the "dynamic" part
2657 * of body_size.
2659 body_size &= ~1;
2661 if (body_size > (full_size - SMB2_HDR_BODY)) {
2663 * this is invalid, just return a zero
2664 * body and let the caller deal with the error
2666 invalid = true;
2670 if (invalid) {
2671 /* the caller should check this */
2672 body_size = 2;
2675 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
2677 state->missing -= (body_size - 2) + dyn_size;
2679 body = talloc_array(req->in.vector, uint8_t, body_size);
2680 if (body == NULL) {
2681 return -1;
2684 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
2685 if (dyn == NULL) {
2686 return -1;
2689 req->in.vector[idx].iov_base = (void *)body;
2690 req->in.vector[idx].iov_len = body_size;
2691 req->in.vector[idx+1].iov_base = (void *)dyn;
2692 req->in.vector[idx+1].iov_len = dyn_size;
2694 vector = talloc_array(mem_ctx, struct iovec, 2);
2695 if (vector == NULL) {
2696 return -1;
2700 * the first 2 bytes of the body were already fetched
2701 * together with the header
2703 memcpy(body, hdr + SMB2_HDR_BODY, 2);
2704 vector[0].iov_base = body + 2;
2705 vector[0].iov_len = body_size - 2;
2707 vector[1] = req->in.vector[idx+1];
2709 *_vector = vector;
2710 *_count = 2;
2711 return 0;
2715 * when we endup here, we're looking for a new SMB2 request
2716 * next. And we ask for its header and the first 2 bytes of
2717 * the body (like we did for the first SMB2 request).
2720 req->in.vector = talloc_realloc(req, req->in.vector,
2721 struct iovec,
2722 req->in.vector_count + 1);
2723 if (req->in.vector == NULL) {
2724 return -1;
2726 req->in.vector_count += 1;
2729 * We assume it's a SMB2 request,
2730 * and we first get the header and the
2731 * first 2 bytes (the struct size) of the body
2733 len = SMB2_HDR_BODY + 2;
2735 if (len > state->missing) {
2736 /* let the caller handle the error */
2737 len = state->missing;
2740 state->missing -= len;
2741 state->asked_for_header = true;
2743 buf = talloc_array(req->in.vector, uint8_t, len);
2744 if (buf == NULL) {
2745 return -1;
2748 req->in.vector[idx].iov_base = (void *)buf;
2749 req->in.vector[idx].iov_len = len;
2751 vector = talloc_array(mem_ctx, struct iovec, 1);
2752 if (vector == NULL) {
2753 return -1;
2756 vector[0] = req->in.vector[idx];
2758 *_vector = vector;
2759 *_count = 1;
2760 return 0;
2763 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2765 struct tevent_req *req =
2766 tevent_req_callback_data(subreq,
2767 struct tevent_req);
2768 int ret;
2769 int sys_errno;
2770 NTSTATUS status;
2772 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2773 if (ret == -1) {
2774 status = map_nt_error_from_unix(sys_errno);
2775 tevent_req_nterror(req, status);
2776 return;
2779 tevent_req_done(req);
2782 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2783 TALLOC_CTX *mem_ctx,
2784 struct smbd_smb2_request **_smb2_req)
2786 struct smbd_smb2_request_read_state *state =
2787 tevent_req_data(req,
2788 struct smbd_smb2_request_read_state);
2789 NTSTATUS status;
2791 if (tevent_req_is_nterror(req, &status)) {
2792 tevent_req_received(req);
2793 return status;
2796 talloc_steal(mem_ctx, state->smb2_req->mem_pool);
2797 *_smb2_req = state->smb2_req;
2798 tevent_req_received(req);
2799 return NT_STATUS_OK;
2802 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2804 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2806 size_t max_send_queue_len;
2807 size_t cur_send_queue_len;
2808 struct tevent_req *subreq;
2810 if (sconn->smb2.compound_related_in_progress) {
2812 * Can't read another until the related
2813 * compound is done.
2815 return NT_STATUS_OK;
2818 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
2820 * if there is already a smbd_smb2_request_read
2821 * pending, we are done.
2823 return NT_STATUS_OK;
2826 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2827 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
2829 if (cur_send_queue_len > max_send_queue_len) {
2831 * if we have a lot of requests to send,
2832 * we wait until they are on the wire until we
2833 * ask for the next request.
2835 return NT_STATUS_OK;
2838 /* ask for the next request */
2839 subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn);
2840 if (subreq == NULL) {
2841 return NT_STATUS_NO_MEMORY;
2843 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2845 return NT_STATUS_OK;
2848 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2849 const uint8_t *inbuf, size_t size)
2851 NTSTATUS status;
2852 struct smbd_smb2_request *req = NULL;
2854 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2855 (unsigned int)size));
2857 status = smbd_initialize_smb2(sconn);
2858 if (!NT_STATUS_IS_OK(status)) {
2859 smbd_server_connection_terminate(sconn, nt_errstr(status));
2860 return;
2863 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2864 if (!NT_STATUS_IS_OK(status)) {
2865 smbd_server_connection_terminate(sconn, nt_errstr(status));
2866 return;
2869 status = smbd_smb2_request_validate(req);
2870 if (!NT_STATUS_IS_OK(status)) {
2871 smbd_server_connection_terminate(sconn, nt_errstr(status));
2872 return;
2875 status = smbd_smb2_request_setup_out(req);
2876 if (!NT_STATUS_IS_OK(status)) {
2877 smbd_server_connection_terminate(sconn, nt_errstr(status));
2878 return;
2881 status = smbd_smb2_request_dispatch(req);
2882 if (!NT_STATUS_IS_OK(status)) {
2883 smbd_server_connection_terminate(sconn, nt_errstr(status));
2884 return;
2887 status = smbd_smb2_request_next_incoming(sconn);
2888 if (!NT_STATUS_IS_OK(status)) {
2889 smbd_server_connection_terminate(sconn, nt_errstr(status));
2890 return;
2893 sconn->num_requests++;
2896 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2898 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2899 struct smbd_server_connection);
2900 NTSTATUS status;
2901 struct smbd_smb2_request *req = NULL;
2903 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2904 TALLOC_FREE(subreq);
2905 if (!NT_STATUS_IS_OK(status)) {
2906 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2907 nt_errstr(status)));
2908 smbd_server_connection_terminate(sconn, nt_errstr(status));
2909 return;
2912 if (req->in.nbt_hdr[0] != 0x00) {
2913 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
2914 req->in.nbt_hdr[0]));
2915 TALLOC_FREE(req);
2916 goto next;
2919 req->current_idx = 1;
2921 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2922 req->current_idx, req->in.vector_count));
2924 status = smbd_smb2_request_validate(req);
2925 if (!NT_STATUS_IS_OK(status)) {
2926 smbd_server_connection_terminate(sconn, nt_errstr(status));
2927 return;
2930 status = smbd_smb2_request_setup_out(req);
2931 if (!NT_STATUS_IS_OK(status)) {
2932 smbd_server_connection_terminate(sconn, nt_errstr(status));
2933 return;
2936 status = smbd_smb2_request_dispatch(req);
2937 if (!NT_STATUS_IS_OK(status)) {
2938 smbd_server_connection_terminate(sconn, nt_errstr(status));
2939 return;
2942 next:
2943 status = smbd_smb2_request_next_incoming(sconn);
2944 if (!NT_STATUS_IS_OK(status)) {
2945 smbd_server_connection_terminate(sconn, nt_errstr(status));
2946 return;
2949 sconn->num_requests++;
2951 /* The timeout_processing function isn't run nearly
2952 often enough to implement 'max log size' without
2953 overrunning the size of the file by many megabytes.
2954 This is especially true if we are running at debug
2955 level 10. Checking every 50 SMB2s is a nice
2956 tradeoff of performance vs log file size overrun. */
2958 if ((sconn->num_requests % 50) == 0 &&
2959 need_to_check_log_size()) {
2960 change_to_root_user();
2961 check_log_size();