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 static void smbd_smb2_connection_handler(struct tevent_context
*ev
,
34 struct tevent_fd
*fde
,
37 static NTSTATUS
smbd_smb2_io_handler(struct smbd_server_connection
*sconn
,
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 smbd_server_connection
*sconn
)
204 TALLOC_FREE(sconn
->smb1
.fde
);
206 sconn
->smb2
.send_queue
= NULL
;
208 sconn
->smb2
.seqnum_low
= 0;
209 sconn
->smb2
.seqnum_range
= 1;
210 sconn
->smb2
.credits_granted
= 1;
211 sconn
->smb2
.max_credits
= lp_smb2_max_credits();
212 sconn
->smb2
.credits_bitmap
= bitmap_talloc(sconn
,
213 sconn
->smb2
.max_credits
);
214 if (sconn
->smb2
.credits_bitmap
== NULL
) {
215 return NT_STATUS_NO_MEMORY
;
218 sconn
->smb2
.fde
= tevent_add_fd(sconn
->ev_ctx
,
222 smbd_smb2_connection_handler
,
224 if (sconn
->smb2
.fde
== NULL
) {
225 return NT_STATUS_NO_MEMORY
;
228 /* Ensure child is set to non-blocking mode */
229 set_blocking(sconn
->sock
, false);
233 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
234 #define _smb2_setlen(_buf,len) do { \
235 uint8_t *buf = (uint8_t *)_buf; \
237 buf[1] = ((len)&0xFF0000)>>16; \
238 buf[2] = ((len)&0xFF00)>>8; \
239 buf[3] = (len)&0xFF; \
242 static void smb2_setup_nbt_length(struct iovec
*vector
, int count
)
247 for (i
=1; i
< count
; i
++) {
248 len
+= vector
[i
].iov_len
;
251 _smb2_setlen(vector
[0].iov_base
, len
);
254 static int smbd_smb2_request_destructor(struct smbd_smb2_request
*req
)
256 if (req
->first_key
.length
> 0) {
257 data_blob_clear_free(&req
->first_key
);
259 if (req
->last_key
.length
> 0) {
260 data_blob_clear_free(&req
->last_key
);
265 static struct smbd_smb2_request
*smbd_smb2_request_allocate(TALLOC_CTX
*mem_ctx
)
267 TALLOC_CTX
*mem_pool
;
268 struct smbd_smb2_request
*req
;
271 /* Enable this to find subtle valgrind errors. */
272 mem_pool
= talloc_init("smbd_smb2_request_allocate");
274 mem_pool
= talloc_tos();
276 if (mem_pool
== NULL
) {
280 req
= talloc_zero(mem_pool
, struct smbd_smb2_request
);
282 talloc_free(mem_pool
);
285 talloc_reparent(mem_pool
, mem_ctx
, req
);
287 TALLOC_FREE(mem_pool
);
290 req
->last_session_id
= UINT64_MAX
;
291 req
->last_tid
= UINT32_MAX
;
293 talloc_set_destructor(req
, smbd_smb2_request_destructor
);
298 static NTSTATUS
smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection
*conn
,
302 struct smbd_smb2_request
*req
,
306 TALLOC_CTX
*mem_ctx
= req
;
310 uint8_t *first_hdr
= buf
;
311 size_t verified_buflen
= 0;
316 * Note: index '0' is reserved for the transport protocol
318 iov
= req
->in
._vector
;
320 while (taken
< buflen
) {
321 size_t len
= buflen
- taken
;
322 uint8_t *hdr
= first_hdr
+ taken
;
325 size_t next_command_ofs
;
327 uint8_t *body
= NULL
;
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 if (num_iov
>= ARRAY_SIZE(req
->in
._vector
)) {
461 struct iovec
*iov_tmp
= NULL
;
462 struct iovec
*iov_alloc
= NULL
;
464 if (iov
!= req
->in
._vector
) {
468 iov_tmp
= talloc_realloc(mem_ctx
, iov_alloc
,
471 SMBD_SMB2_NUM_IOV_PER_REQ
);
472 if (iov_tmp
== NULL
) {
473 TALLOC_FREE(iov_alloc
);
474 return NT_STATUS_NO_MEMORY
;
477 if (iov_alloc
== NULL
) {
480 sizeof(req
->in
._vector
));
486 num_iov
+= SMBD_SMB2_NUM_IOV_PER_REQ
;
488 cur
[SMBD_SMB2_TF_IOV_OFS
].iov_base
= tf
;
489 cur
[SMBD_SMB2_TF_IOV_OFS
].iov_len
= tf_len
;
490 cur
[SMBD_SMB2_HDR_IOV_OFS
].iov_base
= hdr
;
491 cur
[SMBD_SMB2_HDR_IOV_OFS
].iov_len
= SMB2_HDR_BODY
;
492 cur
[SMBD_SMB2_BODY_IOV_OFS
].iov_base
= body
;
493 cur
[SMBD_SMB2_BODY_IOV_OFS
].iov_len
= body_size
;
494 cur
[SMBD_SMB2_DYN_IOV_OFS
].iov_base
= dyn
;
495 cur
[SMBD_SMB2_DYN_IOV_OFS
].iov_len
= dyn_size
;
505 if (iov
!= req
->in
._vector
) {
508 return NT_STATUS_INVALID_PARAMETER
;
511 static NTSTATUS
smbd_smb2_request_create(struct smbd_server_connection
*sconn
,
512 uint8_t *inbuf
, size_t size
,
513 struct smbd_smb2_request
**_req
)
515 struct smbd_smb2_request
*req
;
516 uint32_t protocol_version
;
517 const uint8_t *inhdr
= NULL
;
519 uint32_t next_command_ofs
;
523 if (size
< (4 + 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(sconn
);
553 return NT_STATUS_NO_MEMORY
;
557 talloc_steal(req
, inbuf
);
559 req
->request_time
= timeval_current();
560 now
= timeval_to_nttime(&req
->request_time
);
562 status
= smbd_smb2_inbuf_parse_compound(sconn
->conn
,
564 inbuf
+ NBT_HDR_SIZE
,
566 req
, &req
->in
.vector
,
567 &req
->in
.vector_count
);
568 if (!NT_STATUS_IS_OK(status
)) {
573 req
->current_idx
= 1;
579 static bool smb2_validate_sequence_number(struct smbd_server_connection
*sconn
,
580 uint64_t message_id
, uint64_t seq_id
)
582 struct bitmap
*credits_bm
= sconn
->smb2
.credits_bitmap
;
585 if (seq_id
< sconn
->smb2
.seqnum_low
) {
586 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
587 "%llu (sequence id %llu) "
588 "(granted = %u, low = %llu, range = %u)\n",
589 (unsigned long long)message_id
,
590 (unsigned long long)seq_id
,
591 (unsigned int)sconn
->smb2
.credits_granted
,
592 (unsigned long long)sconn
->smb2
.seqnum_low
,
593 (unsigned int)sconn
->smb2
.seqnum_range
));
597 if (seq_id
>= sconn
->smb2
.seqnum_low
+ sconn
->smb2
.seqnum_range
) {
598 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
599 "%llu (sequence id %llu) "
600 "(granted = %u, low = %llu, range = %u)\n",
601 (unsigned long long)message_id
,
602 (unsigned long long)seq_id
,
603 (unsigned int)sconn
->smb2
.credits_granted
,
604 (unsigned long long)sconn
->smb2
.seqnum_low
,
605 (unsigned int)sconn
->smb2
.seqnum_range
));
609 offset
= seq_id
% sconn
->smb2
.max_credits
;
611 if (bitmap_query(credits_bm
, offset
)) {
612 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
613 "%llu (sequence id %llu) "
614 "(granted = %u, low = %llu, range = %u) "
616 (unsigned long long)message_id
,
617 (unsigned long long)seq_id
,
618 (unsigned int)sconn
->smb2
.credits_granted
,
619 (unsigned long long)sconn
->smb2
.seqnum_low
,
620 (unsigned int)sconn
->smb2
.seqnum_range
,
625 /* Mark the message_ids as seen in the bitmap. */
626 bitmap_set(credits_bm
, offset
);
628 if (seq_id
!= sconn
->smb2
.seqnum_low
) {
633 * Move the window forward by all the message_id's
636 while (bitmap_query(credits_bm
, offset
)) {
637 DEBUG(10,("smb2_validate_sequence_number: clearing "
638 "id %llu (position %u) from bitmap\n",
639 (unsigned long long)(sconn
->smb2
.seqnum_low
),
641 bitmap_clear(credits_bm
, offset
);
643 sconn
->smb2
.seqnum_low
+= 1;
644 sconn
->smb2
.seqnum_range
-= 1;
645 offset
= sconn
->smb2
.seqnum_low
% sconn
->smb2
.max_credits
;
651 static bool smb2_validate_message_id(struct smbd_server_connection
*sconn
,
652 const uint8_t *inhdr
)
654 uint64_t message_id
= BVAL(inhdr
, SMB2_HDR_MESSAGE_ID
);
655 uint16_t opcode
= SVAL(inhdr
, SMB2_HDR_OPCODE
);
656 uint16_t credit_charge
= 1;
659 if (opcode
== SMB2_OP_CANCEL
) {
660 /* SMB2_CANCEL requests by definition resend messageids. */
664 if (sconn
->smb2
.supports_multicredit
) {
665 credit_charge
= SVAL(inhdr
, SMB2_HDR_CREDIT_CHARGE
);
666 credit_charge
= MAX(credit_charge
, 1);
669 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
670 "credits_granted %llu, "
671 "seqnum low/range: %llu/%llu\n",
672 (unsigned long long) message_id
,
673 (unsigned long long) credit_charge
,
674 (unsigned long long) sconn
->smb2
.credits_granted
,
675 (unsigned long long) sconn
->smb2
.seqnum_low
,
676 (unsigned long long) sconn
->smb2
.seqnum_range
));
678 if (sconn
->smb2
.credits_granted
< credit_charge
) {
679 DEBUG(0, ("smb2_validate_message_id: client used more "
680 "credits than granted, mid %llu, charge %llu, "
681 "credits_granted %llu, "
682 "seqnum low/range: %llu/%llu\n",
683 (unsigned long long) message_id
,
684 (unsigned long long) credit_charge
,
685 (unsigned long long) sconn
->smb2
.credits_granted
,
686 (unsigned long long) sconn
->smb2
.seqnum_low
,
687 (unsigned long long) sconn
->smb2
.seqnum_range
));
692 * now check the message ids
694 * for multi-credit requests we need to check all current mid plus
695 * the implicit mids caused by the credit charge
696 * e.g. current mid = 15, charge 5 => mark 15-19 as used
699 for (i
= 0; i
<= (credit_charge
-1); i
++) {
700 uint64_t id
= message_id
+ i
;
703 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
704 (unsigned long long)message_id
,
706 (unsigned long long)id
));
708 ok
= smb2_validate_sequence_number(sconn
, message_id
, id
);
714 /* substract used credits */
715 sconn
->smb2
.credits_granted
-= credit_charge
;
720 static NTSTATUS
smbd_smb2_request_validate(struct smbd_smb2_request
*req
)
725 count
= req
->in
.vector_count
;
727 if (count
< 1 + SMBD_SMB2_NUM_IOV_PER_REQ
) {
728 /* It's not a SMB2 request */
729 return NT_STATUS_INVALID_PARAMETER
;
732 for (idx
=1; idx
< count
; idx
+= SMBD_SMB2_NUM_IOV_PER_REQ
) {
733 struct iovec
*hdr
= SMBD_SMB2_IDX_HDR_IOV(req
,in
,idx
);
734 struct iovec
*body
= SMBD_SMB2_IDX_BODY_IOV(req
,in
,idx
);
735 const uint8_t *inhdr
= NULL
;
737 if (hdr
->iov_len
!= SMB2_HDR_BODY
) {
738 return NT_STATUS_INVALID_PARAMETER
;
741 if (body
->iov_len
< 2) {
742 return NT_STATUS_INVALID_PARAMETER
;
745 inhdr
= (const uint8_t *)hdr
->iov_base
;
747 /* Check the SMB2 header */
748 if (IVAL(inhdr
, SMB2_HDR_PROTOCOL_ID
) != SMB2_MAGIC
) {
749 return NT_STATUS_INVALID_PARAMETER
;
752 if (!smb2_validate_message_id(req
->sconn
, inhdr
)) {
753 return NT_STATUS_INVALID_PARAMETER
;
760 static void smb2_set_operation_credit(struct smbd_server_connection
*sconn
,
761 const struct iovec
*in_vector
,
762 struct iovec
*out_vector
)
764 const uint8_t *inhdr
= (const uint8_t *)in_vector
->iov_base
;
765 uint8_t *outhdr
= (uint8_t *)out_vector
->iov_base
;
766 uint16_t credit_charge
= 1;
767 uint16_t credits_requested
;
771 uint16_t credits_granted
= 0;
772 uint64_t credits_possible
;
773 uint16_t current_max_credits
;
776 * first we grant only 1/16th of the max range.
778 * Windows also starts with the 1/16th and then grants
779 * more later. I was only able to trigger higher
780 * values, when using a very high credit charge.
782 * TODO: scale up depending on load, free memory
784 * Maybe also on the relationship between number
785 * of requests and the used sequence number.
786 * Which means we would grant more credits
787 * for client which use multi credit requests.
789 current_max_credits
= sconn
->smb2
.max_credits
/ 16;
790 current_max_credits
= MAX(current_max_credits
, 1);
792 if (sconn
->smb2
.supports_multicredit
) {
793 credit_charge
= SVAL(inhdr
, SMB2_HDR_CREDIT_CHARGE
);
794 credit_charge
= MAX(credit_charge
, 1);
797 cmd
= SVAL(inhdr
, SMB2_HDR_OPCODE
);
798 credits_requested
= SVAL(inhdr
, SMB2_HDR_CREDIT
);
799 out_flags
= IVAL(outhdr
, SMB2_HDR_FLAGS
);
800 out_status
= NT_STATUS(IVAL(outhdr
, SMB2_HDR_STATUS
));
802 SMB_ASSERT(sconn
->smb2
.max_credits
>= sconn
->smb2
.credits_granted
);
804 if (sconn
->smb2
.max_credits
< credit_charge
) {
805 smbd_server_connection_terminate(sconn
,
806 "client error: credit charge > max credits\n");
810 if (out_flags
& SMB2_HDR_FLAG_ASYNC
) {
812 * In case we already send an async interim
813 * response, we should not grant
814 * credits on the final response.
817 } else if (credits_requested
> 0) {
818 uint16_t additional_max
= 0;
819 uint16_t additional_credits
= credits_requested
- 1;
822 case SMB2_OP_NEGPROT
:
824 case SMB2_OP_SESSSETUP
:
826 * Windows 2012 RC1 starts to grant
828 * with a successful session setup
830 if (NT_STATUS_IS_OK(out_status
)) {
836 * We match windows and only grant additional credits
843 additional_credits
= MIN(additional_credits
, additional_max
);
845 credits_granted
= credit_charge
+ additional_credits
;
846 } else if (sconn
->smb2
.credits_granted
== 0) {
848 * Make sure the client has always at least one credit
854 * sequence numbers should not wrap
856 * 1. calculate the possible credits until
857 * the sequence numbers start to wrap on 64-bit.
859 * 2. UINT64_MAX is used for Break Notifications.
861 * 2. truncate the possible credits to the maximum
862 * credits we want to grant to the client in total.
864 * 3. remove the range we'll already granted to the client
865 * this makes sure the client consumes the lowest sequence
866 * number, before we can grant additional credits.
868 credits_possible
= UINT64_MAX
- sconn
->smb2
.seqnum_low
;
869 if (credits_possible
> 0) {
870 /* remove UINT64_MAX */
871 credits_possible
-= 1;
873 credits_possible
= MIN(credits_possible
, current_max_credits
);
874 credits_possible
-= sconn
->smb2
.seqnum_range
;
876 credits_granted
= MIN(credits_granted
, credits_possible
);
878 SSVAL(outhdr
, SMB2_HDR_CREDIT
, credits_granted
);
879 sconn
->smb2
.credits_granted
+= credits_granted
;
880 sconn
->smb2
.seqnum_range
+= credits_granted
;
882 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
883 "granted %u, current possible/max %u/%u, "
884 "total granted/max/low/range %u/%u/%llu/%u\n",
885 (unsigned int)credits_requested
,
886 (unsigned int)credit_charge
,
887 (unsigned int)credits_granted
,
888 (unsigned int)credits_possible
,
889 (unsigned int)current_max_credits
,
890 (unsigned int)sconn
->smb2
.credits_granted
,
891 (unsigned int)sconn
->smb2
.max_credits
,
892 (unsigned long long)sconn
->smb2
.seqnum_low
,
893 (unsigned int)sconn
->smb2
.seqnum_range
));
896 static void smb2_calculate_credits(const struct smbd_smb2_request
*inreq
,
897 struct smbd_smb2_request
*outreq
)
900 uint16_t total_credits
= 0;
902 count
= outreq
->out
.vector_count
;
904 for (idx
=1; idx
< count
; idx
+= SMBD_SMB2_NUM_IOV_PER_REQ
) {
905 struct iovec
*inhdr_v
= SMBD_SMB2_IDX_HDR_IOV(inreq
,in
,idx
);
906 struct iovec
*outhdr_v
= SMBD_SMB2_IDX_HDR_IOV(outreq
,out
,idx
);
907 uint8_t *outhdr
= (uint8_t *)outhdr_v
->iov_base
;
909 smb2_set_operation_credit(outreq
->sconn
, inhdr_v
, outhdr_v
);
911 /* To match Windows, count up what we
913 total_credits
+= SVAL(outhdr
, SMB2_HDR_CREDIT
);
914 /* Set to zero in all but the last reply. */
915 if (idx
+ SMBD_SMB2_NUM_IOV_PER_REQ
< count
) {
916 SSVAL(outhdr
, SMB2_HDR_CREDIT
, 0);
918 SSVAL(outhdr
, SMB2_HDR_CREDIT
, total_credits
);
923 DATA_BLOB
smbd_smb2_generate_outbody(struct smbd_smb2_request
*req
, size_t size
)
925 if (req
->current_idx
<= 1) {
926 if (size
<= sizeof(req
->out
._body
)) {
927 return data_blob_const(req
->out
._body
, size
);
931 return data_blob_talloc(req
, NULL
, size
);
934 static NTSTATUS
smbd_smb2_request_setup_out(struct smbd_smb2_request
*req
)
937 struct iovec
*vector
;
941 count
= req
->in
.vector_count
;
942 if (count
<= ARRAY_SIZE(req
->out
._vector
)) {
944 vector
= req
->out
._vector
;
946 vector
= talloc_zero_array(req
, struct iovec
, count
);
947 if (vector
== NULL
) {
948 return NT_STATUS_NO_MEMORY
;
953 vector
[0].iov_base
= req
->out
.nbt_hdr
;
954 vector
[0].iov_len
= 4;
955 SIVAL(req
->out
.nbt_hdr
, 0, 0);
957 for (idx
=1; idx
< count
; idx
+= SMBD_SMB2_NUM_IOV_PER_REQ
) {
958 struct iovec
*inhdr_v
= SMBD_SMB2_IDX_HDR_IOV(req
,in
,idx
);
959 const uint8_t *inhdr
= (const uint8_t *)inhdr_v
->iov_base
;
960 uint8_t *outhdr
= NULL
;
961 uint8_t *outbody
= NULL
;
962 uint32_t next_command_ofs
= 0;
963 struct iovec
*current
= &vector
[idx
];
965 if ((idx
+ SMBD_SMB2_NUM_IOV_PER_REQ
) < count
) {
966 /* we have a next command -
967 * setup for the error case. */
968 next_command_ofs
= SMB2_HDR_BODY
+ 9;
972 outhdr
= req
->out
._hdr
;
974 outhdr
= talloc_zero_array(mem_ctx
, uint8_t,
976 if (outhdr
== NULL
) {
977 return NT_STATUS_NO_MEMORY
;
981 outbody
= outhdr
+ SMB2_HDR_BODY
;
984 * SMBD_SMB2_TF_IOV_OFS might be used later
986 current
[SMBD_SMB2_TF_IOV_OFS
].iov_base
= NULL
;
987 current
[SMBD_SMB2_TF_IOV_OFS
].iov_len
= 0;
989 current
[SMBD_SMB2_HDR_IOV_OFS
].iov_base
= (void *)outhdr
;
990 current
[SMBD_SMB2_HDR_IOV_OFS
].iov_len
= SMB2_HDR_BODY
;
992 current
[SMBD_SMB2_BODY_IOV_OFS
].iov_base
= (void *)outbody
;
993 current
[SMBD_SMB2_BODY_IOV_OFS
].iov_len
= 8;
995 current
[SMBD_SMB2_DYN_IOV_OFS
].iov_base
= NULL
;
996 current
[SMBD_SMB2_DYN_IOV_OFS
].iov_len
= 0;
998 /* setup the SMB2 header */
999 SIVAL(outhdr
, SMB2_HDR_PROTOCOL_ID
, SMB2_MAGIC
);
1000 SSVAL(outhdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
1001 SSVAL(outhdr
, SMB2_HDR_CREDIT_CHARGE
,
1002 SVAL(inhdr
, SMB2_HDR_CREDIT_CHARGE
));
1003 SIVAL(outhdr
, SMB2_HDR_STATUS
,
1004 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR
));
1005 SSVAL(outhdr
, SMB2_HDR_OPCODE
,
1006 SVAL(inhdr
, SMB2_HDR_OPCODE
));
1007 SIVAL(outhdr
, SMB2_HDR_FLAGS
,
1008 IVAL(inhdr
, SMB2_HDR_FLAGS
) | SMB2_HDR_FLAG_REDIRECT
);
1009 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, next_command_ofs
);
1010 SBVAL(outhdr
, SMB2_HDR_MESSAGE_ID
,
1011 BVAL(inhdr
, SMB2_HDR_MESSAGE_ID
));
1012 SIVAL(outhdr
, SMB2_HDR_PID
,
1013 IVAL(inhdr
, SMB2_HDR_PID
));
1014 SIVAL(outhdr
, SMB2_HDR_TID
,
1015 IVAL(inhdr
, SMB2_HDR_TID
));
1016 SBVAL(outhdr
, SMB2_HDR_SESSION_ID
,
1017 BVAL(inhdr
, SMB2_HDR_SESSION_ID
));
1018 memcpy(outhdr
+ SMB2_HDR_SIGNATURE
,
1019 inhdr
+ SMB2_HDR_SIGNATURE
, 16);
1021 /* setup error body header */
1022 SSVAL(outbody
, 0x00, 0x08 + 1);
1023 SSVAL(outbody
, 0x02, 0);
1024 SIVAL(outbody
, 0x04, 0);
1027 req
->out
.vector
= vector
;
1028 req
->out
.vector_count
= count
;
1030 /* setup the length of the NBT packet */
1031 smb2_setup_nbt_length(req
->out
.vector
, req
->out
.vector_count
);
1033 DLIST_ADD_END(req
->sconn
->smb2
.requests
, req
, struct smbd_smb2_request
*);
1035 return NT_STATUS_OK
;
1038 void smbd_server_connection_terminate_ex(struct smbd_server_connection
*sconn
,
1040 const char *location
)
1042 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
1044 exit_server_cleanly(reason
);
1047 static bool dup_smb2_vec4(TALLOC_CTX
*ctx
,
1048 struct iovec
*outvec
,
1049 const struct iovec
*srcvec
)
1051 const uint8_t *srctf
;
1053 const uint8_t *srchdr
;
1055 const uint8_t *srcbody
;
1057 const uint8_t *expected_srcbody
;
1058 const uint8_t *srcdyn
;
1060 const uint8_t *expected_srcdyn
;
1066 srctf
= (const uint8_t *)srcvec
[SMBD_SMB2_TF_IOV_OFS
].iov_base
;
1067 srctf_len
= srcvec
[SMBD_SMB2_TF_IOV_OFS
].iov_len
;
1068 srchdr
= (const uint8_t *)srcvec
[SMBD_SMB2_HDR_IOV_OFS
].iov_base
;
1069 srchdr_len
= srcvec
[SMBD_SMB2_HDR_IOV_OFS
].iov_len
;
1070 srcbody
= (const uint8_t *)srcvec
[SMBD_SMB2_BODY_IOV_OFS
].iov_base
;
1071 srcbody_len
= srcvec
[SMBD_SMB2_BODY_IOV_OFS
].iov_len
;
1072 expected_srcbody
= srchdr
+ SMB2_HDR_BODY
;
1073 srcdyn
= (const uint8_t *)srcvec
[SMBD_SMB2_DYN_IOV_OFS
].iov_base
;
1074 srcdyn_len
= srcvec
[SMBD_SMB2_DYN_IOV_OFS
].iov_len
;
1075 expected_srcdyn
= srcbody
+ 8;
1077 if ((srctf_len
!= SMB2_TF_HDR_SIZE
) && (srctf_len
!= 0)) {
1081 if (srchdr_len
!= SMB2_HDR_BODY
) {
1085 if (srctf_len
== SMB2_TF_HDR_SIZE
) {
1086 dsttf
= talloc_memdup(ctx
, srctf
, SMB2_TF_HDR_SIZE
);
1087 if (dsttf
== NULL
) {
1093 outvec
[SMBD_SMB2_TF_IOV_OFS
].iov_base
= (void *)dsttf
;
1094 outvec
[SMBD_SMB2_TF_IOV_OFS
].iov_len
= srctf_len
;
1096 /* vec[SMBD_SMB2_HDR_IOV_OFS] is always boilerplate and must
1097 * be allocated with size OUTVEC_ALLOC_SIZE. */
1099 dsthdr
= talloc_memdup(ctx
, srchdr
, OUTVEC_ALLOC_SIZE
);
1100 if (dsthdr
== NULL
) {
1103 outvec
[SMBD_SMB2_HDR_IOV_OFS
].iov_base
= (void *)dsthdr
;
1104 outvec
[SMBD_SMB2_HDR_IOV_OFS
].iov_len
= SMB2_HDR_BODY
;
1107 * If this is a "standard" vec[SMBD_SMB2_BOFY_IOV_OFS] of length 8,
1108 * pointing to srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + SMB2_HDR_BODY,
1109 * then duplicate this. Else use talloc_memdup().
1112 if ((srcbody
== expected_srcbody
) && (srcbody_len
== 8)) {
1113 dstbody
= dsthdr
+ SMB2_HDR_BODY
;
1115 dstbody
= talloc_memdup(ctx
, srcbody
, srcbody_len
);
1116 if (dstbody
== NULL
) {
1120 outvec
[SMBD_SMB2_BODY_IOV_OFS
].iov_base
= (void *)dstbody
;
1121 outvec
[SMBD_SMB2_BODY_IOV_OFS
].iov_len
= srcbody_len
;
1124 * If this is a "standard" vec[SMBD_SMB2_DYN_IOV_OFS] of length 1,
1126 * srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + 8
1127 * then duplicate this. Else use talloc_memdup().
1130 if ((srcdyn
== expected_srcdyn
) && (srcdyn_len
== 1)) {
1131 dstdyn
= dsthdr
+ SMB2_HDR_BODY
+ 8;
1132 } else if (srcdyn
== NULL
) {
1135 dstdyn
= talloc_memdup(ctx
, srcdyn
, srcdyn_len
);
1136 if (dstdyn
== NULL
) {
1140 outvec
[SMBD_SMB2_DYN_IOV_OFS
].iov_base
= (void *)dstdyn
;
1141 outvec
[SMBD_SMB2_DYN_IOV_OFS
].iov_len
= srcdyn_len
;
1146 static struct smbd_smb2_request
*dup_smb2_req(const struct smbd_smb2_request
*req
)
1148 struct smbd_smb2_request
*newreq
= NULL
;
1149 struct iovec
*outvec
= NULL
;
1150 int count
= req
->out
.vector_count
;
1153 newreq
= smbd_smb2_request_allocate(req
->sconn
);
1158 newreq
->sconn
= req
->sconn
;
1159 newreq
->session
= req
->session
;
1160 newreq
->do_encryption
= req
->do_encryption
;
1161 newreq
->do_signing
= req
->do_signing
;
1162 newreq
->current_idx
= req
->current_idx
;
1164 outvec
= talloc_zero_array(newreq
, struct iovec
, count
);
1166 TALLOC_FREE(newreq
);
1169 newreq
->out
.vector
= outvec
;
1170 newreq
->out
.vector_count
= count
;
1172 /* Setup the outvec's identically to req. */
1173 outvec
[0].iov_base
= newreq
->out
.nbt_hdr
;
1174 outvec
[0].iov_len
= 4;
1175 memcpy(newreq
->out
.nbt_hdr
, req
->out
.nbt_hdr
, 4);
1177 /* Setup the vectors identically to the ones in req. */
1178 for (i
= 1; i
< count
; i
+= SMBD_SMB2_NUM_IOV_PER_REQ
) {
1179 if (!dup_smb2_vec4(outvec
, &outvec
[i
], &req
->out
.vector
[i
])) {
1186 TALLOC_FREE(newreq
);
1190 smb2_setup_nbt_length(newreq
->out
.vector
,
1191 newreq
->out
.vector_count
);
1196 static NTSTATUS
smb2_send_async_interim_response(const struct smbd_smb2_request
*req
)
1198 struct smbd_server_connection
*sconn
= req
->sconn
;
1199 struct smbXsrv_connection
*conn
= req
->sconn
->conn
;
1201 struct iovec
*firsttf
= NULL
;
1202 struct iovec
*outhdr_v
= NULL
;
1203 uint8_t *outhdr
= NULL
;
1204 struct smbd_smb2_request
*nreq
= NULL
;
1207 /* Create a new smb2 request we'll use
1208 for the interim return. */
1209 nreq
= dup_smb2_req(req
);
1211 return NT_STATUS_NO_MEMORY
;
1214 /* Lose the last X out vectors. They're the
1215 ones we'll be using for the async reply. */
1216 nreq
->out
.vector_count
-= SMBD_SMB2_NUM_IOV_PER_REQ
;
1218 smb2_setup_nbt_length(nreq
->out
.vector
,
1219 nreq
->out
.vector_count
);
1221 /* Step back to the previous reply. */
1222 nreq
->current_idx
-= SMBD_SMB2_NUM_IOV_PER_REQ
;
1223 firsttf
= SMBD_SMB2_IDX_TF_IOV(nreq
,out
,first_idx
);
1224 outhdr_v
= SMBD_SMB2_OUT_HDR_IOV(nreq
);
1225 outhdr
= SMBD_SMB2_OUT_HDR_PTR(nreq
);
1226 /* And end the chain. */
1227 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, 0);
1229 /* Calculate outgoing credits */
1230 smb2_calculate_credits(req
, nreq
);
1232 if (DEBUGLEVEL
>= 10) {
1233 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1234 (unsigned int)nreq
->current_idx
);
1235 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1236 (unsigned int)nreq
->out
.vector_count
);
1237 print_req_vectors(nreq
);
1241 * As we have changed the header (SMB2_HDR_NEXT_COMMAND),
1242 * we need to sign/encrypt here with the last/first key we remembered
1244 if (firsttf
->iov_len
== SMB2_TF_HDR_SIZE
) {
1245 status
= smb2_signing_encrypt_pdu(req
->first_key
,
1248 nreq
->out
.vector_count
- first_idx
);
1249 if (!NT_STATUS_IS_OK(status
)) {
1252 } else if (req
->last_key
.length
> 0) {
1253 status
= smb2_signing_sign_pdu(req
->last_key
,
1256 SMBD_SMB2_NUM_IOV_PER_REQ
- 1);
1257 if (!NT_STATUS_IS_OK(status
)) {
1262 nreq
->queue_entry
.mem_ctx
= nreq
;
1263 nreq
->queue_entry
.vector
= nreq
->out
.vector
;
1264 nreq
->queue_entry
.count
= nreq
->out
.vector_count
;
1265 DLIST_ADD_END(nreq
->sconn
->smb2
.send_queue
, &nreq
->queue_entry
, NULL
);
1266 nreq
->sconn
->smb2
.send_queue_len
++;
1268 status
= smbd_smb2_io_handler(sconn
, TEVENT_FD_WRITE
);
1269 if (!NT_STATUS_IS_OK(status
)) {
1273 return NT_STATUS_OK
;
1276 struct smbd_smb2_request_pending_state
{
1277 struct smbd_server_connection
*sconn
;
1278 struct smbd_smb2_send_queue queue_entry
;
1279 uint8_t buf
[NBT_HDR_SIZE
+ SMB2_TF_HDR_SIZE
+ SMB2_HDR_BODY
+ 0x08 + 1];
1280 struct iovec vector
[1 + SMBD_SMB2_NUM_IOV_PER_REQ
];
1283 static void smbd_smb2_request_pending_timer(struct tevent_context
*ev
,
1284 struct tevent_timer
*te
,
1285 struct timeval current_time
,
1286 void *private_data
);
1288 NTSTATUS
smbd_smb2_request_pending_queue(struct smbd_smb2_request
*req
,
1289 struct tevent_req
*subreq
,
1290 uint32_t defer_time
)
1293 struct timeval defer_endtime
;
1294 uint8_t *outhdr
= NULL
;
1297 if (!tevent_req_is_in_progress(subreq
)) {
1299 * This is a performance optimization,
1300 * it avoids one tevent_loop iteration,
1301 * which means we avoid one
1302 * talloc_stackframe_pool/talloc_free pair.
1304 tevent_req_notify_callback(subreq
);
1305 return NT_STATUS_OK
;
1308 req
->subreq
= subreq
;
1311 if (req
->async_te
) {
1312 /* We're already async. */
1313 return NT_STATUS_OK
;
1316 outhdr
= SMBD_SMB2_OUT_HDR_PTR(req
);
1317 flags
= IVAL(outhdr
, SMB2_HDR_FLAGS
);
1318 if (flags
& SMB2_HDR_FLAG_ASYNC
) {
1319 /* We're already async. */
1320 return NT_STATUS_OK
;
1323 if (req
->in
.vector_count
> req
->current_idx
+ SMBD_SMB2_NUM_IOV_PER_REQ
) {
1325 * We're trying to go async in a compound
1327 * This is only allowed for opens that
1328 * cause an oplock break, otherwise it
1329 * is not allowed. See [MS-SMB2].pdf
1330 * note <194> on Section 3.3.5.2.7.
1332 const uint8_t *inhdr
= SMBD_SMB2_IN_HDR_PTR(req
);
1334 if (SVAL(inhdr
, SMB2_HDR_OPCODE
) != SMB2_OP_CREATE
) {
1336 * Cancel the outstanding request.
1338 bool ok
= tevent_req_cancel(req
->subreq
);
1340 return NT_STATUS_OK
;
1342 TALLOC_FREE(req
->subreq
);
1343 return smbd_smb2_request_error(req
,
1344 NT_STATUS_INTERNAL_ERROR
);
1348 if (DEBUGLEVEL
>= 10) {
1349 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1350 (unsigned int)req
->current_idx
);
1351 print_req_vectors(req
);
1354 if (req
->current_idx
> 1) {
1356 * We're going async in a compound
1357 * chain after the first request has
1358 * already been processed. Send an
1359 * interim response containing the
1360 * set of replies already generated.
1362 int idx
= req
->current_idx
;
1364 status
= smb2_send_async_interim_response(req
);
1365 if (!NT_STATUS_IS_OK(status
)) {
1368 if (req
->first_key
.length
> 0) {
1369 data_blob_clear_free(&req
->first_key
);
1372 req
->current_idx
= 1;
1375 * Re-arrange the in.vectors to remove what
1378 memmove(&req
->in
.vector
[1],
1379 &req
->in
.vector
[idx
],
1380 sizeof(req
->in
.vector
[0])*(req
->in
.vector_count
- idx
));
1381 req
->in
.vector_count
= 1 + (req
->in
.vector_count
- idx
);
1383 /* Re-arrange the out.vectors to match. */
1384 memmove(&req
->out
.vector
[1],
1385 &req
->out
.vector
[idx
],
1386 sizeof(req
->out
.vector
[0])*(req
->out
.vector_count
- idx
));
1387 req
->out
.vector_count
= 1 + (req
->out
.vector_count
- idx
);
1389 if (req
->in
.vector_count
== 1 + SMBD_SMB2_NUM_IOV_PER_REQ
) {
1391 * We only have one remaining request as
1392 * we've processed everything else.
1393 * This is no longer a compound request.
1395 req
->compound_related
= false;
1396 outhdr
= SMBD_SMB2_OUT_HDR_PTR(req
);
1397 flags
= (IVAL(outhdr
, SMB2_HDR_FLAGS
) & ~SMB2_HDR_FLAG_CHAINED
);
1398 SIVAL(outhdr
, SMB2_HDR_FLAGS
, flags
);
1401 if (req
->last_key
.length
> 0) {
1402 data_blob_clear_free(&req
->last_key
);
1405 defer_endtime
= timeval_current_ofs_usec(defer_time
);
1406 req
->async_te
= tevent_add_timer(req
->sconn
->ev_ctx
,
1408 smbd_smb2_request_pending_timer
,
1410 if (req
->async_te
== NULL
) {
1411 return NT_STATUS_NO_MEMORY
;
1414 return NT_STATUS_OK
;
1417 static void smbd_smb2_request_pending_timer(struct tevent_context
*ev
,
1418 struct tevent_timer
*te
,
1419 struct timeval current_time
,
1422 struct smbd_smb2_request
*req
=
1423 talloc_get_type_abort(private_data
,
1424 struct smbd_smb2_request
);
1425 struct smbd_server_connection
*sconn
= req
->sconn
;
1426 struct smbd_smb2_request_pending_state
*state
= NULL
;
1427 uint8_t *outhdr
= NULL
;
1428 const uint8_t *inhdr
= NULL
;
1431 uint8_t *hdr
= NULL
;
1432 uint8_t *body
= NULL
;
1433 uint8_t *dyn
= NULL
;
1435 uint64_t session_id
= 0;
1436 uint64_t message_id
= 0;
1437 uint64_t nonce_high
= 0;
1438 uint64_t nonce_low
= 0;
1439 uint64_t async_id
= 0;
1442 TALLOC_FREE(req
->async_te
);
1444 /* Ensure our final reply matches the interim one. */
1445 inhdr
= SMBD_SMB2_IN_HDR_PTR(req
);
1446 outhdr
= SMBD_SMB2_OUT_HDR_PTR(req
);
1447 flags
= IVAL(outhdr
, SMB2_HDR_FLAGS
);
1448 message_id
= BVAL(outhdr
, SMB2_HDR_MESSAGE_ID
);
1449 session_id
= BVAL(outhdr
, SMB2_HDR_SESSION_ID
);
1451 async_id
= message_id
; /* keep it simple for now... */
1453 SIVAL(outhdr
, SMB2_HDR_FLAGS
, flags
| SMB2_HDR_FLAG_ASYNC
);
1454 SBVAL(outhdr
, SMB2_HDR_ASYNC_ID
, async_id
);
1456 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1458 smb2_opcode_name(SVAL(inhdr
, SMB2_HDR_OPCODE
)),
1459 (unsigned long long)async_id
));
1462 * What we send is identical to a smbd_smb2_request_error
1463 * packet with an error status of STATUS_PENDING. Make use
1464 * of this fact sometime when refactoring. JRA.
1467 state
= talloc_zero(req
->sconn
, struct smbd_smb2_request_pending_state
);
1468 if (state
== NULL
) {
1469 smbd_server_connection_terminate(req
->sconn
,
1470 nt_errstr(NT_STATUS_NO_MEMORY
));
1473 state
->sconn
= req
->sconn
;
1475 tf
= state
->buf
+ NBT_HDR_SIZE
;
1476 tf_len
= SMB2_TF_HDR_SIZE
;
1478 hdr
= tf
+ SMB2_TF_HDR_SIZE
;
1479 body
= hdr
+ SMB2_HDR_BODY
;
1482 if (req
->do_encryption
) {
1483 struct smbXsrv_session
*x
= req
->session
;
1485 nonce_high
= x
->nonce_high
;
1486 nonce_low
= x
->nonce_low
;
1489 if (x
->nonce_low
== 0) {
1495 SIVAL(tf
, SMB2_TF_PROTOCOL_ID
, SMB2_TF_MAGIC
);
1496 SBVAL(tf
, SMB2_TF_NONCE
+0, nonce_low
);
1497 SBVAL(tf
, SMB2_TF_NONCE
+8, nonce_high
);
1498 SBVAL(tf
, SMB2_TF_SESSION_ID
, session_id
);
1500 SIVAL(hdr
, SMB2_HDR_PROTOCOL_ID
, SMB2_MAGIC
);
1501 SSVAL(hdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
1502 SSVAL(hdr
, SMB2_HDR_EPOCH
, 0);
1503 SIVAL(hdr
, SMB2_HDR_STATUS
, NT_STATUS_V(STATUS_PENDING
));
1504 SSVAL(hdr
, SMB2_HDR_OPCODE
, SVAL(outhdr
, SMB2_HDR_OPCODE
));
1506 SIVAL(hdr
, SMB2_HDR_FLAGS
, flags
);
1507 SIVAL(hdr
, SMB2_HDR_NEXT_COMMAND
, 0);
1508 SBVAL(hdr
, SMB2_HDR_MESSAGE_ID
, message_id
);
1509 SBVAL(hdr
, SMB2_HDR_PID
, async_id
);
1510 SBVAL(hdr
, SMB2_HDR_SESSION_ID
,
1511 BVAL(outhdr
, SMB2_HDR_SESSION_ID
));
1512 memcpy(hdr
+SMB2_HDR_SIGNATURE
,
1513 outhdr
+SMB2_HDR_SIGNATURE
, 16);
1515 SSVAL(body
, 0x00, 0x08 + 1);
1517 SCVAL(body
, 0x02, 0);
1518 SCVAL(body
, 0x03, 0);
1519 SIVAL(body
, 0x04, 0);
1520 /* Match W2K8R2... */
1521 SCVAL(dyn
, 0x00, 0x21);
1523 state
->vector
[0].iov_base
= (void *)state
->buf
;
1524 state
->vector
[0].iov_len
= NBT_HDR_SIZE
;
1526 if (req
->do_encryption
) {
1527 state
->vector
[1+SMBD_SMB2_TF_IOV_OFS
].iov_base
= tf
;
1528 state
->vector
[1+SMBD_SMB2_TF_IOV_OFS
].iov_len
= tf_len
;
1530 state
->vector
[1+SMBD_SMB2_TF_IOV_OFS
].iov_base
= NULL
;
1531 state
->vector
[1+SMBD_SMB2_TF_IOV_OFS
].iov_len
= 0;
1534 state
->vector
[1+SMBD_SMB2_HDR_IOV_OFS
].iov_base
= hdr
;
1535 state
->vector
[1+SMBD_SMB2_HDR_IOV_OFS
].iov_len
= SMB2_HDR_BODY
;
1537 state
->vector
[1+SMBD_SMB2_BODY_IOV_OFS
].iov_base
= body
;
1538 state
->vector
[1+SMBD_SMB2_BODY_IOV_OFS
].iov_len
= 8;
1540 state
->vector
[1+SMBD_SMB2_DYN_IOV_OFS
].iov_base
= dyn
;
1541 state
->vector
[1+SMBD_SMB2_DYN_IOV_OFS
].iov_len
= 1;
1543 smb2_setup_nbt_length(state
->vector
, 1 + SMBD_SMB2_NUM_IOV_PER_REQ
);
1545 /* Ensure we correctly go through crediting. Grant
1546 the credits now, and zero credits on the final
1548 smb2_set_operation_credit(req
->sconn
,
1549 SMBD_SMB2_IN_HDR_IOV(req
),
1550 &state
->vector
[1+SMBD_SMB2_HDR_IOV_OFS
]);
1552 SIVAL(hdr
, SMB2_HDR_FLAGS
, flags
| SMB2_HDR_FLAG_ASYNC
);
1557 for (i
= 0; i
< ARRAY_SIZE(state
->vector
); i
++) {
1558 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1560 (unsigned int)ARRAY_SIZE(state
->vector
),
1561 (unsigned int)state
->vector
[i
].iov_len
);
1565 if (req
->do_encryption
) {
1566 struct smbXsrv_session
*x
= req
->session
;
1567 struct smbXsrv_connection
*conn
= x
->connection
;
1568 DATA_BLOB encryption_key
= x
->global
->encryption_key
;
1570 status
= smb2_signing_encrypt_pdu(encryption_key
,
1572 &state
->vector
[1+SMBD_SMB2_TF_IOV_OFS
],
1573 SMBD_SMB2_NUM_IOV_PER_REQ
);
1574 if (!NT_STATUS_IS_OK(status
)) {
1575 smbd_server_connection_terminate(req
->sconn
,
1579 } else if (req
->do_signing
) {
1580 struct smbXsrv_session
*x
= req
->session
;
1581 struct smbXsrv_connection
*conn
= x
->connection
;
1582 DATA_BLOB signing_key
= x
->global
->channels
[0].signing_key
;
1584 status
= smb2_signing_sign_pdu(signing_key
,
1586 &state
->vector
[1+SMBD_SMB2_HDR_IOV_OFS
],
1587 SMBD_SMB2_NUM_IOV_PER_REQ
- 1);
1588 if (!NT_STATUS_IS_OK(status
)) {
1589 smbd_server_connection_terminate(req
->sconn
,
1595 state
->queue_entry
.mem_ctx
= state
;
1596 state
->queue_entry
.vector
= state
->vector
;
1597 state
->queue_entry
.count
= ARRAY_SIZE(state
->vector
);
1598 DLIST_ADD_END(sconn
->smb2
.send_queue
, &state
->queue_entry
, NULL
);
1599 sconn
->smb2
.send_queue_len
++;
1601 status
= smbd_smb2_io_handler(sconn
, TEVENT_FD_WRITE
);
1602 if (!NT_STATUS_IS_OK(status
)) {
1603 smbd_server_connection_terminate(sconn
,
1609 static NTSTATUS
smbd_smb2_request_process_cancel(struct smbd_smb2_request
*req
)
1611 struct smbd_server_connection
*sconn
= req
->sconn
;
1612 struct smbd_smb2_request
*cur
;
1613 const uint8_t *inhdr
;
1615 uint64_t search_message_id
;
1616 uint64_t search_async_id
;
1619 inhdr
= SMBD_SMB2_IN_HDR_PTR(req
);
1621 flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
1622 search_message_id
= BVAL(inhdr
, SMB2_HDR_MESSAGE_ID
);
1623 search_async_id
= BVAL(inhdr
, SMB2_HDR_PID
);
1626 * we don't need the request anymore
1627 * cancel requests never have a response
1629 DLIST_REMOVE(req
->sconn
->smb2
.requests
, req
);
1632 for (cur
= sconn
->smb2
.requests
; cur
; cur
= cur
->next
) {
1633 const uint8_t *outhdr
;
1634 uint64_t message_id
;
1637 if (cur
->compound_related
) {
1639 * Never cancel anything in a compound request.
1640 * Way too hard to deal with the result.
1645 outhdr
= SMBD_SMB2_OUT_HDR_PTR(cur
);
1647 message_id
= BVAL(outhdr
, SMB2_HDR_MESSAGE_ID
);
1648 async_id
= BVAL(outhdr
, SMB2_HDR_PID
);
1650 if (flags
& SMB2_HDR_FLAG_ASYNC
) {
1651 if (search_async_id
== async_id
) {
1652 found_id
= async_id
;
1656 if (search_message_id
== message_id
) {
1657 found_id
= message_id
;
1663 if (cur
&& cur
->subreq
) {
1664 inhdr
= SMBD_SMB2_IN_HDR_PTR(cur
);
1665 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1666 "cancel opcode[%s] mid %llu\n",
1667 smb2_opcode_name(SVAL(inhdr
, SMB2_HDR_OPCODE
)),
1668 (unsigned long long)found_id
));
1669 tevent_req_cancel(cur
->subreq
);
1672 return NT_STATUS_OK
;
1675 /*************************************************************
1676 Ensure an incoming tid is a valid one for us to access.
1677 Change to the associated uid credentials and chdir to the
1678 valid tid directory.
1679 *************************************************************/
1681 static NTSTATUS
smbd_smb2_request_check_tcon(struct smbd_smb2_request
*req
)
1683 const uint8_t *inhdr
;
1686 struct smbXsrv_tcon
*tcon
;
1688 NTTIME now
= timeval_to_nttime(&req
->request_time
);
1692 inhdr
= SMBD_SMB2_IN_HDR_PTR(req
);
1694 in_flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
1695 in_tid
= IVAL(inhdr
, SMB2_HDR_TID
);
1697 if (in_flags
& SMB2_HDR_FLAG_CHAINED
) {
1698 in_tid
= req
->last_tid
;
1703 status
= smb2srv_tcon_lookup(req
->session
,
1704 in_tid
, now
, &tcon
);
1705 if (!NT_STATUS_IS_OK(status
)) {
1709 if (!change_to_user(tcon
->compat
, req
->session
->compat
->vuid
)) {
1710 return NT_STATUS_ACCESS_DENIED
;
1713 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1714 if (!set_current_service(tcon
->compat
, 0, true)) {
1715 return NT_STATUS_ACCESS_DENIED
;
1719 req
->last_tid
= in_tid
;
1721 return NT_STATUS_OK
;
1724 /*************************************************************
1725 Ensure an incoming session_id is a valid one for us to access.
1726 *************************************************************/
1728 static NTSTATUS
smbd_smb2_request_check_session(struct smbd_smb2_request
*req
)
1730 const uint8_t *inhdr
;
1733 uint64_t in_session_id
;
1734 struct smbXsrv_session
*session
= NULL
;
1735 struct auth_session_info
*session_info
;
1737 NTTIME now
= timeval_to_nttime(&req
->request_time
);
1739 req
->session
= NULL
;
1742 inhdr
= SMBD_SMB2_IN_HDR_PTR(req
);
1744 in_flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
1745 in_opcode
= SVAL(inhdr
, SMB2_HDR_OPCODE
);
1746 in_session_id
= BVAL(inhdr
, SMB2_HDR_SESSION_ID
);
1748 if (in_flags
& SMB2_HDR_FLAG_CHAINED
) {
1749 in_session_id
= req
->last_session_id
;
1752 req
->last_session_id
= 0;
1754 /* lookup an existing session */
1755 status
= smb2srv_session_lookup(req
->sconn
->conn
,
1759 req
->session
= session
;
1760 req
->last_session_id
= in_session_id
;
1762 if (NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_SESSION_EXPIRED
)) {
1763 switch (in_opcode
) {
1764 case SMB2_OP_SESSSETUP
:
1765 status
= NT_STATUS_OK
;
1771 if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1772 switch (in_opcode
) {
1774 case SMB2_OP_CREATE
:
1775 case SMB2_OP_GETINFO
:
1776 case SMB2_OP_SETINFO
:
1777 return NT_STATUS_INVALID_HANDLE
;
1780 * Notice the check for
1781 * (session_info == NULL)
1784 status
= NT_STATUS_OK
;
1788 if (!NT_STATUS_IS_OK(status
)) {
1792 session_info
= session
->global
->auth_session_info
;
1793 if (session_info
== NULL
) {
1794 return NT_STATUS_INVALID_HANDLE
;
1797 if (in_session_id
!= req
->sconn
->conn
->last_session_id
) {
1798 req
->sconn
->conn
->last_session_id
= in_session_id
;
1799 set_current_user_info(session_info
->unix_info
->sanitized_username
,
1800 session_info
->unix_info
->unix_name
,
1801 session_info
->info
->domain_name
);
1804 return NT_STATUS_OK
;
1807 NTSTATUS
smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request
*req
,
1808 uint32_t data_length
)
1810 uint16_t needed_charge
;
1811 uint16_t credit_charge
= 1;
1812 const uint8_t *inhdr
;
1814 inhdr
= SMBD_SMB2_IN_HDR_PTR(req
);
1816 if (req
->sconn
->smb2
.supports_multicredit
) {
1817 credit_charge
= SVAL(inhdr
, SMB2_HDR_CREDIT_CHARGE
);
1818 credit_charge
= MAX(credit_charge
, 1);
1821 needed_charge
= (data_length
- 1)/ 65536 + 1;
1823 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1824 (unsigned long long) BVAL(inhdr
, SMB2_HDR_MESSAGE_ID
),
1825 credit_charge
, needed_charge
));
1827 if (needed_charge
> credit_charge
) {
1828 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1829 credit_charge
, needed_charge
));
1830 return NT_STATUS_INVALID_PARAMETER
;
1833 return NT_STATUS_OK
;
1836 NTSTATUS
smbd_smb2_request_verify_sizes(struct smbd_smb2_request
*req
,
1837 size_t expected_body_size
)
1839 struct iovec
*inhdr_v
;
1840 const uint8_t *inhdr
;
1842 const uint8_t *inbody
;
1844 size_t min_dyn_size
= expected_body_size
& 0x00000001;
1845 int max_idx
= req
->in
.vector_count
- SMBD_SMB2_NUM_IOV_PER_REQ
;
1848 * The following should be checked already.
1850 if (req
->in
.vector_count
< SMBD_SMB2_NUM_IOV_PER_REQ
) {
1851 return NT_STATUS_INTERNAL_ERROR
;
1853 if (req
->current_idx
> max_idx
) {
1854 return NT_STATUS_INTERNAL_ERROR
;
1857 inhdr_v
= SMBD_SMB2_IN_HDR_IOV(req
);
1858 if (inhdr_v
->iov_len
!= SMB2_HDR_BODY
) {
1859 return NT_STATUS_INTERNAL_ERROR
;
1861 if (SMBD_SMB2_IN_BODY_LEN(req
) < 2) {
1862 return NT_STATUS_INTERNAL_ERROR
;
1865 inhdr
= SMBD_SMB2_IN_HDR_PTR(req
);
1866 opcode
= SVAL(inhdr
, SMB2_HDR_OPCODE
);
1870 case SMB2_OP_GETINFO
:
1876 * Now check the expected body size,
1877 * where the last byte might be in the
1880 if (SMBD_SMB2_IN_BODY_LEN(req
) != (expected_body_size
& 0xFFFFFFFE)) {
1881 return NT_STATUS_INVALID_PARAMETER
;
1883 if (SMBD_SMB2_IN_DYN_LEN(req
) < min_dyn_size
) {
1884 return NT_STATUS_INVALID_PARAMETER
;
1887 inbody
= SMBD_SMB2_IN_BODY_PTR(req
);
1889 body_size
= SVAL(inbody
, 0x00);
1890 if (body_size
!= expected_body_size
) {
1891 return NT_STATUS_INVALID_PARAMETER
;
1894 return NT_STATUS_OK
;
1897 NTSTATUS
smbd_smb2_request_dispatch(struct smbd_smb2_request
*req
)
1899 struct smbXsrv_connection
*conn
= req
->sconn
->conn
;
1900 const struct smbd_smb2_dispatch_table
*call
= NULL
;
1901 const struct iovec
*intf_v
= SMBD_SMB2_IN_TF_IOV(req
);
1902 const uint8_t *inhdr
;
1907 NTSTATUS session_status
;
1908 uint32_t allowed_flags
;
1909 NTSTATUS return_value
;
1910 struct smbXsrv_session
*x
= NULL
;
1911 bool signing_required
= false;
1912 bool encryption_required
= false;
1914 inhdr
= SMBD_SMB2_IN_HDR_PTR(req
);
1916 /* TODO: verify more things */
1918 flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
1919 opcode
= SVAL(inhdr
, SMB2_HDR_OPCODE
);
1920 mid
= BVAL(inhdr
, SMB2_HDR_MESSAGE_ID
);
1921 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1922 smb2_opcode_name(opcode
),
1923 (unsigned long long)mid
));
1925 if (conn
->protocol
>= PROTOCOL_SMB2_02
) {
1927 * once the protocol is negotiated
1928 * SMB2_OP_NEGPROT is not allowed anymore
1930 if (opcode
== SMB2_OP_NEGPROT
) {
1931 /* drop the connection */
1932 return NT_STATUS_INVALID_PARAMETER
;
1936 * if the protocol is not negotiated yet
1937 * only SMB2_OP_NEGPROT is allowed.
1939 if (opcode
!= SMB2_OP_NEGPROT
) {
1940 /* drop the connection */
1941 return NT_STATUS_INVALID_PARAMETER
;
1946 * Check if the client provided a valid session id,
1947 * if so smbd_smb2_request_check_session() calls
1948 * set_current_user_info().
1950 * As some command don't require a valid session id
1951 * we defer the check of the session_status
1953 session_status
= smbd_smb2_request_check_session(req
);
1956 signing_required
= x
->global
->signing_required
;
1957 encryption_required
= x
->global
->encryption_required
;
1959 if (opcode
== SMB2_OP_SESSSETUP
&&
1960 x
->global
->channels
[0].signing_key
.length
) {
1961 signing_required
= true;
1965 req
->do_signing
= false;
1966 req
->do_encryption
= false;
1967 if (intf_v
->iov_len
== SMB2_TF_HDR_SIZE
) {
1968 const uint8_t *intf
= SMBD_SMB2_IN_TF_PTR(req
);
1969 uint64_t tf_session_id
= BVAL(intf
, SMB2_TF_SESSION_ID
);
1971 if (x
!= NULL
&& x
->global
->session_wire_id
!= tf_session_id
) {
1972 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1973 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
1974 (unsigned long long)x
->global
->session_wire_id
,
1975 (unsigned long long)tf_session_id
));
1977 * TODO: windows allows this...
1978 * should we drop the connection?
1980 * For now we just return ACCESS_DENIED
1981 * (Windows clients never trigger this)
1982 * and wait for an update of [MS-SMB2].
1984 return smbd_smb2_request_error(req
,
1985 NT_STATUS_ACCESS_DENIED
);
1988 req
->do_encryption
= true;
1991 if (encryption_required
&& !req
->do_encryption
) {
1992 return smbd_smb2_request_error(req
,
1993 NT_STATUS_ACCESS_DENIED
);
1996 call
= smbd_smb2_call(opcode
);
1998 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
2001 allowed_flags
= SMB2_HDR_FLAG_CHAINED
|
2002 SMB2_HDR_FLAG_SIGNED
|
2004 if (opcode
== SMB2_OP_CANCEL
) {
2005 allowed_flags
|= SMB2_HDR_FLAG_ASYNC
;
2007 if ((flags
& ~allowed_flags
) != 0) {
2008 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
2011 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
2013 * This check is mostly for giving the correct error code
2014 * for compounded requests.
2016 if (!NT_STATUS_IS_OK(session_status
)) {
2017 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
2020 req
->compat_chain_fsp
= NULL
;
2023 if (req
->do_encryption
) {
2024 signing_required
= false;
2025 } else if (signing_required
|| (flags
& SMB2_HDR_FLAG_SIGNED
)) {
2026 DATA_BLOB signing_key
;
2029 return smbd_smb2_request_error(
2030 req
, NT_STATUS_USER_SESSION_DELETED
);
2033 signing_key
= x
->global
->channels
[0].signing_key
;
2036 * If we have a signing key, we should
2039 if (signing_key
.length
> 0) {
2040 req
->do_signing
= true;
2043 status
= smb2_signing_check_pdu(signing_key
,
2045 SMBD_SMB2_IN_HDR_IOV(req
),
2046 SMBD_SMB2_NUM_IOV_PER_REQ
- 1);
2047 if (!NT_STATUS_IS_OK(status
)) {
2048 return smbd_smb2_request_error(req
, status
);
2052 * Now that we know the request was correctly signed
2053 * we have to sign the response too.
2055 req
->do_signing
= true;
2057 if (!NT_STATUS_IS_OK(session_status
)) {
2058 return smbd_smb2_request_error(req
, session_status
);
2060 } else if (opcode
== SMB2_OP_CANCEL
) {
2061 /* Cancel requests are allowed to skip the signing */
2062 } else if (signing_required
) {
2064 * If signing is required we try to sign
2065 * a possible error response
2067 req
->do_signing
= true;
2068 return smbd_smb2_request_error(req
, NT_STATUS_ACCESS_DENIED
);
2071 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
2072 req
->compound_related
= true;
2075 if (call
->need_session
) {
2076 if (!NT_STATUS_IS_OK(session_status
)) {
2077 return smbd_smb2_request_error(req
, session_status
);
2081 if (call
->need_tcon
) {
2082 SMB_ASSERT(call
->need_session
);
2085 * This call needs to be run as user.
2087 * smbd_smb2_request_check_tcon()
2088 * calls change_to_user() on success.
2090 status
= smbd_smb2_request_check_tcon(req
);
2091 if (!NT_STATUS_IS_OK(status
)) {
2092 return smbd_smb2_request_error(req
, status
);
2094 if (req
->tcon
->global
->encryption_required
) {
2095 encryption_required
= true;
2097 if (encryption_required
&& !req
->do_encryption
) {
2098 return smbd_smb2_request_error(req
,
2099 NT_STATUS_ACCESS_DENIED
);
2103 if (call
->fileid_ofs
!= 0) {
2104 size_t needed
= call
->fileid_ofs
+ 16;
2105 const uint8_t *body
= SMBD_SMB2_IN_BODY_PTR(req
);
2106 size_t body_size
= SMBD_SMB2_IN_BODY_LEN(req
);
2107 uint64_t file_id_persistent
;
2108 uint64_t file_id_volatile
;
2109 struct files_struct
*fsp
;
2111 SMB_ASSERT(call
->need_tcon
);
2113 if (needed
> body_size
) {
2114 return smbd_smb2_request_error(req
,
2115 NT_STATUS_INVALID_PARAMETER
);
2118 file_id_persistent
= BVAL(body
, call
->fileid_ofs
+ 0);
2119 file_id_volatile
= BVAL(body
, call
->fileid_ofs
+ 8);
2121 fsp
= file_fsp_smb2(req
, file_id_persistent
, file_id_volatile
);
2123 if (!call
->allow_invalid_fileid
) {
2124 return smbd_smb2_request_error(req
,
2125 NT_STATUS_FILE_CLOSED
);
2128 if (file_id_persistent
!= UINT64_MAX
) {
2129 return smbd_smb2_request_error(req
,
2130 NT_STATUS_FILE_CLOSED
);
2132 if (file_id_volatile
!= UINT64_MAX
) {
2133 return smbd_smb2_request_error(req
,
2134 NT_STATUS_FILE_CLOSED
);
2139 if (call
->as_root
) {
2140 SMB_ASSERT(call
->fileid_ofs
== 0);
2141 /* This call needs to be run as root */
2142 change_to_root_user();
2144 SMB_ASSERT(call
->need_tcon
);
2148 case SMB2_OP_NEGPROT
:
2150 START_PROFILE(smb2_negprot
);
2151 return_value
= smbd_smb2_request_process_negprot(req
);
2152 END_PROFILE(smb2_negprot
);
2156 case SMB2_OP_SESSSETUP
:
2158 START_PROFILE(smb2_sesssetup
);
2159 return_value
= smbd_smb2_request_process_sesssetup(req
);
2160 END_PROFILE(smb2_sesssetup
);
2164 case SMB2_OP_LOGOFF
:
2166 START_PROFILE(smb2_logoff
);
2167 return_value
= smbd_smb2_request_process_logoff(req
);
2168 END_PROFILE(smb2_logoff
);
2174 START_PROFILE(smb2_tcon
);
2175 return_value
= smbd_smb2_request_process_tcon(req
);
2176 END_PROFILE(smb2_tcon
);
2182 START_PROFILE(smb2_tdis
);
2183 return_value
= smbd_smb2_request_process_tdis(req
);
2184 END_PROFILE(smb2_tdis
);
2188 case SMB2_OP_CREATE
:
2190 START_PROFILE(smb2_create
);
2191 return_value
= smbd_smb2_request_process_create(req
);
2192 END_PROFILE(smb2_create
);
2198 START_PROFILE(smb2_close
);
2199 return_value
= smbd_smb2_request_process_close(req
);
2200 END_PROFILE(smb2_close
);
2206 START_PROFILE(smb2_flush
);
2207 return_value
= smbd_smb2_request_process_flush(req
);
2208 END_PROFILE(smb2_flush
);
2214 START_PROFILE(smb2_read
);
2215 return_value
= smbd_smb2_request_process_read(req
);
2216 END_PROFILE(smb2_read
);
2222 START_PROFILE(smb2_write
);
2223 return_value
= smbd_smb2_request_process_write(req
);
2224 END_PROFILE(smb2_write
);
2230 START_PROFILE(smb2_lock
);
2231 return_value
= smbd_smb2_request_process_lock(req
);
2232 END_PROFILE(smb2_lock
);
2238 START_PROFILE(smb2_ioctl
);
2239 return_value
= smbd_smb2_request_process_ioctl(req
);
2240 END_PROFILE(smb2_ioctl
);
2244 case SMB2_OP_CANCEL
:
2246 START_PROFILE(smb2_cancel
);
2247 return_value
= smbd_smb2_request_process_cancel(req
);
2248 END_PROFILE(smb2_cancel
);
2252 case SMB2_OP_KEEPALIVE
:
2254 START_PROFILE(smb2_keepalive
);
2255 return_value
= smbd_smb2_request_process_keepalive(req
);
2256 END_PROFILE(smb2_keepalive
);
2262 START_PROFILE(smb2_find
);
2263 return_value
= smbd_smb2_request_process_find(req
);
2264 END_PROFILE(smb2_find
);
2268 case SMB2_OP_NOTIFY
:
2270 START_PROFILE(smb2_notify
);
2271 return_value
= smbd_smb2_request_process_notify(req
);
2272 END_PROFILE(smb2_notify
);
2276 case SMB2_OP_GETINFO
:
2278 START_PROFILE(smb2_getinfo
);
2279 return_value
= smbd_smb2_request_process_getinfo(req
);
2280 END_PROFILE(smb2_getinfo
);
2284 case SMB2_OP_SETINFO
:
2286 START_PROFILE(smb2_setinfo
);
2287 return_value
= smbd_smb2_request_process_setinfo(req
);
2288 END_PROFILE(smb2_setinfo
);
2294 START_PROFILE(smb2_break
);
2295 return_value
= smbd_smb2_request_process_break(req
);
2296 END_PROFILE(smb2_break
);
2301 return_value
= smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
2304 return return_value
;
2307 static NTSTATUS
smbd_smb2_request_reply(struct smbd_smb2_request
*req
)
2309 struct smbd_server_connection
*sconn
= req
->sconn
;
2310 struct smbXsrv_connection
*conn
= req
->sconn
->conn
;
2312 struct iovec
*firsttf
= SMBD_SMB2_IDX_TF_IOV(req
,out
,first_idx
);
2313 struct iovec
*outhdr
= SMBD_SMB2_OUT_HDR_IOV(req
);
2314 struct iovec
*outdyn
= SMBD_SMB2_OUT_DYN_IOV(req
);
2318 TALLOC_FREE(req
->async_te
);
2320 if (req
->do_encryption
&&
2321 (firsttf
->iov_len
== 0) &&
2322 (req
->first_key
.length
== 0) &&
2323 (req
->session
!= NULL
) &&
2324 (req
->session
->global
->encryption_key
.length
!= 0))
2326 DATA_BLOB encryption_key
= req
->session
->global
->encryption_key
;
2328 uint64_t session_id
= req
->session
->global
->session_wire_id
;
2329 struct smbXsrv_session
*x
= req
->session
;
2330 uint64_t nonce_high
;
2333 nonce_high
= x
->nonce_high
;
2334 nonce_low
= x
->nonce_low
;
2337 if (x
->nonce_low
== 0) {
2343 * We need to place the SMB2_TRANSFORM header before the
2348 * we need to remember the encryption key
2349 * and defer the signing/encryption until
2350 * we are sure that we do not change
2353 req
->first_key
= data_blob_dup_talloc(req
, encryption_key
);
2354 if (req
->first_key
.data
== NULL
) {
2355 return NT_STATUS_NO_MEMORY
;
2358 tf
= talloc_zero_array(req
, uint8_t,
2361 return NT_STATUS_NO_MEMORY
;
2364 SIVAL(tf
, SMB2_TF_PROTOCOL_ID
, SMB2_TF_MAGIC
);
2365 SBVAL(tf
, SMB2_TF_NONCE
+0, nonce_low
);
2366 SBVAL(tf
, SMB2_TF_NONCE
+8, nonce_high
);
2367 SBVAL(tf
, SMB2_TF_SESSION_ID
, session_id
);
2369 firsttf
->iov_base
= (void *)tf
;
2370 firsttf
->iov_len
= SMB2_TF_HDR_SIZE
;
2373 if ((req
->current_idx
> SMBD_SMB2_NUM_IOV_PER_REQ
) &&
2374 (req
->last_key
.length
> 0) &&
2375 (firsttf
->iov_len
== 0))
2377 int last_idx
= req
->current_idx
- SMBD_SMB2_NUM_IOV_PER_REQ
;
2378 struct iovec
*lasthdr
= SMBD_SMB2_IDX_HDR_IOV(req
,out
,last_idx
);
2381 * As we are sure the header of the last request in the
2382 * compound chain will not change, we can to sign here
2383 * with the last signing key we remembered.
2385 status
= smb2_signing_sign_pdu(req
->last_key
,
2388 SMBD_SMB2_NUM_IOV_PER_REQ
- 1);
2389 if (!NT_STATUS_IS_OK(status
)) {
2393 if (req
->last_key
.length
> 0) {
2394 data_blob_clear_free(&req
->last_key
);
2397 req
->current_idx
+= SMBD_SMB2_NUM_IOV_PER_REQ
;
2399 if (req
->current_idx
< req
->out
.vector_count
) {
2401 * We must process the remaining compound
2402 * SMB2 requests before any new incoming SMB2
2403 * requests. This is because incoming SMB2
2404 * requests may include a cancel for a
2405 * compound request we haven't processed
2408 struct tevent_immediate
*im
= tevent_create_immediate(req
);
2410 return NT_STATUS_NO_MEMORY
;
2413 if (req
->do_signing
&& firsttf
->iov_len
== 0) {
2414 struct smbXsrv_session
*x
= req
->session
;
2415 DATA_BLOB signing_key
= x
->global
->channels
[0].signing_key
;
2418 * we need to remember the signing key
2419 * and defer the signing until
2420 * we are sure that we do not change
2423 req
->last_key
= data_blob_dup_talloc(req
, signing_key
);
2424 if (req
->last_key
.data
== NULL
) {
2425 return NT_STATUS_NO_MEMORY
;
2429 tevent_schedule_immediate(im
,
2431 smbd_smb2_request_dispatch_immediate
,
2433 return NT_STATUS_OK
;
2436 if (req
->compound_related
) {
2437 req
->compound_related
= false;
2440 smb2_setup_nbt_length(req
->out
.vector
, req
->out
.vector_count
);
2442 /* Set credit for these operations (zero credits if this
2443 is a final reply for an async operation). */
2444 smb2_calculate_credits(req
, req
);
2447 * now check if we need to sign the current response
2449 if (firsttf
->iov_len
== SMB2_TF_HDR_SIZE
) {
2450 status
= smb2_signing_encrypt_pdu(req
->first_key
,
2453 req
->out
.vector_count
- first_idx
);
2454 if (!NT_STATUS_IS_OK(status
)) {
2457 } else if (req
->do_signing
) {
2458 struct smbXsrv_session
*x
= req
->session
;
2459 DATA_BLOB signing_key
= x
->global
->channels
[0].signing_key
;
2461 status
= smb2_signing_sign_pdu(signing_key
,
2464 SMBD_SMB2_NUM_IOV_PER_REQ
- 1);
2465 if (!NT_STATUS_IS_OK(status
)) {
2469 if (req
->first_key
.length
> 0) {
2470 data_blob_clear_free(&req
->first_key
);
2473 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2474 if (req
->out
.vector_count
< (2*SMBD_SMB2_NUM_IOV_PER_REQ
) &&
2475 outdyn
->iov_base
== NULL
&& outdyn
->iov_len
!= 0) {
2476 /* Dynamic part is NULL. Chop it off,
2477 We're going to send it via sendfile. */
2478 req
->out
.vector_count
-= 1;
2482 * We're done with this request -
2483 * move it off the "being processed" queue.
2485 DLIST_REMOVE(req
->sconn
->smb2
.requests
, req
);
2487 req
->queue_entry
.mem_ctx
= req
;
2488 req
->queue_entry
.vector
= req
->out
.vector
;
2489 req
->queue_entry
.count
= req
->out
.vector_count
;
2490 DLIST_ADD_END(req
->sconn
->smb2
.send_queue
, &req
->queue_entry
, NULL
);
2491 req
->sconn
->smb2
.send_queue_len
++;
2493 status
= smbd_smb2_io_handler(sconn
, TEVENT_FD_WRITE
);
2494 if (!NT_STATUS_IS_OK(status
)) {
2498 return NT_STATUS_OK
;
2501 static NTSTATUS
smbd_smb2_request_next_incoming(struct smbd_server_connection
*sconn
);
2503 void smbd_smb2_request_dispatch_immediate(struct tevent_context
*ctx
,
2504 struct tevent_immediate
*im
,
2507 struct smbd_smb2_request
*req
= talloc_get_type_abort(private_data
,
2508 struct smbd_smb2_request
);
2509 struct smbd_server_connection
*sconn
= req
->sconn
;
2514 if (DEBUGLEVEL
>= 10) {
2515 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2516 req
->current_idx
, req
->in
.vector_count
));
2517 print_req_vectors(req
);
2520 status
= smbd_smb2_request_dispatch(req
);
2521 if (!NT_STATUS_IS_OK(status
)) {
2522 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
2526 status
= smbd_smb2_request_next_incoming(sconn
);
2527 if (!NT_STATUS_IS_OK(status
)) {
2528 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
2533 NTSTATUS
smbd_smb2_request_done_ex(struct smbd_smb2_request
*req
,
2535 DATA_BLOB body
, DATA_BLOB
*dyn
,
2536 const char *location
)
2539 struct iovec
*outbody_v
;
2540 struct iovec
*outdyn_v
;
2541 uint32_t next_command_ofs
;
2543 DEBUG(10,("smbd_smb2_request_done_ex: "
2544 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2545 req
->current_idx
, nt_errstr(status
), (unsigned int)body
.length
,
2547 (unsigned int)(dyn
? dyn
->length
: 0),
2550 if (body
.length
< 2) {
2551 return smbd_smb2_request_error(req
, NT_STATUS_INTERNAL_ERROR
);
2554 if ((body
.length
% 2) != 0) {
2555 return smbd_smb2_request_error(req
, NT_STATUS_INTERNAL_ERROR
);
2558 outhdr
= SMBD_SMB2_OUT_HDR_PTR(req
);
2559 outbody_v
= SMBD_SMB2_OUT_BODY_IOV(req
);
2560 outdyn_v
= SMBD_SMB2_OUT_DYN_IOV(req
);
2562 next_command_ofs
= IVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
);
2563 SIVAL(outhdr
, SMB2_HDR_STATUS
, NT_STATUS_V(status
));
2565 outbody_v
->iov_base
= (void *)body
.data
;
2566 outbody_v
->iov_len
= body
.length
;
2569 outdyn_v
->iov_base
= (void *)dyn
->data
;
2570 outdyn_v
->iov_len
= dyn
->length
;
2572 outdyn_v
->iov_base
= NULL
;
2573 outdyn_v
->iov_len
= 0;
2576 /* see if we need to recalculate the offset to the next response */
2577 if (next_command_ofs
> 0) {
2578 next_command_ofs
= SMB2_HDR_BODY
;
2579 next_command_ofs
+= SMBD_SMB2_OUT_BODY_LEN(req
);
2580 next_command_ofs
+= SMBD_SMB2_OUT_DYN_LEN(req
);
2583 if ((next_command_ofs
% 8) != 0) {
2584 size_t pad_size
= 8 - (next_command_ofs
% 8);
2585 if (SMBD_SMB2_OUT_DYN_LEN(req
) == 0) {
2587 * if the dyn buffer is empty
2588 * we can use it to add padding
2592 pad
= talloc_zero_array(req
,
2595 return smbd_smb2_request_error(req
,
2596 NT_STATUS_NO_MEMORY
);
2599 outdyn_v
->iov_base
= (void *)pad
;
2600 outdyn_v
->iov_len
= pad_size
;
2603 * For now we copy the dynamic buffer
2604 * and add the padding to the new buffer
2611 old_size
= SMBD_SMB2_OUT_DYN_LEN(req
);
2612 old_dyn
= SMBD_SMB2_OUT_DYN_PTR(req
);
2614 new_size
= old_size
+ pad_size
;
2615 new_dyn
= talloc_zero_array(req
,
2617 if (new_dyn
== NULL
) {
2618 return smbd_smb2_request_error(req
,
2619 NT_STATUS_NO_MEMORY
);
2622 memcpy(new_dyn
, old_dyn
, old_size
);
2623 memset(new_dyn
+ old_size
, 0, pad_size
);
2625 outdyn_v
->iov_base
= (void *)new_dyn
;
2626 outdyn_v
->iov_len
= new_size
;
2628 next_command_ofs
+= pad_size
;
2631 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, next_command_ofs
);
2633 return smbd_smb2_request_reply(req
);
2636 NTSTATUS
smbd_smb2_request_error_ex(struct smbd_smb2_request
*req
,
2639 const char *location
)
2643 uint8_t *outhdr
= SMBD_SMB2_OUT_HDR_PTR(req
);
2644 size_t unread_bytes
= smbd_smb2_unread_bytes(req
);
2646 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2647 req
->current_idx
, nt_errstr(status
), info
? " +info" : "",
2651 /* Recvfile error. Drain incoming socket. */
2655 ret
= drain_socket(req
->sconn
->sock
, unread_bytes
);
2656 if (ret
!= unread_bytes
) {
2660 error
= NT_STATUS_IO_DEVICE_ERROR
;
2662 error
= map_nt_error_from_unix_common(errno
);
2665 DEBUG(2, ("Failed to drain %u bytes from SMB2 socket: "
2666 "ret[%u] errno[%d] => %s\n",
2667 (unsigned)unread_bytes
,
2668 (unsigned)ret
, errno
, nt_errstr(error
)));
2673 body
.data
= outhdr
+ SMB2_HDR_BODY
;
2675 SSVAL(body
.data
, 0, 9);
2678 SIVAL(body
.data
, 0x04, info
->length
);
2680 /* Allocated size of req->out.vector[i].iov_base
2681 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2682 * 1 byte without having to do an alloc.
2685 info
->data
= ((uint8_t *)outhdr
) +
2686 OUTVEC_ALLOC_SIZE
- 1;
2688 SCVAL(info
->data
, 0, 0);
2692 * Note: Even if there is an error, continue to process the request.
2696 return smbd_smb2_request_done_ex(req
, status
, body
, info
, __location__
);
2700 struct smbd_smb2_send_oplock_break_state
{
2701 struct smbd_server_connection
*sconn
;
2702 struct smbd_smb2_send_queue queue_entry
;
2703 uint8_t buf
[NBT_HDR_SIZE
+ SMB2_TF_HDR_SIZE
+ SMB2_HDR_BODY
+ 0x18];
2704 struct iovec vector
[1+SMBD_SMB2_NUM_IOV_PER_REQ
];
2707 NTSTATUS
smbd_smb2_send_oplock_break(struct smbd_server_connection
*sconn
,
2708 struct smbXsrv_session
*session
,
2709 struct smbXsrv_tcon
*tcon
,
2710 struct smbXsrv_open
*op
,
2711 uint8_t oplock_level
)
2713 struct smbd_smb2_send_oplock_break_state
*state
;
2714 struct smbXsrv_connection
*conn
= sconn
->conn
;
2722 bool do_encryption
= session
->global
->encryption_required
;
2723 uint64_t nonce_high
= 0;
2724 uint64_t nonce_low
= 0;
2727 if (tcon
->global
->encryption_required
) {
2728 do_encryption
= true;
2731 state
= talloc_zero(sconn
, struct smbd_smb2_send_oplock_break_state
);
2732 if (state
== NULL
) {
2733 return NT_STATUS_NO_MEMORY
;
2735 state
->sconn
= sconn
;
2737 tf
= state
->buf
+ NBT_HDR_SIZE
;
2738 tf_len
= SMB2_TF_HDR_SIZE
;
2740 body
= hdr
+ SMB2_HDR_BODY
;
2742 dyn
= body
+ body_len
;
2745 if (do_encryption
) {
2746 nonce_high
= session
->nonce_high
;
2747 nonce_low
= session
->nonce_low
;
2749 session
->nonce_low
+= 1;
2750 if (session
->nonce_low
== 0) {
2751 session
->nonce_low
+= 1;
2752 session
->nonce_high
+= 1;
2756 SIVAL(tf
, SMB2_TF_PROTOCOL_ID
, SMB2_TF_MAGIC
);
2757 SBVAL(tf
, SMB2_TF_NONCE
+0, nonce_low
);
2758 SBVAL(tf
, SMB2_TF_NONCE
+8, nonce_high
);
2759 SBVAL(tf
, SMB2_TF_SESSION_ID
, session
->global
->session_wire_id
);
2761 SIVAL(hdr
, 0, SMB2_MAGIC
);
2762 SSVAL(hdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
2763 SSVAL(hdr
, SMB2_HDR_EPOCH
, 0);
2764 SIVAL(hdr
, SMB2_HDR_STATUS
, 0);
2765 SSVAL(hdr
, SMB2_HDR_OPCODE
, SMB2_OP_BREAK
);
2766 SSVAL(hdr
, SMB2_HDR_CREDIT
, 0);
2767 SIVAL(hdr
, SMB2_HDR_FLAGS
, SMB2_HDR_FLAG_REDIRECT
);
2768 SIVAL(hdr
, SMB2_HDR_NEXT_COMMAND
, 0);
2769 SBVAL(hdr
, SMB2_HDR_MESSAGE_ID
, UINT64_MAX
);
2770 SIVAL(hdr
, SMB2_HDR_PID
, 0);
2771 SIVAL(hdr
, SMB2_HDR_TID
, 0);
2772 SBVAL(hdr
, SMB2_HDR_SESSION_ID
, 0);
2773 memset(hdr
+SMB2_HDR_SIGNATURE
, 0, 16);
2775 SSVAL(body
, 0x00, body_len
);
2777 SCVAL(body
, 0x02, oplock_level
);
2778 SCVAL(body
, 0x03, 0); /* reserved */
2779 SIVAL(body
, 0x04, 0); /* reserved */
2780 SBVAL(body
, 0x08, op
->global
->open_persistent_id
);
2781 SBVAL(body
, 0x10, op
->global
->open_volatile_id
);
2783 state
->vector
[0].iov_base
= (void *)state
->buf
;
2784 state
->vector
[0].iov_len
= NBT_HDR_SIZE
;
2786 if (do_encryption
) {
2787 state
->vector
[1+SMBD_SMB2_TF_IOV_OFS
].iov_base
= tf
;
2788 state
->vector
[1+SMBD_SMB2_TF_IOV_OFS
].iov_len
= tf_len
;
2790 state
->vector
[1+SMBD_SMB2_TF_IOV_OFS
].iov_base
= NULL
;
2791 state
->vector
[1+SMBD_SMB2_TF_IOV_OFS
].iov_len
= 0;
2794 state
->vector
[1+SMBD_SMB2_HDR_IOV_OFS
].iov_base
= hdr
;
2795 state
->vector
[1+SMBD_SMB2_HDR_IOV_OFS
].iov_len
= SMB2_HDR_BODY
;
2797 state
->vector
[1+SMBD_SMB2_BODY_IOV_OFS
].iov_base
= body
;
2798 state
->vector
[1+SMBD_SMB2_BODY_IOV_OFS
].iov_len
= body_len
;
2800 state
->vector
[1+SMBD_SMB2_DYN_IOV_OFS
].iov_base
= dyn
;
2801 state
->vector
[1+SMBD_SMB2_DYN_IOV_OFS
].iov_len
= dyn_len
;
2803 smb2_setup_nbt_length(state
->vector
, 1 + SMBD_SMB2_NUM_IOV_PER_REQ
);
2805 if (do_encryption
) {
2806 DATA_BLOB encryption_key
= session
->global
->encryption_key
;
2808 status
= smb2_signing_encrypt_pdu(encryption_key
,
2810 &state
->vector
[1+SMBD_SMB2_TF_IOV_OFS
],
2811 SMBD_SMB2_NUM_IOV_PER_REQ
);
2812 if (!NT_STATUS_IS_OK(status
)) {
2817 state
->queue_entry
.mem_ctx
= state
;
2818 state
->queue_entry
.vector
= state
->vector
;
2819 state
->queue_entry
.count
= ARRAY_SIZE(state
->vector
);
2820 DLIST_ADD_END(state
->sconn
->smb2
.send_queue
, &state
->queue_entry
, NULL
);
2821 state
->sconn
->smb2
.send_queue_len
++;
2823 status
= smbd_smb2_io_handler(sconn
, TEVENT_FD_WRITE
);
2824 if (!NT_STATUS_IS_OK(status
)) {
2828 return NT_STATUS_OK
;
2831 static size_t get_min_receive_file_size(struct smbd_smb2_request
*smb2_req
)
2833 if (smb2_req
->do_signing
) {
2836 if (smb2_req
->do_encryption
) {
2839 return (size_t)lp_min_receive_file_size();
2842 static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state
*state
)
2846 if (IVAL(state
->pktbuf
, 0) == SMB2_TF_MAGIC
) {
2847 /* Transform header. Cannot recvfile. */
2850 if (IVAL(state
->pktbuf
, 0) != SMB2_MAGIC
) {
2851 /* Not SMB2. Normal error path will cope. */
2854 if (SVAL(state
->pktbuf
, 4) != SMB2_HDR_BODY
) {
2855 /* Not SMB2. Normal error path will cope. */
2858 if (SVAL(state
->pktbuf
, SMB2_HDR_OPCODE
) != SMB2_OP_WRITE
) {
2859 /* Needs to be a WRITE. */
2862 if (IVAL(state
->pktbuf
, SMB2_HDR_NEXT_COMMAND
) != 0) {
2863 /* Chained. Cannot recvfile. */
2866 flags
= IVAL(state
->pktbuf
, SMB2_HDR_FLAGS
);
2867 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
2868 /* Chained. Cannot recvfile. */
2871 if (flags
& SMB2_HDR_FLAG_SIGNED
) {
2872 /* Signed. Cannot recvfile. */
2876 DEBUG(10,("Doing recvfile write len = %u\n",
2877 (unsigned int)(state
->pktlen
-
2878 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN
)));
2883 static NTSTATUS
smbd_smb2_request_next_incoming(struct smbd_server_connection
*sconn
)
2885 struct smbd_smb2_request_read_state
*state
= &sconn
->smb2
.request_read_state
;
2886 size_t max_send_queue_len
;
2887 size_t cur_send_queue_len
;
2889 if (!NT_STATUS_IS_OK(sconn
->status
)) {
2891 * we're not supposed to do any io
2893 return NT_STATUS_OK
;
2896 if (state
->req
!= NULL
) {
2898 * if there is already a tstream_readv_pdu
2899 * pending, we are done.
2901 return NT_STATUS_OK
;
2904 max_send_queue_len
= MAX(1, sconn
->smb2
.max_credits
/16);
2905 cur_send_queue_len
= sconn
->smb2
.send_queue_len
;
2907 if (cur_send_queue_len
> max_send_queue_len
) {
2909 * if we have a lot of requests to send,
2910 * we wait until they are on the wire until we
2911 * ask for the next request.
2913 return NT_STATUS_OK
;
2916 /* ask for the next request */
2917 ZERO_STRUCTP(state
);
2918 state
->req
= smbd_smb2_request_allocate(sconn
);
2919 if (state
->req
== NULL
) {
2920 return NT_STATUS_NO_MEMORY
;
2922 state
->req
->sconn
= sconn
;
2923 state
->min_recv_size
= get_min_receive_file_size(state
->req
);
2925 TEVENT_FD_READABLE(sconn
->smb2
.fde
);
2927 return NT_STATUS_OK
;
2930 void smbd_smb2_first_negprot(struct smbd_server_connection
*sconn
,
2931 uint8_t *inbuf
, size_t size
)
2934 struct smbd_smb2_request
*req
= NULL
;
2936 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2937 (unsigned int)size
));
2939 status
= smbd_initialize_smb2(sconn
);
2940 if (!NT_STATUS_IS_OK(status
)) {
2941 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
2945 status
= smbd_smb2_request_create(sconn
, inbuf
, size
, &req
);
2946 if (!NT_STATUS_IS_OK(status
)) {
2947 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
2951 status
= smbd_smb2_request_validate(req
);
2952 if (!NT_STATUS_IS_OK(status
)) {
2953 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
2957 status
= smbd_smb2_request_setup_out(req
);
2958 if (!NT_STATUS_IS_OK(status
)) {
2959 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
2963 status
= smbd_smb2_request_dispatch(req
);
2964 if (!NT_STATUS_IS_OK(status
)) {
2965 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
2969 status
= smbd_smb2_request_next_incoming(sconn
);
2970 if (!NT_STATUS_IS_OK(status
)) {
2971 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
2975 sconn
->num_requests
++;
2978 static int socket_error_from_errno(int ret
,
2992 if (sys_errno
== 0) {
2996 if (sys_errno
== EINTR
) {
3001 if (sys_errno
== EINPROGRESS
) {
3006 if (sys_errno
== EAGAIN
) {
3011 /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
3012 if (sys_errno
== ENOMEM
) {
3018 #if EWOULDBLOCK != EAGAIN
3019 if (sys_errno
== EWOULDBLOCK
) {
3029 static NTSTATUS
smbd_smb2_flush_send_queue(struct smbd_server_connection
*sconn
)
3035 if (sconn
->smb2
.send_queue
== NULL
) {
3036 TEVENT_FD_NOT_WRITEABLE(sconn
->smb2
.fde
);
3037 return NT_STATUS_OK
;
3040 while (sconn
->smb2
.send_queue
!= NULL
) {
3041 struct smbd_smb2_send_queue
*e
= sconn
->smb2
.send_queue
;
3043 if (e
->sendfile_header
!= NULL
) {
3048 for (i
=0; i
< e
->count
; i
++) {
3049 size
+= e
->vector
[i
].iov_len
;
3052 if (size
<= e
->sendfile_header
->length
) {
3053 buf
= e
->sendfile_header
->data
;
3055 buf
= talloc_array(e
->mem_ctx
, uint8_t, size
);
3057 return NT_STATUS_NO_MEMORY
;
3062 for (i
=0; i
< e
->count
; i
++) {
3064 e
->vector
[i
].iov_base
,
3065 e
->vector
[i
].iov_len
);
3066 size
+= e
->vector
[i
].iov_len
;
3069 e
->sendfile_header
->data
= buf
;
3070 e
->sendfile_header
->length
= size
;
3073 sconn
->smb2
.send_queue_len
--;
3074 DLIST_REMOVE(sconn
->smb2
.send_queue
, e
);
3076 * This triggers the sendfile path via
3079 talloc_free(e
->mem_ctx
);
3083 ret
= writev(sconn
->sock
, e
->vector
, e
->count
);
3085 /* propagate end of file */
3086 return NT_STATUS_INTERNAL_ERROR
;
3088 err
= socket_error_from_errno(ret
, errno
, &retry
);
3091 TEVENT_FD_WRITEABLE(sconn
->smb2
.fde
);
3092 return NT_STATUS_OK
;
3095 return map_nt_error_from_unix_common(err
);
3098 if (ret
< e
->vector
[0].iov_len
) {
3100 base
= (uint8_t *)e
->vector
[0].iov_base
;
3102 e
->vector
[0].iov_base
= (void *)base
;
3103 e
->vector
[0].iov_len
-= ret
;
3106 ret
-= e
->vector
[0].iov_len
;
3112 * there're maybe some empty vectors at the end
3113 * which we need to skip, otherwise we would get
3114 * ret == 0 from the readv() call and return EPIPE
3116 while (e
->count
> 0) {
3117 if (e
->vector
[0].iov_len
> 0) {
3125 /* we have more to write */
3126 TEVENT_FD_WRITEABLE(sconn
->smb2
.fde
);
3127 return NT_STATUS_OK
;
3130 sconn
->smb2
.send_queue_len
--;
3131 DLIST_REMOVE(sconn
->smb2
.send_queue
, e
);
3132 talloc_free(e
->mem_ctx
);
3135 return NT_STATUS_OK
;
3138 static NTSTATUS
smbd_smb2_io_handler(struct smbd_server_connection
*sconn
,
3141 struct smbd_smb2_request_read_state
*state
= &sconn
->smb2
.request_read_state
;
3142 struct smbd_smb2_request
*req
= NULL
;
3143 size_t min_recvfile_size
= UINT32_MAX
;
3150 if (!NT_STATUS_IS_OK(sconn
->status
)) {
3152 * we're not supposed to do any io
3154 TEVENT_FD_NOT_READABLE(sconn
->smb2
.fde
);
3155 TEVENT_FD_NOT_WRITEABLE(sconn
->smb2
.fde
);
3156 return NT_STATUS_OK
;
3159 if (fde_flags
& TEVENT_FD_WRITE
) {
3160 status
= smbd_smb2_flush_send_queue(sconn
);
3161 if (!NT_STATUS_IS_OK(status
)) {
3166 if (!(fde_flags
& TEVENT_FD_READ
)) {
3167 return NT_STATUS_OK
;
3170 if (state
->req
== NULL
) {
3171 TEVENT_FD_NOT_READABLE(sconn
->smb2
.fde
);
3172 return NT_STATUS_OK
;
3176 if (!state
->hdr
.done
) {
3177 state
->hdr
.done
= true;
3179 state
->vector
.iov_base
= (void *)state
->hdr
.nbt
;
3180 state
->vector
.iov_len
= NBT_HDR_SIZE
;
3183 ret
= readv(sconn
->sock
, &state
->vector
, 1);
3185 /* propagate end of file */
3186 return NT_STATUS_END_OF_FILE
;
3188 err
= socket_error_from_errno(ret
, errno
, &retry
);
3191 TEVENT_FD_READABLE(sconn
->smb2
.fde
);
3192 return NT_STATUS_OK
;
3195 return map_nt_error_from_unix_common(err
);
3198 if (ret
< state
->vector
.iov_len
) {
3200 base
= (uint8_t *)state
->vector
.iov_base
;
3202 state
->vector
.iov_base
= (void *)base
;
3203 state
->vector
.iov_len
-= ret
;
3204 /* we have more to read */
3205 TEVENT_FD_READABLE(sconn
->smb2
.fde
);
3206 return NT_STATUS_OK
;
3209 if (state
->pktlen
> 0) {
3210 if (state
->doing_receivefile
&& !is_smb2_recvfile_write(state
)) {
3212 * Not a possible receivefile write.
3213 * Read the rest of the data.
3215 state
->doing_receivefile
= false;
3216 state
->vector
.iov_base
= (void *)(state
->pktbuf
+
3217 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN
);
3218 state
->vector
.iov_len
= (state
->pktlen
-
3219 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN
);
3224 * Either this is a receivefile write so we've
3225 * done a short read, or if not we have all the data.
3231 * Now we analyze the NBT header
3233 state
->pktlen
= smb2_len(state
->hdr
.nbt
);
3234 if (state
->pktlen
== 0) {
3238 state
->pktbuf
= talloc_array(state
->req
, uint8_t, state
->pktlen
);
3239 if (state
->pktbuf
== NULL
) {
3240 return NT_STATUS_NO_MEMORY
;
3243 state
->vector
.iov_base
= (void *)state
->pktbuf
;
3245 if (state
->min_recv_size
!= 0) {
3246 min_recvfile_size
= SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN
;
3247 min_recvfile_size
+= state
->min_recv_size
;
3250 if (state
->pktlen
> min_recvfile_size
) {
3252 * Might be a receivefile write. Read the SMB2 HEADER +
3253 * SMB2_WRITE header first. Set 'doing_receivefile'
3254 * as we're *attempting* receivefile write. If this
3255 * turns out not to be a SMB2_WRITE request or otherwise
3256 * not suitable then we'll just read the rest of the data
3257 * the next time this function is called.
3259 state
->vector
.iov_len
= SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN
;
3260 state
->doing_receivefile
= true;
3262 state
->vector
.iov_len
= state
->pktlen
;
3269 if (state
->hdr
.nbt
[0] != 0x00) {
3270 DEBUG(1,("ignore NBT[0x%02X] msg\n",
3271 state
->hdr
.nbt
[0]));
3274 ZERO_STRUCTP(state
);
3276 state
->min_recv_size
= get_min_receive_file_size(state
->req
);
3284 req
->request_time
= timeval_current();
3285 now
= timeval_to_nttime(&req
->request_time
);
3287 status
= smbd_smb2_inbuf_parse_compound(req
->sconn
->conn
,
3293 &req
->in
.vector_count
);
3294 if (!NT_STATUS_IS_OK(status
)) {
3298 if (state
->doing_receivefile
) {
3299 req
->smb1req
= talloc_zero(req
, struct smb_request
);
3300 if (req
->smb1req
== NULL
) {
3301 return NT_STATUS_NO_MEMORY
;
3303 req
->smb1req
->unread_bytes
=
3304 state
->pktlen
- SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN
;
3307 ZERO_STRUCTP(state
);
3309 req
->current_idx
= 1;
3311 DEBUG(10,("smbd_smb2_request idx[%d] of %d vectors\n",
3312 req
->current_idx
, req
->in
.vector_count
));
3314 status
= smbd_smb2_request_validate(req
);
3315 if (!NT_STATUS_IS_OK(status
)) {
3319 status
= smbd_smb2_request_setup_out(req
);
3320 if (!NT_STATUS_IS_OK(status
)) {
3324 status
= smbd_smb2_request_dispatch(req
);
3325 if (!NT_STATUS_IS_OK(status
)) {
3329 sconn
->num_requests
++;
3331 /* The timeout_processing function isn't run nearly
3332 often enough to implement 'max log size' without
3333 overrunning the size of the file by many megabytes.
3334 This is especially true if we are running at debug
3335 level 10. Checking every 50 SMB2s is a nice
3336 tradeoff of performance vs log file size overrun. */
3338 if ((sconn
->num_requests
% 50) == 0 &&
3339 need_to_check_log_size()) {
3340 change_to_root_user();
3344 status
= smbd_smb2_request_next_incoming(sconn
);
3345 if (!NT_STATUS_IS_OK(status
)) {
3349 return NT_STATUS_OK
;
3352 static void smbd_smb2_connection_handler(struct tevent_context
*ev
,
3353 struct tevent_fd
*fde
,
3357 struct smbd_server_connection
*sconn
=
3358 talloc_get_type_abort(private_data
,
3359 struct smbd_server_connection
);
3362 status
= smbd_smb2_io_handler(sconn
, flags
);
3363 if (!NT_STATUS_IS_OK(status
)) {
3364 smbd_server_connection_terminate(sconn
, nt_errstr(status
));