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/util/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 bool smb2_setup_nbt_length(struct iovec *vector, int count)
248 len = iov_buflen(vector+1, count-1);
250 if ((len == -1) || (len > 0xFFFFFF)) {
254 _smb2_setlen(vector[0].iov_base, len);
258 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
260 if (req->first_key.length > 0) {
261 data_blob_clear_free(&req->first_key);
263 if (req->last_key.length > 0) {
264 data_blob_clear_free(&req->last_key);
269 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
271 TALLOC_CTX *mem_pool;
272 struct smbd_smb2_request *req;
275 /* Enable this to find subtle valgrind errors. */
276 mem_pool = talloc_init("smbd_smb2_request_allocate");
278 mem_pool = talloc_tos();
280 if (mem_pool == NULL) {
284 req = talloc_zero(mem_pool, struct smbd_smb2_request);
286 talloc_free(mem_pool);
289 talloc_reparent(mem_pool, mem_ctx, req);
291 TALLOC_FREE(mem_pool);
294 req->last_session_id = UINT64_MAX;
295 req->last_tid = UINT32_MAX;
297 talloc_set_destructor(req, smbd_smb2_request_destructor);
302 static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *xconn,
306 struct smbd_smb2_request *req,
310 TALLOC_CTX *mem_ctx = req;
314 uint8_t *first_hdr = buf;
315 size_t verified_buflen = 0;
320 * Note: index '0' is reserved for the transport protocol
322 iov = req->in._vector;
324 while (taken < buflen) {
325 size_t len = buflen - taken;
326 uint8_t *hdr = first_hdr + taken;
329 size_t next_command_ofs;
331 uint8_t *body = NULL;
334 struct iovec *iov_alloc = NULL;
336 if (iov != req->in._vector) {
340 if (verified_buflen > taken) {
341 len = verified_buflen - taken;
348 DEBUG(10, ("%d bytes left, expected at least %d\n",
352 if (IVAL(hdr, 0) == SMB2_TF_MAGIC) {
353 struct smbXsrv_session *s = NULL;
355 struct iovec tf_iov[2];
359 if (xconn->protocol < PROTOCOL_SMB2_24) {
360 DEBUG(10, ("Got SMB2_TRANSFORM header, "
361 "but dialect[0x%04X] is used\n",
362 xconn->smb2.server.dialect));
366 if (xconn->smb2.server.cipher == 0) {
367 DEBUG(10, ("Got SMB2_TRANSFORM header, "
368 "but not negotiated "
369 "client[0x%08X] server[0x%08X]\n",
370 xconn->smb2.client.capabilities,
371 xconn->smb2.server.capabilities));
375 if (len < SMB2_TF_HDR_SIZE) {
376 DEBUG(1, ("%d bytes left, expected at least %d\n",
377 (int)len, SMB2_TF_HDR_SIZE));
381 tf_len = SMB2_TF_HDR_SIZE;
384 hdr = first_hdr + taken;
385 enc_len = IVAL(tf, SMB2_TF_MSG_SIZE);
386 uid = BVAL(tf, SMB2_TF_SESSION_ID);
388 if (len < SMB2_TF_HDR_SIZE + enc_len) {
389 DEBUG(1, ("%d bytes left, expected at least %d\n",
391 (int)(SMB2_TF_HDR_SIZE + enc_len)));
395 status = smb2srv_session_lookup(xconn, uid, now, &s);
397 DEBUG(1, ("invalid session[%llu] in "
398 "SMB2_TRANSFORM header\n",
399 (unsigned long long)uid));
400 TALLOC_FREE(iov_alloc);
401 return NT_STATUS_USER_SESSION_DELETED;
404 tf_iov[0].iov_base = (void *)tf;
405 tf_iov[0].iov_len = tf_len;
406 tf_iov[1].iov_base = (void *)hdr;
407 tf_iov[1].iov_len = enc_len;
409 status = smb2_signing_decrypt_pdu(s->global->decryption_key,
410 xconn->smb2.server.cipher,
412 if (!NT_STATUS_IS_OK(status)) {
413 TALLOC_FREE(iov_alloc);
417 verified_buflen = taken + enc_len;
422 * We need the header plus the body length field
425 if (len < SMB2_HDR_BODY + 2) {
426 DEBUG(10, ("%d bytes left, expected at least %d\n",
427 (int)len, SMB2_HDR_BODY));
430 if (IVAL(hdr, 0) != SMB2_MAGIC) {
431 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
435 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
436 DEBUG(10, ("Got HDR len %d, expected %d\n",
437 SVAL(hdr, 4), SMB2_HDR_BODY));
442 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
443 body_size = SVAL(hdr, SMB2_HDR_BODY);
445 if (next_command_ofs != 0) {
446 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
449 if (next_command_ofs > full_size) {
452 full_size = next_command_ofs;
459 if (body_size > (full_size - SMB2_HDR_BODY)) {
461 * let the caller handle the error
463 body_size = full_size - SMB2_HDR_BODY;
465 body = hdr + SMB2_HDR_BODY;
466 dyn = body + body_size;
467 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
469 if (num_iov >= ARRAY_SIZE(req->in._vector)) {
470 struct iovec *iov_tmp = NULL;
472 iov_tmp = talloc_realloc(mem_ctx, iov_alloc,
475 SMBD_SMB2_NUM_IOV_PER_REQ);
476 if (iov_tmp == NULL) {
477 TALLOC_FREE(iov_alloc);
478 return NT_STATUS_NO_MEMORY;
481 if (iov_alloc == NULL) {
484 sizeof(req->in._vector));
490 num_iov += SMBD_SMB2_NUM_IOV_PER_REQ;
492 cur[SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
493 cur[SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
494 cur[SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
495 cur[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
496 cur[SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
497 cur[SMBD_SMB2_BODY_IOV_OFS].iov_len = body_size;
498 cur[SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
499 cur[SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_size;
509 if (iov != req->in._vector) {
512 return NT_STATUS_INVALID_PARAMETER;
515 static NTSTATUS smbd_smb2_request_create(struct smbXsrv_connection *xconn,
516 const uint8_t *_inpdu, size_t size,
517 struct smbd_smb2_request **_req)
519 struct smbd_server_connection *sconn = xconn->client->sconn;
520 struct smbd_smb2_request *req;
521 uint32_t protocol_version;
522 uint8_t *inpdu = NULL;
523 const uint8_t *inhdr = NULL;
525 uint32_t next_command_ofs;
529 if (size < (SMB2_HDR_BODY + 2)) {
530 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
531 return NT_STATUS_INVALID_PARAMETER;
536 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
537 if (protocol_version != SMB2_MAGIC) {
538 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
540 return NT_STATUS_INVALID_PARAMETER;
543 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
544 if (cmd != SMB2_OP_NEGPROT) {
545 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
547 return NT_STATUS_INVALID_PARAMETER;
550 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
551 if (next_command_ofs != 0) {
552 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
554 return NT_STATUS_INVALID_PARAMETER;
557 req = smbd_smb2_request_allocate(xconn);
559 return NT_STATUS_NO_MEMORY;
564 inpdu = talloc_memdup(req, _inpdu, size);
566 return NT_STATUS_NO_MEMORY;
569 req->request_time = timeval_current();
570 now = timeval_to_nttime(&req->request_time);
572 status = smbd_smb2_inbuf_parse_compound(xconn,
576 req, &req->in.vector,
577 &req->in.vector_count);
578 if (!NT_STATUS_IS_OK(status)) {
583 req->current_idx = 1;
589 static bool smb2_validate_sequence_number(struct smbXsrv_connection *xconn,
590 uint64_t message_id, uint64_t seq_id)
592 struct bitmap *credits_bm = xconn->smb2.credits.bitmap;
596 seq_tmp = xconn->smb2.credits.seq_low;
597 if (seq_id < seq_tmp) {
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)xconn->smb2.credits.granted,
604 (unsigned long long)xconn->smb2.credits.seq_low,
605 (unsigned int)xconn->smb2.credits.seq_range));
609 seq_tmp += xconn->smb2.credits.seq_range;
610 if (seq_id >= seq_tmp) {
611 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
612 "%llu (sequence id %llu) "
613 "(granted = %u, low = %llu, range = %u)\n",
614 (unsigned long long)message_id,
615 (unsigned long long)seq_id,
616 (unsigned int)xconn->smb2.credits.granted,
617 (unsigned long long)xconn->smb2.credits.seq_low,
618 (unsigned int)xconn->smb2.credits.seq_range));
622 offset = seq_id % xconn->smb2.credits.max;
624 if (bitmap_query(credits_bm, offset)) {
625 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
626 "%llu (sequence id %llu) "
627 "(granted = %u, low = %llu, range = %u) "
629 (unsigned long long)message_id,
630 (unsigned long long)seq_id,
631 (unsigned int)xconn->smb2.credits.granted,
632 (unsigned long long)xconn->smb2.credits.seq_low,
633 (unsigned int)xconn->smb2.credits.seq_range,
638 /* Mark the message_ids as seen in the bitmap. */
639 bitmap_set(credits_bm, offset);
641 if (seq_id != xconn->smb2.credits.seq_low) {
646 * Move the window forward by all the message_id's
649 while (bitmap_query(credits_bm, offset)) {
650 DEBUG(10,("smb2_validate_sequence_number: clearing "
651 "id %llu (position %u) from bitmap\n",
652 (unsigned long long)(xconn->smb2.credits.seq_low),
654 bitmap_clear(credits_bm, offset);
656 xconn->smb2.credits.seq_low += 1;
657 xconn->smb2.credits.seq_range -= 1;
658 offset = xconn->smb2.credits.seq_low % xconn->smb2.credits.max;
664 static bool smb2_validate_message_id(struct smbXsrv_connection *xconn,
665 const uint8_t *inhdr)
667 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
668 uint16_t opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
669 uint16_t credit_charge = 1;
672 if (opcode == SMB2_OP_CANCEL) {
673 /* SMB2_CANCEL requests by definition resend messageids. */
677 if (xconn->smb2.credits.multicredit) {
678 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
679 credit_charge = MAX(credit_charge, 1);
682 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
683 "credits_granted %llu, "
684 "seqnum low/range: %llu/%llu\n",
685 (unsigned long long) message_id,
686 (unsigned long long) credit_charge,
687 (unsigned long long) xconn->smb2.credits.granted,
688 (unsigned long long) xconn->smb2.credits.seq_low,
689 (unsigned long long) xconn->smb2.credits.seq_range));
691 if (xconn->smb2.credits.granted < credit_charge) {
692 DEBUG(0, ("smb2_validate_message_id: client used more "
693 "credits than granted, mid %llu, charge %llu, "
694 "credits_granted %llu, "
695 "seqnum low/range: %llu/%llu\n",
696 (unsigned long long) message_id,
697 (unsigned long long) credit_charge,
698 (unsigned long long) xconn->smb2.credits.granted,
699 (unsigned long long) xconn->smb2.credits.seq_low,
700 (unsigned long long) xconn->smb2.credits.seq_range));
705 * now check the message ids
707 * for multi-credit requests we need to check all current mid plus
708 * the implicit mids caused by the credit charge
709 * e.g. current mid = 15, charge 5 => mark 15-19 as used
712 for (i = 0; i <= (credit_charge-1); i++) {
713 uint64_t id = message_id + i;
716 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
717 (unsigned long long)message_id,
719 (unsigned long long)id));
721 ok = smb2_validate_sequence_number(xconn, message_id, id);
727 /* substract used credits */
728 xconn->smb2.credits.granted -= credit_charge;
733 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
738 count = req->in.vector_count;
740 if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
741 /* It's not a SMB2 request */
742 return NT_STATUS_INVALID_PARAMETER;
745 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
746 struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
747 struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx);
748 const uint8_t *inhdr = NULL;
750 if (hdr->iov_len != SMB2_HDR_BODY) {
751 return NT_STATUS_INVALID_PARAMETER;
754 if (body->iov_len < 2) {
755 return NT_STATUS_INVALID_PARAMETER;
758 inhdr = (const uint8_t *)hdr->iov_base;
760 /* Check the SMB2 header */
761 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
762 return NT_STATUS_INVALID_PARAMETER;
765 if (!smb2_validate_message_id(req->xconn, inhdr)) {
766 return NT_STATUS_INVALID_PARAMETER;
773 static void smb2_set_operation_credit(struct smbXsrv_connection *xconn,
774 const struct iovec *in_vector,
775 struct iovec *out_vector)
777 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
778 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
779 uint16_t credit_charge = 1;
780 uint16_t credits_requested;
784 uint16_t credits_granted = 0;
785 uint64_t credits_possible;
786 uint16_t current_max_credits;
789 * first we grant only 1/16th of the max range.
791 * Windows also starts with the 1/16th and then grants
792 * more later. I was only able to trigger higher
793 * values, when using a very high credit charge.
795 * TODO: scale up depending on load, free memory
797 * Maybe also on the relationship between number
798 * of requests and the used sequence number.
799 * Which means we would grant more credits
800 * for client which use multi credit requests.
802 current_max_credits = xconn->smb2.credits.max / 16;
803 current_max_credits = MAX(current_max_credits, 1);
805 if (xconn->smb2.credits.multicredit) {
806 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
807 credit_charge = MAX(credit_charge, 1);
810 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
811 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
812 credits_requested = MAX(credits_requested, 1);
813 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
814 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
816 SMB_ASSERT(xconn->smb2.credits.max >= xconn->smb2.credits.granted);
818 if (xconn->smb2.credits.max < credit_charge) {
819 smbd_server_connection_terminate(xconn,
820 "client error: credit charge > max credits\n");
824 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
826 * In case we already send an async interim
827 * response, we should not grant
828 * credits on the final response.
832 uint16_t additional_possible =
833 xconn->smb2.credits.max - credit_charge;
834 uint16_t additional_max = 0;
835 uint16_t additional_credits = credits_requested - 1;
838 case SMB2_OP_NEGPROT:
840 case SMB2_OP_SESSSETUP:
842 * Windows 2012 RC1 starts to grant
844 * with a successful session setup
846 if (NT_STATUS_IS_OK(out_status)) {
852 * We match windows and only grant additional credits
859 additional_max = MIN(additional_max, additional_possible);
860 additional_credits = MIN(additional_credits, additional_max);
862 credits_granted = credit_charge + additional_credits;
866 * sequence numbers should not wrap
868 * 1. calculate the possible credits until
869 * the sequence numbers start to wrap on 64-bit.
871 * 2. UINT64_MAX is used for Break Notifications.
873 * 2. truncate the possible credits to the maximum
874 * credits we want to grant to the client in total.
876 * 3. remove the range we'll already granted to the client
877 * this makes sure the client consumes the lowest sequence
878 * number, before we can grant additional credits.
880 credits_possible = UINT64_MAX - xconn->smb2.credits.seq_low;
881 if (credits_possible > 0) {
882 /* remove UINT64_MAX */
883 credits_possible -= 1;
885 credits_possible = MIN(credits_possible, current_max_credits);
886 credits_possible -= xconn->smb2.credits.seq_range;
888 credits_granted = MIN(credits_granted, credits_possible);
890 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
891 xconn->smb2.credits.granted += credits_granted;
892 xconn->smb2.credits.seq_range += credits_granted;
894 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
895 "granted %u, current possible/max %u/%u, "
896 "total granted/max/low/range %u/%u/%llu/%u\n",
897 (unsigned int)credits_requested,
898 (unsigned int)credit_charge,
899 (unsigned int)credits_granted,
900 (unsigned int)credits_possible,
901 (unsigned int)current_max_credits,
902 (unsigned int)xconn->smb2.credits.granted,
903 (unsigned int)xconn->smb2.credits.max,
904 (unsigned long long)xconn->smb2.credits.seq_low,
905 (unsigned int)xconn->smb2.credits.seq_range));
908 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
909 struct smbd_smb2_request *outreq)
912 uint16_t total_credits = 0;
914 count = outreq->out.vector_count;
916 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
917 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(inreq,in,idx);
918 struct iovec *outhdr_v = SMBD_SMB2_IDX_HDR_IOV(outreq,out,idx);
919 uint8_t *outhdr = (uint8_t *)outhdr_v->iov_base;
921 smb2_set_operation_credit(outreq->xconn, inhdr_v, outhdr_v);
923 /* To match Windows, count up what we
925 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
926 /* Set to zero in all but the last reply. */
927 if (idx + SMBD_SMB2_NUM_IOV_PER_REQ < count) {
928 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
930 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
935 DATA_BLOB smbd_smb2_generate_outbody(struct smbd_smb2_request *req, size_t size)
937 if (req->current_idx <= 1) {
938 if (size <= sizeof(req->out._body)) {
939 return data_blob_const(req->out._body, size);
943 return data_blob_talloc(req, NULL, size);
946 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
948 struct smbXsrv_connection *xconn = req->xconn;
950 struct iovec *vector;
955 count = req->in.vector_count;
956 if (count <= ARRAY_SIZE(req->out._vector)) {
958 vector = req->out._vector;
960 vector = talloc_zero_array(req, struct iovec, count);
961 if (vector == NULL) {
962 return NT_STATUS_NO_MEMORY;
967 vector[0].iov_base = req->out.nbt_hdr;
968 vector[0].iov_len = 4;
969 SIVAL(req->out.nbt_hdr, 0, 0);
971 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
972 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
973 const uint8_t *inhdr = (const uint8_t *)inhdr_v->iov_base;
974 uint8_t *outhdr = NULL;
975 uint8_t *outbody = NULL;
976 uint32_t next_command_ofs = 0;
977 struct iovec *current = &vector[idx];
979 if ((idx + SMBD_SMB2_NUM_IOV_PER_REQ) < count) {
980 /* we have a next command -
981 * setup for the error case. */
982 next_command_ofs = SMB2_HDR_BODY + 9;
986 outhdr = req->out._hdr;
988 outhdr = talloc_zero_array(mem_ctx, uint8_t,
990 if (outhdr == NULL) {
991 return NT_STATUS_NO_MEMORY;
995 outbody = outhdr + SMB2_HDR_BODY;
998 * SMBD_SMB2_TF_IOV_OFS might be used later
1000 current[SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1001 current[SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1003 current[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)outhdr;
1004 current[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1006 current[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)outbody;
1007 current[SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1009 current[SMBD_SMB2_DYN_IOV_OFS].iov_base = NULL;
1010 current[SMBD_SMB2_DYN_IOV_OFS].iov_len = 0;
1012 /* setup the SMB2 header */
1013 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1014 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1015 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
1016 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
1017 SIVAL(outhdr, SMB2_HDR_STATUS,
1018 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
1019 SSVAL(outhdr, SMB2_HDR_OPCODE,
1020 SVAL(inhdr, SMB2_HDR_OPCODE));
1021 SIVAL(outhdr, SMB2_HDR_FLAGS,
1022 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
1023 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
1024 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
1025 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
1026 SIVAL(outhdr, SMB2_HDR_PID,
1027 IVAL(inhdr, SMB2_HDR_PID));
1028 SIVAL(outhdr, SMB2_HDR_TID,
1029 IVAL(inhdr, SMB2_HDR_TID));
1030 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
1031 BVAL(inhdr, SMB2_HDR_SESSION_ID));
1032 memcpy(outhdr + SMB2_HDR_SIGNATURE,
1033 inhdr + SMB2_HDR_SIGNATURE, 16);
1035 /* setup error body header */
1036 SSVAL(outbody, 0x00, 0x08 + 1);
1037 SSVAL(outbody, 0x02, 0);
1038 SIVAL(outbody, 0x04, 0);
1041 req->out.vector = vector;
1042 req->out.vector_count = count;
1044 /* setup the length of the NBT packet */
1045 ok = smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
1047 return NT_STATUS_INVALID_PARAMETER_MIX;
1050 DLIST_ADD_END(xconn->smb2.requests, req, struct smbd_smb2_request *);
1052 return NT_STATUS_OK;
1055 void smbd_server_connection_terminate_ex(struct smbXsrv_connection *xconn,
1057 const char *location)
1059 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
1061 exit_server_cleanly(reason);
1064 static bool dup_smb2_vec4(TALLOC_CTX *ctx,
1065 struct iovec *outvec,
1066 const struct iovec *srcvec)
1068 const uint8_t *srctf;
1070 const uint8_t *srchdr;
1072 const uint8_t *srcbody;
1074 const uint8_t *expected_srcbody;
1075 const uint8_t *srcdyn;
1077 const uint8_t *expected_srcdyn;
1083 srctf = (const uint8_t *)srcvec[SMBD_SMB2_TF_IOV_OFS].iov_base;
1084 srctf_len = srcvec[SMBD_SMB2_TF_IOV_OFS].iov_len;
1085 srchdr = (const uint8_t *)srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base;
1086 srchdr_len = srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_len;
1087 srcbody = (const uint8_t *)srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_base;
1088 srcbody_len = srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_len;
1089 expected_srcbody = srchdr + SMB2_HDR_BODY;
1090 srcdyn = (const uint8_t *)srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_base;
1091 srcdyn_len = srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_len;
1092 expected_srcdyn = srcbody + 8;
1094 if ((srctf_len != SMB2_TF_HDR_SIZE) && (srctf_len != 0)) {
1098 if (srchdr_len != SMB2_HDR_BODY) {
1102 if (srctf_len == SMB2_TF_HDR_SIZE) {
1103 dsttf = talloc_memdup(ctx, srctf, SMB2_TF_HDR_SIZE);
1104 if (dsttf == NULL) {
1110 outvec[SMBD_SMB2_TF_IOV_OFS].iov_base = (void *)dsttf;
1111 outvec[SMBD_SMB2_TF_IOV_OFS].iov_len = srctf_len;
1113 /* vec[SMBD_SMB2_HDR_IOV_OFS] is always boilerplate and must
1114 * be allocated with size OUTVEC_ALLOC_SIZE. */
1116 dsthdr = talloc_memdup(ctx, srchdr, OUTVEC_ALLOC_SIZE);
1117 if (dsthdr == NULL) {
1120 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)dsthdr;
1121 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1124 * If this is a "standard" vec[SMBD_SMB2_BOFY_IOV_OFS] of length 8,
1125 * pointing to srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + SMB2_HDR_BODY,
1126 * then duplicate this. Else use talloc_memdup().
1129 if ((srcbody == expected_srcbody) && (srcbody_len == 8)) {
1130 dstbody = dsthdr + SMB2_HDR_BODY;
1132 dstbody = talloc_memdup(ctx, srcbody, srcbody_len);
1133 if (dstbody == NULL) {
1137 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)dstbody;
1138 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_len = srcbody_len;
1141 * If this is a "standard" vec[SMBD_SMB2_DYN_IOV_OFS] of length 1,
1143 * srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + 8
1144 * then duplicate this. Else use talloc_memdup().
1147 if ((srcdyn == expected_srcdyn) && (srcdyn_len == 1)) {
1148 dstdyn = dsthdr + SMB2_HDR_BODY + 8;
1149 } else if (srcdyn == NULL) {
1152 dstdyn = talloc_memdup(ctx, srcdyn, srcdyn_len);
1153 if (dstdyn == NULL) {
1157 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_base = (void *)dstdyn;
1158 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_len = srcdyn_len;
1163 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
1165 struct smbd_smb2_request *newreq = NULL;
1166 struct iovec *outvec = NULL;
1167 int count = req->out.vector_count;
1171 newreq = smbd_smb2_request_allocate(req->xconn);
1176 newreq->sconn = req->sconn;
1177 newreq->xconn = req->xconn;
1178 newreq->session = req->session;
1179 newreq->do_encryption = req->do_encryption;
1180 newreq->do_signing = req->do_signing;
1181 newreq->current_idx = req->current_idx;
1183 outvec = talloc_zero_array(newreq, struct iovec, count);
1185 TALLOC_FREE(newreq);
1188 newreq->out.vector = outvec;
1189 newreq->out.vector_count = count;
1191 /* Setup the outvec's identically to req. */
1192 outvec[0].iov_base = newreq->out.nbt_hdr;
1193 outvec[0].iov_len = 4;
1194 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
1196 /* Setup the vectors identically to the ones in req. */
1197 for (i = 1; i < count; i += SMBD_SMB2_NUM_IOV_PER_REQ) {
1198 if (!dup_smb2_vec4(outvec, &outvec[i], &req->out.vector[i])) {
1205 TALLOC_FREE(newreq);
1209 ok = smb2_setup_nbt_length(newreq->out.vector,
1210 newreq->out.vector_count);
1212 TALLOC_FREE(newreq);
1219 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1221 struct smbXsrv_connection *xconn = req->xconn;
1223 struct iovec *firsttf = NULL;
1224 struct iovec *outhdr_v = NULL;
1225 uint8_t *outhdr = NULL;
1226 struct smbd_smb2_request *nreq = NULL;
1230 /* Create a new smb2 request we'll use
1231 for the interim return. */
1232 nreq = dup_smb2_req(req);
1234 return NT_STATUS_NO_MEMORY;
1237 /* Lose the last X out vectors. They're the
1238 ones we'll be using for the async reply. */
1239 nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ;
1241 ok = smb2_setup_nbt_length(nreq->out.vector,
1242 nreq->out.vector_count);
1244 return NT_STATUS_INVALID_PARAMETER_MIX;
1247 /* Step back to the previous reply. */
1248 nreq->current_idx -= SMBD_SMB2_NUM_IOV_PER_REQ;
1249 firsttf = SMBD_SMB2_IDX_TF_IOV(nreq,out,first_idx);
1250 outhdr_v = SMBD_SMB2_OUT_HDR_IOV(nreq);
1251 outhdr = SMBD_SMB2_OUT_HDR_PTR(nreq);
1252 /* And end the chain. */
1253 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1255 /* Calculate outgoing credits */
1256 smb2_calculate_credits(req, nreq);
1258 if (DEBUGLEVEL >= 10) {
1259 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1260 (unsigned int)nreq->current_idx );
1261 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1262 (unsigned int)nreq->out.vector_count );
1263 print_req_vectors(nreq);
1267 * As we have changed the header (SMB2_HDR_NEXT_COMMAND),
1268 * we need to sign/encrypt here with the last/first key we remembered
1270 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
1271 status = smb2_signing_encrypt_pdu(req->first_key,
1272 xconn->smb2.server.cipher,
1274 nreq->out.vector_count - first_idx);
1275 if (!NT_STATUS_IS_OK(status)) {
1278 } else if (req->last_key.length > 0) {
1279 status = smb2_signing_sign_pdu(req->last_key,
1282 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1283 if (!NT_STATUS_IS_OK(status)) {
1288 nreq->queue_entry.mem_ctx = nreq;
1289 nreq->queue_entry.vector = nreq->out.vector;
1290 nreq->queue_entry.count = nreq->out.vector_count;
1291 DLIST_ADD_END(xconn->smb2.send_queue, &nreq->queue_entry, NULL);
1292 xconn->smb2.send_queue_len++;
1294 status = smbd_smb2_flush_send_queue(xconn);
1295 if (!NT_STATUS_IS_OK(status)) {
1299 return NT_STATUS_OK;
1302 struct smbd_smb2_request_pending_state {
1303 struct smbd_smb2_send_queue queue_entry;
1304 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x08 + 1];
1305 struct iovec vector[1 + SMBD_SMB2_NUM_IOV_PER_REQ];
1308 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1309 struct tevent_timer *te,
1310 struct timeval current_time,
1311 void *private_data);
1313 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1314 struct tevent_req *subreq,
1315 uint32_t defer_time)
1318 struct timeval defer_endtime;
1319 uint8_t *outhdr = NULL;
1322 if (!tevent_req_is_in_progress(subreq)) {
1324 * This is a performance optimization,
1325 * it avoids one tevent_loop iteration,
1326 * which means we avoid one
1327 * talloc_stackframe_pool/talloc_free pair.
1329 tevent_req_notify_callback(subreq);
1330 return NT_STATUS_OK;
1333 req->subreq = subreq;
1336 if (req->async_te) {
1337 /* We're already async. */
1338 return NT_STATUS_OK;
1341 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1342 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1343 if (flags & SMB2_HDR_FLAG_ASYNC) {
1344 /* We're already async. */
1345 return NT_STATUS_OK;
1348 if (req->in.vector_count > req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
1350 * We're trying to go async in a compound
1352 * This is only allowed for opens that
1353 * cause an oplock break, otherwise it
1354 * is not allowed. See [MS-SMB2].pdf
1355 * note <194> on Section 3.3.5.2.7.
1357 const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1359 if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_CREATE) {
1361 * Cancel the outstanding request.
1363 bool ok = tevent_req_cancel(req->subreq);
1365 return NT_STATUS_OK;
1367 TALLOC_FREE(req->subreq);
1368 return smbd_smb2_request_error(req,
1369 NT_STATUS_INTERNAL_ERROR);
1373 if (DEBUGLEVEL >= 10) {
1374 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1375 (unsigned int)req->current_idx );
1376 print_req_vectors(req);
1379 if (req->current_idx > 1) {
1381 * We're going async in a compound
1382 * chain after the first request has
1383 * already been processed. Send an
1384 * interim response containing the
1385 * set of replies already generated.
1387 int idx = req->current_idx;
1389 status = smb2_send_async_interim_response(req);
1390 if (!NT_STATUS_IS_OK(status)) {
1393 if (req->first_key.length > 0) {
1394 data_blob_clear_free(&req->first_key);
1397 req->current_idx = 1;
1400 * Re-arrange the in.vectors to remove what
1403 memmove(&req->in.vector[1],
1404 &req->in.vector[idx],
1405 sizeof(req->in.vector[0])*(req->in.vector_count - idx));
1406 req->in.vector_count = 1 + (req->in.vector_count - idx);
1408 /* Re-arrange the out.vectors to match. */
1409 memmove(&req->out.vector[1],
1410 &req->out.vector[idx],
1411 sizeof(req->out.vector[0])*(req->out.vector_count - idx));
1412 req->out.vector_count = 1 + (req->out.vector_count - idx);
1414 if (req->in.vector_count == 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
1416 * We only have one remaining request as
1417 * we've processed everything else.
1418 * This is no longer a compound request.
1420 req->compound_related = false;
1421 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1422 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1423 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1426 if (req->last_key.length > 0) {
1427 data_blob_clear_free(&req->last_key);
1430 defer_endtime = timeval_current_ofs_usec(defer_time);
1431 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1433 smbd_smb2_request_pending_timer,
1435 if (req->async_te == NULL) {
1436 return NT_STATUS_NO_MEMORY;
1439 return NT_STATUS_OK;
1442 static DATA_BLOB smbd_smb2_signing_key(struct smbXsrv_session *session,
1443 struct smbXsrv_connection *xconn)
1445 struct smbXsrv_channel_global0 *c = NULL;
1447 DATA_BLOB key = data_blob_null;
1449 status = smbXsrv_session_find_channel(session, xconn, &c);
1450 if (NT_STATUS_IS_OK(status)) {
1451 key = c->signing_key;
1454 if (key.length == 0) {
1455 key = session->global->signing_key;
1461 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1462 struct tevent_timer *te,
1463 struct timeval current_time,
1466 struct smbd_smb2_request *req =
1467 talloc_get_type_abort(private_data,
1468 struct smbd_smb2_request);
1469 struct smbXsrv_connection *xconn = req->xconn;
1470 struct smbd_smb2_request_pending_state *state = NULL;
1471 uint8_t *outhdr = NULL;
1472 const uint8_t *inhdr = NULL;
1475 uint8_t *hdr = NULL;
1476 uint8_t *body = NULL;
1477 uint8_t *dyn = NULL;
1479 uint64_t session_id = 0;
1480 uint64_t message_id = 0;
1481 uint64_t nonce_high = 0;
1482 uint64_t nonce_low = 0;
1483 uint64_t async_id = 0;
1487 TALLOC_FREE(req->async_te);
1489 /* Ensure our final reply matches the interim one. */
1490 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1491 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1492 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1493 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1494 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1496 async_id = message_id; /* keep it simple for now... */
1498 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1499 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1501 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1503 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1504 (unsigned long long)async_id ));
1507 * What we send is identical to a smbd_smb2_request_error
1508 * packet with an error status of STATUS_PENDING. Make use
1509 * of this fact sometime when refactoring. JRA.
1512 state = talloc_zero(req->xconn, struct smbd_smb2_request_pending_state);
1513 if (state == NULL) {
1514 smbd_server_connection_terminate(xconn,
1515 nt_errstr(NT_STATUS_NO_MEMORY));
1519 tf = state->buf + NBT_HDR_SIZE;
1520 tf_len = SMB2_TF_HDR_SIZE;
1522 hdr = tf + SMB2_TF_HDR_SIZE;
1523 body = hdr + SMB2_HDR_BODY;
1526 if (req->do_encryption) {
1527 struct smbXsrv_session *x = req->session;
1529 nonce_high = x->nonce_high;
1530 nonce_low = x->nonce_low;
1533 if (x->nonce_low == 0) {
1539 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1540 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1541 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1542 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1544 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1545 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1546 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1547 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1548 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1550 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1551 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1552 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1553 SBVAL(hdr, SMB2_HDR_PID, async_id);
1554 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1555 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1556 memcpy(hdr+SMB2_HDR_SIGNATURE,
1557 outhdr+SMB2_HDR_SIGNATURE, 16);
1559 SSVAL(body, 0x00, 0x08 + 1);
1561 SCVAL(body, 0x02, 0);
1562 SCVAL(body, 0x03, 0);
1563 SIVAL(body, 0x04, 0);
1564 /* Match W2K8R2... */
1565 SCVAL(dyn, 0x00, 0x21);
1567 state->vector[0].iov_base = (void *)state->buf;
1568 state->vector[0].iov_len = NBT_HDR_SIZE;
1570 if (req->do_encryption) {
1571 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1572 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1574 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1575 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1578 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1579 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1581 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1582 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1584 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1585 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1587 ok = smb2_setup_nbt_length(state->vector,
1588 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1590 smbd_server_connection_terminate(
1591 xconn, nt_errstr(NT_STATUS_INTERNAL_ERROR));
1595 /* Ensure we correctly go through crediting. Grant
1596 the credits now, and zero credits on the final
1598 smb2_set_operation_credit(req->xconn,
1599 SMBD_SMB2_IN_HDR_IOV(req),
1600 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1602 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1607 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1608 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1610 (unsigned int)ARRAY_SIZE(state->vector),
1611 (unsigned int)state->vector[i].iov_len);
1615 if (req->do_encryption) {
1616 struct smbXsrv_session *x = req->session;
1617 DATA_BLOB encryption_key = x->global->encryption_key;
1619 status = smb2_signing_encrypt_pdu(encryption_key,
1620 xconn->smb2.server.cipher,
1621 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1622 SMBD_SMB2_NUM_IOV_PER_REQ);
1623 if (!NT_STATUS_IS_OK(status)) {
1624 smbd_server_connection_terminate(xconn,
1628 } else if (req->do_signing) {
1629 struct smbXsrv_session *x = req->session;
1630 DATA_BLOB signing_key = smbd_smb2_signing_key(x, xconn);
1632 status = smb2_signing_sign_pdu(signing_key,
1634 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1635 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1636 if (!NT_STATUS_IS_OK(status)) {
1637 smbd_server_connection_terminate(xconn,
1643 state->queue_entry.mem_ctx = state;
1644 state->queue_entry.vector = state->vector;
1645 state->queue_entry.count = ARRAY_SIZE(state->vector);
1646 DLIST_ADD_END(xconn->smb2.send_queue, &state->queue_entry, NULL);
1647 xconn->smb2.send_queue_len++;
1649 status = smbd_smb2_flush_send_queue(xconn);
1650 if (!NT_STATUS_IS_OK(status)) {
1651 smbd_server_connection_terminate(xconn,
1657 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1659 struct smbXsrv_connection *xconn = req->xconn;
1660 struct smbd_smb2_request *cur;
1661 const uint8_t *inhdr;
1663 uint64_t search_message_id;
1664 uint64_t search_async_id;
1667 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1669 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1670 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1671 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1674 * we don't need the request anymore
1675 * cancel requests never have a response
1677 DLIST_REMOVE(xconn->smb2.requests, req);
1680 for (cur = xconn->smb2.requests; cur; cur = cur->next) {
1681 const uint8_t *outhdr;
1682 uint64_t message_id;
1685 if (cur->compound_related) {
1687 * Never cancel anything in a compound request.
1688 * Way too hard to deal with the result.
1693 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1695 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1696 async_id = BVAL(outhdr, SMB2_HDR_PID);
1698 if (flags & SMB2_HDR_FLAG_ASYNC) {
1699 if (search_async_id == async_id) {
1700 found_id = async_id;
1704 if (search_message_id == message_id) {
1705 found_id = message_id;
1711 if (cur && cur->subreq) {
1712 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1713 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1714 "cancel opcode[%s] mid %llu\n",
1715 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1716 (unsigned long long)found_id ));
1717 tevent_req_cancel(cur->subreq);
1720 return NT_STATUS_OK;
1723 /*************************************************************
1724 Ensure an incoming tid is a valid one for us to access.
1725 Change to the associated uid credentials and chdir to the
1726 valid tid directory.
1727 *************************************************************/
1729 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1731 const uint8_t *inhdr;
1734 struct smbXsrv_tcon *tcon;
1736 NTTIME now = timeval_to_nttime(&req->request_time);
1740 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1742 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1743 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1745 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1746 in_tid = req->last_tid;
1751 status = smb2srv_tcon_lookup(req->session,
1752 in_tid, now, &tcon);
1753 if (!NT_STATUS_IS_OK(status)) {
1757 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1758 return NT_STATUS_ACCESS_DENIED;
1761 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1762 if (!set_current_service(tcon->compat, 0, true)) {
1763 return NT_STATUS_ACCESS_DENIED;
1767 req->last_tid = in_tid;
1769 return NT_STATUS_OK;
1772 /*************************************************************
1773 Ensure an incoming session_id is a valid one for us to access.
1774 *************************************************************/
1776 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1778 const uint8_t *inhdr;
1781 uint64_t in_session_id;
1782 struct smbXsrv_session *session = NULL;
1783 struct auth_session_info *session_info;
1785 NTTIME now = timeval_to_nttime(&req->request_time);
1787 req->session = NULL;
1790 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1792 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1793 in_opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1794 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1796 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1797 in_session_id = req->last_session_id;
1800 req->last_session_id = 0;
1802 /* lookup an existing session */
1803 status = smb2srv_session_lookup(req->xconn,
1807 req->session = session;
1808 req->last_session_id = in_session_id;
1810 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1811 switch (in_opcode) {
1812 case SMB2_OP_SESSSETUP:
1813 status = NT_STATUS_OK;
1819 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1820 switch (in_opcode) {
1822 case SMB2_OP_CREATE:
1823 case SMB2_OP_GETINFO:
1824 case SMB2_OP_SETINFO:
1825 return NT_STATUS_INVALID_HANDLE;
1828 * Notice the check for
1829 * (session_info == NULL)
1832 status = NT_STATUS_OK;
1836 if (!NT_STATUS_IS_OK(status)) {
1840 session_info = session->global->auth_session_info;
1841 if (session_info == NULL) {
1842 return NT_STATUS_INVALID_HANDLE;
1845 if (in_session_id != req->xconn->client->last_session_id) {
1846 req->xconn->client->last_session_id = in_session_id;
1847 set_current_user_info(session_info->unix_info->sanitized_username,
1848 session_info->unix_info->unix_name,
1849 session_info->info->domain_name);
1852 return NT_STATUS_OK;
1855 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1856 uint32_t data_length)
1858 struct smbXsrv_connection *xconn = req->xconn;
1859 uint16_t needed_charge;
1860 uint16_t credit_charge = 1;
1861 const uint8_t *inhdr;
1863 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1865 if (xconn->smb2.credits.multicredit) {
1866 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1867 credit_charge = MAX(credit_charge, 1);
1870 needed_charge = (data_length - 1)/ 65536 + 1;
1872 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1873 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1874 credit_charge, needed_charge));
1876 if (needed_charge > credit_charge) {
1877 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1878 credit_charge, needed_charge));
1879 return NT_STATUS_INVALID_PARAMETER;
1882 return NT_STATUS_OK;
1885 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1886 size_t expected_body_size)
1888 struct iovec *inhdr_v;
1889 const uint8_t *inhdr;
1891 const uint8_t *inbody;
1893 size_t min_dyn_size = expected_body_size & 0x00000001;
1894 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1897 * The following should be checked already.
1899 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1900 return NT_STATUS_INTERNAL_ERROR;
1902 if (req->current_idx > max_idx) {
1903 return NT_STATUS_INTERNAL_ERROR;
1906 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1907 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1908 return NT_STATUS_INTERNAL_ERROR;
1910 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1911 return NT_STATUS_INTERNAL_ERROR;
1914 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1915 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1919 case SMB2_OP_GETINFO:
1923 if (req->smb1req != NULL && req->smb1req->unread_bytes > 0) {
1924 if (req->smb1req->unread_bytes < min_dyn_size) {
1925 return NT_STATUS_INVALID_PARAMETER;
1934 * Now check the expected body size,
1935 * where the last byte might be in the
1938 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1939 return NT_STATUS_INVALID_PARAMETER;
1941 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1942 return NT_STATUS_INVALID_PARAMETER;
1945 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1947 body_size = SVAL(inbody, 0x00);
1948 if (body_size != expected_body_size) {
1949 return NT_STATUS_INVALID_PARAMETER;
1952 return NT_STATUS_OK;
1955 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1957 struct smbXsrv_connection *xconn = req->xconn;
1958 const struct smbd_smb2_dispatch_table *call = NULL;
1959 const struct iovec *intf_v = SMBD_SMB2_IN_TF_IOV(req);
1960 const uint8_t *inhdr;
1965 NTSTATUS session_status;
1966 uint32_t allowed_flags;
1967 NTSTATUS return_value;
1968 struct smbXsrv_session *x = NULL;
1969 bool signing_required = false;
1970 bool encryption_required = false;
1972 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1974 DO_PROFILE_INC(request);
1976 /* TODO: verify more things */
1978 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1979 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1980 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1981 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1982 smb2_opcode_name(opcode),
1983 (unsigned long long)mid));
1985 if (xconn->protocol >= PROTOCOL_SMB2_02) {
1987 * once the protocol is negotiated
1988 * SMB2_OP_NEGPROT is not allowed anymore
1990 if (opcode == SMB2_OP_NEGPROT) {
1991 /* drop the connection */
1992 return NT_STATUS_INVALID_PARAMETER;
1996 * if the protocol is not negotiated yet
1997 * only SMB2_OP_NEGPROT is allowed.
1999 if (opcode != SMB2_OP_NEGPROT) {
2000 /* drop the connection */
2001 return NT_STATUS_INVALID_PARAMETER;
2006 * Check if the client provided a valid session id,
2007 * if so smbd_smb2_request_check_session() calls
2008 * set_current_user_info().
2010 * As some command don't require a valid session id
2011 * we defer the check of the session_status
2013 session_status = smbd_smb2_request_check_session(req);
2016 signing_required = x->global->signing_required;
2017 encryption_required = x->global->encryption_required;
2020 req->do_signing = false;
2021 req->do_encryption = false;
2022 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
2023 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
2024 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
2026 if (x != NULL && x->global->session_wire_id != tf_session_id) {
2027 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
2028 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
2029 (unsigned long long)x->global->session_wire_id,
2030 (unsigned long long)tf_session_id));
2032 * TODO: windows allows this...
2033 * should we drop the connection?
2035 * For now we just return ACCESS_DENIED
2036 * (Windows clients never trigger this)
2037 * and wait for an update of [MS-SMB2].
2039 return smbd_smb2_request_error(req,
2040 NT_STATUS_ACCESS_DENIED);
2043 req->do_encryption = true;
2046 if (encryption_required && !req->do_encryption) {
2047 return smbd_smb2_request_error(req,
2048 NT_STATUS_ACCESS_DENIED);
2051 call = smbd_smb2_call(opcode);
2053 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2056 allowed_flags = SMB2_HDR_FLAG_CHAINED |
2057 SMB2_HDR_FLAG_SIGNED |
2059 if (opcode == SMB2_OP_CANCEL) {
2060 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
2062 if ((flags & ~allowed_flags) != 0) {
2063 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2066 if (flags & SMB2_HDR_FLAG_CHAINED) {
2068 * This check is mostly for giving the correct error code
2069 * for compounded requests.
2071 if (!NT_STATUS_IS_OK(session_status)) {
2072 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2075 req->compat_chain_fsp = NULL;
2078 if (req->do_encryption) {
2079 signing_required = false;
2080 } else if (signing_required || (flags & SMB2_HDR_FLAG_SIGNED)) {
2081 DATA_BLOB signing_key = data_blob_null;
2085 * MS-SMB2: 3.3.5.2.4 Verifying the Signature.
2086 * If the SMB2 header of the SMB2 NEGOTIATE
2087 * request has the SMB2_FLAGS_SIGNED bit set in the
2088 * Flags field, the server MUST fail the request
2089 * with STATUS_INVALID_PARAMETER.
2091 * Microsoft test tool checks this.
2094 if ((opcode == SMB2_OP_NEGPROT) &&
2095 (flags & SMB2_HDR_FLAG_SIGNED)) {
2096 status = NT_STATUS_INVALID_PARAMETER;
2098 status = NT_STATUS_USER_SESSION_DELETED;
2100 return smbd_smb2_request_error(req, status);
2103 signing_key = smbd_smb2_signing_key(x, xconn);
2106 * If we have a signing key, we should
2109 if (signing_key.length > 0) {
2110 req->do_signing = true;
2113 status = smb2_signing_check_pdu(signing_key,
2115 SMBD_SMB2_IN_HDR_IOV(req),
2116 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2117 if (!NT_STATUS_IS_OK(status)) {
2118 return smbd_smb2_request_error(req, status);
2122 * Now that we know the request was correctly signed
2123 * we have to sign the response too.
2125 req->do_signing = true;
2127 if (!NT_STATUS_IS_OK(session_status)) {
2128 return smbd_smb2_request_error(req, session_status);
2130 } else if (opcode == SMB2_OP_CANCEL) {
2131 /* Cancel requests are allowed to skip the signing */
2132 } else if (signing_required) {
2134 * If signing is required we try to sign
2135 * a possible error response
2137 req->do_signing = true;
2138 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2141 if (flags & SMB2_HDR_FLAG_CHAINED) {
2142 req->compound_related = true;
2145 if (call->need_session) {
2146 if (!NT_STATUS_IS_OK(session_status)) {
2147 return smbd_smb2_request_error(req, session_status);
2151 if (call->need_tcon) {
2152 SMB_ASSERT(call->need_session);
2155 * This call needs to be run as user.
2157 * smbd_smb2_request_check_tcon()
2158 * calls change_to_user() on success.
2160 status = smbd_smb2_request_check_tcon(req);
2161 if (!NT_STATUS_IS_OK(status)) {
2162 return smbd_smb2_request_error(req, status);
2164 if (req->tcon->global->encryption_required) {
2165 encryption_required = true;
2167 if (encryption_required && !req->do_encryption) {
2168 return smbd_smb2_request_error(req,
2169 NT_STATUS_ACCESS_DENIED);
2173 if (call->fileid_ofs != 0) {
2174 size_t needed = call->fileid_ofs + 16;
2175 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2176 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2177 uint64_t file_id_persistent;
2178 uint64_t file_id_volatile;
2179 struct files_struct *fsp;
2181 SMB_ASSERT(call->need_tcon);
2183 if (needed > body_size) {
2184 return smbd_smb2_request_error(req,
2185 NT_STATUS_INVALID_PARAMETER);
2188 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2189 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2191 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2193 if (!call->allow_invalid_fileid) {
2194 return smbd_smb2_request_error(req,
2195 NT_STATUS_FILE_CLOSED);
2198 if (file_id_persistent != UINT64_MAX) {
2199 return smbd_smb2_request_error(req,
2200 NT_STATUS_FILE_CLOSED);
2202 if (file_id_volatile != UINT64_MAX) {
2203 return smbd_smb2_request_error(req,
2204 NT_STATUS_FILE_CLOSED);
2209 if (call->as_root) {
2210 SMB_ASSERT(call->fileid_ofs == 0);
2211 /* This call needs to be run as root */
2212 change_to_root_user();
2214 SMB_ASSERT(call->need_tcon);
2217 #define _INBYTES(_r) \
2218 iov_buflen(SMBD_SMB2_IN_HDR_IOV(_r), SMBD_SMB2_NUM_IOV_PER_REQ-1)
2221 case SMB2_OP_NEGPROT:
2222 SMBPROFILE_IOBYTES_ASYNC_START(smb2_negprot, profile_p,
2223 req->profile, _INBYTES(req));
2224 return_value = smbd_smb2_request_process_negprot(req);
2227 case SMB2_OP_SESSSETUP:
2228 SMBPROFILE_IOBYTES_ASYNC_START(smb2_sesssetup, profile_p,
2229 req->profile, _INBYTES(req));
2230 return_value = smbd_smb2_request_process_sesssetup(req);
2233 case SMB2_OP_LOGOFF:
2234 SMBPROFILE_IOBYTES_ASYNC_START(smb2_logoff, profile_p,
2235 req->profile, _INBYTES(req));
2236 return_value = smbd_smb2_request_process_logoff(req);
2240 SMBPROFILE_IOBYTES_ASYNC_START(smb2_tcon, profile_p,
2241 req->profile, _INBYTES(req));
2242 return_value = smbd_smb2_request_process_tcon(req);
2246 SMBPROFILE_IOBYTES_ASYNC_START(smb2_tdis, profile_p,
2247 req->profile, _INBYTES(req));
2248 return_value = smbd_smb2_request_process_tdis(req);
2251 case SMB2_OP_CREATE:
2252 if (req->subreq == NULL) {
2253 SMBPROFILE_IOBYTES_ASYNC_START(smb2_create, profile_p,
2254 req->profile, _INBYTES(req));
2256 SMBPROFILE_IOBYTES_ASYNC_SET_BUSY(req->profile);
2258 return_value = smbd_smb2_request_process_create(req);
2262 SMBPROFILE_IOBYTES_ASYNC_START(smb2_close, profile_p,
2263 req->profile, _INBYTES(req));
2264 return_value = smbd_smb2_request_process_close(req);
2268 SMBPROFILE_IOBYTES_ASYNC_START(smb2_flush, profile_p,
2269 req->profile, _INBYTES(req));
2270 return_value = smbd_smb2_request_process_flush(req);
2274 SMBPROFILE_IOBYTES_ASYNC_START(smb2_read, profile_p,
2275 req->profile, _INBYTES(req));
2276 return_value = smbd_smb2_request_process_read(req);
2280 SMBPROFILE_IOBYTES_ASYNC_START(smb2_write, profile_p,
2281 req->profile, _INBYTES(req));
2282 return_value = smbd_smb2_request_process_write(req);
2286 SMBPROFILE_IOBYTES_ASYNC_START(smb2_lock, profile_p,
2287 req->profile, _INBYTES(req));
2288 return_value = smbd_smb2_request_process_lock(req);
2292 SMBPROFILE_IOBYTES_ASYNC_START(smb2_ioctl, profile_p,
2293 req->profile, _INBYTES(req));
2294 return_value = smbd_smb2_request_process_ioctl(req);
2297 case SMB2_OP_CANCEL:
2298 SMBPROFILE_IOBYTES_ASYNC_START(smb2_cancel, profile_p,
2299 req->profile, _INBYTES(req));
2300 return_value = smbd_smb2_request_process_cancel(req);
2301 SMBPROFILE_IOBYTES_ASYNC_END(req->profile, 0);
2304 case SMB2_OP_KEEPALIVE:
2305 SMBPROFILE_IOBYTES_ASYNC_START(smb2_keepalive, profile_p,
2306 req->profile, _INBYTES(req));
2307 return_value = smbd_smb2_request_process_keepalive(req);
2311 SMBPROFILE_IOBYTES_ASYNC_START(smb2_find, profile_p,
2312 req->profile, _INBYTES(req));
2313 return_value = smbd_smb2_request_process_find(req);
2316 case SMB2_OP_NOTIFY:
2317 SMBPROFILE_IOBYTES_ASYNC_START(smb2_notify, profile_p,
2318 req->profile, _INBYTES(req));
2319 return_value = smbd_smb2_request_process_notify(req);
2322 case SMB2_OP_GETINFO:
2323 SMBPROFILE_IOBYTES_ASYNC_START(smb2_getinfo, profile_p,
2324 req->profile, _INBYTES(req));
2325 return_value = smbd_smb2_request_process_getinfo(req);
2328 case SMB2_OP_SETINFO:
2329 SMBPROFILE_IOBYTES_ASYNC_START(smb2_setinfo, profile_p,
2330 req->profile, _INBYTES(req));
2331 return_value = smbd_smb2_request_process_setinfo(req);
2335 SMBPROFILE_IOBYTES_ASYNC_START(smb2_break, profile_p,
2336 req->profile, _INBYTES(req));
2337 return_value = smbd_smb2_request_process_break(req);
2341 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2344 return return_value;
2347 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2349 struct smbXsrv_connection *xconn = req->xconn;
2351 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2352 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2353 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2358 TALLOC_FREE(req->async_te);
2360 if (req->do_encryption &&
2361 (firsttf->iov_len == 0) &&
2362 (req->first_key.length == 0) &&
2363 (req->session != NULL) &&
2364 (req->session->global->encryption_key.length != 0))
2366 DATA_BLOB encryption_key = req->session->global->encryption_key;
2368 uint64_t session_id = req->session->global->session_wire_id;
2369 struct smbXsrv_session *x = req->session;
2370 uint64_t nonce_high;
2373 nonce_high = x->nonce_high;
2374 nonce_low = x->nonce_low;
2377 if (x->nonce_low == 0) {
2383 * We need to place the SMB2_TRANSFORM header before the
2388 * we need to remember the encryption key
2389 * and defer the signing/encryption until
2390 * we are sure that we do not change
2393 req->first_key = data_blob_dup_talloc(req, encryption_key);
2394 if (req->first_key.data == NULL) {
2395 return NT_STATUS_NO_MEMORY;
2398 tf = talloc_zero_array(req, uint8_t,
2401 return NT_STATUS_NO_MEMORY;
2404 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2405 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2406 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2407 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2409 firsttf->iov_base = (void *)tf;
2410 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2413 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2414 (req->last_key.length > 0) &&
2415 (firsttf->iov_len == 0))
2417 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2418 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2421 * As we are sure the header of the last request in the
2422 * compound chain will not change, we can to sign here
2423 * with the last signing key we remembered.
2425 status = smb2_signing_sign_pdu(req->last_key,
2428 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2429 if (!NT_STATUS_IS_OK(status)) {
2433 if (req->last_key.length > 0) {
2434 data_blob_clear_free(&req->last_key);
2437 SMBPROFILE_IOBYTES_ASYNC_END(req->profile,
2438 iov_buflen(outhdr, SMBD_SMB2_NUM_IOV_PER_REQ-1));
2440 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2442 if (req->current_idx < req->out.vector_count) {
2444 * We must process the remaining compound
2445 * SMB2 requests before any new incoming SMB2
2446 * requests. This is because incoming SMB2
2447 * requests may include a cancel for a
2448 * compound request we haven't processed
2451 struct tevent_immediate *im = tevent_create_immediate(req);
2453 return NT_STATUS_NO_MEMORY;
2456 if (req->do_signing && firsttf->iov_len == 0) {
2457 struct smbXsrv_session *x = req->session;
2458 DATA_BLOB signing_key = smbd_smb2_signing_key(x, xconn);
2461 * we need to remember the signing key
2462 * and defer the signing until
2463 * we are sure that we do not change
2466 req->last_key = data_blob_dup_talloc(req, signing_key);
2467 if (req->last_key.data == NULL) {
2468 return NT_STATUS_NO_MEMORY;
2472 tevent_schedule_immediate(im,
2474 smbd_smb2_request_dispatch_immediate,
2476 return NT_STATUS_OK;
2479 if (req->compound_related) {
2480 req->compound_related = false;
2483 ok = smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2485 return NT_STATUS_INVALID_PARAMETER_MIX;
2488 /* Set credit for these operations (zero credits if this
2489 is a final reply for an async operation). */
2490 smb2_calculate_credits(req, req);
2493 * now check if we need to sign the current response
2495 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2496 status = smb2_signing_encrypt_pdu(req->first_key,
2497 xconn->smb2.server.cipher,
2499 req->out.vector_count - first_idx);
2500 if (!NT_STATUS_IS_OK(status)) {
2503 } else if (req->do_signing) {
2504 struct smbXsrv_session *x = req->session;
2505 DATA_BLOB signing_key = smbd_smb2_signing_key(x, xconn);
2507 status = smb2_signing_sign_pdu(signing_key,
2510 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2511 if (!NT_STATUS_IS_OK(status)) {
2515 if (req->first_key.length > 0) {
2516 data_blob_clear_free(&req->first_key);
2519 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2520 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2521 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2522 /* Dynamic part is NULL. Chop it off,
2523 We're going to send it via sendfile. */
2524 req->out.vector_count -= 1;
2528 * We're done with this request -
2529 * move it off the "being processed" queue.
2531 DLIST_REMOVE(xconn->smb2.requests, req);
2533 req->queue_entry.mem_ctx = req;
2534 req->queue_entry.vector = req->out.vector;
2535 req->queue_entry.count = req->out.vector_count;
2536 DLIST_ADD_END(xconn->smb2.send_queue, &req->queue_entry, NULL);
2537 xconn->smb2.send_queue_len++;
2539 status = smbd_smb2_flush_send_queue(xconn);
2540 if (!NT_STATUS_IS_OK(status)) {
2544 return NT_STATUS_OK;
2547 static NTSTATUS smbd_smb2_request_next_incoming(struct smbXsrv_connection *xconn);
2549 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2550 struct tevent_immediate *im,
2553 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2554 struct smbd_smb2_request);
2555 struct smbXsrv_connection *xconn = req->xconn;
2560 if (DEBUGLEVEL >= 10) {
2561 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2562 req->current_idx, req->in.vector_count));
2563 print_req_vectors(req);
2566 status = smbd_smb2_request_dispatch(req);
2567 if (!NT_STATUS_IS_OK(status)) {
2568 smbd_server_connection_terminate(xconn, nt_errstr(status));
2572 status = smbd_smb2_request_next_incoming(xconn);
2573 if (!NT_STATUS_IS_OK(status)) {
2574 smbd_server_connection_terminate(xconn, nt_errstr(status));
2579 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2581 DATA_BLOB body, DATA_BLOB *dyn,
2582 const char *location)
2585 struct iovec *outbody_v;
2586 struct iovec *outdyn_v;
2587 uint32_t next_command_ofs;
2589 DEBUG(10,("smbd_smb2_request_done_ex: "
2590 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2591 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2593 (unsigned int)(dyn ? dyn->length : 0),
2596 if (body.length < 2) {
2597 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2600 if ((body.length % 2) != 0) {
2601 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2604 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2605 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2606 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2608 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2609 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2611 outbody_v->iov_base = (void *)body.data;
2612 outbody_v->iov_len = body.length;
2615 outdyn_v->iov_base = (void *)dyn->data;
2616 outdyn_v->iov_len = dyn->length;
2618 outdyn_v->iov_base = NULL;
2619 outdyn_v->iov_len = 0;
2622 /* see if we need to recalculate the offset to the next response */
2623 if (next_command_ofs > 0) {
2624 next_command_ofs = SMB2_HDR_BODY;
2625 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2626 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2629 if ((next_command_ofs % 8) != 0) {
2630 size_t pad_size = 8 - (next_command_ofs % 8);
2631 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2633 * if the dyn buffer is empty
2634 * we can use it to add padding
2638 pad = talloc_zero_array(req,
2641 return smbd_smb2_request_error(req,
2642 NT_STATUS_NO_MEMORY);
2645 outdyn_v->iov_base = (void *)pad;
2646 outdyn_v->iov_len = pad_size;
2649 * For now we copy the dynamic buffer
2650 * and add the padding to the new buffer
2657 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2658 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2660 new_size = old_size + pad_size;
2661 new_dyn = talloc_zero_array(req,
2663 if (new_dyn == NULL) {
2664 return smbd_smb2_request_error(req,
2665 NT_STATUS_NO_MEMORY);
2668 memcpy(new_dyn, old_dyn, old_size);
2669 memset(new_dyn + old_size, 0, pad_size);
2671 outdyn_v->iov_base = (void *)new_dyn;
2672 outdyn_v->iov_len = new_size;
2674 next_command_ofs += pad_size;
2677 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2679 return smbd_smb2_request_reply(req);
2682 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2685 const char *location)
2687 struct smbXsrv_connection *xconn = req->xconn;
2690 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2691 size_t unread_bytes = smbd_smb2_unread_bytes(req);
2693 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2694 req->current_idx, nt_errstr(status), info ? " +info" : "",
2698 /* Recvfile error. Drain incoming socket. */
2702 ret = drain_socket(xconn->transport.sock, unread_bytes);
2703 if (ret != unread_bytes) {
2707 error = NT_STATUS_IO_DEVICE_ERROR;
2709 error = map_nt_error_from_unix_common(errno);
2712 DEBUG(2, ("Failed to drain %u bytes from SMB2 socket: "
2713 "ret[%u] errno[%d] => %s\n",
2714 (unsigned)unread_bytes,
2715 (unsigned)ret, errno, nt_errstr(error)));
2720 body.data = outhdr + SMB2_HDR_BODY;
2722 SSVAL(body.data, 0, 9);
2725 SIVAL(body.data, 0x04, info->length);
2727 /* Allocated size of req->out.vector[i].iov_base
2728 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2729 * 1 byte without having to do an alloc.
2732 info->data = ((uint8_t *)outhdr) +
2733 OUTVEC_ALLOC_SIZE - 1;
2735 SCVAL(info->data, 0, 0);
2739 * Note: Even if there is an error, continue to process the request.
2743 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2747 struct smbd_smb2_send_break_state {
2748 struct smbd_smb2_send_queue queue_entry;
2749 uint8_t nbt_hdr[NBT_HDR_SIZE];
2750 uint8_t tf[SMB2_TF_HDR_SIZE];
2751 uint8_t hdr[SMB2_HDR_BODY];
2752 struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ];
2756 static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
2757 struct smbXsrv_session *session,
2758 struct smbXsrv_tcon *tcon,
2759 const uint8_t *body,
2762 struct smbd_smb2_send_break_state *state;
2763 bool do_encryption = false;
2764 uint64_t session_wire_id = 0;
2765 uint64_t nonce_high = 0;
2766 uint64_t nonce_low = 0;
2771 if (session != NULL) {
2772 session_wire_id = session->global->session_wire_id;
2773 do_encryption = session->global->encryption_required;
2774 if (tcon->global->encryption_required) {
2775 do_encryption = true;
2779 statelen = offsetof(struct smbd_smb2_send_break_state, body) +
2782 state = talloc_zero_size(xconn, statelen);
2783 if (state == NULL) {
2784 return NT_STATUS_NO_MEMORY;
2786 talloc_set_name_const(state, "struct smbd_smb2_send_break_state");
2788 if (do_encryption) {
2789 nonce_high = session->nonce_high;
2790 nonce_low = session->nonce_low;
2792 session->nonce_low += 1;
2793 if (session->nonce_low == 0) {
2794 session->nonce_low += 1;
2795 session->nonce_high += 1;
2799 SIVAL(state->tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2800 SBVAL(state->tf, SMB2_TF_NONCE+0, nonce_low);
2801 SBVAL(state->tf, SMB2_TF_NONCE+8, nonce_high);
2802 SBVAL(state->tf, SMB2_TF_SESSION_ID, session_wire_id);
2804 SIVAL(state->hdr, 0, SMB2_MAGIC);
2805 SSVAL(state->hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2806 SSVAL(state->hdr, SMB2_HDR_EPOCH, 0);
2807 SIVAL(state->hdr, SMB2_HDR_STATUS, 0);
2808 SSVAL(state->hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2809 SSVAL(state->hdr, SMB2_HDR_CREDIT, 0);
2810 SIVAL(state->hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2811 SIVAL(state->hdr, SMB2_HDR_NEXT_COMMAND, 0);
2812 SBVAL(state->hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2813 SIVAL(state->hdr, SMB2_HDR_PID, 0);
2814 SIVAL(state->hdr, SMB2_HDR_TID, 0);
2815 SBVAL(state->hdr, SMB2_HDR_SESSION_ID, 0);
2816 memset(state->hdr+SMB2_HDR_SIGNATURE, 0, 16);
2818 state->vector[0] = (struct iovec) {
2819 .iov_base = state->nbt_hdr,
2820 .iov_len = sizeof(state->nbt_hdr)
2823 if (do_encryption) {
2824 state->vector[1+SMBD_SMB2_TF_IOV_OFS] = (struct iovec) {
2825 .iov_base = state->tf,
2826 .iov_len = sizeof(state->tf)
2829 state->vector[1+SMBD_SMB2_TF_IOV_OFS] = (struct iovec) {
2835 state->vector[1+SMBD_SMB2_HDR_IOV_OFS] = (struct iovec) {
2836 .iov_base = state->hdr,
2837 .iov_len = sizeof(state->hdr)
2840 memcpy(state->body, body, body_len);
2842 state->vector[1+SMBD_SMB2_BODY_IOV_OFS] = (struct iovec) {
2843 .iov_base = state->body,
2844 .iov_len = body_len /* no sizeof(state->body) .. :-) */
2848 * state->vector[1+SMBD_SMB2_DYN_IOV_OFS] is NULL by talloc_zero above
2851 ok = smb2_setup_nbt_length(state->vector,
2852 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
2854 return NT_STATUS_INVALID_PARAMETER_MIX;
2857 if (do_encryption) {
2858 DATA_BLOB encryption_key = session->global->encryption_key;
2860 status = smb2_signing_encrypt_pdu(encryption_key,
2861 xconn->smb2.server.cipher,
2862 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
2863 SMBD_SMB2_NUM_IOV_PER_REQ);
2864 if (!NT_STATUS_IS_OK(status)) {
2869 state->queue_entry.mem_ctx = state;
2870 state->queue_entry.vector = state->vector;
2871 state->queue_entry.count = ARRAY_SIZE(state->vector);
2872 DLIST_ADD_END(xconn->smb2.send_queue, &state->queue_entry, NULL);
2873 xconn->smb2.send_queue_len++;
2875 status = smbd_smb2_flush_send_queue(xconn);
2876 if (!NT_STATUS_IS_OK(status)) {
2880 return NT_STATUS_OK;
2883 NTSTATUS smbd_smb2_send_oplock_break(struct smbXsrv_connection *xconn,
2884 struct smbXsrv_session *session,
2885 struct smbXsrv_tcon *tcon,
2886 struct smbXsrv_open *op,
2887 uint8_t oplock_level)
2891 SSVAL(body, 0x00, sizeof(body));
2892 SCVAL(body, 0x02, oplock_level);
2893 SCVAL(body, 0x03, 0); /* reserved */
2894 SIVAL(body, 0x04, 0); /* reserved */
2895 SBVAL(body, 0x08, op->global->open_persistent_id);
2896 SBVAL(body, 0x10, op->global->open_volatile_id);
2898 return smbd_smb2_send_break(xconn, session, tcon, body, sizeof(body));
2901 NTSTATUS smbd_smb2_send_lease_break(struct smbXsrv_connection *xconn,
2903 uint32_t lease_flags,
2904 struct smb2_lease_key *lease_key,
2905 uint32_t current_lease_state,
2906 uint32_t new_lease_state)
2910 SSVAL(body, 0x00, sizeof(body));
2911 SSVAL(body, 0x02, new_epoch);
2912 SIVAL(body, 0x04, lease_flags);
2913 SBVAL(body, 0x08, lease_key->data[0]);
2914 SBVAL(body, 0x10, lease_key->data[1]);
2915 SIVAL(body, 0x18, current_lease_state);
2916 SIVAL(body, 0x1c, new_lease_state);
2917 SIVAL(body, 0x20, 0); /* BreakReason, MUST be 0 */
2918 SIVAL(body, 0x24, 0); /* AccessMaskHint, MUST be 0 */
2919 SIVAL(body, 0x28, 0); /* ShareMaskHint, MUST be 0 */
2921 return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body));
2924 static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
2928 uint64_t file_id_persistent;
2929 uint64_t file_id_volatile;
2930 struct smbXsrv_open *op = NULL;
2931 struct files_struct *fsp = NULL;
2932 const uint8_t *body = NULL;
2935 * This is only called with a pktbuf
2936 * of at least SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN
2940 if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
2941 /* Transform header. Cannot recvfile. */
2944 if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
2945 /* Not SMB2. Normal error path will cope. */
2948 if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
2949 /* Not SMB2. Normal error path will cope. */
2952 if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
2953 /* Needs to be a WRITE. */
2956 if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
2957 /* Chained. Cannot recvfile. */
2960 flags = IVAL(state->pktbuf, SMB2_HDR_FLAGS);
2961 if (flags & SMB2_HDR_FLAG_CHAINED) {
2962 /* Chained. Cannot recvfile. */
2965 if (flags & SMB2_HDR_FLAG_SIGNED) {
2966 /* Signed. Cannot recvfile. */
2970 body = &state->pktbuf[SMB2_HDR_BODY];
2972 file_id_persistent = BVAL(body, 0x10);
2973 file_id_volatile = BVAL(body, 0x18);
2975 status = smb2srv_open_lookup(state->req->xconn,
2980 if (!NT_STATUS_IS_OK(status)) {
2988 if (fsp->conn == NULL) {
2992 if (IS_IPC(fsp->conn)) {
2995 if (IS_PRINT(fsp->conn)) {
2999 DEBUG(10,("Doing recvfile write len = %u\n",
3000 (unsigned int)(state->pktfull - state->pktlen)));
3005 static NTSTATUS smbd_smb2_request_next_incoming(struct smbXsrv_connection *xconn)
3007 struct smbd_server_connection *sconn = xconn->client->sconn;
3008 struct smbd_smb2_request_read_state *state = &xconn->smb2.request_read_state;
3009 size_t max_send_queue_len;
3010 size_t cur_send_queue_len;
3012 if (!NT_STATUS_IS_OK(xconn->transport.status)) {
3014 * we're not supposed to do any io
3016 return NT_STATUS_OK;
3019 if (state->req != NULL) {
3021 * if there is already a tstream_readv_pdu
3022 * pending, we are done.
3024 return NT_STATUS_OK;
3027 max_send_queue_len = MAX(1, xconn->smb2.credits.max/16);
3028 cur_send_queue_len = xconn->smb2.send_queue_len;
3030 if (cur_send_queue_len > max_send_queue_len) {
3032 * if we have a lot of requests to send,
3033 * we wait until they are on the wire until we
3034 * ask for the next request.
3036 return NT_STATUS_OK;
3039 /* ask for the next request */
3040 ZERO_STRUCTP(state);
3041 state->req = smbd_smb2_request_allocate(xconn);
3042 if (state->req == NULL) {
3043 return NT_STATUS_NO_MEMORY;
3045 state->req->sconn = sconn;
3046 state->req->xconn = xconn;
3047 state->min_recv_size = lp_min_receive_file_size();
3049 TEVENT_FD_READABLE(xconn->transport.fde);
3051 return NT_STATUS_OK;
3054 void smbd_smb2_first_negprot(struct smbXsrv_connection *xconn,
3055 const uint8_t *inpdu, size_t size)
3057 struct smbd_server_connection *sconn = xconn->client->sconn;
3059 struct smbd_smb2_request *req = NULL;
3061 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
3062 (unsigned int)size));
3064 status = smbd_initialize_smb2(xconn);
3065 if (!NT_STATUS_IS_OK(status)) {
3066 smbd_server_connection_terminate(xconn, nt_errstr(status));
3070 status = smbd_smb2_request_create(xconn, inpdu, size, &req);
3071 if (!NT_STATUS_IS_OK(status)) {
3072 smbd_server_connection_terminate(xconn, nt_errstr(status));
3076 status = smbd_smb2_request_validate(req);
3077 if (!NT_STATUS_IS_OK(status)) {
3078 smbd_server_connection_terminate(xconn, nt_errstr(status));
3082 status = smbd_smb2_request_setup_out(req);
3083 if (!NT_STATUS_IS_OK(status)) {
3084 smbd_server_connection_terminate(xconn, nt_errstr(status));
3090 * this was already counted at the SMB1 layer =>
3091 * smbd_smb2_request_dispatch() should not count it twice.
3093 if (profile_p->request_stats.count > 0) {
3094 profile_p->request_stats.count--;
3097 status = smbd_smb2_request_dispatch(req);
3098 if (!NT_STATUS_IS_OK(status)) {
3099 smbd_server_connection_terminate(xconn, nt_errstr(status));
3103 status = smbd_smb2_request_next_incoming(xconn);
3104 if (!NT_STATUS_IS_OK(status)) {
3105 smbd_server_connection_terminate(xconn, nt_errstr(status));
3109 sconn->num_requests++;
3112 static int socket_error_from_errno(int ret,
3126 if (sys_errno == 0) {
3130 if (sys_errno == EINTR) {
3135 if (sys_errno == EINPROGRESS) {
3140 if (sys_errno == EAGAIN) {
3145 /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
3146 if (sys_errno == ENOMEM) {
3152 #if EWOULDBLOCK != EAGAIN
3153 if (sys_errno == EWOULDBLOCK) {
3163 static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
3169 if (xconn->smb2.send_queue == NULL) {
3170 TEVENT_FD_NOT_WRITEABLE(xconn->transport.fde);
3171 return NT_STATUS_OK;
3174 while (xconn->smb2.send_queue != NULL) {
3175 struct smbd_smb2_send_queue *e = xconn->smb2.send_queue;
3177 if (e->sendfile_header != NULL) {
3178 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3183 for (i=0; i < e->count; i++) {
3184 size += e->vector[i].iov_len;
3187 if (size <= e->sendfile_header->length) {
3188 buf = e->sendfile_header->data;
3190 buf = talloc_array(e->mem_ctx, uint8_t, size);
3192 return NT_STATUS_NO_MEMORY;
3197 for (i=0; i < e->count; i++) {
3199 e->vector[i].iov_base,
3200 e->vector[i].iov_len);
3201 size += e->vector[i].iov_len;
3204 e->sendfile_header->data = buf;
3205 e->sendfile_header->length = size;
3206 e->sendfile_status = &status;
3209 xconn->smb2.send_queue_len--;
3210 DLIST_REMOVE(xconn->smb2.send_queue, e);
3212 * This triggers the sendfile path via
3215 talloc_free(e->mem_ctx);
3217 if (!NT_STATUS_IS_OK(status)) {
3223 ret = writev(xconn->transport.sock, e->vector, e->count);
3225 /* propagate end of file */
3226 return NT_STATUS_INTERNAL_ERROR;
3228 err = socket_error_from_errno(ret, errno, &retry);
3231 TEVENT_FD_WRITEABLE(xconn->transport.fde);
3232 return NT_STATUS_OK;
3235 return map_nt_error_from_unix_common(err);
3238 if (ret < e->vector[0].iov_len) {
3240 base = (uint8_t *)e->vector[0].iov_base;
3242 e->vector[0].iov_base = (void *)base;
3243 e->vector[0].iov_len -= ret;
3246 ret -= e->vector[0].iov_len;
3252 * there're maybe some empty vectors at the end
3253 * which we need to skip, otherwise we would get
3254 * ret == 0 from the readv() call and return EPIPE
3256 while (e->count > 0) {
3257 if (e->vector[0].iov_len > 0) {
3265 /* we have more to write */
3266 TEVENT_FD_WRITEABLE(xconn->transport.fde);
3267 return NT_STATUS_OK;
3270 xconn->smb2.send_queue_len--;
3271 DLIST_REMOVE(xconn->smb2.send_queue, e);
3272 talloc_free(e->mem_ctx);
3275 return NT_STATUS_OK;
3278 static NTSTATUS smbd_smb2_io_handler(struct smbXsrv_connection *xconn,
3281 struct smbd_server_connection *sconn = xconn->client->sconn;
3282 struct smbd_smb2_request_read_state *state = &xconn->smb2.request_read_state;
3283 struct smbd_smb2_request *req = NULL;
3284 size_t min_recvfile_size = UINT32_MAX;
3291 if (!NT_STATUS_IS_OK(xconn->transport.status)) {
3293 * we're not supposed to do any io
3295 TEVENT_FD_NOT_READABLE(xconn->transport.fde);
3296 TEVENT_FD_NOT_WRITEABLE(xconn->transport.fde);
3297 return NT_STATUS_OK;
3300 if (fde_flags & TEVENT_FD_WRITE) {
3301 status = smbd_smb2_flush_send_queue(xconn);
3302 if (!NT_STATUS_IS_OK(status)) {
3307 if (!(fde_flags & TEVENT_FD_READ)) {
3308 return NT_STATUS_OK;
3311 if (state->req == NULL) {
3312 TEVENT_FD_NOT_READABLE(xconn->transport.fde);
3313 return NT_STATUS_OK;
3317 if (!state->hdr.done) {
3318 state->hdr.done = true;
3320 state->vector.iov_base = (void *)state->hdr.nbt;
3321 state->vector.iov_len = NBT_HDR_SIZE;
3324 ret = readv(xconn->transport.sock, &state->vector, 1);
3326 /* propagate end of file */
3327 return NT_STATUS_END_OF_FILE;
3329 err = socket_error_from_errno(ret, errno, &retry);
3332 TEVENT_FD_READABLE(xconn->transport.fde);
3333 return NT_STATUS_OK;
3336 return map_nt_error_from_unix_common(err);
3339 if (ret < state->vector.iov_len) {
3341 base = (uint8_t *)state->vector.iov_base;
3343 state->vector.iov_base = (void *)base;
3344 state->vector.iov_len -= ret;
3345 /* we have more to read */
3346 TEVENT_FD_READABLE(xconn->transport.fde);
3347 return NT_STATUS_OK;
3350 if (state->pktlen > 0) {
3351 if (state->doing_receivefile && !is_smb2_recvfile_write(state)) {
3353 * Not a possible receivefile write.
3354 * Read the rest of the data.
3356 state->doing_receivefile = false;
3358 state->pktbuf = talloc_realloc(state->req,
3362 if (state->pktbuf == NULL) {
3363 return NT_STATUS_NO_MEMORY;
3366 state->vector.iov_base = (void *)(state->pktbuf +
3368 state->vector.iov_len = (state->pktfull -
3371 state->pktlen = state->pktfull;
3376 * Either this is a receivefile write so we've
3377 * done a short read, or if not we have all the data.
3383 * Now we analyze the NBT header
3385 if (state->hdr.nbt[0] != 0x00) {
3386 state->min_recv_size = 0;
3388 state->pktfull = smb2_len(state->hdr.nbt);
3389 if (state->pktfull == 0) {
3393 if (state->min_recv_size != 0) {
3394 min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3395 min_recvfile_size += state->min_recv_size;
3398 if (state->pktfull > min_recvfile_size) {
3400 * Might be a receivefile write. Read the SMB2 HEADER +
3401 * SMB2_WRITE header first. Set 'doing_receivefile'
3402 * as we're *attempting* receivefile write. If this
3403 * turns out not to be a SMB2_WRITE request or otherwise
3404 * not suitable then we'll just read the rest of the data
3405 * the next time this function is called.
3407 state->pktlen = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3408 state->doing_receivefile = true;
3410 state->pktlen = state->pktfull;
3413 state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen);
3414 if (state->pktbuf == NULL) {
3415 return NT_STATUS_NO_MEMORY;
3418 state->vector.iov_base = (void *)state->pktbuf;
3419 state->vector.iov_len = state->pktlen;
3425 if (state->hdr.nbt[0] != 0x00) {
3426 DEBUG(1,("ignore NBT[0x%02X] msg\n",
3427 state->hdr.nbt[0]));
3430 ZERO_STRUCTP(state);
3432 state->min_recv_size = lp_min_receive_file_size();
3440 req->request_time = timeval_current();
3441 now = timeval_to_nttime(&req->request_time);
3443 status = smbd_smb2_inbuf_parse_compound(xconn,
3449 &req->in.vector_count);
3450 if (!NT_STATUS_IS_OK(status)) {
3454 if (state->doing_receivefile) {
3455 req->smb1req = talloc_zero(req, struct smb_request);
3456 if (req->smb1req == NULL) {
3457 return NT_STATUS_NO_MEMORY;
3459 req->smb1req->unread_bytes = state->pktfull - state->pktlen;
3462 ZERO_STRUCTP(state);
3464 req->current_idx = 1;
3466 DEBUG(10,("smbd_smb2_request idx[%d] of %d vectors\n",
3467 req->current_idx, req->in.vector_count));
3469 status = smbd_smb2_request_validate(req);
3470 if (!NT_STATUS_IS_OK(status)) {
3474 status = smbd_smb2_request_setup_out(req);
3475 if (!NT_STATUS_IS_OK(status)) {
3479 status = smbd_smb2_request_dispatch(req);
3480 if (!NT_STATUS_IS_OK(status)) {
3484 sconn->num_requests++;
3486 /* The timeout_processing function isn't run nearly
3487 often enough to implement 'max log size' without
3488 overrunning the size of the file by many megabytes.
3489 This is especially true if we are running at debug
3490 level 10. Checking every 50 SMB2s is a nice
3491 tradeoff of performance vs log file size overrun. */
3493 if ((sconn->num_requests % 50) == 0 &&
3494 need_to_check_log_size()) {
3495 change_to_root_user();
3499 status = smbd_smb2_request_next_incoming(xconn);
3500 if (!NT_STATUS_IS_OK(status)) {
3504 return NT_STATUS_OK;
3507 static void smbd_smb2_connection_handler(struct tevent_context *ev,
3508 struct tevent_fd *fde,
3512 struct smbXsrv_connection *xconn =
3513 talloc_get_type_abort(private_data,
3514 struct smbXsrv_connection);
3517 status = smbd_smb2_io_handler(xconn, flags);
3518 if (!NT_STATUS_IS_OK(status)) {
3519 smbd_server_connection_terminate(xconn, nt_errstr(status));