2 Unix SMB/CIFS implementation.
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/>.
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"
33 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
35 static const struct smbd_smb2_dispatch_table {
42 bool allow_invalid_fileid;
43 } smbd_smb2_table[] = {
44 #define _OP(o) .opcode = o, .name = #o
49 _OP(SMB2_OP_SESSSETUP),
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.
102 .need_session = true,
105 .allow_invalid_fileid = true,
110 _OP(SMB2_OP_KEEPALIVE),
114 .need_session = true,
119 .need_session = true,
123 _OP(SMB2_OP_GETINFO),
124 .need_session = true,
128 _OP(SMB2_OP_SETINFO),
129 .need_session = true,
134 .need_session = true,
139 * as LEASE breaks does not
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)) {
161 ret = &smbd_smb2_table[opcode];
163 SMB_ASSERT(ret->opcode == opcode);
168 static void print_req_vectors(struct smbd_smb2_request *req)
172 for (i = 0; i < req->in.vector_count; i++) {
173 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
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",
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)) {
190 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
197 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
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);
227 status = map_nt_error_from_unix(errno);
231 /* Ensure child is set to non-blocking mode */
232 set_blocking(sconn->sock, false);
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; \
240 buf[1] = ((len)&0xFF0000)>>16; \
241 buf[2] = ((len)&0xFF00)>>8; \
242 buf[3] = (len)&0xFF; \
245 static void smb2_setup_nbt_length(struct iovec *vector, int count)
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);
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;
269 /* Enable this to find subtle valgrind errors. */
270 mem_pool = talloc_init("smbd_smb2_request_allocate");
272 mem_pool = talloc_pool(mem_ctx, 8192);
274 if (mem_pool == NULL) {
278 req = talloc_zero(mem_pool, struct smbd_smb2_request);
280 talloc_free(mem_pool);
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);
294 static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
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);
312 return NT_STATUS_NO_MEMORY;
315 while (taken < buflen) {
316 size_t len = buflen - taken;
317 uint8_t *hdr = first_hdr + taken;
320 size_t next_command_ofs;
322 uint8_t *body = 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));
336 if (IVAL(hdr, 0) != SMB2_MAGIC) {
337 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
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));
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)) {
355 if (next_command_ofs > full_size) {
358 full_size = next_command_ofs;
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) {
379 return NT_STATUS_NO_MEMORY;
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;
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;
412 uint32_t next_command_ofs;
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;
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",
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",
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",
441 return NT_STATUS_INVALID_PARAMETER;
444 req = smbd_smb2_request_allocate(sconn);
446 return NT_STATUS_NO_MEMORY;
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,
457 inbuf + NBT_HDR_SIZE,
459 req, &req->in.vector,
460 &req->in.vector_count);
461 if (!NT_STATUS_IS_OK(status)) {
466 req->current_idx = 1;
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;
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));
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));
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) "
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,
518 /* Mark the message_ids as seen in the bitmap. */
519 bitmap_set(credits_bm, offset);
521 if (seq_id != sconn->smb2.seqnum_low) {
526 * Move the window forward by all the message_id's
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),
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;
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;
552 if (opcode == SMB2_OP_CANCEL) {
553 /* SMB2_CANCEL requests by definition resend messageids. */
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));
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;
596 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
597 (unsigned long long)message_id,
599 (unsigned long long)id));
601 ok = smb2_validate_sequence_number(sconn, message_id, id);
607 /* substract used credits */
608 sconn->smb2.credits_granted -= credit_charge;
613 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
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;
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);
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;
660 } else if (idx == 4) {
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 if (idx > 4) {
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) {
681 NT_STATUS_INVALID_PARAMETER;
685 if (req->compound_related) {
687 NT_STATUS_INVALID_PARAMETER;
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;
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
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.
750 } else if (credits_requested > 0) {
751 uint16_t additional_max = 0;
752 uint16_t additional_credits = credits_requested - 1;
755 case SMB2_OP_NEGPROT:
757 case SMB2_OP_SESSSETUP:
759 * Windows 2012 RC1 starts to grant
761 * with a successful session setup
763 if (NT_STATUS_IS_OK(out_status)) {
769 * We match windows and only grant additional credits
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
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)
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
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);
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;
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,
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 *);
943 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
945 const char *location)
947 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
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;
958 const uint8_t *srcbody;
960 const uint8_t *expected_srcbody;
961 const uint8_t *srcdyn;
963 const uint8_t *expected_srcdyn;
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) {
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) {
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;
1000 dstbody = talloc_memdup(ctx, srcbody, srcbody_len);
1001 if (dstbody == NULL) {
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,
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) {
1020 dstdyn = talloc_memdup(ctx, srcdyn, srcdyn_len);
1021 if (dstdyn == NULL) {
1025 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_base = (void *)dstdyn;
1026 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_len = srcdyn_len;
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;
1038 newreq = smbd_smb2_request_allocate(req->sconn);
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);
1051 TALLOC_FREE(newreq);
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])) {
1071 TALLOC_FREE(newreq);
1075 smb2_setup_nbt_length(newreq->out.vector,
1076 newreq->out.vector_count);
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;
1091 /* Create a new smb2 request we'll use
1092 for the interim return. */
1093 nreq = dup_smb2_req(req);
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,
1123 SMBD_SMB2_NUM_IOV_PER_REQ);
1124 if (!NT_STATUS_IS_OK(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,
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,
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;
1169 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1170 TALLOC_FREE(subreq);
1172 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1173 smbd_server_connection_terminate(sconn, nt_errstr(status));
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)
1190 int idx = req->current_idx;
1191 struct timeval defer_endtime;
1192 uint8_t *outhdr = NULL;
1195 if (!tevent_req_is_in_progress(subreq)) {
1196 return NT_STATUS_OK;
1199 req->subreq = subreq;
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
1238 status = smb2_send_async_interim_response(req);
1239 if (!NT_STATUS_IS_OK(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
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,
1280 smbd_smb2_request_pending_timer,
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,
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;
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 "
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));
1338 state->sconn = req->sconn;
1341 hdr = state->buf + NBT_HDR_SIZE;
1342 body = hdr + SMB2_HDR_BODY;
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
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) {
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,
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,
1411 subreq = tstream_writev_queue_send(state,
1412 state->sconn->ev_ctx,
1413 state->sconn->smb2.stream,
1414 state->sconn->smb2.send_queue,
1416 ARRAY_SIZE(state->vector));
1417 if (subreq == NULL) {
1418 smbd_server_connection_terminate(state->sconn,
1419 nt_errstr(NT_STATUS_NO_MEMORY));
1422 tevent_req_set_callback(subreq,
1423 smbd_smb2_request_pending_writev_done,
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;
1433 uint64_t search_message_id;
1434 uint64_t search_async_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);
1450 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1451 const uint8_t *outhdr;
1452 uint64_t message_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;
1466 if (search_message_id == message_id) {
1467 found_id = message_id;
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;
1496 struct smbXsrv_tcon *tcon;
1498 NTTIME now = timeval_to_nttime(&req->request_time);
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)) {
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;
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;
1541 uint64_t in_session_id;
1542 struct smbXsrv_session *session = NULL;
1543 struct auth_session_info *session_info;
1545 NTTIME now = timeval_to_nttime(&req->request_time);
1547 req->session = 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,
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;
1577 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1578 switch (in_opcode) {
1580 case SMB2_OP_CREATE:
1581 case SMB2_OP_GETINFO:
1582 case SMB2_OP_SETINFO:
1583 return NT_STATUS_INVALID_HANDLE;
1586 * Notice the check for
1587 * (session_info == NULL)
1590 status = NT_STATUS_OK;
1594 if (!NT_STATUS_IS_OK(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;
1645 const uint8_t *inbody;
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);
1673 case SMB2_OP_GETINFO:
1679 * Now check the expected body size,
1680 * where the last byte might be in the
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;
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;
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);
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);
1768 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1771 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1772 SMB2_HDR_FLAG_SIGNED |
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;
1786 return smbd_smb2_request_error(
1787 req, NT_STATUS_ACCESS_DENIED);
1790 signing_key = x->global->channels[0].signing_key;
1792 if (!NT_STATUS_IS_OK(session_status)) {
1793 return smbd_smb2_request_error(req, session_status);
1796 req->do_signing = true;
1797 status = smb2_signing_check_pdu(signing_key,
1799 SMBD_SMB2_IN_HDR_IOV(req),
1800 SMBD_SMB2_NUM_IOV_PER_REQ);
1801 if (!NT_STATUS_IS_OK(status)) {
1802 return smbd_smb2_request_error(req, status);
1804 } else if (opcode == SMB2_OP_CANCEL) {
1805 /* Cancel requests are allowed to skip the signing */
1806 } else if (signing_required) {
1807 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1810 if (flags & SMB2_HDR_FLAG_CHAINED) {
1812 * This check is mostly for giving the correct error code
1813 * for compounded requests.
1815 * TODO: we may need to move this after the session
1818 if (!NT_STATUS_IS_OK(req->next_status)) {
1819 return smbd_smb2_request_error(req, req->next_status);
1822 req->compat_chain_fsp = NULL;
1825 if (req->compound_related) {
1826 req->sconn->smb2.compound_related_in_progress = true;
1829 if (call->need_session) {
1830 if (!NT_STATUS_IS_OK(session_status)) {
1831 return smbd_smb2_request_error(req, session_status);
1835 if (call->need_tcon) {
1836 SMB_ASSERT(call->need_session);
1839 * This call needs to be run as user.
1841 * smbd_smb2_request_check_tcon()
1842 * calls change_to_user() on success.
1844 status = smbd_smb2_request_check_tcon(req);
1845 if (!NT_STATUS_IS_OK(status)) {
1846 return smbd_smb2_request_error(req, status);
1850 if (call->fileid_ofs != 0) {
1851 size_t needed = call->fileid_ofs + 16;
1852 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
1853 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
1854 uint64_t file_id_persistent;
1855 uint64_t file_id_volatile;
1856 struct files_struct *fsp;
1858 SMB_ASSERT(call->need_tcon);
1860 if (needed > body_size) {
1861 return smbd_smb2_request_error(req,
1862 NT_STATUS_INVALID_PARAMETER);
1865 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
1866 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
1868 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
1870 if (!call->allow_invalid_fileid) {
1871 return smbd_smb2_request_error(req,
1872 NT_STATUS_FILE_CLOSED);
1875 if (file_id_persistent != UINT64_MAX) {
1876 return smbd_smb2_request_error(req,
1877 NT_STATUS_FILE_CLOSED);
1879 if (file_id_volatile != UINT64_MAX) {
1880 return smbd_smb2_request_error(req,
1881 NT_STATUS_FILE_CLOSED);
1886 if (call->as_root) {
1887 SMB_ASSERT(call->fileid_ofs == 0);
1888 /* This call needs to be run as root */
1889 change_to_root_user();
1891 SMB_ASSERT(call->need_tcon);
1895 case SMB2_OP_NEGPROT:
1897 START_PROFILE(smb2_negprot);
1898 return_value = smbd_smb2_request_process_negprot(req);
1899 END_PROFILE(smb2_negprot);
1903 case SMB2_OP_SESSSETUP:
1905 START_PROFILE(smb2_sesssetup);
1906 return_value = smbd_smb2_request_process_sesssetup(req);
1907 END_PROFILE(smb2_sesssetup);
1911 case SMB2_OP_LOGOFF:
1913 START_PROFILE(smb2_logoff);
1914 return_value = smbd_smb2_request_process_logoff(req);
1915 END_PROFILE(smb2_logoff);
1921 START_PROFILE(smb2_tcon);
1922 return_value = smbd_smb2_request_process_tcon(req);
1923 END_PROFILE(smb2_tcon);
1929 START_PROFILE(smb2_tdis);
1930 return_value = smbd_smb2_request_process_tdis(req);
1931 END_PROFILE(smb2_tdis);
1935 case SMB2_OP_CREATE:
1937 START_PROFILE(smb2_create);
1938 return_value = smbd_smb2_request_process_create(req);
1939 END_PROFILE(smb2_create);
1945 START_PROFILE(smb2_close);
1946 return_value = smbd_smb2_request_process_close(req);
1947 END_PROFILE(smb2_close);
1953 START_PROFILE(smb2_flush);
1954 return_value = smbd_smb2_request_process_flush(req);
1955 END_PROFILE(smb2_flush);
1961 START_PROFILE(smb2_read);
1962 return_value = smbd_smb2_request_process_read(req);
1963 END_PROFILE(smb2_read);
1969 START_PROFILE(smb2_write);
1970 return_value = smbd_smb2_request_process_write(req);
1971 END_PROFILE(smb2_write);
1977 START_PROFILE(smb2_lock);
1978 return_value = smbd_smb2_request_process_lock(req);
1979 END_PROFILE(smb2_lock);
1985 START_PROFILE(smb2_ioctl);
1986 return_value = smbd_smb2_request_process_ioctl(req);
1987 END_PROFILE(smb2_ioctl);
1991 case SMB2_OP_CANCEL:
1993 START_PROFILE(smb2_cancel);
1994 return_value = smbd_smb2_request_process_cancel(req);
1995 END_PROFILE(smb2_cancel);
1999 case SMB2_OP_KEEPALIVE:
2001 START_PROFILE(smb2_keepalive);
2002 return_value = smbd_smb2_request_process_keepalive(req);
2003 END_PROFILE(smb2_keepalive);
2009 START_PROFILE(smb2_find);
2010 return_value = smbd_smb2_request_process_find(req);
2011 END_PROFILE(smb2_find);
2015 case SMB2_OP_NOTIFY:
2017 START_PROFILE(smb2_notify);
2018 return_value = smbd_smb2_request_process_notify(req);
2019 END_PROFILE(smb2_notify);
2023 case SMB2_OP_GETINFO:
2025 START_PROFILE(smb2_getinfo);
2026 return_value = smbd_smb2_request_process_getinfo(req);
2027 END_PROFILE(smb2_getinfo);
2031 case SMB2_OP_SETINFO:
2033 START_PROFILE(smb2_setinfo);
2034 return_value = smbd_smb2_request_process_setinfo(req);
2035 END_PROFILE(smb2_setinfo);
2041 START_PROFILE(smb2_break);
2042 return_value = smbd_smb2_request_process_break(req);
2043 END_PROFILE(smb2_break);
2048 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2051 return return_value;
2054 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2056 struct smbXsrv_connection *conn = req->sconn->conn;
2057 struct tevent_req *subreq;
2058 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2059 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2062 TALLOC_FREE(req->async_te);
2064 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2065 (req->last_key.length > 0)) {
2066 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2067 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2071 * As we are sure the header of the last request in the
2072 * compound chain will not change, we can to sign here
2073 * with the last signing key we remembered.
2076 status = smb2_signing_sign_pdu(req->last_key,
2079 SMBD_SMB2_NUM_IOV_PER_REQ);
2080 if (!NT_STATUS_IS_OK(status)) {
2084 data_blob_clear_free(&req->last_key);
2086 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2088 if (req->current_idx < req->out.vector_count) {
2090 * We must process the remaining compound
2091 * SMB2 requests before any new incoming SMB2
2092 * requests. This is because incoming SMB2
2093 * requests may include a cancel for a
2094 * compound request we haven't processed
2097 struct tevent_immediate *im = tevent_create_immediate(req);
2099 return NT_STATUS_NO_MEMORY;
2102 if (req->do_signing) {
2103 struct smbXsrv_session *x = req->session;
2104 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2107 * we need to remember the signing key
2108 * and defer the signing until
2109 * we are sure that we do not change
2112 req->last_key = data_blob_dup_talloc(req, signing_key);
2113 if (req->last_key.data == NULL) {
2114 return NT_STATUS_NO_MEMORY;
2118 tevent_schedule_immediate(im,
2120 smbd_smb2_request_dispatch_immediate,
2122 return NT_STATUS_OK;
2125 if (req->compound_related) {
2126 req->sconn->smb2.compound_related_in_progress = false;
2129 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2131 /* Set credit for these operations (zero credits if this
2132 is a final reply for an async operation). */
2133 smb2_calculate_credits(req, req);
2136 * now check if we need to sign the current response
2138 if (req->do_signing) {
2140 struct smbXsrv_session *x = req->session;
2141 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2143 status = smb2_signing_sign_pdu(signing_key,
2146 SMBD_SMB2_NUM_IOV_PER_REQ);
2147 if (!NT_STATUS_IS_OK(status)) {
2152 if (DEBUGLEVEL >= 10) {
2153 dbgtext("smbd_smb2_request_reply: sending...\n");
2154 print_req_vectors(req);
2157 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2158 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2159 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2160 /* Dynamic part is NULL. Chop it off,
2161 We're going to send it via sendfile. */
2162 req->out.vector_count -= 1;
2165 subreq = tstream_writev_queue_send(req,
2167 req->sconn->smb2.stream,
2168 req->sconn->smb2.send_queue,
2170 req->out.vector_count);
2171 if (subreq == NULL) {
2172 return NT_STATUS_NO_MEMORY;
2174 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
2176 * We're done with this request -
2177 * move it off the "being processed" queue.
2179 DLIST_REMOVE(req->sconn->smb2.requests, req);
2181 return NT_STATUS_OK;
2184 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2186 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2187 struct tevent_immediate *im,
2190 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2191 struct smbd_smb2_request);
2192 struct smbd_server_connection *sconn = req->sconn;
2197 if (DEBUGLEVEL >= 10) {
2198 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2199 req->current_idx, req->in.vector_count));
2200 print_req_vectors(req);
2203 status = smbd_smb2_request_dispatch(req);
2204 if (!NT_STATUS_IS_OK(status)) {
2205 smbd_server_connection_terminate(sconn, nt_errstr(status));
2209 status = smbd_smb2_request_next_incoming(sconn);
2210 if (!NT_STATUS_IS_OK(status)) {
2211 smbd_server_connection_terminate(sconn, nt_errstr(status));
2216 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
2218 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
2219 struct smbd_smb2_request);
2220 struct smbd_server_connection *sconn = req->sconn;
2225 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2226 TALLOC_FREE(subreq);
2229 status = map_nt_error_from_unix(sys_errno);
2230 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
2231 nt_errstr(status)));
2232 smbd_server_connection_terminate(sconn, nt_errstr(status));
2236 status = smbd_smb2_request_next_incoming(sconn);
2237 if (!NT_STATUS_IS_OK(status)) {
2238 smbd_server_connection_terminate(sconn, nt_errstr(status));
2243 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2245 DATA_BLOB body, DATA_BLOB *dyn,
2246 const char *location)
2249 struct iovec *outbody_v;
2250 struct iovec *outdyn_v;
2251 uint32_t next_command_ofs;
2253 DEBUG(10,("smbd_smb2_request_done_ex: "
2254 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2255 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2257 (unsigned int)(dyn ? dyn->length : 0),
2260 if (body.length < 2) {
2261 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2264 if ((body.length % 2) != 0) {
2265 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2268 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2269 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2270 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2272 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2273 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2275 outbody_v->iov_base = (void *)body.data;
2276 outbody_v->iov_len = body.length;
2279 outdyn_v->iov_base = (void *)dyn->data;
2280 outdyn_v->iov_len = dyn->length;
2282 outdyn_v->iov_base = NULL;
2283 outdyn_v->iov_len = 0;
2286 /* see if we need to recalculate the offset to the next response */
2287 if (next_command_ofs > 0) {
2288 next_command_ofs = SMB2_HDR_BODY;
2289 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2290 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2293 if ((next_command_ofs % 8) != 0) {
2294 size_t pad_size = 8 - (next_command_ofs % 8);
2295 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2297 * if the dyn buffer is empty
2298 * we can use it to add padding
2302 pad = talloc_zero_array(req->out.vector,
2305 return smbd_smb2_request_error(req,
2306 NT_STATUS_NO_MEMORY);
2309 outdyn_v->iov_base = (void *)pad;
2310 outdyn_v->iov_len = pad_size;
2313 * For now we copy the dynamic buffer
2314 * and add the padding to the new buffer
2321 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2322 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2324 new_size = old_size + pad_size;
2325 new_dyn = talloc_zero_array(req->out.vector,
2327 if (new_dyn == NULL) {
2328 return smbd_smb2_request_error(req,
2329 NT_STATUS_NO_MEMORY);
2332 memcpy(new_dyn, old_dyn, old_size);
2333 memset(new_dyn + old_size, 0, pad_size);
2335 outdyn_v->iov_base = (void *)new_dyn;
2336 outdyn_v->iov_len = new_size;
2338 next_command_ofs += pad_size;
2341 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2343 return smbd_smb2_request_reply(req);
2346 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2349 const char *location)
2352 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2354 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2355 req->current_idx, nt_errstr(status), info ? " +info" : "",
2358 body.data = outhdr + SMB2_HDR_BODY;
2360 SSVAL(body.data, 0, 9);
2363 SIVAL(body.data, 0x04, info->length);
2365 /* Allocated size of req->out.vector[i].iov_base
2366 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2367 * 1 byte without having to do an alloc.
2369 info = talloc_zero_array(req->out.vector,
2373 return NT_STATUS_NO_MEMORY;
2375 info->data = ((uint8_t *)outhdr) +
2376 OUTVEC_ALLOC_SIZE - 1;
2378 SCVAL(info->data, 0, 0);
2382 * if a request fails, all other remaining
2383 * compounded requests should fail too
2385 req->next_status = NT_STATUS_INVALID_PARAMETER;
2387 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2391 struct smbd_smb2_send_oplock_break_state {
2392 struct smbd_server_connection *sconn;
2393 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
2394 struct iovec vector;
2397 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2399 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2400 uint64_t file_id_persistent,
2401 uint64_t file_id_volatile,
2402 uint8_t oplock_level)
2404 struct smbd_smb2_send_oplock_break_state *state;
2405 struct tevent_req *subreq;
2409 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2410 if (state == NULL) {
2411 return NT_STATUS_NO_MEMORY;
2413 state->sconn = sconn;
2415 state->vector.iov_base = (void *)state->buf;
2416 state->vector.iov_len = sizeof(state->buf);
2418 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
2419 hdr = state->buf + 4;
2420 body = hdr + SMB2_HDR_BODY;
2422 SIVAL(hdr, 0, SMB2_MAGIC);
2423 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2424 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2425 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2426 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2427 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2428 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2429 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2430 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2431 SIVAL(hdr, SMB2_HDR_PID, 0);
2432 SIVAL(hdr, SMB2_HDR_TID, 0);
2433 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2434 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2436 SSVAL(body, 0x00, 0x18);
2438 SCVAL(body, 0x02, oplock_level);
2439 SCVAL(body, 0x03, 0); /* reserved */
2440 SIVAL(body, 0x04, 0); /* reserved */
2441 SBVAL(body, 0x08, file_id_persistent);
2442 SBVAL(body, 0x10, file_id_volatile);
2444 subreq = tstream_writev_queue_send(state,
2447 sconn->smb2.send_queue,
2449 if (subreq == NULL) {
2450 return NT_STATUS_NO_MEMORY;
2452 tevent_req_set_callback(subreq,
2453 smbd_smb2_oplock_break_writev_done,
2456 return NT_STATUS_OK;
2459 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2461 struct smbd_smb2_send_oplock_break_state *state =
2462 tevent_req_callback_data(subreq,
2463 struct smbd_smb2_send_oplock_break_state);
2464 struct smbd_server_connection *sconn = state->sconn;
2468 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2469 TALLOC_FREE(subreq);
2471 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2472 smbd_server_connection_terminate(sconn, nt_errstr(status));
2479 struct smbd_smb2_request_read_state {
2480 struct tevent_context *ev;
2481 struct smbd_server_connection *sconn;
2482 struct smbd_smb2_request *smb2_req;
2484 uint8_t nbt[NBT_HDR_SIZE];
2491 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2493 TALLOC_CTX *mem_ctx,
2494 struct iovec **_vector,
2496 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2498 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2499 struct tevent_context *ev,
2500 struct smbd_server_connection *sconn)
2502 struct tevent_req *req;
2503 struct smbd_smb2_request_read_state *state;
2504 struct tevent_req *subreq;
2506 req = tevent_req_create(mem_ctx, &state,
2507 struct smbd_smb2_request_read_state);
2512 state->sconn = sconn;
2514 state->smb2_req = smbd_smb2_request_allocate(state);
2515 if (tevent_req_nomem(state->smb2_req, req)) {
2516 return tevent_req_post(req, ev);
2518 state->smb2_req->sconn = sconn;
2520 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2522 state->sconn->smb2.stream,
2523 state->sconn->smb2.recv_queue,
2524 smbd_smb2_request_next_vector,
2526 if (tevent_req_nomem(subreq, req)) {
2527 return tevent_req_post(req, ev);
2529 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2534 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2536 TALLOC_CTX *mem_ctx,
2537 struct iovec **_vector,
2540 struct smbd_smb2_request_read_state *state =
2541 talloc_get_type_abort(private_data,
2542 struct smbd_smb2_request_read_state);
2543 struct iovec *vector;
2545 if (state->pktlen > 0) {
2546 /* if there're no remaining bytes, we're done */
2552 if (!state->hdr.done) {
2554 * first we need to get the NBT header
2556 vector = talloc_array(mem_ctx, struct iovec, 1);
2557 if (vector == NULL) {
2561 vector[0].iov_base = (void *)state->hdr.nbt;
2562 vector[0].iov_len = NBT_HDR_SIZE;
2567 state->hdr.done = true;
2572 * Now we analyze the NBT header
2574 state->pktlen = smb2_len(state->hdr.nbt);
2576 if (state->pktlen == 0) {
2577 /* if there're no remaining bytes, we're done */
2583 state->pktbuf = talloc_array(state->smb2_req, uint8_t, state->pktlen);
2584 if (state->pktbuf == NULL) {
2588 vector = talloc_array(mem_ctx, struct iovec, 1);
2589 if (vector == NULL) {
2593 vector[0].iov_base = (void *)state->pktbuf;
2594 vector[0].iov_len = state->pktlen;
2601 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2603 struct tevent_req *req =
2604 tevent_req_callback_data(subreq,
2606 struct smbd_smb2_request_read_state *state =
2607 tevent_req_data(req,
2608 struct smbd_smb2_request_read_state);
2614 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2615 TALLOC_FREE(subreq);
2617 status = map_nt_error_from_unix(sys_errno);
2618 tevent_req_nterror(req, status);
2622 if (state->hdr.nbt[0] != 0x00) {
2623 DEBUG(1,("smbd_smb2_request_read_done: ignore NBT[0x%02X] msg\n",
2624 state->hdr.nbt[0]));
2626 ZERO_STRUCT(state->hdr);
2627 TALLOC_FREE(state->pktbuf);
2630 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2632 state->sconn->smb2.stream,
2633 state->sconn->smb2.recv_queue,
2634 smbd_smb2_request_next_vector,
2636 if (tevent_req_nomem(subreq, req)) {
2639 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2643 state->smb2_req->request_time = timeval_current();
2644 now = timeval_to_nttime(&state->smb2_req->request_time);
2646 status = smbd_smb2_inbuf_parse_compound(state->smb2_req->sconn->conn,
2651 &state->smb2_req->in.vector,
2652 &state->smb2_req->in.vector_count);
2653 if (tevent_req_nterror(req, status)) {
2657 state->smb2_req->current_idx = 1;
2659 tevent_req_done(req);
2662 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2663 TALLOC_CTX *mem_ctx,
2664 struct smbd_smb2_request **_smb2_req)
2666 struct smbd_smb2_request_read_state *state =
2667 tevent_req_data(req,
2668 struct smbd_smb2_request_read_state);
2671 if (tevent_req_is_nterror(req, &status)) {
2672 tevent_req_received(req);
2676 *_smb2_req = talloc_move(mem_ctx, &state->smb2_req);
2677 tevent_req_received(req);
2678 return NT_STATUS_OK;
2681 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2683 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2685 size_t max_send_queue_len;
2686 size_t cur_send_queue_len;
2687 struct tevent_req *subreq;
2689 if (sconn->smb2.compound_related_in_progress) {
2691 * Can't read another until the related
2694 return NT_STATUS_OK;
2697 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
2699 * if there is already a smbd_smb2_request_read
2700 * pending, we are done.
2702 return NT_STATUS_OK;
2705 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2706 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
2708 if (cur_send_queue_len > max_send_queue_len) {
2710 * if we have a lot of requests to send,
2711 * we wait until they are on the wire until we
2712 * ask for the next request.
2714 return NT_STATUS_OK;
2717 /* ask for the next request */
2718 subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn);
2719 if (subreq == NULL) {
2720 return NT_STATUS_NO_MEMORY;
2722 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2724 return NT_STATUS_OK;
2727 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2728 uint8_t *inbuf, size_t size)
2731 struct smbd_smb2_request *req = NULL;
2733 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2734 (unsigned int)size));
2736 status = smbd_initialize_smb2(sconn);
2737 if (!NT_STATUS_IS_OK(status)) {
2738 smbd_server_connection_terminate(sconn, nt_errstr(status));
2742 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2743 if (!NT_STATUS_IS_OK(status)) {
2744 smbd_server_connection_terminate(sconn, nt_errstr(status));
2748 status = smbd_smb2_request_validate(req);
2749 if (!NT_STATUS_IS_OK(status)) {
2750 smbd_server_connection_terminate(sconn, nt_errstr(status));
2754 status = smbd_smb2_request_setup_out(req);
2755 if (!NT_STATUS_IS_OK(status)) {
2756 smbd_server_connection_terminate(sconn, nt_errstr(status));
2760 status = smbd_smb2_request_dispatch(req);
2761 if (!NT_STATUS_IS_OK(status)) {
2762 smbd_server_connection_terminate(sconn, nt_errstr(status));
2766 status = smbd_smb2_request_next_incoming(sconn);
2767 if (!NT_STATUS_IS_OK(status)) {
2768 smbd_server_connection_terminate(sconn, nt_errstr(status));
2772 sconn->num_requests++;
2775 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2777 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2778 struct smbd_server_connection);
2780 struct smbd_smb2_request *req = NULL;
2782 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2783 TALLOC_FREE(subreq);
2784 if (!NT_STATUS_IS_OK(status)) {
2785 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2786 nt_errstr(status)));
2787 smbd_server_connection_terminate(sconn, nt_errstr(status));
2791 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2792 req->current_idx, req->in.vector_count));
2794 status = smbd_smb2_request_validate(req);
2795 if (!NT_STATUS_IS_OK(status)) {
2796 smbd_server_connection_terminate(sconn, nt_errstr(status));
2800 status = smbd_smb2_request_setup_out(req);
2801 if (!NT_STATUS_IS_OK(status)) {
2802 smbd_server_connection_terminate(sconn, nt_errstr(status));
2806 status = smbd_smb2_request_dispatch(req);
2807 if (!NT_STATUS_IS_OK(status)) {
2808 smbd_server_connection_terminate(sconn, nt_errstr(status));
2812 status = smbd_smb2_request_next_incoming(sconn);
2813 if (!NT_STATUS_IS_OK(status)) {
2814 smbd_server_connection_terminate(sconn, nt_errstr(status));
2818 sconn->num_requests++;
2820 /* The timeout_processing function isn't run nearly
2821 often enough to implement 'max log size' without
2822 overrunning the size of the file by many megabytes.
2823 This is especially true if we are running at debug
2824 level 10. Checking every 50 SMB2s is a nice
2825 tradeoff of performance vs log file size overrun. */
2827 if ((sconn->num_requests % 50) == 0 &&
2828 need_to_check_log_size()) {
2829 change_to_root_user();