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"
31 #include "lib/iov_buf.h"
34 static void smbd_smb2_connection_handler(struct tevent_context *ev,
35 struct tevent_fd *fde,
38 static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn);
40 static const struct smbd_smb2_dispatch_table {
47 bool allow_invalid_fileid;
48 } smbd_smb2_table[] = {
49 #define _OP(o) .opcode = o, .name = #o
54 _OP(SMB2_OP_SESSSETUP),
64 * This call needs to be run as root.
66 * smbd_smb2_request_process_tcon()
67 * calls make_connection_snum(), which will call
68 * change_to_user(), when needed.
102 .need_session = true,
107 .need_session = true,
110 .allow_invalid_fileid = true,
115 _OP(SMB2_OP_KEEPALIVE),
119 .need_session = true,
124 .need_session = true,
128 _OP(SMB2_OP_GETINFO),
129 .need_session = true,
133 _OP(SMB2_OP_SETINFO),
134 .need_session = true,
139 .need_session = true,
144 * as LEASE breaks does not
150 const char *smb2_opcode_name(uint16_t opcode)
152 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
153 return "Bad SMB2 opcode";
155 return smbd_smb2_table[opcode].name;
158 static const struct smbd_smb2_dispatch_table *smbd_smb2_call(uint16_t opcode)
160 const struct smbd_smb2_dispatch_table *ret = NULL;
162 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
166 ret = &smbd_smb2_table[opcode];
168 SMB_ASSERT(ret->opcode == opcode);
173 static void print_req_vectors(const struct smbd_smb2_request *req)
177 for (i = 0; i < req->in.vector_count; i++) {
178 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
180 (unsigned int)req->in.vector[i].iov_len);
182 for (i = 0; i < req->out.vector_count; i++) {
183 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
185 (unsigned int)req->out.vector[i].iov_len);
189 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
191 if (size < (4 + SMB2_HDR_BODY)) {
195 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
202 static NTSTATUS smbd_initialize_smb2(struct smbXsrv_connection *xconn)
204 TALLOC_FREE(xconn->transport.fde);
206 xconn->smb2.credits.seq_low = 0;
207 xconn->smb2.credits.seq_range = 1;
208 xconn->smb2.credits.granted = 1;
209 xconn->smb2.credits.max = lp_smb2_max_credits();
210 xconn->smb2.credits.bitmap = bitmap_talloc(xconn,
211 xconn->smb2.credits.max);
212 if (xconn->smb2.credits.bitmap == NULL) {
213 return NT_STATUS_NO_MEMORY;
216 xconn->transport.fde = tevent_add_fd(xconn->ev_ctx,
218 xconn->transport.sock,
220 smbd_smb2_connection_handler,
222 if (xconn->transport.fde == NULL) {
223 return NT_STATUS_NO_MEMORY;
226 /* Ensure child is set to non-blocking mode */
227 set_blocking(xconn->transport.sock, false);
231 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
232 #define _smb2_setlen(_buf,len) do { \
233 uint8_t *buf = (uint8_t *)_buf; \
235 buf[1] = ((len)&0xFF0000)>>16; \
236 buf[2] = ((len)&0xFF00)>>8; \
237 buf[3] = (len)&0xFF; \
240 static void smb2_setup_nbt_length(struct iovec *vector, int count)
245 for (i=1; i < count; i++) {
246 len += vector[i].iov_len;
249 _smb2_setlen(vector[0].iov_base, len);
252 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
254 if (req->first_key.length > 0) {
255 data_blob_clear_free(&req->first_key);
257 if (req->last_key.length > 0) {
258 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_tos();
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);
285 TALLOC_FREE(mem_pool);
288 req->last_session_id = UINT64_MAX;
289 req->last_tid = UINT32_MAX;
291 talloc_set_destructor(req, smbd_smb2_request_destructor);
296 static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *xconn,
300 struct smbd_smb2_request *req,
304 TALLOC_CTX *mem_ctx = req;
308 uint8_t *first_hdr = buf;
309 size_t verified_buflen = 0;
314 * Note: index '0' is reserved for the transport protocol
316 iov = req->in._vector;
318 while (taken < buflen) {
319 size_t len = buflen - taken;
320 uint8_t *hdr = first_hdr + taken;
323 size_t next_command_ofs;
325 uint8_t *body = NULL;
328 struct iovec *iov_alloc = NULL;
330 if (iov != req->in._vector) {
334 if (verified_buflen > taken) {
335 len = verified_buflen - taken;
342 DEBUG(10, ("%d bytes left, expected at least %d\n",
346 if (IVAL(hdr, 0) == SMB2_TF_MAGIC) {
347 struct smbXsrv_session *s = NULL;
349 struct iovec tf_iov[2];
353 if (xconn->protocol < PROTOCOL_SMB2_24) {
354 DEBUG(10, ("Got SMB2_TRANSFORM header, "
355 "but dialect[0x%04X] is used\n",
356 xconn->smb2.server.dialect));
360 if (xconn->smb2.server.cipher == 0) {
361 DEBUG(10, ("Got SMB2_TRANSFORM header, "
362 "but not negotiated "
363 "client[0x%08X] server[0x%08X]\n",
364 xconn->smb2.client.capabilities,
365 xconn->smb2.server.capabilities));
369 if (len < SMB2_TF_HDR_SIZE) {
370 DEBUG(1, ("%d bytes left, expected at least %d\n",
371 (int)len, SMB2_TF_HDR_SIZE));
375 tf_len = SMB2_TF_HDR_SIZE;
378 hdr = first_hdr + taken;
379 enc_len = IVAL(tf, SMB2_TF_MSG_SIZE);
380 uid = BVAL(tf, SMB2_TF_SESSION_ID);
382 if (len < SMB2_TF_HDR_SIZE + enc_len) {
383 DEBUG(1, ("%d bytes left, expected at least %d\n",
385 (int)(SMB2_TF_HDR_SIZE + enc_len)));
389 status = smb2srv_session_lookup(xconn, uid, now, &s);
391 DEBUG(1, ("invalid session[%llu] in "
392 "SMB2_TRANSFORM header\n",
393 (unsigned long long)uid));
394 TALLOC_FREE(iov_alloc);
395 return NT_STATUS_USER_SESSION_DELETED;
398 tf_iov[0].iov_base = (void *)tf;
399 tf_iov[0].iov_len = tf_len;
400 tf_iov[1].iov_base = (void *)hdr;
401 tf_iov[1].iov_len = enc_len;
403 status = smb2_signing_decrypt_pdu(s->global->decryption_key,
404 xconn->smb2.server.cipher,
406 if (!NT_STATUS_IS_OK(status)) {
407 TALLOC_FREE(iov_alloc);
411 verified_buflen = taken + enc_len;
416 * We need the header plus the body length field
419 if (len < SMB2_HDR_BODY + 2) {
420 DEBUG(10, ("%d bytes left, expected at least %d\n",
421 (int)len, SMB2_HDR_BODY));
424 if (IVAL(hdr, 0) != SMB2_MAGIC) {
425 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
429 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
430 DEBUG(10, ("Got HDR len %d, expected %d\n",
431 SVAL(hdr, 4), SMB2_HDR_BODY));
436 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
437 body_size = SVAL(hdr, SMB2_HDR_BODY);
439 if (next_command_ofs != 0) {
440 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
443 if (next_command_ofs > full_size) {
446 full_size = next_command_ofs;
453 if (body_size > (full_size - SMB2_HDR_BODY)) {
455 * let the caller handle the error
457 body_size = full_size - SMB2_HDR_BODY;
459 body = hdr + SMB2_HDR_BODY;
460 dyn = body + body_size;
461 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
463 if (num_iov >= ARRAY_SIZE(req->in._vector)) {
464 struct iovec *iov_tmp = NULL;
466 iov_tmp = talloc_realloc(mem_ctx, iov_alloc,
469 SMBD_SMB2_NUM_IOV_PER_REQ);
470 if (iov_tmp == NULL) {
471 TALLOC_FREE(iov_alloc);
472 return NT_STATUS_NO_MEMORY;
475 if (iov_alloc == NULL) {
478 sizeof(req->in._vector));
484 num_iov += SMBD_SMB2_NUM_IOV_PER_REQ;
486 cur[SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
487 cur[SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
488 cur[SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
489 cur[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
490 cur[SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
491 cur[SMBD_SMB2_BODY_IOV_OFS].iov_len = body_size;
492 cur[SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
493 cur[SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_size;
503 if (iov != req->in._vector) {
506 return NT_STATUS_INVALID_PARAMETER;
509 static NTSTATUS smbd_smb2_request_create(struct smbXsrv_connection *xconn,
510 const uint8_t *_inpdu, size_t size,
511 struct smbd_smb2_request **_req)
513 struct smbd_server_connection *sconn = xconn->client->sconn;
514 struct smbd_smb2_request *req;
515 uint32_t protocol_version;
516 uint8_t *inpdu = NULL;
517 const uint8_t *inhdr = NULL;
519 uint32_t next_command_ofs;
523 if (size < (SMB2_HDR_BODY + 2)) {
524 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
525 return NT_STATUS_INVALID_PARAMETER;
530 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
531 if (protocol_version != SMB2_MAGIC) {
532 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
534 return NT_STATUS_INVALID_PARAMETER;
537 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
538 if (cmd != SMB2_OP_NEGPROT) {
539 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
541 return NT_STATUS_INVALID_PARAMETER;
544 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
545 if (next_command_ofs != 0) {
546 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
548 return NT_STATUS_INVALID_PARAMETER;
551 req = smbd_smb2_request_allocate(xconn);
553 return NT_STATUS_NO_MEMORY;
558 inpdu = talloc_memdup(req, _inpdu, size);
560 return NT_STATUS_NO_MEMORY;
563 req->request_time = timeval_current();
564 now = timeval_to_nttime(&req->request_time);
566 status = smbd_smb2_inbuf_parse_compound(xconn,
570 req, &req->in.vector,
571 &req->in.vector_count);
572 if (!NT_STATUS_IS_OK(status)) {
577 req->current_idx = 1;
583 static bool smb2_validate_sequence_number(struct smbXsrv_connection *xconn,
584 uint64_t message_id, uint64_t seq_id)
586 struct bitmap *credits_bm = xconn->smb2.credits.bitmap;
590 seq_tmp = xconn->smb2.credits.seq_low;
591 if (seq_id < seq_tmp) {
592 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
593 "%llu (sequence id %llu) "
594 "(granted = %u, low = %llu, range = %u)\n",
595 (unsigned long long)message_id,
596 (unsigned long long)seq_id,
597 (unsigned int)xconn->smb2.credits.granted,
598 (unsigned long long)xconn->smb2.credits.seq_low,
599 (unsigned int)xconn->smb2.credits.seq_range));
603 seq_tmp += xconn->smb2.credits.seq_range;
604 if (seq_id >= seq_tmp) {
605 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
606 "%llu (sequence id %llu) "
607 "(granted = %u, low = %llu, range = %u)\n",
608 (unsigned long long)message_id,
609 (unsigned long long)seq_id,
610 (unsigned int)xconn->smb2.credits.granted,
611 (unsigned long long)xconn->smb2.credits.seq_low,
612 (unsigned int)xconn->smb2.credits.seq_range));
616 offset = seq_id % xconn->smb2.credits.max;
618 if (bitmap_query(credits_bm, offset)) {
619 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
620 "%llu (sequence id %llu) "
621 "(granted = %u, low = %llu, range = %u) "
623 (unsigned long long)message_id,
624 (unsigned long long)seq_id,
625 (unsigned int)xconn->smb2.credits.granted,
626 (unsigned long long)xconn->smb2.credits.seq_low,
627 (unsigned int)xconn->smb2.credits.seq_range,
632 /* Mark the message_ids as seen in the bitmap. */
633 bitmap_set(credits_bm, offset);
635 if (seq_id != xconn->smb2.credits.seq_low) {
640 * Move the window forward by all the message_id's
643 while (bitmap_query(credits_bm, offset)) {
644 DEBUG(10,("smb2_validate_sequence_number: clearing "
645 "id %llu (position %u) from bitmap\n",
646 (unsigned long long)(xconn->smb2.credits.seq_low),
648 bitmap_clear(credits_bm, offset);
650 xconn->smb2.credits.seq_low += 1;
651 xconn->smb2.credits.seq_range -= 1;
652 offset = xconn->smb2.credits.seq_low % xconn->smb2.credits.max;
658 static bool smb2_validate_message_id(struct smbXsrv_connection *xconn,
659 const uint8_t *inhdr)
661 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
662 uint16_t opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
663 uint16_t credit_charge = 1;
666 if (opcode == SMB2_OP_CANCEL) {
667 /* SMB2_CANCEL requests by definition resend messageids. */
671 if (xconn->smb2.credits.multicredit) {
672 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
673 credit_charge = MAX(credit_charge, 1);
676 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
677 "credits_granted %llu, "
678 "seqnum low/range: %llu/%llu\n",
679 (unsigned long long) message_id,
680 (unsigned long long) credit_charge,
681 (unsigned long long) xconn->smb2.credits.granted,
682 (unsigned long long) xconn->smb2.credits.seq_low,
683 (unsigned long long) xconn->smb2.credits.seq_range));
685 if (xconn->smb2.credits.granted < credit_charge) {
686 DEBUG(0, ("smb2_validate_message_id: client used more "
687 "credits than granted, mid %llu, charge %llu, "
688 "credits_granted %llu, "
689 "seqnum low/range: %llu/%llu\n",
690 (unsigned long long) message_id,
691 (unsigned long long) credit_charge,
692 (unsigned long long) xconn->smb2.credits.granted,
693 (unsigned long long) xconn->smb2.credits.seq_low,
694 (unsigned long long) xconn->smb2.credits.seq_range));
699 * now check the message ids
701 * for multi-credit requests we need to check all current mid plus
702 * the implicit mids caused by the credit charge
703 * e.g. current mid = 15, charge 5 => mark 15-19 as used
706 for (i = 0; i <= (credit_charge-1); i++) {
707 uint64_t id = message_id + i;
710 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
711 (unsigned long long)message_id,
713 (unsigned long long)id));
715 ok = smb2_validate_sequence_number(xconn, message_id, id);
721 /* substract used credits */
722 xconn->smb2.credits.granted -= credit_charge;
727 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
732 count = req->in.vector_count;
734 if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
735 /* It's not a SMB2 request */
736 return NT_STATUS_INVALID_PARAMETER;
739 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
740 struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
741 struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx);
742 const uint8_t *inhdr = NULL;
744 if (hdr->iov_len != SMB2_HDR_BODY) {
745 return NT_STATUS_INVALID_PARAMETER;
748 if (body->iov_len < 2) {
749 return NT_STATUS_INVALID_PARAMETER;
752 inhdr = (const uint8_t *)hdr->iov_base;
754 /* Check the SMB2 header */
755 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
756 return NT_STATUS_INVALID_PARAMETER;
759 if (!smb2_validate_message_id(req->xconn, inhdr)) {
760 return NT_STATUS_INVALID_PARAMETER;
767 static void smb2_set_operation_credit(struct smbXsrv_connection *xconn,
768 const struct iovec *in_vector,
769 struct iovec *out_vector)
771 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
772 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
773 uint16_t credit_charge = 1;
774 uint16_t credits_requested;
778 uint16_t credits_granted = 0;
779 uint64_t credits_possible;
780 uint16_t current_max_credits;
783 * first we grant only 1/16th of the max range.
785 * Windows also starts with the 1/16th and then grants
786 * more later. I was only able to trigger higher
787 * values, when using a very high credit charge.
789 * TODO: scale up depending on load, free memory
791 * Maybe also on the relationship between number
792 * of requests and the used sequence number.
793 * Which means we would grant more credits
794 * for client which use multi credit requests.
796 current_max_credits = xconn->smb2.credits.max / 16;
797 current_max_credits = MAX(current_max_credits, 1);
799 if (xconn->smb2.credits.multicredit) {
800 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
801 credit_charge = MAX(credit_charge, 1);
804 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
805 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
806 credits_requested = MAX(credits_requested, 1);
807 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
808 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
810 SMB_ASSERT(xconn->smb2.credits.max >= xconn->smb2.credits.granted);
812 if (xconn->smb2.credits.max < credit_charge) {
813 smbd_server_connection_terminate(xconn,
814 "client error: credit charge > max credits\n");
818 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
820 * In case we already send an async interim
821 * response, we should not grant
822 * credits on the final response.
826 uint16_t additional_max = 0;
827 uint16_t additional_credits = credits_requested - 1;
830 case SMB2_OP_NEGPROT:
832 case SMB2_OP_SESSSETUP:
834 * Windows 2012 RC1 starts to grant
836 * with a successful session setup
838 if (NT_STATUS_IS_OK(out_status)) {
844 * We match windows and only grant additional credits
851 additional_credits = MIN(additional_credits, additional_max);
853 credits_granted = credit_charge + additional_credits;
857 * sequence numbers should not wrap
859 * 1. calculate the possible credits until
860 * the sequence numbers start to wrap on 64-bit.
862 * 2. UINT64_MAX is used for Break Notifications.
864 * 2. truncate the possible credits to the maximum
865 * credits we want to grant to the client in total.
867 * 3. remove the range we'll already granted to the client
868 * this makes sure the client consumes the lowest sequence
869 * number, before we can grant additional credits.
871 credits_possible = UINT64_MAX - xconn->smb2.credits.seq_low;
872 if (credits_possible > 0) {
873 /* remove UINT64_MAX */
874 credits_possible -= 1;
876 credits_possible = MIN(credits_possible, current_max_credits);
877 credits_possible -= xconn->smb2.credits.seq_range;
879 credits_granted = MIN(credits_granted, credits_possible);
881 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
882 xconn->smb2.credits.granted += credits_granted;
883 xconn->smb2.credits.seq_range += credits_granted;
885 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
886 "granted %u, current possible/max %u/%u, "
887 "total granted/max/low/range %u/%u/%llu/%u\n",
888 (unsigned int)credits_requested,
889 (unsigned int)credit_charge,
890 (unsigned int)credits_granted,
891 (unsigned int)credits_possible,
892 (unsigned int)current_max_credits,
893 (unsigned int)xconn->smb2.credits.granted,
894 (unsigned int)xconn->smb2.credits.max,
895 (unsigned long long)xconn->smb2.credits.seq_low,
896 (unsigned int)xconn->smb2.credits.seq_range));
899 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
900 struct smbd_smb2_request *outreq)
903 uint16_t total_credits = 0;
905 count = outreq->out.vector_count;
907 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
908 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(inreq,in,idx);
909 struct iovec *outhdr_v = SMBD_SMB2_IDX_HDR_IOV(outreq,out,idx);
910 uint8_t *outhdr = (uint8_t *)outhdr_v->iov_base;
912 smb2_set_operation_credit(outreq->xconn, inhdr_v, outhdr_v);
914 /* To match Windows, count up what we
916 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
917 /* Set to zero in all but the last reply. */
918 if (idx + SMBD_SMB2_NUM_IOV_PER_REQ < count) {
919 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
921 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
926 DATA_BLOB smbd_smb2_generate_outbody(struct smbd_smb2_request *req, size_t size)
928 if (req->current_idx <= 1) {
929 if (size <= sizeof(req->out._body)) {
930 return data_blob_const(req->out._body, size);
934 return data_blob_talloc(req, NULL, size);
937 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
939 struct smbXsrv_connection *xconn = req->xconn;
941 struct iovec *vector;
945 count = req->in.vector_count;
946 if (count <= ARRAY_SIZE(req->out._vector)) {
948 vector = req->out._vector;
950 vector = talloc_zero_array(req, struct iovec, count);
951 if (vector == NULL) {
952 return NT_STATUS_NO_MEMORY;
957 vector[0].iov_base = req->out.nbt_hdr;
958 vector[0].iov_len = 4;
959 SIVAL(req->out.nbt_hdr, 0, 0);
961 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
962 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
963 const uint8_t *inhdr = (const uint8_t *)inhdr_v->iov_base;
964 uint8_t *outhdr = NULL;
965 uint8_t *outbody = NULL;
966 uint32_t next_command_ofs = 0;
967 struct iovec *current = &vector[idx];
969 if ((idx + SMBD_SMB2_NUM_IOV_PER_REQ) < count) {
970 /* we have a next command -
971 * setup for the error case. */
972 next_command_ofs = SMB2_HDR_BODY + 9;
976 outhdr = req->out._hdr;
978 outhdr = talloc_zero_array(mem_ctx, uint8_t,
980 if (outhdr == NULL) {
981 return NT_STATUS_NO_MEMORY;
985 outbody = outhdr + SMB2_HDR_BODY;
988 * SMBD_SMB2_TF_IOV_OFS might be used later
990 current[SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
991 current[SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
993 current[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)outhdr;
994 current[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
996 current[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)outbody;
997 current[SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
999 current[SMBD_SMB2_DYN_IOV_OFS].iov_base = NULL;
1000 current[SMBD_SMB2_DYN_IOV_OFS].iov_len = 0;
1002 /* setup the SMB2 header */
1003 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1004 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1005 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
1006 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
1007 SIVAL(outhdr, SMB2_HDR_STATUS,
1008 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
1009 SSVAL(outhdr, SMB2_HDR_OPCODE,
1010 SVAL(inhdr, SMB2_HDR_OPCODE));
1011 SIVAL(outhdr, SMB2_HDR_FLAGS,
1012 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
1013 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
1014 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
1015 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
1016 SIVAL(outhdr, SMB2_HDR_PID,
1017 IVAL(inhdr, SMB2_HDR_PID));
1018 SIVAL(outhdr, SMB2_HDR_TID,
1019 IVAL(inhdr, SMB2_HDR_TID));
1020 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
1021 BVAL(inhdr, SMB2_HDR_SESSION_ID));
1022 memcpy(outhdr + SMB2_HDR_SIGNATURE,
1023 inhdr + SMB2_HDR_SIGNATURE, 16);
1025 /* setup error body header */
1026 SSVAL(outbody, 0x00, 0x08 + 1);
1027 SSVAL(outbody, 0x02, 0);
1028 SIVAL(outbody, 0x04, 0);
1031 req->out.vector = vector;
1032 req->out.vector_count = count;
1034 /* setup the length of the NBT packet */
1035 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
1037 DLIST_ADD_END(xconn->smb2.requests, req, struct smbd_smb2_request *);
1039 return NT_STATUS_OK;
1042 void smbd_server_connection_terminate_ex(struct smbXsrv_connection *xconn,
1044 const char *location)
1046 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
1048 exit_server_cleanly(reason);
1051 static bool dup_smb2_vec4(TALLOC_CTX *ctx,
1052 struct iovec *outvec,
1053 const struct iovec *srcvec)
1055 const uint8_t *srctf;
1057 const uint8_t *srchdr;
1059 const uint8_t *srcbody;
1061 const uint8_t *expected_srcbody;
1062 const uint8_t *srcdyn;
1064 const uint8_t *expected_srcdyn;
1070 srctf = (const uint8_t *)srcvec[SMBD_SMB2_TF_IOV_OFS].iov_base;
1071 srctf_len = srcvec[SMBD_SMB2_TF_IOV_OFS].iov_len;
1072 srchdr = (const uint8_t *)srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base;
1073 srchdr_len = srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_len;
1074 srcbody = (const uint8_t *)srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_base;
1075 srcbody_len = srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_len;
1076 expected_srcbody = srchdr + SMB2_HDR_BODY;
1077 srcdyn = (const uint8_t *)srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_base;
1078 srcdyn_len = srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_len;
1079 expected_srcdyn = srcbody + 8;
1081 if ((srctf_len != SMB2_TF_HDR_SIZE) && (srctf_len != 0)) {
1085 if (srchdr_len != SMB2_HDR_BODY) {
1089 if (srctf_len == SMB2_TF_HDR_SIZE) {
1090 dsttf = talloc_memdup(ctx, srctf, SMB2_TF_HDR_SIZE);
1091 if (dsttf == NULL) {
1097 outvec[SMBD_SMB2_TF_IOV_OFS].iov_base = (void *)dsttf;
1098 outvec[SMBD_SMB2_TF_IOV_OFS].iov_len = srctf_len;
1100 /* vec[SMBD_SMB2_HDR_IOV_OFS] is always boilerplate and must
1101 * be allocated with size OUTVEC_ALLOC_SIZE. */
1103 dsthdr = talloc_memdup(ctx, srchdr, OUTVEC_ALLOC_SIZE);
1104 if (dsthdr == NULL) {
1107 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)dsthdr;
1108 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1111 * If this is a "standard" vec[SMBD_SMB2_BOFY_IOV_OFS] of length 8,
1112 * pointing to srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + SMB2_HDR_BODY,
1113 * then duplicate this. Else use talloc_memdup().
1116 if ((srcbody == expected_srcbody) && (srcbody_len == 8)) {
1117 dstbody = dsthdr + SMB2_HDR_BODY;
1119 dstbody = talloc_memdup(ctx, srcbody, srcbody_len);
1120 if (dstbody == NULL) {
1124 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)dstbody;
1125 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_len = srcbody_len;
1128 * If this is a "standard" vec[SMBD_SMB2_DYN_IOV_OFS] of length 1,
1130 * srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + 8
1131 * then duplicate this. Else use talloc_memdup().
1134 if ((srcdyn == expected_srcdyn) && (srcdyn_len == 1)) {
1135 dstdyn = dsthdr + SMB2_HDR_BODY + 8;
1136 } else if (srcdyn == NULL) {
1139 dstdyn = talloc_memdup(ctx, srcdyn, srcdyn_len);
1140 if (dstdyn == NULL) {
1144 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_base = (void *)dstdyn;
1145 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_len = srcdyn_len;
1150 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
1152 struct smbd_smb2_request *newreq = NULL;
1153 struct iovec *outvec = NULL;
1154 int count = req->out.vector_count;
1157 newreq = smbd_smb2_request_allocate(req->xconn);
1162 newreq->sconn = req->sconn;
1163 newreq->xconn = req->xconn;
1164 newreq->session = req->session;
1165 newreq->do_encryption = req->do_encryption;
1166 newreq->do_signing = req->do_signing;
1167 newreq->current_idx = req->current_idx;
1169 outvec = talloc_zero_array(newreq, struct iovec, count);
1171 TALLOC_FREE(newreq);
1174 newreq->out.vector = outvec;
1175 newreq->out.vector_count = count;
1177 /* Setup the outvec's identically to req. */
1178 outvec[0].iov_base = newreq->out.nbt_hdr;
1179 outvec[0].iov_len = 4;
1180 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
1182 /* Setup the vectors identically to the ones in req. */
1183 for (i = 1; i < count; i += SMBD_SMB2_NUM_IOV_PER_REQ) {
1184 if (!dup_smb2_vec4(outvec, &outvec[i], &req->out.vector[i])) {
1191 TALLOC_FREE(newreq);
1195 smb2_setup_nbt_length(newreq->out.vector,
1196 newreq->out.vector_count);
1201 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1203 struct smbXsrv_connection *xconn = req->xconn;
1205 struct iovec *firsttf = NULL;
1206 struct iovec *outhdr_v = NULL;
1207 uint8_t *outhdr = NULL;
1208 struct smbd_smb2_request *nreq = NULL;
1211 /* Create a new smb2 request we'll use
1212 for the interim return. */
1213 nreq = dup_smb2_req(req);
1215 return NT_STATUS_NO_MEMORY;
1218 /* Lose the last X out vectors. They're the
1219 ones we'll be using for the async reply. */
1220 nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ;
1222 smb2_setup_nbt_length(nreq->out.vector,
1223 nreq->out.vector_count);
1225 /* Step back to the previous reply. */
1226 nreq->current_idx -= SMBD_SMB2_NUM_IOV_PER_REQ;
1227 firsttf = SMBD_SMB2_IDX_TF_IOV(nreq,out,first_idx);
1228 outhdr_v = SMBD_SMB2_OUT_HDR_IOV(nreq);
1229 outhdr = SMBD_SMB2_OUT_HDR_PTR(nreq);
1230 /* And end the chain. */
1231 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1233 /* Calculate outgoing credits */
1234 smb2_calculate_credits(req, nreq);
1236 if (DEBUGLEVEL >= 10) {
1237 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1238 (unsigned int)nreq->current_idx );
1239 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1240 (unsigned int)nreq->out.vector_count );
1241 print_req_vectors(nreq);
1245 * As we have changed the header (SMB2_HDR_NEXT_COMMAND),
1246 * we need to sign/encrypt here with the last/first key we remembered
1248 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
1249 status = smb2_signing_encrypt_pdu(req->first_key,
1250 xconn->smb2.server.cipher,
1252 nreq->out.vector_count - first_idx);
1253 if (!NT_STATUS_IS_OK(status)) {
1256 } else if (req->last_key.length > 0) {
1257 status = smb2_signing_sign_pdu(req->last_key,
1260 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1261 if (!NT_STATUS_IS_OK(status)) {
1266 nreq->queue_entry.mem_ctx = nreq;
1267 nreq->queue_entry.vector = nreq->out.vector;
1268 nreq->queue_entry.count = nreq->out.vector_count;
1269 DLIST_ADD_END(xconn->smb2.send_queue, &nreq->queue_entry, NULL);
1270 xconn->smb2.send_queue_len++;
1272 status = smbd_smb2_flush_send_queue(xconn);
1273 if (!NT_STATUS_IS_OK(status)) {
1277 return NT_STATUS_OK;
1280 struct smbd_smb2_request_pending_state {
1281 struct smbd_smb2_send_queue queue_entry;
1282 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x08 + 1];
1283 struct iovec vector[1 + SMBD_SMB2_NUM_IOV_PER_REQ];
1286 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1287 struct tevent_timer *te,
1288 struct timeval current_time,
1289 void *private_data);
1291 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1292 struct tevent_req *subreq,
1293 uint32_t defer_time)
1296 struct timeval defer_endtime;
1297 uint8_t *outhdr = NULL;
1300 if (!tevent_req_is_in_progress(subreq)) {
1302 * This is a performance optimization,
1303 * it avoids one tevent_loop iteration,
1304 * which means we avoid one
1305 * talloc_stackframe_pool/talloc_free pair.
1307 tevent_req_notify_callback(subreq);
1308 return NT_STATUS_OK;
1311 req->subreq = subreq;
1314 if (req->async_te) {
1315 /* We're already async. */
1316 return NT_STATUS_OK;
1319 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1320 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1321 if (flags & SMB2_HDR_FLAG_ASYNC) {
1322 /* We're already async. */
1323 return NT_STATUS_OK;
1326 if (req->in.vector_count > req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
1328 * We're trying to go async in a compound
1330 * This is only allowed for opens that
1331 * cause an oplock break, otherwise it
1332 * is not allowed. See [MS-SMB2].pdf
1333 * note <194> on Section 3.3.5.2.7.
1335 const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1337 if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_CREATE) {
1339 * Cancel the outstanding request.
1341 bool ok = tevent_req_cancel(req->subreq);
1343 return NT_STATUS_OK;
1345 TALLOC_FREE(req->subreq);
1346 return smbd_smb2_request_error(req,
1347 NT_STATUS_INTERNAL_ERROR);
1351 if (DEBUGLEVEL >= 10) {
1352 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1353 (unsigned int)req->current_idx );
1354 print_req_vectors(req);
1357 if (req->current_idx > 1) {
1359 * We're going async in a compound
1360 * chain after the first request has
1361 * already been processed. Send an
1362 * interim response containing the
1363 * set of replies already generated.
1365 int idx = req->current_idx;
1367 status = smb2_send_async_interim_response(req);
1368 if (!NT_STATUS_IS_OK(status)) {
1371 if (req->first_key.length > 0) {
1372 data_blob_clear_free(&req->first_key);
1375 req->current_idx = 1;
1378 * Re-arrange the in.vectors to remove what
1381 memmove(&req->in.vector[1],
1382 &req->in.vector[idx],
1383 sizeof(req->in.vector[0])*(req->in.vector_count - idx));
1384 req->in.vector_count = 1 + (req->in.vector_count - idx);
1386 /* Re-arrange the out.vectors to match. */
1387 memmove(&req->out.vector[1],
1388 &req->out.vector[idx],
1389 sizeof(req->out.vector[0])*(req->out.vector_count - idx));
1390 req->out.vector_count = 1 + (req->out.vector_count - idx);
1392 if (req->in.vector_count == 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
1394 * We only have one remaining request as
1395 * we've processed everything else.
1396 * This is no longer a compound request.
1398 req->compound_related = false;
1399 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1400 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1401 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1404 if (req->last_key.length > 0) {
1405 data_blob_clear_free(&req->last_key);
1408 defer_endtime = timeval_current_ofs_usec(defer_time);
1409 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1411 smbd_smb2_request_pending_timer,
1413 if (req->async_te == NULL) {
1414 return NT_STATUS_NO_MEMORY;
1417 return NT_STATUS_OK;
1420 static DATA_BLOB smbd_smb2_signing_key(struct smbXsrv_session *session,
1421 struct smbXsrv_connection *xconn)
1423 struct smbXsrv_channel_global0 *c = NULL;
1425 DATA_BLOB key = data_blob_null;
1427 status = smbXsrv_session_find_channel(session, xconn, &c);
1428 if (NT_STATUS_IS_OK(status)) {
1429 key = c->signing_key;
1432 if (key.length == 0) {
1433 key = session->global->signing_key;
1439 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1440 struct tevent_timer *te,
1441 struct timeval current_time,
1444 struct smbd_smb2_request *req =
1445 talloc_get_type_abort(private_data,
1446 struct smbd_smb2_request);
1447 struct smbXsrv_connection *xconn = req->xconn;
1448 struct smbd_smb2_request_pending_state *state = NULL;
1449 uint8_t *outhdr = NULL;
1450 const uint8_t *inhdr = NULL;
1453 uint8_t *hdr = NULL;
1454 uint8_t *body = NULL;
1455 uint8_t *dyn = NULL;
1457 uint64_t session_id = 0;
1458 uint64_t message_id = 0;
1459 uint64_t nonce_high = 0;
1460 uint64_t nonce_low = 0;
1461 uint64_t async_id = 0;
1464 TALLOC_FREE(req->async_te);
1466 /* Ensure our final reply matches the interim one. */
1467 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1468 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1469 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1470 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1471 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1473 async_id = message_id; /* keep it simple for now... */
1475 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1476 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1478 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1480 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1481 (unsigned long long)async_id ));
1484 * What we send is identical to a smbd_smb2_request_error
1485 * packet with an error status of STATUS_PENDING. Make use
1486 * of this fact sometime when refactoring. JRA.
1489 state = talloc_zero(req->xconn, struct smbd_smb2_request_pending_state);
1490 if (state == NULL) {
1491 smbd_server_connection_terminate(xconn,
1492 nt_errstr(NT_STATUS_NO_MEMORY));
1496 tf = state->buf + NBT_HDR_SIZE;
1497 tf_len = SMB2_TF_HDR_SIZE;
1499 hdr = tf + SMB2_TF_HDR_SIZE;
1500 body = hdr + SMB2_HDR_BODY;
1503 if (req->do_encryption) {
1504 struct smbXsrv_session *x = req->session;
1506 nonce_high = x->nonce_high;
1507 nonce_low = x->nonce_low;
1510 if (x->nonce_low == 0) {
1516 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1517 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1518 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1519 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1521 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1522 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1523 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1524 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1525 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1527 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1528 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1529 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1530 SBVAL(hdr, SMB2_HDR_PID, async_id);
1531 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1532 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1533 memcpy(hdr+SMB2_HDR_SIGNATURE,
1534 outhdr+SMB2_HDR_SIGNATURE, 16);
1536 SSVAL(body, 0x00, 0x08 + 1);
1538 SCVAL(body, 0x02, 0);
1539 SCVAL(body, 0x03, 0);
1540 SIVAL(body, 0x04, 0);
1541 /* Match W2K8R2... */
1542 SCVAL(dyn, 0x00, 0x21);
1544 state->vector[0].iov_base = (void *)state->buf;
1545 state->vector[0].iov_len = NBT_HDR_SIZE;
1547 if (req->do_encryption) {
1548 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1549 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1551 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1552 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1555 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1556 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1558 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1559 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1561 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1562 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1564 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1566 /* Ensure we correctly go through crediting. Grant
1567 the credits now, and zero credits on the final
1569 smb2_set_operation_credit(req->xconn,
1570 SMBD_SMB2_IN_HDR_IOV(req),
1571 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1573 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1578 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1579 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1581 (unsigned int)ARRAY_SIZE(state->vector),
1582 (unsigned int)state->vector[i].iov_len);
1586 if (req->do_encryption) {
1587 struct smbXsrv_session *x = req->session;
1588 DATA_BLOB encryption_key = x->global->encryption_key;
1590 status = smb2_signing_encrypt_pdu(encryption_key,
1591 xconn->smb2.server.cipher,
1592 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1593 SMBD_SMB2_NUM_IOV_PER_REQ);
1594 if (!NT_STATUS_IS_OK(status)) {
1595 smbd_server_connection_terminate(xconn,
1599 } else if (req->do_signing) {
1600 struct smbXsrv_session *x = req->session;
1601 DATA_BLOB signing_key = smbd_smb2_signing_key(x, xconn);
1603 status = smb2_signing_sign_pdu(signing_key,
1605 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1606 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1607 if (!NT_STATUS_IS_OK(status)) {
1608 smbd_server_connection_terminate(xconn,
1614 state->queue_entry.mem_ctx = state;
1615 state->queue_entry.vector = state->vector;
1616 state->queue_entry.count = ARRAY_SIZE(state->vector);
1617 DLIST_ADD_END(xconn->smb2.send_queue, &state->queue_entry, NULL);
1618 xconn->smb2.send_queue_len++;
1620 status = smbd_smb2_flush_send_queue(xconn);
1621 if (!NT_STATUS_IS_OK(status)) {
1622 smbd_server_connection_terminate(xconn,
1628 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1630 struct smbXsrv_connection *xconn = req->xconn;
1631 struct smbd_smb2_request *cur;
1632 const uint8_t *inhdr;
1634 uint64_t search_message_id;
1635 uint64_t search_async_id;
1638 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1640 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1641 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1642 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1645 * we don't need the request anymore
1646 * cancel requests never have a response
1648 DLIST_REMOVE(xconn->smb2.requests, req);
1651 for (cur = xconn->smb2.requests; cur; cur = cur->next) {
1652 const uint8_t *outhdr;
1653 uint64_t message_id;
1656 if (cur->compound_related) {
1658 * Never cancel anything in a compound request.
1659 * Way too hard to deal with the result.
1664 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1666 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1667 async_id = BVAL(outhdr, SMB2_HDR_PID);
1669 if (flags & SMB2_HDR_FLAG_ASYNC) {
1670 if (search_async_id == async_id) {
1671 found_id = async_id;
1675 if (search_message_id == message_id) {
1676 found_id = message_id;
1682 if (cur && cur->subreq) {
1683 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1684 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1685 "cancel opcode[%s] mid %llu\n",
1686 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1687 (unsigned long long)found_id ));
1688 tevent_req_cancel(cur->subreq);
1691 return NT_STATUS_OK;
1694 /*************************************************************
1695 Ensure an incoming tid is a valid one for us to access.
1696 Change to the associated uid credentials and chdir to the
1697 valid tid directory.
1698 *************************************************************/
1700 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1702 const uint8_t *inhdr;
1705 struct smbXsrv_tcon *tcon;
1707 NTTIME now = timeval_to_nttime(&req->request_time);
1711 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1713 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1714 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1716 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1717 in_tid = req->last_tid;
1722 status = smb2srv_tcon_lookup(req->session,
1723 in_tid, now, &tcon);
1724 if (!NT_STATUS_IS_OK(status)) {
1728 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1729 return NT_STATUS_ACCESS_DENIED;
1732 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1733 if (!set_current_service(tcon->compat, 0, true)) {
1734 return NT_STATUS_ACCESS_DENIED;
1738 req->last_tid = in_tid;
1740 return NT_STATUS_OK;
1743 /*************************************************************
1744 Ensure an incoming session_id is a valid one for us to access.
1745 *************************************************************/
1747 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1749 const uint8_t *inhdr;
1752 uint64_t in_session_id;
1753 struct smbXsrv_session *session = NULL;
1754 struct auth_session_info *session_info;
1756 NTTIME now = timeval_to_nttime(&req->request_time);
1758 req->session = NULL;
1761 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1763 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1764 in_opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1765 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1767 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1768 in_session_id = req->last_session_id;
1771 req->last_session_id = 0;
1773 /* lookup an existing session */
1774 status = smb2srv_session_lookup(req->xconn,
1778 req->session = session;
1779 req->last_session_id = in_session_id;
1781 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1782 switch (in_opcode) {
1783 case SMB2_OP_SESSSETUP:
1784 status = NT_STATUS_OK;
1790 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1791 switch (in_opcode) {
1793 case SMB2_OP_CREATE:
1794 case SMB2_OP_GETINFO:
1795 case SMB2_OP_SETINFO:
1796 return NT_STATUS_INVALID_HANDLE;
1799 * Notice the check for
1800 * (session_info == NULL)
1803 status = NT_STATUS_OK;
1807 if (!NT_STATUS_IS_OK(status)) {
1811 session_info = session->global->auth_session_info;
1812 if (session_info == NULL) {
1813 return NT_STATUS_INVALID_HANDLE;
1816 if (in_session_id != req->xconn->client->last_session_id) {
1817 req->xconn->client->last_session_id = in_session_id;
1818 set_current_user_info(session_info->unix_info->sanitized_username,
1819 session_info->unix_info->unix_name,
1820 session_info->info->domain_name);
1823 return NT_STATUS_OK;
1826 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1827 uint32_t data_length)
1829 struct smbXsrv_connection *xconn = req->xconn;
1830 uint16_t needed_charge;
1831 uint16_t credit_charge = 1;
1832 const uint8_t *inhdr;
1834 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1836 if (xconn->smb2.credits.multicredit) {
1837 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1838 credit_charge = MAX(credit_charge, 1);
1841 needed_charge = (data_length - 1)/ 65536 + 1;
1843 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1844 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1845 credit_charge, needed_charge));
1847 if (needed_charge > credit_charge) {
1848 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1849 credit_charge, needed_charge));
1850 return NT_STATUS_INVALID_PARAMETER;
1853 return NT_STATUS_OK;
1856 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1857 size_t expected_body_size)
1859 struct iovec *inhdr_v;
1860 const uint8_t *inhdr;
1862 const uint8_t *inbody;
1864 size_t min_dyn_size = expected_body_size & 0x00000001;
1865 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1868 * The following should be checked already.
1870 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1871 return NT_STATUS_INTERNAL_ERROR;
1873 if (req->current_idx > max_idx) {
1874 return NT_STATUS_INTERNAL_ERROR;
1877 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1878 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1879 return NT_STATUS_INTERNAL_ERROR;
1881 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1882 return NT_STATUS_INTERNAL_ERROR;
1885 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1886 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1890 case SMB2_OP_GETINFO:
1894 if (req->smb1req != NULL && req->smb1req->unread_bytes > 0) {
1895 if (req->smb1req->unread_bytes < min_dyn_size) {
1896 return NT_STATUS_INVALID_PARAMETER;
1905 * Now check the expected body size,
1906 * where the last byte might be in the
1909 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1910 return NT_STATUS_INVALID_PARAMETER;
1912 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1913 return NT_STATUS_INVALID_PARAMETER;
1916 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1918 body_size = SVAL(inbody, 0x00);
1919 if (body_size != expected_body_size) {
1920 return NT_STATUS_INVALID_PARAMETER;
1923 return NT_STATUS_OK;
1926 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1928 struct smbXsrv_connection *xconn = req->xconn;
1929 const struct smbd_smb2_dispatch_table *call = NULL;
1930 const struct iovec *intf_v = SMBD_SMB2_IN_TF_IOV(req);
1931 const uint8_t *inhdr;
1936 NTSTATUS session_status;
1937 uint32_t allowed_flags;
1938 NTSTATUS return_value;
1939 struct smbXsrv_session *x = NULL;
1940 bool signing_required = false;
1941 bool encryption_required = false;
1943 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1945 DO_PROFILE_INC(request);
1947 /* TODO: verify more things */
1949 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1950 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1951 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1952 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1953 smb2_opcode_name(opcode),
1954 (unsigned long long)mid));
1956 if (xconn->protocol >= PROTOCOL_SMB2_02) {
1958 * once the protocol is negotiated
1959 * SMB2_OP_NEGPROT is not allowed anymore
1961 if (opcode == SMB2_OP_NEGPROT) {
1962 /* drop the connection */
1963 return NT_STATUS_INVALID_PARAMETER;
1967 * if the protocol is not negotiated yet
1968 * only SMB2_OP_NEGPROT is allowed.
1970 if (opcode != SMB2_OP_NEGPROT) {
1971 /* drop the connection */
1972 return NT_STATUS_INVALID_PARAMETER;
1977 * Check if the client provided a valid session id,
1978 * if so smbd_smb2_request_check_session() calls
1979 * set_current_user_info().
1981 * As some command don't require a valid session id
1982 * we defer the check of the session_status
1984 session_status = smbd_smb2_request_check_session(req);
1987 signing_required = x->global->signing_required;
1988 encryption_required = x->global->encryption_required;
1991 req->do_signing = false;
1992 req->do_encryption = false;
1993 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
1994 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
1995 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
1997 if (x != NULL && x->global->session_wire_id != tf_session_id) {
1998 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1999 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
2000 (unsigned long long)x->global->session_wire_id,
2001 (unsigned long long)tf_session_id));
2003 * TODO: windows allows this...
2004 * should we drop the connection?
2006 * For now we just return ACCESS_DENIED
2007 * (Windows clients never trigger this)
2008 * and wait for an update of [MS-SMB2].
2010 return smbd_smb2_request_error(req,
2011 NT_STATUS_ACCESS_DENIED);
2014 req->do_encryption = true;
2017 if (encryption_required && !req->do_encryption) {
2018 return smbd_smb2_request_error(req,
2019 NT_STATUS_ACCESS_DENIED);
2022 call = smbd_smb2_call(opcode);
2024 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2027 allowed_flags = SMB2_HDR_FLAG_CHAINED |
2028 SMB2_HDR_FLAG_SIGNED |
2030 if (opcode == SMB2_OP_CANCEL) {
2031 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
2033 if ((flags & ~allowed_flags) != 0) {
2034 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2037 if (flags & SMB2_HDR_FLAG_CHAINED) {
2039 * This check is mostly for giving the correct error code
2040 * for compounded requests.
2042 if (!NT_STATUS_IS_OK(session_status)) {
2043 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2046 req->compat_chain_fsp = NULL;
2049 if (req->do_encryption) {
2050 signing_required = false;
2051 } else if (signing_required || (flags & SMB2_HDR_FLAG_SIGNED)) {
2052 DATA_BLOB signing_key = data_blob_null;
2056 * MS-SMB2: 3.3.5.2.4 Verifying the Signature.
2057 * If the SMB2 header of the SMB2 NEGOTIATE
2058 * request has the SMB2_FLAGS_SIGNED bit set in the
2059 * Flags field, the server MUST fail the request
2060 * with STATUS_INVALID_PARAMETER.
2062 * Microsoft test tool checks this.
2065 if ((opcode == SMB2_OP_NEGPROT) &&
2066 (flags & SMB2_HDR_FLAG_SIGNED)) {
2067 status = NT_STATUS_INVALID_PARAMETER;
2069 status = NT_STATUS_USER_SESSION_DELETED;
2071 return smbd_smb2_request_error(req, status);
2074 signing_key = smbd_smb2_signing_key(x, xconn);
2077 * If we have a signing key, we should
2080 if (signing_key.length > 0) {
2081 req->do_signing = true;
2084 status = smb2_signing_check_pdu(signing_key,
2086 SMBD_SMB2_IN_HDR_IOV(req),
2087 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2088 if (!NT_STATUS_IS_OK(status)) {
2089 return smbd_smb2_request_error(req, status);
2093 * Now that we know the request was correctly signed
2094 * we have to sign the response too.
2096 req->do_signing = true;
2098 if (!NT_STATUS_IS_OK(session_status)) {
2099 return smbd_smb2_request_error(req, session_status);
2101 } else if (opcode == SMB2_OP_CANCEL) {
2102 /* Cancel requests are allowed to skip the signing */
2103 } else if (signing_required) {
2105 * If signing is required we try to sign
2106 * a possible error response
2108 req->do_signing = true;
2109 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2112 if (flags & SMB2_HDR_FLAG_CHAINED) {
2113 req->compound_related = true;
2116 if (call->need_session) {
2117 if (!NT_STATUS_IS_OK(session_status)) {
2118 return smbd_smb2_request_error(req, session_status);
2122 if (call->need_tcon) {
2123 SMB_ASSERT(call->need_session);
2126 * This call needs to be run as user.
2128 * smbd_smb2_request_check_tcon()
2129 * calls change_to_user() on success.
2131 status = smbd_smb2_request_check_tcon(req);
2132 if (!NT_STATUS_IS_OK(status)) {
2133 return smbd_smb2_request_error(req, status);
2135 if (req->tcon->global->encryption_required) {
2136 encryption_required = true;
2138 if (encryption_required && !req->do_encryption) {
2139 return smbd_smb2_request_error(req,
2140 NT_STATUS_ACCESS_DENIED);
2144 if (call->fileid_ofs != 0) {
2145 size_t needed = call->fileid_ofs + 16;
2146 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2147 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2148 uint64_t file_id_persistent;
2149 uint64_t file_id_volatile;
2150 struct files_struct *fsp;
2152 SMB_ASSERT(call->need_tcon);
2154 if (needed > body_size) {
2155 return smbd_smb2_request_error(req,
2156 NT_STATUS_INVALID_PARAMETER);
2159 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2160 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2162 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2164 if (!call->allow_invalid_fileid) {
2165 return smbd_smb2_request_error(req,
2166 NT_STATUS_FILE_CLOSED);
2169 if (file_id_persistent != UINT64_MAX) {
2170 return smbd_smb2_request_error(req,
2171 NT_STATUS_FILE_CLOSED);
2173 if (file_id_volatile != UINT64_MAX) {
2174 return smbd_smb2_request_error(req,
2175 NT_STATUS_FILE_CLOSED);
2180 if (call->as_root) {
2181 SMB_ASSERT(call->fileid_ofs == 0);
2182 /* This call needs to be run as root */
2183 change_to_root_user();
2185 SMB_ASSERT(call->need_tcon);
2188 #define _INBYTES(_r) \
2189 iov_buflen(SMBD_SMB2_IN_HDR_IOV(_r), SMBD_SMB2_NUM_IOV_PER_REQ-1)
2192 case SMB2_OP_NEGPROT:
2193 SMBPROFILE_IOBYTES_ASYNC_START(smb2_negprot, profile_p,
2194 req->profile, _INBYTES(req));
2195 return_value = smbd_smb2_request_process_negprot(req);
2198 case SMB2_OP_SESSSETUP:
2199 SMBPROFILE_IOBYTES_ASYNC_START(smb2_sesssetup, profile_p,
2200 req->profile, _INBYTES(req));
2201 return_value = smbd_smb2_request_process_sesssetup(req);
2204 case SMB2_OP_LOGOFF:
2205 SMBPROFILE_IOBYTES_ASYNC_START(smb2_logoff, profile_p,
2206 req->profile, _INBYTES(req));
2207 return_value = smbd_smb2_request_process_logoff(req);
2211 SMBPROFILE_IOBYTES_ASYNC_START(smb2_tcon, profile_p,
2212 req->profile, _INBYTES(req));
2213 return_value = smbd_smb2_request_process_tcon(req);
2217 SMBPROFILE_IOBYTES_ASYNC_START(smb2_tdis, profile_p,
2218 req->profile, _INBYTES(req));
2219 return_value = smbd_smb2_request_process_tdis(req);
2222 case SMB2_OP_CREATE:
2223 if (req->subreq == NULL) {
2224 SMBPROFILE_IOBYTES_ASYNC_START(smb2_create, profile_p,
2225 req->profile, _INBYTES(req));
2227 SMBPROFILE_IOBYTES_ASYNC_SET_BUSY(req->profile);
2229 return_value = smbd_smb2_request_process_create(req);
2233 SMBPROFILE_IOBYTES_ASYNC_START(smb2_close, profile_p,
2234 req->profile, _INBYTES(req));
2235 return_value = smbd_smb2_request_process_close(req);
2239 SMBPROFILE_IOBYTES_ASYNC_START(smb2_flush, profile_p,
2240 req->profile, _INBYTES(req));
2241 return_value = smbd_smb2_request_process_flush(req);
2245 SMBPROFILE_IOBYTES_ASYNC_START(smb2_read, profile_p,
2246 req->profile, _INBYTES(req));
2247 return_value = smbd_smb2_request_process_read(req);
2251 SMBPROFILE_IOBYTES_ASYNC_START(smb2_write, profile_p,
2252 req->profile, _INBYTES(req));
2253 return_value = smbd_smb2_request_process_write(req);
2257 SMBPROFILE_IOBYTES_ASYNC_START(smb2_lock, profile_p,
2258 req->profile, _INBYTES(req));
2259 return_value = smbd_smb2_request_process_lock(req);
2263 SMBPROFILE_IOBYTES_ASYNC_START(smb2_ioctl, profile_p,
2264 req->profile, _INBYTES(req));
2265 return_value = smbd_smb2_request_process_ioctl(req);
2268 case SMB2_OP_CANCEL:
2269 SMBPROFILE_IOBYTES_ASYNC_START(smb2_cancel, profile_p,
2270 req->profile, _INBYTES(req));
2271 return_value = smbd_smb2_request_process_cancel(req);
2272 SMBPROFILE_IOBYTES_ASYNC_END(req->profile, 0);
2275 case SMB2_OP_KEEPALIVE:
2276 SMBPROFILE_IOBYTES_ASYNC_START(smb2_keepalive, profile_p,
2277 req->profile, _INBYTES(req));
2278 return_value = smbd_smb2_request_process_keepalive(req);
2282 SMBPROFILE_IOBYTES_ASYNC_START(smb2_find, profile_p,
2283 req->profile, _INBYTES(req));
2284 return_value = smbd_smb2_request_process_find(req);
2287 case SMB2_OP_NOTIFY:
2288 SMBPROFILE_IOBYTES_ASYNC_START(smb2_notify, profile_p,
2289 req->profile, _INBYTES(req));
2290 return_value = smbd_smb2_request_process_notify(req);
2293 case SMB2_OP_GETINFO:
2294 SMBPROFILE_IOBYTES_ASYNC_START(smb2_getinfo, profile_p,
2295 req->profile, _INBYTES(req));
2296 return_value = smbd_smb2_request_process_getinfo(req);
2299 case SMB2_OP_SETINFO:
2300 SMBPROFILE_IOBYTES_ASYNC_START(smb2_setinfo, profile_p,
2301 req->profile, _INBYTES(req));
2302 return_value = smbd_smb2_request_process_setinfo(req);
2306 SMBPROFILE_IOBYTES_ASYNC_START(smb2_break, profile_p,
2307 req->profile, _INBYTES(req));
2308 return_value = smbd_smb2_request_process_break(req);
2312 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2315 return return_value;
2318 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2320 struct smbXsrv_connection *xconn = req->xconn;
2322 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2323 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2324 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2328 TALLOC_FREE(req->async_te);
2330 if (req->do_encryption &&
2331 (firsttf->iov_len == 0) &&
2332 (req->first_key.length == 0) &&
2333 (req->session != NULL) &&
2334 (req->session->global->encryption_key.length != 0))
2336 DATA_BLOB encryption_key = req->session->global->encryption_key;
2338 uint64_t session_id = req->session->global->session_wire_id;
2339 struct smbXsrv_session *x = req->session;
2340 uint64_t nonce_high;
2343 nonce_high = x->nonce_high;
2344 nonce_low = x->nonce_low;
2347 if (x->nonce_low == 0) {
2353 * We need to place the SMB2_TRANSFORM header before the
2358 * we need to remember the encryption key
2359 * and defer the signing/encryption until
2360 * we are sure that we do not change
2363 req->first_key = data_blob_dup_talloc(req, encryption_key);
2364 if (req->first_key.data == NULL) {
2365 return NT_STATUS_NO_MEMORY;
2368 tf = talloc_zero_array(req, uint8_t,
2371 return NT_STATUS_NO_MEMORY;
2374 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2375 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2376 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2377 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2379 firsttf->iov_base = (void *)tf;
2380 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2383 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2384 (req->last_key.length > 0) &&
2385 (firsttf->iov_len == 0))
2387 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2388 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2391 * As we are sure the header of the last request in the
2392 * compound chain will not change, we can to sign here
2393 * with the last signing key we remembered.
2395 status = smb2_signing_sign_pdu(req->last_key,
2398 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2399 if (!NT_STATUS_IS_OK(status)) {
2403 if (req->last_key.length > 0) {
2404 data_blob_clear_free(&req->last_key);
2407 SMBPROFILE_IOBYTES_ASYNC_END(req->profile,
2408 iov_buflen(outhdr, SMBD_SMB2_NUM_IOV_PER_REQ-1));
2410 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2412 if (req->current_idx < req->out.vector_count) {
2414 * We must process the remaining compound
2415 * SMB2 requests before any new incoming SMB2
2416 * requests. This is because incoming SMB2
2417 * requests may include a cancel for a
2418 * compound request we haven't processed
2421 struct tevent_immediate *im = tevent_create_immediate(req);
2423 return NT_STATUS_NO_MEMORY;
2426 if (req->do_signing && firsttf->iov_len == 0) {
2427 struct smbXsrv_session *x = req->session;
2428 DATA_BLOB signing_key = smbd_smb2_signing_key(x, xconn);
2431 * we need to remember the signing key
2432 * and defer the signing until
2433 * we are sure that we do not change
2436 req->last_key = data_blob_dup_talloc(req, signing_key);
2437 if (req->last_key.data == NULL) {
2438 return NT_STATUS_NO_MEMORY;
2442 tevent_schedule_immediate(im,
2444 smbd_smb2_request_dispatch_immediate,
2446 return NT_STATUS_OK;
2449 if (req->compound_related) {
2450 req->compound_related = false;
2453 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2455 /* Set credit for these operations (zero credits if this
2456 is a final reply for an async operation). */
2457 smb2_calculate_credits(req, req);
2460 * now check if we need to sign the current response
2462 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2463 status = smb2_signing_encrypt_pdu(req->first_key,
2464 xconn->smb2.server.cipher,
2466 req->out.vector_count - first_idx);
2467 if (!NT_STATUS_IS_OK(status)) {
2470 } else if (req->do_signing) {
2471 struct smbXsrv_session *x = req->session;
2472 DATA_BLOB signing_key = smbd_smb2_signing_key(x, xconn);
2474 status = smb2_signing_sign_pdu(signing_key,
2477 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2478 if (!NT_STATUS_IS_OK(status)) {
2482 if (req->first_key.length > 0) {
2483 data_blob_clear_free(&req->first_key);
2486 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2487 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2488 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2489 /* Dynamic part is NULL. Chop it off,
2490 We're going to send it via sendfile. */
2491 req->out.vector_count -= 1;
2495 * We're done with this request -
2496 * move it off the "being processed" queue.
2498 DLIST_REMOVE(xconn->smb2.requests, req);
2500 req->queue_entry.mem_ctx = req;
2501 req->queue_entry.vector = req->out.vector;
2502 req->queue_entry.count = req->out.vector_count;
2503 DLIST_ADD_END(xconn->smb2.send_queue, &req->queue_entry, NULL);
2504 xconn->smb2.send_queue_len++;
2506 status = smbd_smb2_flush_send_queue(xconn);
2507 if (!NT_STATUS_IS_OK(status)) {
2511 return NT_STATUS_OK;
2514 static NTSTATUS smbd_smb2_request_next_incoming(struct smbXsrv_connection *xconn);
2516 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2517 struct tevent_immediate *im,
2520 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2521 struct smbd_smb2_request);
2522 struct smbXsrv_connection *xconn = req->xconn;
2527 if (DEBUGLEVEL >= 10) {
2528 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2529 req->current_idx, req->in.vector_count));
2530 print_req_vectors(req);
2533 status = smbd_smb2_request_dispatch(req);
2534 if (!NT_STATUS_IS_OK(status)) {
2535 smbd_server_connection_terminate(xconn, nt_errstr(status));
2539 status = smbd_smb2_request_next_incoming(xconn);
2540 if (!NT_STATUS_IS_OK(status)) {
2541 smbd_server_connection_terminate(xconn, nt_errstr(status));
2546 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2548 DATA_BLOB body, DATA_BLOB *dyn,
2549 const char *location)
2552 struct iovec *outbody_v;
2553 struct iovec *outdyn_v;
2554 uint32_t next_command_ofs;
2556 DEBUG(10,("smbd_smb2_request_done_ex: "
2557 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2558 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2560 (unsigned int)(dyn ? dyn->length : 0),
2563 if (body.length < 2) {
2564 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2567 if ((body.length % 2) != 0) {
2568 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2571 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2572 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2573 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2575 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2576 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2578 outbody_v->iov_base = (void *)body.data;
2579 outbody_v->iov_len = body.length;
2582 outdyn_v->iov_base = (void *)dyn->data;
2583 outdyn_v->iov_len = dyn->length;
2585 outdyn_v->iov_base = NULL;
2586 outdyn_v->iov_len = 0;
2589 /* see if we need to recalculate the offset to the next response */
2590 if (next_command_ofs > 0) {
2591 next_command_ofs = SMB2_HDR_BODY;
2592 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2593 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2596 if ((next_command_ofs % 8) != 0) {
2597 size_t pad_size = 8 - (next_command_ofs % 8);
2598 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2600 * if the dyn buffer is empty
2601 * we can use it to add padding
2605 pad = talloc_zero_array(req,
2608 return smbd_smb2_request_error(req,
2609 NT_STATUS_NO_MEMORY);
2612 outdyn_v->iov_base = (void *)pad;
2613 outdyn_v->iov_len = pad_size;
2616 * For now we copy the dynamic buffer
2617 * and add the padding to the new buffer
2624 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2625 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2627 new_size = old_size + pad_size;
2628 new_dyn = talloc_zero_array(req,
2630 if (new_dyn == NULL) {
2631 return smbd_smb2_request_error(req,
2632 NT_STATUS_NO_MEMORY);
2635 memcpy(new_dyn, old_dyn, old_size);
2636 memset(new_dyn + old_size, 0, pad_size);
2638 outdyn_v->iov_base = (void *)new_dyn;
2639 outdyn_v->iov_len = new_size;
2641 next_command_ofs += pad_size;
2644 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2646 return smbd_smb2_request_reply(req);
2649 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2652 const char *location)
2654 struct smbXsrv_connection *xconn = req->xconn;
2657 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2658 size_t unread_bytes = smbd_smb2_unread_bytes(req);
2660 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2661 req->current_idx, nt_errstr(status), info ? " +info" : "",
2665 /* Recvfile error. Drain incoming socket. */
2669 ret = drain_socket(xconn->transport.sock, unread_bytes);
2670 if (ret != unread_bytes) {
2674 error = NT_STATUS_IO_DEVICE_ERROR;
2676 error = map_nt_error_from_unix_common(errno);
2679 DEBUG(2, ("Failed to drain %u bytes from SMB2 socket: "
2680 "ret[%u] errno[%d] => %s\n",
2681 (unsigned)unread_bytes,
2682 (unsigned)ret, errno, nt_errstr(error)));
2687 body.data = outhdr + SMB2_HDR_BODY;
2689 SSVAL(body.data, 0, 9);
2692 SIVAL(body.data, 0x04, info->length);
2694 /* Allocated size of req->out.vector[i].iov_base
2695 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2696 * 1 byte without having to do an alloc.
2699 info->data = ((uint8_t *)outhdr) +
2700 OUTVEC_ALLOC_SIZE - 1;
2702 SCVAL(info->data, 0, 0);
2706 * Note: Even if there is an error, continue to process the request.
2710 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2714 struct smbd_smb2_send_break_state {
2715 struct smbd_smb2_send_queue queue_entry;
2716 uint8_t nbt_hdr[NBT_HDR_SIZE];
2717 uint8_t tf[SMB2_TF_HDR_SIZE];
2718 uint8_t hdr[SMB2_HDR_BODY];
2719 struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ];
2723 static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
2724 struct smbXsrv_session *session,
2725 struct smbXsrv_tcon *tcon,
2726 const uint8_t *body,
2729 struct smbd_smb2_send_break_state *state;
2730 bool do_encryption = false;
2731 uint64_t session_wire_id = 0;
2732 uint64_t nonce_high = 0;
2733 uint64_t nonce_low = 0;
2737 if (session != NULL) {
2738 session_wire_id = session->global->session_wire_id;
2739 do_encryption = session->global->encryption_required;
2740 if (tcon->global->encryption_required) {
2741 do_encryption = true;
2745 statelen = offsetof(struct smbd_smb2_send_break_state, body) +
2748 state = talloc_zero_size(xconn, statelen);
2749 if (state == NULL) {
2750 return NT_STATUS_NO_MEMORY;
2752 talloc_set_name_const(state, "struct smbd_smb2_send_break_state");
2754 if (do_encryption) {
2755 nonce_high = session->nonce_high;
2756 nonce_low = session->nonce_low;
2758 session->nonce_low += 1;
2759 if (session->nonce_low == 0) {
2760 session->nonce_low += 1;
2761 session->nonce_high += 1;
2765 SIVAL(state->tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2766 SBVAL(state->tf, SMB2_TF_NONCE+0, nonce_low);
2767 SBVAL(state->tf, SMB2_TF_NONCE+8, nonce_high);
2768 SBVAL(state->tf, SMB2_TF_SESSION_ID, session_wire_id);
2770 SIVAL(state->hdr, 0, SMB2_MAGIC);
2771 SSVAL(state->hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2772 SSVAL(state->hdr, SMB2_HDR_EPOCH, 0);
2773 SIVAL(state->hdr, SMB2_HDR_STATUS, 0);
2774 SSVAL(state->hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2775 SSVAL(state->hdr, SMB2_HDR_CREDIT, 0);
2776 SIVAL(state->hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2777 SIVAL(state->hdr, SMB2_HDR_NEXT_COMMAND, 0);
2778 SBVAL(state->hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2779 SIVAL(state->hdr, SMB2_HDR_PID, 0);
2780 SIVAL(state->hdr, SMB2_HDR_TID, 0);
2781 SBVAL(state->hdr, SMB2_HDR_SESSION_ID, 0);
2782 memset(state->hdr+SMB2_HDR_SIGNATURE, 0, 16);
2784 state->vector[0] = (struct iovec) {
2785 .iov_base = state->nbt_hdr,
2786 .iov_len = sizeof(state->nbt_hdr)
2789 if (do_encryption) {
2790 state->vector[1+SMBD_SMB2_TF_IOV_OFS] = (struct iovec) {
2791 .iov_base = state->tf,
2792 .iov_len = sizeof(state->tf)
2795 state->vector[1+SMBD_SMB2_TF_IOV_OFS] = (struct iovec) {
2801 state->vector[1+SMBD_SMB2_HDR_IOV_OFS] = (struct iovec) {
2802 .iov_base = state->hdr,
2803 .iov_len = sizeof(state->hdr)
2806 memcpy(state->body, body, body_len);
2808 state->vector[1+SMBD_SMB2_BODY_IOV_OFS] = (struct iovec) {
2809 .iov_base = state->body,
2810 .iov_len = body_len /* no sizeof(state->body) .. :-) */
2814 * state->vector[1+SMBD_SMB2_DYN_IOV_OFS] is NULL by talloc_zero above
2817 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
2819 if (do_encryption) {
2820 DATA_BLOB encryption_key = session->global->encryption_key;
2822 status = smb2_signing_encrypt_pdu(encryption_key,
2823 xconn->smb2.server.cipher,
2824 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
2825 SMBD_SMB2_NUM_IOV_PER_REQ);
2826 if (!NT_STATUS_IS_OK(status)) {
2831 state->queue_entry.mem_ctx = state;
2832 state->queue_entry.vector = state->vector;
2833 state->queue_entry.count = ARRAY_SIZE(state->vector);
2834 DLIST_ADD_END(xconn->smb2.send_queue, &state->queue_entry, NULL);
2835 xconn->smb2.send_queue_len++;
2837 status = smbd_smb2_flush_send_queue(xconn);
2838 if (!NT_STATUS_IS_OK(status)) {
2842 return NT_STATUS_OK;
2845 NTSTATUS smbd_smb2_send_oplock_break(struct smbXsrv_connection *xconn,
2846 struct smbXsrv_session *session,
2847 struct smbXsrv_tcon *tcon,
2848 struct smbXsrv_open *op,
2849 uint8_t oplock_level)
2853 SSVAL(body, 0x00, sizeof(body));
2854 SCVAL(body, 0x02, oplock_level);
2855 SCVAL(body, 0x03, 0); /* reserved */
2856 SIVAL(body, 0x04, 0); /* reserved */
2857 SBVAL(body, 0x08, op->global->open_persistent_id);
2858 SBVAL(body, 0x10, op->global->open_volatile_id);
2860 return smbd_smb2_send_break(xconn, session, tcon, body, sizeof(body));
2863 NTSTATUS smbd_smb2_send_lease_break(struct smbXsrv_connection *xconn,
2865 uint32_t lease_flags,
2866 struct smb2_lease_key *lease_key,
2867 uint32_t current_lease_state,
2868 uint32_t new_lease_state)
2872 SSVAL(body, 0x00, sizeof(body));
2873 SSVAL(body, 0x02, new_epoch);
2874 SIVAL(body, 0x04, lease_flags);
2875 SBVAL(body, 0x08, lease_key->data[0]);
2876 SBVAL(body, 0x10, lease_key->data[1]);
2877 SIVAL(body, 0x18, current_lease_state);
2878 SIVAL(body, 0x1c, new_lease_state);
2879 SIVAL(body, 0x20, 0); /* BreakReason, MUST be 0 */
2880 SIVAL(body, 0x24, 0); /* AccessMaskHint, MUST be 0 */
2881 SIVAL(body, 0x28, 0); /* ShareMaskHint, MUST be 0 */
2883 return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body));
2886 static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
2890 uint64_t file_id_persistent;
2891 uint64_t file_id_volatile;
2892 struct smbXsrv_open *op = NULL;
2893 struct files_struct *fsp = NULL;
2894 const uint8_t *body = NULL;
2897 * This is only called with a pktbuf
2898 * of at least SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN
2902 if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
2903 /* Transform header. Cannot recvfile. */
2906 if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
2907 /* Not SMB2. Normal error path will cope. */
2910 if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
2911 /* Not SMB2. Normal error path will cope. */
2914 if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
2915 /* Needs to be a WRITE. */
2918 if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
2919 /* Chained. Cannot recvfile. */
2922 flags = IVAL(state->pktbuf, SMB2_HDR_FLAGS);
2923 if (flags & SMB2_HDR_FLAG_CHAINED) {
2924 /* Chained. Cannot recvfile. */
2927 if (flags & SMB2_HDR_FLAG_SIGNED) {
2928 /* Signed. Cannot recvfile. */
2932 body = &state->pktbuf[SMB2_HDR_BODY];
2934 file_id_persistent = BVAL(body, 0x10);
2935 file_id_volatile = BVAL(body, 0x18);
2937 status = smb2srv_open_lookup(state->req->xconn,
2942 if (!NT_STATUS_IS_OK(status)) {
2950 if (fsp->conn == NULL) {
2954 if (IS_IPC(fsp->conn)) {
2957 if (IS_PRINT(fsp->conn)) {
2961 DEBUG(10,("Doing recvfile write len = %u\n",
2962 (unsigned int)(state->pktfull - state->pktlen)));
2967 static NTSTATUS smbd_smb2_request_next_incoming(struct smbXsrv_connection *xconn)
2969 struct smbd_server_connection *sconn = xconn->client->sconn;
2970 struct smbd_smb2_request_read_state *state = &xconn->smb2.request_read_state;
2971 size_t max_send_queue_len;
2972 size_t cur_send_queue_len;
2974 if (!NT_STATUS_IS_OK(xconn->transport.status)) {
2976 * we're not supposed to do any io
2978 return NT_STATUS_OK;
2981 if (state->req != NULL) {
2983 * if there is already a tstream_readv_pdu
2984 * pending, we are done.
2986 return NT_STATUS_OK;
2989 max_send_queue_len = MAX(1, xconn->smb2.credits.max/16);
2990 cur_send_queue_len = xconn->smb2.send_queue_len;
2992 if (cur_send_queue_len > max_send_queue_len) {
2994 * if we have a lot of requests to send,
2995 * we wait until they are on the wire until we
2996 * ask for the next request.
2998 return NT_STATUS_OK;
3001 /* ask for the next request */
3002 ZERO_STRUCTP(state);
3003 state->req = smbd_smb2_request_allocate(xconn);
3004 if (state->req == NULL) {
3005 return NT_STATUS_NO_MEMORY;
3007 state->req->sconn = sconn;
3008 state->req->xconn = xconn;
3009 state->min_recv_size = lp_min_receive_file_size();
3011 TEVENT_FD_READABLE(xconn->transport.fde);
3013 return NT_STATUS_OK;
3016 void smbd_smb2_first_negprot(struct smbXsrv_connection *xconn,
3017 const uint8_t *inpdu, size_t size)
3019 struct smbd_server_connection *sconn = xconn->client->sconn;
3021 struct smbd_smb2_request *req = NULL;
3023 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
3024 (unsigned int)size));
3026 status = smbd_initialize_smb2(xconn);
3027 if (!NT_STATUS_IS_OK(status)) {
3028 smbd_server_connection_terminate(xconn, nt_errstr(status));
3032 status = smbd_smb2_request_create(xconn, inpdu, size, &req);
3033 if (!NT_STATUS_IS_OK(status)) {
3034 smbd_server_connection_terminate(xconn, nt_errstr(status));
3038 status = smbd_smb2_request_validate(req);
3039 if (!NT_STATUS_IS_OK(status)) {
3040 smbd_server_connection_terminate(xconn, nt_errstr(status));
3044 status = smbd_smb2_request_setup_out(req);
3045 if (!NT_STATUS_IS_OK(status)) {
3046 smbd_server_connection_terminate(xconn, nt_errstr(status));
3052 * this was already counted at the SMB1 layer =>
3053 * smbd_smb2_request_dispatch() should not count it twice.
3055 if (profile_p->request_stats.count > 0) {
3056 profile_p->request_stats.count--;
3059 status = smbd_smb2_request_dispatch(req);
3060 if (!NT_STATUS_IS_OK(status)) {
3061 smbd_server_connection_terminate(xconn, nt_errstr(status));
3065 status = smbd_smb2_request_next_incoming(xconn);
3066 if (!NT_STATUS_IS_OK(status)) {
3067 smbd_server_connection_terminate(xconn, nt_errstr(status));
3071 sconn->num_requests++;
3074 static int socket_error_from_errno(int ret,
3088 if (sys_errno == 0) {
3092 if (sys_errno == EINTR) {
3097 if (sys_errno == EINPROGRESS) {
3102 if (sys_errno == EAGAIN) {
3107 /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
3108 if (sys_errno == ENOMEM) {
3114 #if EWOULDBLOCK != EAGAIN
3115 if (sys_errno == EWOULDBLOCK) {
3125 static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
3131 if (xconn->smb2.send_queue == NULL) {
3132 TEVENT_FD_NOT_WRITEABLE(xconn->transport.fde);
3133 return NT_STATUS_OK;
3136 while (xconn->smb2.send_queue != NULL) {
3137 struct smbd_smb2_send_queue *e = xconn->smb2.send_queue;
3139 if (e->sendfile_header != NULL) {
3140 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3145 for (i=0; i < e->count; i++) {
3146 size += e->vector[i].iov_len;
3149 if (size <= e->sendfile_header->length) {
3150 buf = e->sendfile_header->data;
3152 buf = talloc_array(e->mem_ctx, uint8_t, size);
3154 return NT_STATUS_NO_MEMORY;
3159 for (i=0; i < e->count; i++) {
3161 e->vector[i].iov_base,
3162 e->vector[i].iov_len);
3163 size += e->vector[i].iov_len;
3166 e->sendfile_header->data = buf;
3167 e->sendfile_header->length = size;
3168 e->sendfile_status = &status;
3171 xconn->smb2.send_queue_len--;
3172 DLIST_REMOVE(xconn->smb2.send_queue, e);
3174 * This triggers the sendfile path via
3177 talloc_free(e->mem_ctx);
3179 if (!NT_STATUS_IS_OK(status)) {
3185 ret = writev(xconn->transport.sock, e->vector, e->count);
3187 /* propagate end of file */
3188 return NT_STATUS_INTERNAL_ERROR;
3190 err = socket_error_from_errno(ret, errno, &retry);
3193 TEVENT_FD_WRITEABLE(xconn->transport.fde);
3194 return NT_STATUS_OK;
3197 return map_nt_error_from_unix_common(err);
3200 if (ret < e->vector[0].iov_len) {
3202 base = (uint8_t *)e->vector[0].iov_base;
3204 e->vector[0].iov_base = (void *)base;
3205 e->vector[0].iov_len -= ret;
3208 ret -= e->vector[0].iov_len;
3214 * there're maybe some empty vectors at the end
3215 * which we need to skip, otherwise we would get
3216 * ret == 0 from the readv() call and return EPIPE
3218 while (e->count > 0) {
3219 if (e->vector[0].iov_len > 0) {
3227 /* we have more to write */
3228 TEVENT_FD_WRITEABLE(xconn->transport.fde);
3229 return NT_STATUS_OK;
3232 xconn->smb2.send_queue_len--;
3233 DLIST_REMOVE(xconn->smb2.send_queue, e);
3234 talloc_free(e->mem_ctx);
3237 return NT_STATUS_OK;
3240 static NTSTATUS smbd_smb2_io_handler(struct smbXsrv_connection *xconn,
3243 struct smbd_server_connection *sconn = xconn->client->sconn;
3244 struct smbd_smb2_request_read_state *state = &xconn->smb2.request_read_state;
3245 struct smbd_smb2_request *req = NULL;
3246 size_t min_recvfile_size = UINT32_MAX;
3253 if (!NT_STATUS_IS_OK(xconn->transport.status)) {
3255 * we're not supposed to do any io
3257 TEVENT_FD_NOT_READABLE(xconn->transport.fde);
3258 TEVENT_FD_NOT_WRITEABLE(xconn->transport.fde);
3259 return NT_STATUS_OK;
3262 if (fde_flags & TEVENT_FD_WRITE) {
3263 status = smbd_smb2_flush_send_queue(xconn);
3264 if (!NT_STATUS_IS_OK(status)) {
3269 if (!(fde_flags & TEVENT_FD_READ)) {
3270 return NT_STATUS_OK;
3273 if (state->req == NULL) {
3274 TEVENT_FD_NOT_READABLE(xconn->transport.fde);
3275 return NT_STATUS_OK;
3279 if (!state->hdr.done) {
3280 state->hdr.done = true;
3282 state->vector.iov_base = (void *)state->hdr.nbt;
3283 state->vector.iov_len = NBT_HDR_SIZE;
3286 ret = readv(xconn->transport.sock, &state->vector, 1);
3288 /* propagate end of file */
3289 return NT_STATUS_END_OF_FILE;
3291 err = socket_error_from_errno(ret, errno, &retry);
3294 TEVENT_FD_READABLE(xconn->transport.fde);
3295 return NT_STATUS_OK;
3298 return map_nt_error_from_unix_common(err);
3301 if (ret < state->vector.iov_len) {
3303 base = (uint8_t *)state->vector.iov_base;
3305 state->vector.iov_base = (void *)base;
3306 state->vector.iov_len -= ret;
3307 /* we have more to read */
3308 TEVENT_FD_READABLE(xconn->transport.fde);
3309 return NT_STATUS_OK;
3312 if (state->pktlen > 0) {
3313 if (state->doing_receivefile && !is_smb2_recvfile_write(state)) {
3315 * Not a possible receivefile write.
3316 * Read the rest of the data.
3318 state->doing_receivefile = false;
3320 state->pktbuf = talloc_realloc(state->req,
3324 if (state->pktbuf == NULL) {
3325 return NT_STATUS_NO_MEMORY;
3328 state->vector.iov_base = (void *)(state->pktbuf +
3330 state->vector.iov_len = (state->pktfull -
3333 state->pktlen = state->pktfull;
3338 * Either this is a receivefile write so we've
3339 * done a short read, or if not we have all the data.
3345 * Now we analyze the NBT header
3347 if (state->hdr.nbt[0] != 0x00) {
3348 state->min_recv_size = 0;
3350 state->pktfull = smb2_len(state->hdr.nbt);
3351 if (state->pktfull == 0) {
3355 if (state->min_recv_size != 0) {
3356 min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3357 min_recvfile_size += state->min_recv_size;
3360 if (state->pktfull > min_recvfile_size) {
3362 * Might be a receivefile write. Read the SMB2 HEADER +
3363 * SMB2_WRITE header first. Set 'doing_receivefile'
3364 * as we're *attempting* receivefile write. If this
3365 * turns out not to be a SMB2_WRITE request or otherwise
3366 * not suitable then we'll just read the rest of the data
3367 * the next time this function is called.
3369 state->pktlen = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3370 state->doing_receivefile = true;
3372 state->pktlen = state->pktfull;
3375 state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen);
3376 if (state->pktbuf == NULL) {
3377 return NT_STATUS_NO_MEMORY;
3380 state->vector.iov_base = (void *)state->pktbuf;
3381 state->vector.iov_len = state->pktlen;
3387 if (state->hdr.nbt[0] != 0x00) {
3388 DEBUG(1,("ignore NBT[0x%02X] msg\n",
3389 state->hdr.nbt[0]));
3392 ZERO_STRUCTP(state);
3394 state->min_recv_size = lp_min_receive_file_size();
3402 req->request_time = timeval_current();
3403 now = timeval_to_nttime(&req->request_time);
3405 status = smbd_smb2_inbuf_parse_compound(xconn,
3411 &req->in.vector_count);
3412 if (!NT_STATUS_IS_OK(status)) {
3416 if (state->doing_receivefile) {
3417 req->smb1req = talloc_zero(req, struct smb_request);
3418 if (req->smb1req == NULL) {
3419 return NT_STATUS_NO_MEMORY;
3421 req->smb1req->unread_bytes = state->pktfull - state->pktlen;
3424 ZERO_STRUCTP(state);
3426 req->current_idx = 1;
3428 DEBUG(10,("smbd_smb2_request idx[%d] of %d vectors\n",
3429 req->current_idx, req->in.vector_count));
3431 status = smbd_smb2_request_validate(req);
3432 if (!NT_STATUS_IS_OK(status)) {
3436 status = smbd_smb2_request_setup_out(req);
3437 if (!NT_STATUS_IS_OK(status)) {
3441 status = smbd_smb2_request_dispatch(req);
3442 if (!NT_STATUS_IS_OK(status)) {
3446 sconn->num_requests++;
3448 /* The timeout_processing function isn't run nearly
3449 often enough to implement 'max log size' without
3450 overrunning the size of the file by many megabytes.
3451 This is especially true if we are running at debug
3452 level 10. Checking every 50 SMB2s is a nice
3453 tradeoff of performance vs log file size overrun. */
3455 if ((sconn->num_requests % 50) == 0 &&
3456 need_to_check_log_size()) {
3457 change_to_root_user();
3461 status = smbd_smb2_request_next_incoming(xconn);
3462 if (!NT_STATUS_IS_OK(status)) {
3466 return NT_STATUS_OK;
3469 static void smbd_smb2_connection_handler(struct tevent_context *ev,
3470 struct tevent_fd *fde,
3474 struct smbXsrv_connection *xconn =
3475 talloc_get_type_abort(private_data,
3476 struct smbXsrv_connection);
3479 status = smbd_smb2_io_handler(xconn, flags);
3480 if (!NT_STATUS_IS_OK(status)) {
3481 smbd_server_connection_terminate(xconn, nt_errstr(status));