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(const 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->first_key);
260 data_blob_clear_free(&req->last_key);
264 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
266 TALLOC_CTX *mem_pool;
267 struct smbd_smb2_request *req;
270 /* Enable this to find subtle valgrind errors. */
271 mem_pool = talloc_init("smbd_smb2_request_allocate");
273 mem_pool = talloc_pool(mem_ctx, 8192);
275 if (mem_pool == NULL) {
279 req = talloc_zero(mem_pool, struct smbd_smb2_request);
281 talloc_free(mem_pool);
284 talloc_reparent(mem_pool, mem_ctx, req);
285 TALLOC_FREE(mem_pool);
287 req->last_session_id = UINT64_MAX;
288 req->last_tid = UINT32_MAX;
290 talloc_set_destructor(req, smbd_smb2_request_destructor);
295 static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
306 uint8_t *first_hdr = buf;
307 size_t verified_buflen = 0;
312 * Note: index '0' is reserved for the transport protocol
314 iov = talloc_zero_array(mem_ctx, struct iovec, num_iov);
316 return NT_STATUS_NO_MEMORY;
319 while (taken < buflen) {
320 size_t len = buflen - taken;
321 uint8_t *hdr = first_hdr + taken;
324 size_t next_command_ofs;
326 uint8_t *body = NULL;
329 struct iovec *iov_tmp;
331 if (verified_buflen > taken) {
332 len = verified_buflen - taken;
339 DEBUG(10, ("%d bytes left, expected at least %d\n",
343 if (IVAL(hdr, 0) == SMB2_TF_MAGIC) {
344 struct smbXsrv_session *s = NULL;
346 struct iovec tf_iov[2];
350 if (conn->protocol < PROTOCOL_SMB2_24) {
351 DEBUG(10, ("Got SMB2_TRANSFORM header, "
352 "but dialect[0x%04X] is used\n",
353 conn->smb2.server.dialect));
357 if (!(conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) {
358 DEBUG(10, ("Got SMB2_TRANSFORM header, "
359 "but not negotiated "
360 "client[0x%08X] server[0x%08X]\n",
361 conn->smb2.client.capabilities,
362 conn->smb2.server.capabilities));
366 if (len < SMB2_TF_HDR_SIZE) {
367 DEBUG(1, ("%d bytes left, expected at least %d\n",
368 (int)len, SMB2_TF_HDR_SIZE));
372 tf_len = SMB2_TF_HDR_SIZE;
375 hdr = first_hdr + taken;
376 enc_len = IVAL(tf, SMB2_TF_MSG_SIZE);
377 uid = BVAL(tf, SMB2_TF_SESSION_ID);
379 if (len < SMB2_TF_HDR_SIZE + enc_len) {
380 DEBUG(1, ("%d bytes left, expected at least %d\n",
382 (int)(SMB2_TF_HDR_SIZE + enc_len)));
386 status = smb2srv_session_lookup(conn, uid, now, &s);
388 DEBUG(1, ("invalid session[%llu] in "
389 "SMB2_TRANSFORM header\n",
390 (unsigned long long)uid));
392 return NT_STATUS_USER_SESSION_DELETED;
395 tf_iov[0].iov_base = (void *)tf;
396 tf_iov[0].iov_len = tf_len;
397 tf_iov[1].iov_base = (void *)hdr;
398 tf_iov[1].iov_len = enc_len;
400 status = smb2_signing_decrypt_pdu(s->global->decryption_key,
403 if (!NT_STATUS_IS_OK(status)) {
408 verified_buflen = taken + enc_len;
413 * We need the header plus the body length field
416 if (len < SMB2_HDR_BODY + 2) {
417 DEBUG(10, ("%d bytes left, expected at least %d\n",
418 (int)len, SMB2_HDR_BODY));
421 if (IVAL(hdr, 0) != SMB2_MAGIC) {
422 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
426 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
427 DEBUG(10, ("Got HDR len %d, expected %d\n",
428 SVAL(hdr, 4), SMB2_HDR_BODY));
433 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
434 body_size = SVAL(hdr, SMB2_HDR_BODY);
436 if (next_command_ofs != 0) {
437 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
440 if (next_command_ofs > full_size) {
443 full_size = next_command_ofs;
450 if (body_size > (full_size - SMB2_HDR_BODY)) {
452 * let the caller handle the error
454 body_size = full_size - SMB2_HDR_BODY;
456 body = hdr + SMB2_HDR_BODY;
457 dyn = body + body_size;
458 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
460 iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
461 num_iov + SMBD_SMB2_NUM_IOV_PER_REQ);
462 if (iov_tmp == NULL) {
464 return NT_STATUS_NO_MEMORY;
468 num_iov += SMBD_SMB2_NUM_IOV_PER_REQ;
470 cur[SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
471 cur[SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
472 cur[SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
473 cur[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
474 cur[SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
475 cur[SMBD_SMB2_BODY_IOV_OFS].iov_len = body_size;
476 cur[SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
477 cur[SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_size;
488 return NT_STATUS_INVALID_PARAMETER;
491 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
492 uint8_t *inbuf, size_t size,
493 struct smbd_smb2_request **_req)
495 struct smbd_smb2_request *req;
496 uint32_t protocol_version;
497 const uint8_t *inhdr = NULL;
499 uint32_t next_command_ofs;
503 if (size < (4 + SMB2_HDR_BODY + 2)) {
504 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
505 return NT_STATUS_INVALID_PARAMETER;
510 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
511 if (protocol_version != SMB2_MAGIC) {
512 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
514 return NT_STATUS_INVALID_PARAMETER;
517 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
518 if (cmd != SMB2_OP_NEGPROT) {
519 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
521 return NT_STATUS_INVALID_PARAMETER;
524 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
525 if (next_command_ofs != 0) {
526 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
528 return NT_STATUS_INVALID_PARAMETER;
531 req = smbd_smb2_request_allocate(sconn);
533 return NT_STATUS_NO_MEMORY;
537 talloc_steal(req, inbuf);
539 req->request_time = timeval_current();
540 now = timeval_to_nttime(&req->request_time);
542 status = smbd_smb2_inbuf_parse_compound(sconn->conn,
544 inbuf + NBT_HDR_SIZE,
546 req, &req->in.vector,
547 &req->in.vector_count);
548 if (!NT_STATUS_IS_OK(status)) {
553 req->current_idx = 1;
559 static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
560 uint64_t message_id, uint64_t seq_id)
562 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
565 if (seq_id < sconn->smb2.seqnum_low) {
566 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
567 "%llu (sequence id %llu) "
568 "(granted = %u, low = %llu, range = %u)\n",
569 (unsigned long long)message_id,
570 (unsigned long long)seq_id,
571 (unsigned int)sconn->smb2.credits_granted,
572 (unsigned long long)sconn->smb2.seqnum_low,
573 (unsigned int)sconn->smb2.seqnum_range));
577 if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
578 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
579 "%llu (sequence id %llu) "
580 "(granted = %u, low = %llu, range = %u)\n",
581 (unsigned long long)message_id,
582 (unsigned long long)seq_id,
583 (unsigned int)sconn->smb2.credits_granted,
584 (unsigned long long)sconn->smb2.seqnum_low,
585 (unsigned int)sconn->smb2.seqnum_range));
589 offset = seq_id % sconn->smb2.max_credits;
591 if (bitmap_query(credits_bm, offset)) {
592 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
593 "%llu (sequence id %llu) "
594 "(granted = %u, low = %llu, range = %u) "
596 (unsigned long long)message_id,
597 (unsigned long long)seq_id,
598 (unsigned int)sconn->smb2.credits_granted,
599 (unsigned long long)sconn->smb2.seqnum_low,
600 (unsigned int)sconn->smb2.seqnum_range,
605 /* Mark the message_ids as seen in the bitmap. */
606 bitmap_set(credits_bm, offset);
608 if (seq_id != sconn->smb2.seqnum_low) {
613 * Move the window forward by all the message_id's
616 while (bitmap_query(credits_bm, offset)) {
617 DEBUG(10,("smb2_validate_sequence_number: clearing "
618 "id %llu (position %u) from bitmap\n",
619 (unsigned long long)(sconn->smb2.seqnum_low),
621 bitmap_clear(credits_bm, offset);
623 sconn->smb2.seqnum_low += 1;
624 sconn->smb2.seqnum_range -= 1;
625 offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
631 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
632 const uint8_t *inhdr)
634 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
635 uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
636 uint16_t credit_charge = 1;
639 if (opcode == SMB2_OP_CANCEL) {
640 /* SMB2_CANCEL requests by definition resend messageids. */
644 if (sconn->smb2.supports_multicredit) {
645 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
646 credit_charge = MAX(credit_charge, 1);
649 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
650 "credits_granted %llu, "
651 "seqnum low/range: %llu/%llu\n",
652 (unsigned long long) message_id,
653 (unsigned long long) credit_charge,
654 (unsigned long long) sconn->smb2.credits_granted,
655 (unsigned long long) sconn->smb2.seqnum_low,
656 (unsigned long long) sconn->smb2.seqnum_range));
658 if (sconn->smb2.credits_granted < credit_charge) {
659 DEBUG(0, ("smb2_validate_message_id: client used more "
660 "credits than granted, mid %llu, charge %llu, "
661 "credits_granted %llu, "
662 "seqnum low/range: %llu/%llu\n",
663 (unsigned long long) message_id,
664 (unsigned long long) credit_charge,
665 (unsigned long long) sconn->smb2.credits_granted,
666 (unsigned long long) sconn->smb2.seqnum_low,
667 (unsigned long long) sconn->smb2.seqnum_range));
672 * now check the message ids
674 * for multi-credit requests we need to check all current mid plus
675 * the implicit mids caused by the credit charge
676 * e.g. current mid = 15, charge 5 => mark 15-19 as used
679 for (i = 0; i <= (credit_charge-1); i++) {
680 uint64_t id = message_id + i;
683 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
684 (unsigned long long)message_id,
686 (unsigned long long)id));
688 ok = smb2_validate_sequence_number(sconn, message_id, id);
694 /* substract used credits */
695 sconn->smb2.credits_granted -= credit_charge;
700 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
705 count = req->in.vector_count;
707 if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
708 /* It's not a SMB2 request */
709 return NT_STATUS_INVALID_PARAMETER;
712 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
713 struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
714 struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx);
715 const uint8_t *inhdr = NULL;
718 if (hdr->iov_len != SMB2_HDR_BODY) {
719 return NT_STATUS_INVALID_PARAMETER;
722 if (body->iov_len < 2) {
723 return NT_STATUS_INVALID_PARAMETER;
726 inhdr = (const uint8_t *)hdr->iov_base;
728 /* Check the SMB2 header */
729 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
730 return NT_STATUS_INVALID_PARAMETER;
733 if (!smb2_validate_message_id(req->sconn, inhdr)) {
734 return NT_STATUS_INVALID_PARAMETER;
737 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
738 if (idx < SMBD_SMB2_NUM_IOV_PER_REQ) {
740 * the 1st request should never have the
741 * SMB2_HDR_FLAG_CHAINED flag set
743 if (flags & SMB2_HDR_FLAG_CHAINED) {
744 req->next_status = NT_STATUS_INVALID_PARAMETER;
747 } else if (idx < 2*SMBD_SMB2_NUM_IOV_PER_REQ) {
749 * the 2nd request triggers related vs. unrelated
750 * compounded requests
752 if (flags & SMB2_HDR_FLAG_CHAINED) {
753 req->compound_related = true;
758 * It seems the this tests are wrong
759 * see the SMB2-COMPOUND test
763 * all other requests should match the 2nd one
765 if (flags & SMB2_HDR_FLAG_CHAINED) {
766 if (!req->compound_related) {
768 NT_STATUS_INVALID_PARAMETER;
772 if (req->compound_related) {
774 NT_STATUS_INVALID_PARAMETER;
785 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
786 const struct iovec *in_vector,
787 struct iovec *out_vector)
789 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
790 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
791 uint16_t credit_charge = 1;
792 uint16_t credits_requested;
796 uint16_t credits_granted = 0;
797 uint64_t credits_possible;
798 uint16_t current_max_credits;
801 * first we grant only 1/16th of the max range.
803 * Windows also starts with the 1/16th and then grants
804 * more later. I was only able to trigger higher
805 * values, when using a verify high credit charge.
807 * TODO: scale up depending one load, free memory
809 * Maybe also on the relationship between number
810 * of requests and the used sequence number.
811 * Which means we would grant more credits
812 * for client which use multi credit requests.
814 current_max_credits = sconn->smb2.max_credits / 16;
815 current_max_credits = MAX(current_max_credits, 1);
817 if (sconn->smb2.supports_multicredit) {
818 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
819 credit_charge = MAX(credit_charge, 1);
822 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
823 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
824 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
825 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
827 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
828 SMB_ASSERT(sconn->smb2.max_credits >= credit_charge);
830 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
832 * In case we already send an async interim
833 * response, we should not grant
834 * credits on the final response.
837 } else if (credits_requested > 0) {
838 uint16_t additional_max = 0;
839 uint16_t additional_credits = credits_requested - 1;
842 case SMB2_OP_NEGPROT:
844 case SMB2_OP_SESSSETUP:
846 * Windows 2012 RC1 starts to grant
848 * with a successful session setup
850 if (NT_STATUS_IS_OK(out_status)) {
856 * We match windows and only grant additional credits
863 additional_credits = MIN(additional_credits, additional_max);
865 credits_granted = credit_charge + additional_credits;
866 } else if (sconn->smb2.credits_granted == 0) {
868 * Make sure the client has always at least one credit
874 * sequence numbers should not wrap
876 * 1. calculate the possible credits until
877 * the sequence numbers start to wrap on 64-bit.
879 * 2. UINT64_MAX is used for Break Notifications.
881 * 2. truncate the possible credits to the maximum
882 * credits we want to grant to the client in total.
884 * 3. remove the range we'll already granted to the client
885 * this makes sure the client consumes the lowest sequence
886 * number, before we can grant additional credits.
888 credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
889 if (credits_possible > 0) {
890 /* remove UINT64_MAX */
891 credits_possible -= 1;
893 credits_possible = MIN(credits_possible, current_max_credits);
894 credits_possible -= sconn->smb2.seqnum_range;
896 credits_granted = MIN(credits_granted, credits_possible);
898 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
899 sconn->smb2.credits_granted += credits_granted;
900 sconn->smb2.seqnum_range += credits_granted;
902 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
903 "granted %u, current possible/max %u/%u, "
904 "total granted/max/low/range %u/%u/%llu/%u\n",
905 (unsigned int)credits_requested,
906 (unsigned int)credit_charge,
907 (unsigned int)credits_granted,
908 (unsigned int)credits_possible,
909 (unsigned int)current_max_credits,
910 (unsigned int)sconn->smb2.credits_granted,
911 (unsigned int)sconn->smb2.max_credits,
912 (unsigned long long)sconn->smb2.seqnum_low,
913 (unsigned int)sconn->smb2.seqnum_range));
916 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
917 struct smbd_smb2_request *outreq)
920 uint16_t total_credits = 0;
922 count = outreq->out.vector_count;
924 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
925 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(inreq,in,idx);
926 struct iovec *outhdr_v = SMBD_SMB2_IDX_HDR_IOV(outreq,out,idx);
927 uint8_t *outhdr = (uint8_t *)outhdr_v->iov_base;
929 smb2_set_operation_credit(outreq->sconn, inhdr_v, outhdr_v);
931 /* To match Windows, count up what we
933 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
934 /* Set to zero in all but the last reply. */
935 if (idx + SMBD_SMB2_NUM_IOV_PER_REQ < count) {
936 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
938 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
943 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
945 struct iovec *vector;
949 count = req->in.vector_count;
950 vector = talloc_zero_array(req, struct iovec, count);
951 if (vector == NULL) {
952 return NT_STATUS_NO_MEMORY;
955 vector[0].iov_base = req->out.nbt_hdr;
956 vector[0].iov_len = 4;
957 SIVAL(req->out.nbt_hdr, 0, 0);
959 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
960 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
961 const uint8_t *inhdr = (const uint8_t *)inhdr_v->iov_base;
962 uint8_t *outhdr = NULL;
963 uint8_t *outbody = NULL;
964 uint32_t next_command_ofs = 0;
965 struct iovec *current = &vector[idx];
967 if ((idx + SMBD_SMB2_NUM_IOV_PER_REQ) < count) {
968 /* we have a next command -
969 * setup for the error case. */
970 next_command_ofs = SMB2_HDR_BODY + 9;
973 outhdr = talloc_zero_array(vector, uint8_t,
975 if (outhdr == NULL) {
976 return NT_STATUS_NO_MEMORY;
979 outbody = outhdr + SMB2_HDR_BODY;
982 * SMBD_SMB2_TF_IOV_OFS might be used later
984 current[SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
985 current[SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
987 current[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)outhdr;
988 current[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
990 current[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)outbody;
991 current[SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
993 current[SMBD_SMB2_DYN_IOV_OFS].iov_base = NULL;
994 current[SMBD_SMB2_DYN_IOV_OFS].iov_len = 0;
996 /* setup the SMB2 header */
997 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
998 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
999 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
1000 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
1001 SIVAL(outhdr, SMB2_HDR_STATUS,
1002 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
1003 SSVAL(outhdr, SMB2_HDR_OPCODE,
1004 SVAL(inhdr, SMB2_HDR_OPCODE));
1005 SIVAL(outhdr, SMB2_HDR_FLAGS,
1006 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
1007 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
1008 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
1009 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
1010 SIVAL(outhdr, SMB2_HDR_PID,
1011 IVAL(inhdr, SMB2_HDR_PID));
1012 SIVAL(outhdr, SMB2_HDR_TID,
1013 IVAL(inhdr, SMB2_HDR_TID));
1014 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
1015 BVAL(inhdr, SMB2_HDR_SESSION_ID));
1016 memcpy(outhdr + SMB2_HDR_SIGNATURE,
1017 inhdr + SMB2_HDR_SIGNATURE, 16);
1019 /* setup error body header */
1020 SSVAL(outbody, 0x00, 0x08 + 1);
1021 SSVAL(outbody, 0x02, 0);
1022 SIVAL(outbody, 0x04, 0);
1025 req->out.vector = vector;
1026 req->out.vector_count = count;
1028 /* setup the length of the NBT packet */
1029 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
1031 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
1033 return NT_STATUS_OK;
1036 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
1038 const char *location)
1040 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
1042 exit_server_cleanly(reason);
1045 static bool dup_smb2_vec4(TALLOC_CTX *ctx,
1046 struct iovec *outvec,
1047 const struct iovec *srcvec)
1049 const uint8_t *srctf;
1051 const uint8_t *srchdr;
1053 const uint8_t *srcbody;
1055 const uint8_t *expected_srcbody;
1056 const uint8_t *srcdyn;
1058 const uint8_t *expected_srcdyn;
1064 srctf = (const uint8_t *)srcvec[SMBD_SMB2_TF_IOV_OFS].iov_base;
1065 srctf_len = srcvec[SMBD_SMB2_TF_IOV_OFS].iov_len;
1066 srchdr = (const uint8_t *)srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base;
1067 srchdr_len = srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_len;
1068 srcbody = (const uint8_t *)srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_base;
1069 srcbody_len = srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_len;
1070 expected_srcbody = srchdr + SMB2_HDR_BODY;
1071 srcdyn = (const uint8_t *)srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_base;
1072 srcdyn_len = srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_len;
1073 expected_srcdyn = srcbody + 8;
1075 if ((srctf_len != SMB2_TF_HDR_SIZE) && (srctf_len != 0)) {
1079 if (srchdr_len != SMB2_HDR_BODY) {
1083 if (srctf_len == SMB2_TF_HDR_SIZE) {
1084 dsttf = talloc_memdup(ctx, srctf, SMB2_TF_HDR_SIZE);
1085 if (dsttf == NULL) {
1091 outvec[SMBD_SMB2_TF_IOV_OFS].iov_base = (void *)dsttf;
1092 outvec[SMBD_SMB2_TF_IOV_OFS].iov_len = srctf_len;
1094 /* vec[SMBD_SMB2_HDR_IOV_OFS] is always boilerplate and must
1095 * be allocated with size OUTVEC_ALLOC_SIZE. */
1097 dsthdr = talloc_memdup(ctx, srchdr, OUTVEC_ALLOC_SIZE);
1098 if (dsthdr == NULL) {
1101 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)dsthdr;
1102 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1105 * If this is a "standard" vec[SMBD_SMB2_BOFY_IOV_OFS] of length 8,
1106 * pointing to srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + SMB2_HDR_BODY,
1107 * then duplicate this. Else use talloc_memdup().
1110 if ((srcbody == expected_srcbody) && (srcbody_len == 8)) {
1111 dstbody = dsthdr + SMB2_HDR_BODY;
1113 dstbody = talloc_memdup(ctx, srcbody, srcbody_len);
1114 if (dstbody == NULL) {
1118 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)dstbody;
1119 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_len = srcbody_len;
1122 * If this is a "standard" vec[SMBD_SMB2_DYN_IOV_OFS] of length 1,
1124 * srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + 8
1125 * then duplicate this. Else use talloc_memdup().
1128 if ((srcdyn == expected_srcdyn) && (srcdyn_len == 1)) {
1129 dstdyn = dsthdr + SMB2_HDR_BODY + 8;
1130 } else if (srcdyn == NULL) {
1133 dstdyn = talloc_memdup(ctx, srcdyn, srcdyn_len);
1134 if (dstdyn == NULL) {
1138 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_base = (void *)dstdyn;
1139 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_len = srcdyn_len;
1144 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
1146 struct smbd_smb2_request *newreq = NULL;
1147 struct iovec *outvec = NULL;
1148 int count = req->out.vector_count;
1151 newreq = smbd_smb2_request_allocate(req->sconn);
1156 newreq->sconn = req->sconn;
1157 newreq->session = req->session;
1158 newreq->do_encryption = req->do_encryption;
1159 newreq->do_signing = req->do_signing;
1160 newreq->current_idx = req->current_idx;
1162 outvec = talloc_zero_array(newreq, struct iovec, count);
1164 TALLOC_FREE(newreq);
1167 newreq->out.vector = outvec;
1168 newreq->out.vector_count = count;
1170 /* Setup the outvec's identically to req. */
1171 outvec[0].iov_base = newreq->out.nbt_hdr;
1172 outvec[0].iov_len = 4;
1173 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
1175 /* Setup the vectors identically to the ones in req. */
1176 for (i = 1; i < count; i += SMBD_SMB2_NUM_IOV_PER_REQ) {
1177 if (!dup_smb2_vec4(outvec, &outvec[i], &req->out.vector[i])) {
1184 TALLOC_FREE(newreq);
1188 smb2_setup_nbt_length(newreq->out.vector,
1189 newreq->out.vector_count);
1194 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
1196 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1198 struct smbXsrv_connection *conn = req->sconn->conn;
1200 struct iovec *firsttf = NULL;
1201 struct iovec *outhdr_v = NULL;
1202 uint8_t *outhdr = NULL;
1203 struct smbd_smb2_request *nreq = NULL;
1206 /* Create a new smb2 request we'll use
1207 for the interim return. */
1208 nreq = dup_smb2_req(req);
1210 return NT_STATUS_NO_MEMORY;
1213 /* Lose the last X out vectors. They're the
1214 ones we'll be using for the async reply. */
1215 nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ;
1217 smb2_setup_nbt_length(nreq->out.vector,
1218 nreq->out.vector_count);
1220 /* Step back to the previous reply. */
1221 nreq->current_idx -= SMBD_SMB2_NUM_IOV_PER_REQ;
1222 firsttf = SMBD_SMB2_IDX_TF_IOV(nreq,out,first_idx);
1223 outhdr_v = SMBD_SMB2_OUT_HDR_IOV(nreq);
1224 outhdr = SMBD_SMB2_OUT_HDR_PTR(nreq);
1225 /* And end the chain. */
1226 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1228 /* Calculate outgoing credits */
1229 smb2_calculate_credits(req, nreq);
1231 if (DEBUGLEVEL >= 10) {
1232 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1233 (unsigned int)nreq->current_idx );
1234 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1235 (unsigned int)nreq->out.vector_count );
1236 print_req_vectors(nreq);
1240 * As we have changed the header (SMB2_HDR_NEXT_COMMAND),
1241 * we need to sign/encrypt here with the last/first key we remembered
1243 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
1244 status = smb2_signing_encrypt_pdu(req->first_key,
1247 nreq->out.vector_count - first_idx);
1248 if (!NT_STATUS_IS_OK(status)) {
1251 } else if (req->last_key.length > 0) {
1252 status = smb2_signing_sign_pdu(req->last_key,
1255 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1256 if (!NT_STATUS_IS_OK(status)) {
1261 nreq->subreq = tstream_writev_queue_send(nreq,
1262 nreq->sconn->ev_ctx,
1263 nreq->sconn->smb2.stream,
1264 nreq->sconn->smb2.send_queue,
1266 nreq->out.vector_count);
1268 if (nreq->subreq == NULL) {
1269 return NT_STATUS_NO_MEMORY;
1272 tevent_req_set_callback(nreq->subreq,
1273 smbd_smb2_request_writev_done,
1276 return NT_STATUS_OK;
1279 struct smbd_smb2_request_pending_state {
1280 struct smbd_server_connection *sconn;
1281 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x08 + 1];
1282 struct iovec vector[1 + SMBD_SMB2_NUM_IOV_PER_REQ];
1285 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
1287 struct smbd_smb2_request_pending_state *state =
1288 tevent_req_callback_data(subreq,
1289 struct smbd_smb2_request_pending_state);
1290 struct smbd_server_connection *sconn = state->sconn;
1294 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1295 TALLOC_FREE(subreq);
1297 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1298 smbd_server_connection_terminate(sconn, nt_errstr(status));
1305 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1306 struct tevent_timer *te,
1307 struct timeval current_time,
1308 void *private_data);
1310 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1311 struct tevent_req *subreq,
1312 uint32_t defer_time)
1315 int idx = req->current_idx;
1316 struct timeval defer_endtime;
1317 uint8_t *outhdr = NULL;
1320 if (!tevent_req_is_in_progress(subreq)) {
1321 return NT_STATUS_OK;
1324 req->subreq = subreq;
1327 if (req->async_te) {
1328 /* We're already async. */
1329 return NT_STATUS_OK;
1332 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1333 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1334 if (flags & SMB2_HDR_FLAG_ASYNC) {
1335 /* We're already async. */
1336 return NT_STATUS_OK;
1339 if (req->in.vector_count > idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
1341 * We're trying to go async in a compound
1342 * request chain. This is not allowed.
1343 * Cancel the outstanding request.
1345 tevent_req_cancel(req->subreq);
1346 return smbd_smb2_request_error(req,
1347 NT_STATUS_INSUFFICIENT_RESOURCES);
1350 if (DEBUGLEVEL >= 10) {
1351 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1352 (unsigned int)req->current_idx );
1353 print_req_vectors(req);
1356 if (req->out.vector_count >= (2*SMBD_SMB2_NUM_IOV_PER_REQ)) {
1358 * This is a compound reply. We
1359 * must do an interim response
1360 * followed by the async response
1363 status = smb2_send_async_interim_response(req);
1364 if (!NT_STATUS_IS_OK(status)) {
1367 data_blob_clear_free(&req->first_key);
1370 * We're splitting off the last SMB2
1371 * request in a compound set, and the
1372 * smb2_send_async_interim_response()
1373 * call above just sent all the replies
1374 * for the previous SMB2 requests in
1375 * this compound set. So we're no longer
1376 * in the "compound_related_in_progress"
1377 * state, and this is no longer a compound
1380 req->compound_related = false;
1381 req->sconn->smb2.compound_related_in_progress = false;
1383 req->current_idx = 1;
1385 /* Re-arrange the in.vectors. */
1386 memmove(&req->in.vector[req->current_idx],
1387 &req->in.vector[idx],
1388 sizeof(req->in.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
1389 req->in.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
1391 /* Re-arrange the out.vectors. */
1392 memmove(&req->out.vector[req->current_idx],
1393 &req->out.vector[idx],
1394 sizeof(req->out.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
1395 req->out.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
1397 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1398 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1399 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1401 data_blob_clear_free(&req->last_key);
1403 defer_endtime = timeval_current_ofs_usec(defer_time);
1404 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1406 smbd_smb2_request_pending_timer,
1408 if (req->async_te == NULL) {
1409 return NT_STATUS_NO_MEMORY;
1412 return NT_STATUS_OK;
1415 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1416 struct tevent_timer *te,
1417 struct timeval current_time,
1420 struct smbd_smb2_request *req =
1421 talloc_get_type_abort(private_data,
1422 struct smbd_smb2_request);
1423 struct smbd_smb2_request_pending_state *state = NULL;
1424 uint8_t *outhdr = NULL;
1425 const uint8_t *inhdr = NULL;
1428 uint8_t *hdr = NULL;
1429 uint8_t *body = NULL;
1430 uint8_t *dyn = NULL;
1432 uint64_t session_id = 0;
1433 uint64_t message_id = 0;
1434 uint64_t nonce_high;
1436 uint64_t async_id = 0;
1437 struct tevent_req *subreq = NULL;
1439 TALLOC_FREE(req->async_te);
1441 /* Ensure our final reply matches the interim one. */
1442 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1443 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1444 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1445 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1446 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1448 async_id = message_id; /* keep it simple for now... */
1450 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1451 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1453 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1455 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1456 (unsigned long long)async_id ));
1459 * What we send is identical to a smbd_smb2_request_error
1460 * packet with an error status of STATUS_PENDING. Make use
1461 * of this fact sometime when refactoring. JRA.
1464 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1465 if (state == NULL) {
1466 smbd_server_connection_terminate(req->sconn,
1467 nt_errstr(NT_STATUS_NO_MEMORY));
1470 state->sconn = req->sconn;
1472 tf = state->buf + NBT_HDR_SIZE;
1473 tf_len = SMB2_TF_HDR_SIZE;
1475 hdr = tf + SMB2_TF_HDR_SIZE;
1476 body = hdr + SMB2_HDR_BODY;
1480 * We may have 2 responses (PENDING, FINAL),
1481 * so alter the nonce.
1483 * The PENDING response has the SMB2_HDR_FLAG_ASYNC bit
1486 nonce_high = session_id | SMB2_HDR_FLAG_ASYNC;
1487 nonce_low = message_id;
1489 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1490 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1491 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1492 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1494 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1495 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1496 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1497 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1498 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1500 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1501 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1502 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1503 SBVAL(hdr, SMB2_HDR_PID, async_id);
1504 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1505 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1506 memcpy(hdr+SMB2_HDR_SIGNATURE,
1507 outhdr+SMB2_HDR_SIGNATURE, 16);
1509 SSVAL(body, 0x00, 0x08 + 1);
1511 SCVAL(body, 0x02, 0);
1512 SCVAL(body, 0x03, 0);
1513 SIVAL(body, 0x04, 0);
1514 /* Match W2K8R2... */
1515 SCVAL(dyn, 0x00, 0x21);
1517 state->vector[0].iov_base = (void *)state->buf;
1518 state->vector[0].iov_len = NBT_HDR_SIZE;
1520 if (req->do_encryption) {
1521 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1522 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1524 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1525 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1528 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1529 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1531 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1532 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1534 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1535 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1537 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1539 /* Ensure we correctly go through crediting. Grant
1540 the credits now, and zero credits on the final
1542 smb2_set_operation_credit(req->sconn,
1543 SMBD_SMB2_IN_HDR_IOV(req),
1544 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1546 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1551 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1552 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1554 (unsigned int)ARRAY_SIZE(state->vector),
1555 (unsigned int)state->vector[i].iov_len);
1559 if (req->do_encryption) {
1561 struct smbXsrv_session *x = req->session;
1562 struct smbXsrv_connection *conn = x->connection;
1563 DATA_BLOB encryption_key = x->global->encryption_key;
1565 status = smb2_signing_encrypt_pdu(encryption_key,
1567 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1568 SMBD_SMB2_NUM_IOV_PER_REQ);
1569 if (!NT_STATUS_IS_OK(status)) {
1570 smbd_server_connection_terminate(req->sconn,
1574 } else if (req->do_signing) {
1576 struct smbXsrv_session *x = req->session;
1577 struct smbXsrv_connection *conn = x->connection;
1578 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1580 status = smb2_signing_sign_pdu(signing_key,
1582 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1583 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1584 if (!NT_STATUS_IS_OK(status)) {
1585 smbd_server_connection_terminate(req->sconn,
1591 subreq = tstream_writev_queue_send(state,
1592 state->sconn->ev_ctx,
1593 state->sconn->smb2.stream,
1594 state->sconn->smb2.send_queue,
1596 ARRAY_SIZE(state->vector));
1597 if (subreq == NULL) {
1598 smbd_server_connection_terminate(state->sconn,
1599 nt_errstr(NT_STATUS_NO_MEMORY));
1602 tevent_req_set_callback(subreq,
1603 smbd_smb2_request_pending_writev_done,
1607 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1609 struct smbd_server_connection *sconn = req->sconn;
1610 struct smbd_smb2_request *cur;
1611 const uint8_t *inhdr;
1613 uint64_t search_message_id;
1614 uint64_t search_async_id;
1617 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1619 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1620 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1621 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1624 * we don't need the request anymore
1625 * cancel requests never have a response
1627 DLIST_REMOVE(req->sconn->smb2.requests, req);
1630 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1631 const uint8_t *outhdr;
1632 uint64_t message_id;
1635 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1637 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1638 async_id = BVAL(outhdr, SMB2_HDR_PID);
1640 if (flags & SMB2_HDR_FLAG_ASYNC) {
1641 if (search_async_id == async_id) {
1642 found_id = async_id;
1646 if (search_message_id == message_id) {
1647 found_id = message_id;
1653 if (cur && cur->subreq) {
1654 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1655 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1656 "cancel opcode[%s] mid %llu\n",
1657 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1658 (unsigned long long)found_id ));
1659 tevent_req_cancel(cur->subreq);
1662 return NT_STATUS_OK;
1665 /*************************************************************
1666 Ensure an incoming tid is a valid one for us to access.
1667 Change to the associated uid credentials and chdir to the
1668 valid tid directory.
1669 *************************************************************/
1671 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1673 const uint8_t *inhdr;
1676 struct smbXsrv_tcon *tcon;
1678 NTTIME now = timeval_to_nttime(&req->request_time);
1682 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1684 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1685 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1687 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1688 in_tid = req->last_tid;
1691 status = smb2srv_tcon_lookup(req->session,
1692 in_tid, now, &tcon);
1693 if (!NT_STATUS_IS_OK(status)) {
1697 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1698 return NT_STATUS_ACCESS_DENIED;
1701 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1702 if (!set_current_service(tcon->compat, 0, true)) {
1703 return NT_STATUS_ACCESS_DENIED;
1707 req->last_tid = in_tid;
1709 return NT_STATUS_OK;
1712 /*************************************************************
1713 Ensure an incoming session_id is a valid one for us to access.
1714 *************************************************************/
1716 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1718 const uint8_t *inhdr;
1721 uint64_t in_session_id;
1722 struct smbXsrv_session *session = NULL;
1723 struct auth_session_info *session_info;
1725 NTTIME now = timeval_to_nttime(&req->request_time);
1727 req->session = NULL;
1730 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1732 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1733 in_opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1734 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1736 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1737 in_session_id = req->last_session_id;
1740 /* lookup an existing session */
1741 status = smb2srv_session_lookup(req->sconn->conn,
1745 req->session = session;
1746 req->last_session_id = in_session_id;
1748 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1749 switch (in_opcode) {
1750 case SMB2_OP_SESSSETUP:
1751 status = NT_STATUS_OK;
1757 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1758 switch (in_opcode) {
1760 case SMB2_OP_CREATE:
1761 case SMB2_OP_GETINFO:
1762 case SMB2_OP_SETINFO:
1763 return NT_STATUS_INVALID_HANDLE;
1766 * Notice the check for
1767 * (session_info == NULL)
1770 status = NT_STATUS_OK;
1774 if (!NT_STATUS_IS_OK(status)) {
1778 session_info = session->global->auth_session_info;
1779 if (session_info == NULL) {
1780 return NT_STATUS_INVALID_HANDLE;
1783 set_current_user_info(session_info->unix_info->sanitized_username,
1784 session_info->unix_info->unix_name,
1785 session_info->info->domain_name);
1787 return NT_STATUS_OK;
1790 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1791 uint32_t data_length)
1793 uint16_t needed_charge;
1794 uint16_t credit_charge = 1;
1795 const uint8_t *inhdr;
1797 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1799 if (req->sconn->smb2.supports_multicredit) {
1800 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1801 credit_charge = MAX(credit_charge, 1);
1804 needed_charge = (data_length - 1)/ 65536 + 1;
1806 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1807 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1808 credit_charge, needed_charge));
1810 if (needed_charge > credit_charge) {
1811 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1812 credit_charge, needed_charge));
1813 return NT_STATUS_INVALID_PARAMETER;
1816 return NT_STATUS_OK;
1819 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1820 size_t expected_body_size)
1822 struct iovec *inhdr_v;
1823 const uint8_t *inhdr;
1825 const uint8_t *inbody;
1827 size_t min_dyn_size = expected_body_size & 0x00000001;
1828 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1831 * The following should be checked already.
1833 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1834 return NT_STATUS_INTERNAL_ERROR;
1836 if (req->current_idx > max_idx) {
1837 return NT_STATUS_INTERNAL_ERROR;
1840 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1841 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1842 return NT_STATUS_INTERNAL_ERROR;
1844 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1845 return NT_STATUS_INTERNAL_ERROR;
1848 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1849 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1853 case SMB2_OP_GETINFO:
1859 * Now check the expected body size,
1860 * where the last byte might be in the
1863 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1864 return NT_STATUS_INVALID_PARAMETER;
1866 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1867 return NT_STATUS_INVALID_PARAMETER;
1870 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1872 body_size = SVAL(inbody, 0x00);
1873 if (body_size != expected_body_size) {
1874 return NT_STATUS_INVALID_PARAMETER;
1877 return NT_STATUS_OK;
1880 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1882 struct smbXsrv_connection *conn = req->sconn->conn;
1883 const struct smbd_smb2_dispatch_table *call = NULL;
1884 const struct iovec *intf_v = SMBD_SMB2_IN_TF_IOV(req);
1885 const uint8_t *inhdr;
1890 NTSTATUS session_status;
1891 uint32_t allowed_flags;
1892 NTSTATUS return_value;
1893 struct smbXsrv_session *x = NULL;
1894 bool signing_required = false;
1895 bool encryption_required = false;
1897 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1899 /* TODO: verify more things */
1901 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1902 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1903 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1904 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1905 smb2_opcode_name(opcode),
1906 (unsigned long long)mid));
1908 if (conn->protocol >= PROTOCOL_SMB2_02) {
1910 * once the protocol is negotiated
1911 * SMB2_OP_NEGPROT is not allowed anymore
1913 if (opcode == SMB2_OP_NEGPROT) {
1914 /* drop the connection */
1915 return NT_STATUS_INVALID_PARAMETER;
1919 * if the protocol is not negotiated yet
1920 * only SMB2_OP_NEGPROT is allowed.
1922 if (opcode != SMB2_OP_NEGPROT) {
1923 /* drop the connection */
1924 return NT_STATUS_INVALID_PARAMETER;
1929 * Check if the client provided a valid session id,
1930 * if so smbd_smb2_request_check_session() calls
1931 * set_current_user_info().
1933 * As some command don't require a valid session id
1934 * we defer the check of the session_status
1936 session_status = smbd_smb2_request_check_session(req);
1939 signing_required = x->global->signing_required;
1940 encryption_required = x->global->encryption_required;
1942 if (opcode == SMB2_OP_SESSSETUP &&
1943 x->global->channels[0].signing_key.length) {
1944 signing_required = true;
1948 req->do_signing = false;
1949 req->do_encryption = false;
1950 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
1951 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
1952 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
1954 if (x != NULL && x->global->session_wire_id != tf_session_id) {
1955 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1956 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
1957 (unsigned long long)x->global->session_wire_id,
1958 (unsigned long long)tf_session_id));
1960 * TODO: windows allows this...
1961 * should we drop the connection?
1963 * For now we just return ACCESS_DENIED
1964 * (Windows clients never trigger this)
1965 * and wait for an update of [MS-SMB2].
1967 return smbd_smb2_request_error(req,
1968 NT_STATUS_ACCESS_DENIED);
1971 req->do_encryption = true;
1974 if (encryption_required && !req->do_encryption) {
1975 return smbd_smb2_request_error(req,
1976 NT_STATUS_ACCESS_DENIED);
1979 call = smbd_smb2_call(opcode);
1981 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1984 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1985 SMB2_HDR_FLAG_SIGNED |
1987 if (opcode == SMB2_OP_CANCEL) {
1988 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1990 if ((flags & ~allowed_flags) != 0) {
1991 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1994 if (req->do_encryption) {
1995 signing_required = false;
1996 } else if (flags & SMB2_HDR_FLAG_SIGNED) {
1997 DATA_BLOB signing_key;
2000 return smbd_smb2_request_error(
2001 req, NT_STATUS_ACCESS_DENIED);
2004 signing_key = x->global->channels[0].signing_key;
2007 * If we have a signing key, we should
2010 if (signing_key.length > 0) {
2011 req->do_signing = true;
2014 status = smb2_signing_check_pdu(signing_key,
2016 SMBD_SMB2_IN_HDR_IOV(req),
2017 SMBD_SMB2_NUM_IOV_PER_REQ);
2018 if (!NT_STATUS_IS_OK(status)) {
2019 return smbd_smb2_request_error(req, status);
2023 * Now that we know the request was correctly signed
2024 * we have to sign the response too.
2026 req->do_signing = true;
2028 if (!NT_STATUS_IS_OK(session_status)) {
2029 return smbd_smb2_request_error(req, session_status);
2031 } else if (opcode == SMB2_OP_CANCEL) {
2032 /* Cancel requests are allowed to skip the signing */
2033 } else if (signing_required) {
2035 * If signing is required we try to sign
2036 * a possible error response
2038 req->do_signing = true;
2039 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2042 if (flags & SMB2_HDR_FLAG_CHAINED) {
2044 * This check is mostly for giving the correct error code
2045 * for compounded requests.
2047 * TODO: we may need to move this after the session
2050 if (!NT_STATUS_IS_OK(req->next_status)) {
2051 return smbd_smb2_request_error(req, req->next_status);
2054 req->compat_chain_fsp = NULL;
2057 if (req->compound_related) {
2058 req->sconn->smb2.compound_related_in_progress = true;
2061 if (call->need_session) {
2062 if (!NT_STATUS_IS_OK(session_status)) {
2063 return smbd_smb2_request_error(req, session_status);
2067 if (call->need_tcon) {
2068 SMB_ASSERT(call->need_session);
2071 * This call needs to be run as user.
2073 * smbd_smb2_request_check_tcon()
2074 * calls change_to_user() on success.
2076 status = smbd_smb2_request_check_tcon(req);
2077 if (!NT_STATUS_IS_OK(status)) {
2078 return smbd_smb2_request_error(req, status);
2080 if (req->tcon->global->encryption_required) {
2081 encryption_required = true;
2083 if (encryption_required && !req->do_encryption) {
2084 return smbd_smb2_request_error(req,
2085 NT_STATUS_ACCESS_DENIED);
2089 if (call->fileid_ofs != 0) {
2090 size_t needed = call->fileid_ofs + 16;
2091 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2092 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2093 uint64_t file_id_persistent;
2094 uint64_t file_id_volatile;
2095 struct files_struct *fsp;
2097 SMB_ASSERT(call->need_tcon);
2099 if (needed > body_size) {
2100 return smbd_smb2_request_error(req,
2101 NT_STATUS_INVALID_PARAMETER);
2104 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2105 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2107 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2109 if (!call->allow_invalid_fileid) {
2110 return smbd_smb2_request_error(req,
2111 NT_STATUS_FILE_CLOSED);
2114 if (file_id_persistent != UINT64_MAX) {
2115 return smbd_smb2_request_error(req,
2116 NT_STATUS_FILE_CLOSED);
2118 if (file_id_volatile != UINT64_MAX) {
2119 return smbd_smb2_request_error(req,
2120 NT_STATUS_FILE_CLOSED);
2125 if (call->as_root) {
2126 SMB_ASSERT(call->fileid_ofs == 0);
2127 /* This call needs to be run as root */
2128 change_to_root_user();
2130 SMB_ASSERT(call->need_tcon);
2134 case SMB2_OP_NEGPROT:
2136 START_PROFILE(smb2_negprot);
2137 return_value = smbd_smb2_request_process_negprot(req);
2138 END_PROFILE(smb2_negprot);
2142 case SMB2_OP_SESSSETUP:
2144 START_PROFILE(smb2_sesssetup);
2145 return_value = smbd_smb2_request_process_sesssetup(req);
2146 END_PROFILE(smb2_sesssetup);
2150 case SMB2_OP_LOGOFF:
2152 START_PROFILE(smb2_logoff);
2153 return_value = smbd_smb2_request_process_logoff(req);
2154 END_PROFILE(smb2_logoff);
2160 START_PROFILE(smb2_tcon);
2161 return_value = smbd_smb2_request_process_tcon(req);
2162 END_PROFILE(smb2_tcon);
2168 START_PROFILE(smb2_tdis);
2169 return_value = smbd_smb2_request_process_tdis(req);
2170 END_PROFILE(smb2_tdis);
2174 case SMB2_OP_CREATE:
2176 START_PROFILE(smb2_create);
2177 return_value = smbd_smb2_request_process_create(req);
2178 END_PROFILE(smb2_create);
2184 START_PROFILE(smb2_close);
2185 return_value = smbd_smb2_request_process_close(req);
2186 END_PROFILE(smb2_close);
2192 START_PROFILE(smb2_flush);
2193 return_value = smbd_smb2_request_process_flush(req);
2194 END_PROFILE(smb2_flush);
2200 START_PROFILE(smb2_read);
2201 return_value = smbd_smb2_request_process_read(req);
2202 END_PROFILE(smb2_read);
2208 START_PROFILE(smb2_write);
2209 return_value = smbd_smb2_request_process_write(req);
2210 END_PROFILE(smb2_write);
2216 START_PROFILE(smb2_lock);
2217 return_value = smbd_smb2_request_process_lock(req);
2218 END_PROFILE(smb2_lock);
2224 START_PROFILE(smb2_ioctl);
2225 return_value = smbd_smb2_request_process_ioctl(req);
2226 END_PROFILE(smb2_ioctl);
2230 case SMB2_OP_CANCEL:
2232 START_PROFILE(smb2_cancel);
2233 return_value = smbd_smb2_request_process_cancel(req);
2234 END_PROFILE(smb2_cancel);
2238 case SMB2_OP_KEEPALIVE:
2240 START_PROFILE(smb2_keepalive);
2241 return_value = smbd_smb2_request_process_keepalive(req);
2242 END_PROFILE(smb2_keepalive);
2248 START_PROFILE(smb2_find);
2249 return_value = smbd_smb2_request_process_find(req);
2250 END_PROFILE(smb2_find);
2254 case SMB2_OP_NOTIFY:
2256 START_PROFILE(smb2_notify);
2257 return_value = smbd_smb2_request_process_notify(req);
2258 END_PROFILE(smb2_notify);
2262 case SMB2_OP_GETINFO:
2264 START_PROFILE(smb2_getinfo);
2265 return_value = smbd_smb2_request_process_getinfo(req);
2266 END_PROFILE(smb2_getinfo);
2270 case SMB2_OP_SETINFO:
2272 START_PROFILE(smb2_setinfo);
2273 return_value = smbd_smb2_request_process_setinfo(req);
2274 END_PROFILE(smb2_setinfo);
2280 START_PROFILE(smb2_break);
2281 return_value = smbd_smb2_request_process_break(req);
2282 END_PROFILE(smb2_break);
2287 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2290 return return_value;
2293 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2295 struct smbXsrv_connection *conn = req->sconn->conn;
2296 struct tevent_req *subreq;
2298 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2299 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2300 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2303 TALLOC_FREE(req->async_te);
2305 if (req->do_encryption &&
2306 (firsttf->iov_len == 0) &&
2307 (req->first_key.length == 0) &&
2308 (req->session != NULL) &&
2309 (req->session->global->encryption_key.length != 0))
2311 DATA_BLOB encryption_key = req->session->global->encryption_key;
2313 const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
2314 uint64_t session_id = req->session->global->session_wire_id;
2315 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
2316 uint64_t async_id = BVAL(inhdr, SMB2_HDR_ASYNC_ID);
2318 * We may have 2 responses (PENDING, FINAL),
2319 * so alter the nonce.
2321 * The FINAL response has the SMB2_HDR_FLAG_ASYNC bit
2324 uint64_t nonce_high = session_id & ~SMB2_HDR_FLAG_ASYNC;
2325 uint64_t nonce_low = message_id;
2327 if (nonce_low == 0) {
2328 nonce_low = async_id;
2332 * We need to place the SMB2_TRANSFORM header before the
2337 * we need to remember the encryption key
2338 * and defer the signing/encryption until
2339 * we are sure that we do not change
2342 req->first_key = data_blob_dup_talloc(req, encryption_key);
2343 if (req->first_key.data == NULL) {
2344 return NT_STATUS_NO_MEMORY;
2347 tf = talloc_zero_array(req->out.vector, uint8_t,
2350 return NT_STATUS_NO_MEMORY;
2353 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2354 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2355 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2356 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2358 firsttf->iov_base = (void *)tf;
2359 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2362 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2363 (req->last_key.length > 0) &&
2364 (firsttf->iov_len == 0))
2366 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2367 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2371 * As we are sure the header of the last request in the
2372 * compound chain will not change, we can to sign here
2373 * with the last signing key we remembered.
2375 status = smb2_signing_sign_pdu(req->last_key,
2378 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2379 if (!NT_STATUS_IS_OK(status)) {
2383 data_blob_clear_free(&req->last_key);
2385 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2387 if (req->current_idx < req->out.vector_count) {
2389 * We must process the remaining compound
2390 * SMB2 requests before any new incoming SMB2
2391 * requests. This is because incoming SMB2
2392 * requests may include a cancel for a
2393 * compound request we haven't processed
2396 struct tevent_immediate *im = tevent_create_immediate(req);
2398 return NT_STATUS_NO_MEMORY;
2401 if (req->do_signing && firsttf->iov_len == 0) {
2402 struct smbXsrv_session *x = req->session;
2403 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2406 * we need to remember the signing key
2407 * and defer the signing until
2408 * we are sure that we do not change
2411 req->last_key = data_blob_dup_talloc(req, signing_key);
2412 if (req->last_key.data == NULL) {
2413 return NT_STATUS_NO_MEMORY;
2417 tevent_schedule_immediate(im,
2419 smbd_smb2_request_dispatch_immediate,
2421 return NT_STATUS_OK;
2424 if (req->compound_related) {
2425 req->sconn->smb2.compound_related_in_progress = false;
2428 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2430 /* Set credit for these operations (zero credits if this
2431 is a final reply for an async operation). */
2432 smb2_calculate_credits(req, req);
2435 * now check if we need to sign the current response
2437 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2440 status = smb2_signing_encrypt_pdu(req->first_key,
2443 req->out.vector_count - first_idx);
2444 if (!NT_STATUS_IS_OK(status)) {
2447 } else if (req->do_signing) {
2449 struct smbXsrv_session *x = req->session;
2450 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2452 status = smb2_signing_sign_pdu(signing_key,
2455 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2456 if (!NT_STATUS_IS_OK(status)) {
2460 data_blob_clear_free(&req->first_key);
2462 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2463 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2464 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2465 /* Dynamic part is NULL. Chop it off,
2466 We're going to send it via sendfile. */
2467 req->out.vector_count -= 1;
2470 subreq = tstream_writev_queue_send(req,
2472 req->sconn->smb2.stream,
2473 req->sconn->smb2.send_queue,
2475 req->out.vector_count);
2476 if (subreq == NULL) {
2477 return NT_STATUS_NO_MEMORY;
2479 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
2481 * We're done with this request -
2482 * move it off the "being processed" queue.
2484 DLIST_REMOVE(req->sconn->smb2.requests, req);
2486 return NT_STATUS_OK;
2489 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2491 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2492 struct tevent_immediate *im,
2495 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2496 struct smbd_smb2_request);
2497 struct smbd_server_connection *sconn = req->sconn;
2502 if (DEBUGLEVEL >= 10) {
2503 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2504 req->current_idx, req->in.vector_count));
2505 print_req_vectors(req);
2508 status = smbd_smb2_request_dispatch(req);
2509 if (!NT_STATUS_IS_OK(status)) {
2510 smbd_server_connection_terminate(sconn, nt_errstr(status));
2514 status = smbd_smb2_request_next_incoming(sconn);
2515 if (!NT_STATUS_IS_OK(status)) {
2516 smbd_server_connection_terminate(sconn, nt_errstr(status));
2521 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
2523 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
2524 struct smbd_smb2_request);
2525 struct smbd_server_connection *sconn = req->sconn;
2530 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2531 TALLOC_FREE(subreq);
2534 status = map_nt_error_from_unix(sys_errno);
2535 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
2536 nt_errstr(status)));
2537 smbd_server_connection_terminate(sconn, nt_errstr(status));
2541 status = smbd_smb2_request_next_incoming(sconn);
2542 if (!NT_STATUS_IS_OK(status)) {
2543 smbd_server_connection_terminate(sconn, nt_errstr(status));
2548 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2550 DATA_BLOB body, DATA_BLOB *dyn,
2551 const char *location)
2554 struct iovec *outbody_v;
2555 struct iovec *outdyn_v;
2556 uint32_t next_command_ofs;
2558 DEBUG(10,("smbd_smb2_request_done_ex: "
2559 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2560 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2562 (unsigned int)(dyn ? dyn->length : 0),
2565 if (body.length < 2) {
2566 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2569 if ((body.length % 2) != 0) {
2570 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2573 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2574 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2575 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2577 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2578 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2580 outbody_v->iov_base = (void *)body.data;
2581 outbody_v->iov_len = body.length;
2584 outdyn_v->iov_base = (void *)dyn->data;
2585 outdyn_v->iov_len = dyn->length;
2587 outdyn_v->iov_base = NULL;
2588 outdyn_v->iov_len = 0;
2591 /* see if we need to recalculate the offset to the next response */
2592 if (next_command_ofs > 0) {
2593 next_command_ofs = SMB2_HDR_BODY;
2594 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2595 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2598 if ((next_command_ofs % 8) != 0) {
2599 size_t pad_size = 8 - (next_command_ofs % 8);
2600 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2602 * if the dyn buffer is empty
2603 * we can use it to add padding
2607 pad = talloc_zero_array(req->out.vector,
2610 return smbd_smb2_request_error(req,
2611 NT_STATUS_NO_MEMORY);
2614 outdyn_v->iov_base = (void *)pad;
2615 outdyn_v->iov_len = pad_size;
2618 * For now we copy the dynamic buffer
2619 * and add the padding to the new buffer
2626 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2627 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2629 new_size = old_size + pad_size;
2630 new_dyn = talloc_zero_array(req->out.vector,
2632 if (new_dyn == NULL) {
2633 return smbd_smb2_request_error(req,
2634 NT_STATUS_NO_MEMORY);
2637 memcpy(new_dyn, old_dyn, old_size);
2638 memset(new_dyn + old_size, 0, pad_size);
2640 outdyn_v->iov_base = (void *)new_dyn;
2641 outdyn_v->iov_len = new_size;
2643 next_command_ofs += pad_size;
2646 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2648 return smbd_smb2_request_reply(req);
2651 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2654 const char *location)
2657 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2659 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2660 req->current_idx, nt_errstr(status), info ? " +info" : "",
2663 body.data = outhdr + SMB2_HDR_BODY;
2665 SSVAL(body.data, 0, 9);
2668 SIVAL(body.data, 0x04, info->length);
2670 /* Allocated size of req->out.vector[i].iov_base
2671 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2672 * 1 byte without having to do an alloc.
2674 info = talloc_zero_array(req->out.vector,
2678 return NT_STATUS_NO_MEMORY;
2680 info->data = ((uint8_t *)outhdr) +
2681 OUTVEC_ALLOC_SIZE - 1;
2683 SCVAL(info->data, 0, 0);
2687 * if a request fails, all other remaining
2688 * compounded requests should fail too
2690 req->next_status = NT_STATUS_INVALID_PARAMETER;
2692 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2696 struct smbd_smb2_send_oplock_break_state {
2697 struct smbd_server_connection *sconn;
2698 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
2699 struct iovec vector;
2702 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2704 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2705 uint64_t file_id_persistent,
2706 uint64_t file_id_volatile,
2707 uint8_t oplock_level)
2709 struct smbd_smb2_send_oplock_break_state *state;
2710 struct tevent_req *subreq;
2714 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2715 if (state == NULL) {
2716 return NT_STATUS_NO_MEMORY;
2718 state->sconn = sconn;
2720 state->vector.iov_base = (void *)state->buf;
2721 state->vector.iov_len = sizeof(state->buf);
2723 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
2724 hdr = state->buf + 4;
2725 body = hdr + SMB2_HDR_BODY;
2727 SIVAL(hdr, 0, SMB2_MAGIC);
2728 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2729 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2730 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2731 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2732 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2733 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2734 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2735 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2736 SIVAL(hdr, SMB2_HDR_PID, 0);
2737 SIVAL(hdr, SMB2_HDR_TID, 0);
2738 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2739 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2741 SSVAL(body, 0x00, 0x18);
2743 SCVAL(body, 0x02, oplock_level);
2744 SCVAL(body, 0x03, 0); /* reserved */
2745 SIVAL(body, 0x04, 0); /* reserved */
2746 SBVAL(body, 0x08, file_id_persistent);
2747 SBVAL(body, 0x10, file_id_volatile);
2749 subreq = tstream_writev_queue_send(state,
2752 sconn->smb2.send_queue,
2754 if (subreq == NULL) {
2755 return NT_STATUS_NO_MEMORY;
2757 tevent_req_set_callback(subreq,
2758 smbd_smb2_oplock_break_writev_done,
2761 return NT_STATUS_OK;
2764 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2766 struct smbd_smb2_send_oplock_break_state *state =
2767 tevent_req_callback_data(subreq,
2768 struct smbd_smb2_send_oplock_break_state);
2769 struct smbd_server_connection *sconn = state->sconn;
2773 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2774 TALLOC_FREE(subreq);
2776 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2777 smbd_server_connection_terminate(sconn, nt_errstr(status));
2784 struct smbd_smb2_request_read_state {
2785 struct tevent_context *ev;
2786 struct smbd_server_connection *sconn;
2787 struct smbd_smb2_request *smb2_req;
2789 uint8_t nbt[NBT_HDR_SIZE];
2796 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2798 TALLOC_CTX *mem_ctx,
2799 struct iovec **_vector,
2801 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2803 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2804 struct tevent_context *ev,
2805 struct smbd_server_connection *sconn)
2807 struct tevent_req *req;
2808 struct smbd_smb2_request_read_state *state;
2809 struct tevent_req *subreq;
2811 req = tevent_req_create(mem_ctx, &state,
2812 struct smbd_smb2_request_read_state);
2817 state->sconn = sconn;
2819 state->smb2_req = smbd_smb2_request_allocate(state);
2820 if (tevent_req_nomem(state->smb2_req, req)) {
2821 return tevent_req_post(req, ev);
2823 state->smb2_req->sconn = sconn;
2825 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2827 state->sconn->smb2.stream,
2828 state->sconn->smb2.recv_queue,
2829 smbd_smb2_request_next_vector,
2831 if (tevent_req_nomem(subreq, req)) {
2832 return tevent_req_post(req, ev);
2834 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2839 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2841 TALLOC_CTX *mem_ctx,
2842 struct iovec **_vector,
2845 struct smbd_smb2_request_read_state *state =
2846 talloc_get_type_abort(private_data,
2847 struct smbd_smb2_request_read_state);
2848 struct iovec *vector;
2850 if (state->pktlen > 0) {
2851 /* if there're no remaining bytes, we're done */
2857 if (!state->hdr.done) {
2859 * first we need to get the NBT header
2861 vector = talloc_array(mem_ctx, struct iovec, 1);
2862 if (vector == NULL) {
2866 vector[0].iov_base = (void *)state->hdr.nbt;
2867 vector[0].iov_len = NBT_HDR_SIZE;
2872 state->hdr.done = true;
2877 * Now we analyze the NBT header
2879 state->pktlen = smb2_len(state->hdr.nbt);
2881 if (state->pktlen == 0) {
2882 /* if there're no remaining bytes, we're done */
2888 state->pktbuf = talloc_array(state->smb2_req, uint8_t, state->pktlen);
2889 if (state->pktbuf == NULL) {
2893 vector = talloc_array(mem_ctx, struct iovec, 1);
2894 if (vector == NULL) {
2898 vector[0].iov_base = (void *)state->pktbuf;
2899 vector[0].iov_len = state->pktlen;
2906 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2908 struct tevent_req *req =
2909 tevent_req_callback_data(subreq,
2911 struct smbd_smb2_request_read_state *state =
2912 tevent_req_data(req,
2913 struct smbd_smb2_request_read_state);
2919 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2920 TALLOC_FREE(subreq);
2922 status = map_nt_error_from_unix(sys_errno);
2923 tevent_req_nterror(req, status);
2927 if (state->hdr.nbt[0] != 0x00) {
2928 DEBUG(1,("smbd_smb2_request_read_done: ignore NBT[0x%02X] msg\n",
2929 state->hdr.nbt[0]));
2931 ZERO_STRUCT(state->hdr);
2932 TALLOC_FREE(state->pktbuf);
2935 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2937 state->sconn->smb2.stream,
2938 state->sconn->smb2.recv_queue,
2939 smbd_smb2_request_next_vector,
2941 if (tevent_req_nomem(subreq, req)) {
2944 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2948 state->smb2_req->request_time = timeval_current();
2949 now = timeval_to_nttime(&state->smb2_req->request_time);
2951 status = smbd_smb2_inbuf_parse_compound(state->smb2_req->sconn->conn,
2956 &state->smb2_req->in.vector,
2957 &state->smb2_req->in.vector_count);
2958 if (tevent_req_nterror(req, status)) {
2962 state->smb2_req->current_idx = 1;
2964 tevent_req_done(req);
2967 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2968 TALLOC_CTX *mem_ctx,
2969 struct smbd_smb2_request **_smb2_req)
2971 struct smbd_smb2_request_read_state *state =
2972 tevent_req_data(req,
2973 struct smbd_smb2_request_read_state);
2976 if (tevent_req_is_nterror(req, &status)) {
2977 tevent_req_received(req);
2981 *_smb2_req = talloc_move(mem_ctx, &state->smb2_req);
2982 tevent_req_received(req);
2983 return NT_STATUS_OK;
2986 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2988 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2990 size_t max_send_queue_len;
2991 size_t cur_send_queue_len;
2992 struct tevent_req *subreq;
2994 if (sconn->smb2.compound_related_in_progress) {
2996 * Can't read another until the related
2999 return NT_STATUS_OK;
3002 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
3004 * if there is already a smbd_smb2_request_read
3005 * pending, we are done.
3007 return NT_STATUS_OK;
3010 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
3011 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
3013 if (cur_send_queue_len > max_send_queue_len) {
3015 * if we have a lot of requests to send,
3016 * we wait until they are on the wire until we
3017 * ask for the next request.
3019 return NT_STATUS_OK;
3022 /* ask for the next request */
3023 subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn);
3024 if (subreq == NULL) {
3025 return NT_STATUS_NO_MEMORY;
3027 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
3029 return NT_STATUS_OK;
3032 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
3033 uint8_t *inbuf, size_t size)
3036 struct smbd_smb2_request *req = NULL;
3038 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
3039 (unsigned int)size));
3041 status = smbd_initialize_smb2(sconn);
3042 if (!NT_STATUS_IS_OK(status)) {
3043 smbd_server_connection_terminate(sconn, nt_errstr(status));
3047 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
3048 if (!NT_STATUS_IS_OK(status)) {
3049 smbd_server_connection_terminate(sconn, nt_errstr(status));
3053 status = smbd_smb2_request_validate(req);
3054 if (!NT_STATUS_IS_OK(status)) {
3055 smbd_server_connection_terminate(sconn, nt_errstr(status));
3059 status = smbd_smb2_request_setup_out(req);
3060 if (!NT_STATUS_IS_OK(status)) {
3061 smbd_server_connection_terminate(sconn, nt_errstr(status));
3065 status = smbd_smb2_request_dispatch(req);
3066 if (!NT_STATUS_IS_OK(status)) {
3067 smbd_server_connection_terminate(sconn, nt_errstr(status));
3071 status = smbd_smb2_request_next_incoming(sconn);
3072 if (!NT_STATUS_IS_OK(status)) {
3073 smbd_server_connection_terminate(sconn, nt_errstr(status));
3077 sconn->num_requests++;
3080 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
3082 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
3083 struct smbd_server_connection);
3085 struct smbd_smb2_request *req = NULL;
3087 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
3088 TALLOC_FREE(subreq);
3089 if (!NT_STATUS_IS_OK(status)) {
3090 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
3091 nt_errstr(status)));
3092 smbd_server_connection_terminate(sconn, nt_errstr(status));
3096 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
3097 req->current_idx, req->in.vector_count));
3099 status = smbd_smb2_request_validate(req);
3100 if (!NT_STATUS_IS_OK(status)) {
3101 smbd_server_connection_terminate(sconn, nt_errstr(status));
3105 status = smbd_smb2_request_setup_out(req);
3106 if (!NT_STATUS_IS_OK(status)) {
3107 smbd_server_connection_terminate(sconn, nt_errstr(status));
3111 status = smbd_smb2_request_dispatch(req);
3112 if (!NT_STATUS_IS_OK(status)) {
3113 smbd_server_connection_terminate(sconn, nt_errstr(status));
3117 status = smbd_smb2_request_next_incoming(sconn);
3118 if (!NT_STATUS_IS_OK(status)) {
3119 smbd_server_connection_terminate(sconn, nt_errstr(status));
3123 sconn->num_requests++;
3125 /* The timeout_processing function isn't run nearly
3126 often enough to implement 'max log size' without
3127 overrunning the size of the file by many megabytes.
3128 This is especially true if we are running at debug
3129 level 10. Checking every 50 SMB2s is a nice
3130 tradeoff of performance vs log file size overrun. */
3132 if ((sconn->num_requests % 50) == 0 &&
3133 need_to_check_log_size()) {
3134 change_to_root_user();