2 Unix SMB/CIFS implementation.
5 Copyright (C) Stefan Metzmacher 2009
6 Copyright (C) Jeremy Allison 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../libcli/smb/smb_common.h"
26 #include "../lib/tsocket/tsocket.h"
27 #include "../lib/util/tevent_ntstatus.h"
28 #include "smbprofile.h"
29 #include "../lib/util/bitmap.h"
30 #include "../librpc/gen_ndr/krb5pac.h"
33 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
35 static const char *smb2_names[] = {
57 const char *smb2_opcode_name(uint16_t opcode)
60 return "Bad SMB2 opcode";
62 return smb2_names[opcode];
65 static void print_req_vectors(struct smbd_smb2_request *req)
69 for (i = 0; i < req->in.vector_count; i++) {
70 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
72 (unsigned int)req->in.vector[i].iov_len);
74 for (i = 0; i < req->out.vector_count; i++) {
75 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
77 (unsigned int)req->out.vector[i].iov_len);
81 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
83 if (size < (4 + SMB2_HDR_BODY)) {
87 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
94 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
99 TALLOC_FREE(sconn->smb1.fde);
101 sconn->smb2.event_ctx = server_event_context();
103 sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
104 if (sconn->smb2.recv_queue == NULL) {
105 return NT_STATUS_NO_MEMORY;
108 sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
109 if (sconn->smb2.send_queue == NULL) {
110 return NT_STATUS_NO_MEMORY;
113 sconn->smb2.sessions.idtree = idr_init(sconn);
114 if (sconn->smb2.sessions.idtree == NULL) {
115 return NT_STATUS_NO_MEMORY;
117 sconn->smb2.sessions.limit = 0x0000FFFE;
118 sconn->smb2.sessions.list = NULL;
119 sconn->smb2.seqnum_low = 0;
120 sconn->smb2.credits_granted = 0;
121 sconn->smb2.max_credits = lp_smb2_max_credits();
122 sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
123 DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR*sconn->smb2.max_credits);
124 if (sconn->smb2.credits_bitmap == NULL) {
125 return NT_STATUS_NO_MEMORY;
128 ret = tstream_bsd_existing_socket(sconn, sconn->sock,
129 &sconn->smb2.stream);
131 status = map_nt_error_from_unix(errno);
135 /* Ensure child is set to non-blocking mode */
136 set_blocking(sconn->sock, false);
140 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
141 #define _smb2_setlen(_buf,len) do { \
142 uint8_t *buf = (uint8_t *)_buf; \
144 buf[1] = ((len)&0xFF0000)>>16; \
145 buf[2] = ((len)&0xFF00)>>8; \
146 buf[3] = (len)&0xFF; \
149 static void smb2_setup_nbt_length(struct iovec *vector, int count)
154 for (i=1; i < count; i++) {
155 len += vector[i].iov_len;
158 _smb2_setlen(vector[0].iov_base, len);
161 static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request **req)
164 (*req)->parent = NULL;
165 (*req)->mem_pool = NULL;
171 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
175 talloc_free(req->mem_pool);
181 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
183 TALLOC_CTX *mem_pool;
184 struct smbd_smb2_request **parent;
185 struct smbd_smb2_request *req;
188 /* Enable this to find subtle valgrind errors. */
189 mem_pool = talloc_init("smbd_smb2_request_allocate");
191 mem_pool = talloc_pool(mem_ctx, 8192);
193 if (mem_pool == NULL) {
197 parent = talloc(mem_pool, struct smbd_smb2_request *);
198 if (parent == NULL) {
199 talloc_free(mem_pool);
203 req = talloc_zero(parent, struct smbd_smb2_request);
205 talloc_free(mem_pool);
209 req->mem_pool = mem_pool;
210 req->parent = parent;
212 talloc_set_destructor(parent, smbd_smb2_request_parent_destructor);
213 talloc_set_destructor(req, smbd_smb2_request_destructor);
218 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
219 const uint8_t *inbuf, size_t size,
220 struct smbd_smb2_request **_req)
222 struct smbd_smb2_request *req;
223 uint32_t protocol_version;
224 const uint8_t *inhdr = NULL;
227 uint32_t next_command_ofs;
229 if (size < (4 + SMB2_HDR_BODY + 2)) {
230 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
231 return NT_STATUS_INVALID_PARAMETER;
236 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
237 if (protocol_version != SMB2_MAGIC) {
238 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
240 return NT_STATUS_INVALID_PARAMETER;
243 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
244 if (cmd != SMB2_OP_NEGPROT) {
245 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
247 return NT_STATUS_INVALID_PARAMETER;
250 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
251 if (next_command_ofs != 0) {
252 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
254 return NT_STATUS_INVALID_PARAMETER;
257 req = smbd_smb2_request_allocate(sconn);
259 return NT_STATUS_NO_MEMORY;
263 talloc_steal(req, inbuf);
265 req->in.vector = talloc_array(req, struct iovec, 4);
266 if (req->in.vector == NULL) {
268 return NT_STATUS_NO_MEMORY;
270 req->in.vector_count = 4;
272 memcpy(req->in.nbt_hdr, inbuf, 4);
275 req->in.vector[0].iov_base = discard_const_p(void, req->in.nbt_hdr);
276 req->in.vector[0].iov_len = 4;
277 ofs += req->in.vector[0].iov_len;
279 req->in.vector[1].iov_base = discard_const_p(void, (inbuf + ofs));
280 req->in.vector[1].iov_len = SMB2_HDR_BODY;
281 ofs += req->in.vector[1].iov_len;
283 req->in.vector[2].iov_base = discard_const_p(void, (inbuf + ofs));
284 req->in.vector[2].iov_len = SVAL(inbuf, ofs) & 0xFFFE;
285 ofs += req->in.vector[2].iov_len;
288 return NT_STATUS_INVALID_PARAMETER;
291 req->in.vector[3].iov_base = discard_const_p(void, (inbuf + ofs));
292 req->in.vector[3].iov_len = size - ofs;
293 ofs += req->in.vector[3].iov_len;
295 req->current_idx = 1;
301 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
302 const uint8_t *inhdr)
304 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
305 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
306 uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
307 unsigned int bitmap_offset;
309 if (opcode == SMB2_OP_CANCEL) {
310 /* SMB2_CANCEL requests by definition resend messageids. */
314 if (message_id < sconn->smb2.seqnum_low ||
315 message_id > (sconn->smb2.seqnum_low +
316 (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR))) {
317 DEBUG(0,("smb2_validate_message_id: bad message_id "
318 "%llu (low = %llu, max = %lu)\n",
319 (unsigned long long)message_id,
320 (unsigned long long)sconn->smb2.seqnum_low,
321 (unsigned long)sconn->smb2.max_credits ));
325 if (sconn->smb2.credits_granted == 0) {
326 DEBUG(0,("smb2_validate_message_id: client used more "
327 "credits than granted message_id (%llu)\n",
328 (unsigned long long)message_id));
332 /* client just used a credit. */
333 sconn->smb2.credits_granted -= 1;
335 /* Mark the message_id as seen in the bitmap. */
336 bitmap_offset = (unsigned int)(message_id %
337 (uint64_t)(sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR));
338 if (bitmap_query(credits_bm, bitmap_offset)) {
339 DEBUG(0,("smb2_validate_message_id: duplicate message_id "
340 "%llu (bm offset %u)\n",
341 (unsigned long long)message_id,
345 bitmap_set(credits_bm, bitmap_offset);
347 if (message_id == sconn->smb2.seqnum_low + 1) {
348 /* Move the window forward by all the message_id's
350 while (bitmap_query(credits_bm, bitmap_offset)) {
351 DEBUG(10,("smb2_validate_message_id: clearing "
352 "id %llu (position %u) from bitmap\n",
353 (unsigned long long)(sconn->smb2.seqnum_low + 1),
355 bitmap_clear(credits_bm, bitmap_offset);
356 sconn->smb2.seqnum_low += 1;
357 bitmap_offset = (bitmap_offset + 1) %
358 (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR);
365 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
370 count = req->in.vector_count;
373 /* It's not a SMB2 request */
374 return NT_STATUS_INVALID_PARAMETER;
377 for (idx=1; idx < count; idx += 3) {
378 const uint8_t *inhdr = NULL;
381 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
382 return NT_STATUS_INVALID_PARAMETER;
385 if (req->in.vector[idx+1].iov_len < 2) {
386 return NT_STATUS_INVALID_PARAMETER;
389 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
391 /* Check the SMB2 header */
392 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
393 return NT_STATUS_INVALID_PARAMETER;
396 if (!smb2_validate_message_id(req->sconn, inhdr)) {
397 return NT_STATUS_INVALID_PARAMETER;
400 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
403 * the 1st request should never have the
404 * SMB2_HDR_FLAG_CHAINED flag set
406 if (flags & SMB2_HDR_FLAG_CHAINED) {
407 req->next_status = NT_STATUS_INVALID_PARAMETER;
410 } else if (idx == 4) {
412 * the 2nd request triggers related vs. unrelated
413 * compounded requests
415 if (flags & SMB2_HDR_FLAG_CHAINED) {
416 req->compound_related = true;
418 } else if (idx > 4) {
421 * It seems the this tests are wrong
422 * see the SMB2-COMPOUND test
426 * all other requests should match the 2nd one
428 if (flags & SMB2_HDR_FLAG_CHAINED) {
429 if (!req->compound_related) {
431 NT_STATUS_INVALID_PARAMETER;
435 if (req->compound_related) {
437 NT_STATUS_INVALID_PARAMETER;
448 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
449 const struct iovec *in_vector,
450 struct iovec *out_vector)
452 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
453 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
454 uint16_t credits_requested;
456 uint16_t credits_granted = 0;
458 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
459 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
461 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
463 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
465 * In case we already send an async interim
466 * response, we should not grant
467 * credits on the final response.
469 credits_requested = 0;
472 if (credits_requested) {
473 uint16_t modified_credits_requested;
477 * Split up max_credits into 1/16ths, and then scale
478 * the requested credits by how many 16ths have been
479 * currently granted. Less than 1/16th == grant all
480 * requested (100%), scale down as more have been
481 * granted. Never ask for less than 1 as the client
482 * asked for at least 1. JRA.
485 multiplier = 16 - (((sconn->smb2.credits_granted * 16) / sconn->smb2.max_credits) % 16);
487 modified_credits_requested = (multiplier * credits_requested) / 16;
488 if (modified_credits_requested == 0) {
489 modified_credits_requested = 1;
492 /* Remember what we gave out. */
493 credits_granted = MIN(modified_credits_requested,
494 (sconn->smb2.max_credits - sconn->smb2.credits_granted));
497 if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
498 /* First negprot packet, or ensure the client credits can
499 never drop to zero. */
503 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
504 sconn->smb2.credits_granted += credits_granted;
506 DEBUG(10,("smb2_set_operation_credit: requested %u, "
507 "granted %u, total granted %u\n",
508 (unsigned int)credits_requested,
509 (unsigned int)credits_granted,
510 (unsigned int)sconn->smb2.credits_granted ));
513 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
514 struct smbd_smb2_request *outreq)
518 count = outreq->out.vector_count;
520 for (idx=1; idx < count; idx += 3) {
521 smb2_set_operation_credit(outreq->sconn,
522 &inreq->in.vector[idx],
523 &outreq->out.vector[idx]);
527 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
529 struct iovec *vector;
533 count = req->in.vector_count;
534 vector = talloc_zero_array(req, struct iovec, count);
535 if (vector == NULL) {
536 return NT_STATUS_NO_MEMORY;
539 vector[0].iov_base = req->out.nbt_hdr;
540 vector[0].iov_len = 4;
541 SIVAL(req->out.nbt_hdr, 0, 0);
543 for (idx=1; idx < count; idx += 3) {
544 const uint8_t *inhdr = NULL;
546 uint8_t *outhdr = NULL;
547 uint8_t *outbody = NULL;
548 uint32_t next_command_ofs = 0;
549 struct iovec *current = &vector[idx];
551 if ((idx + 3) < count) {
552 /* we have a next command -
553 * setup for the error case. */
554 next_command_ofs = SMB2_HDR_BODY + 9;
557 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
558 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
560 outhdr = talloc_zero_array(vector, uint8_t,
562 if (outhdr == NULL) {
563 return NT_STATUS_NO_MEMORY;
566 outbody = outhdr + SMB2_HDR_BODY;
568 current[0].iov_base = (void *)outhdr;
569 current[0].iov_len = SMB2_HDR_BODY;
571 current[1].iov_base = (void *)outbody;
572 current[1].iov_len = 8;
574 current[2].iov_base = NULL;
575 current[2].iov_len = 0;
577 /* setup the SMB2 header */
578 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
579 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
580 SSVAL(outhdr, SMB2_HDR_EPOCH, 0);
581 SIVAL(outhdr, SMB2_HDR_STATUS,
582 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
583 SSVAL(outhdr, SMB2_HDR_OPCODE,
584 SVAL(inhdr, SMB2_HDR_OPCODE));
585 SIVAL(outhdr, SMB2_HDR_FLAGS,
586 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
587 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
588 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
589 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
590 SIVAL(outhdr, SMB2_HDR_PID,
591 IVAL(inhdr, SMB2_HDR_PID));
592 SIVAL(outhdr, SMB2_HDR_TID,
593 IVAL(inhdr, SMB2_HDR_TID));
594 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
595 BVAL(inhdr, SMB2_HDR_SESSION_ID));
596 memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16);
598 /* setup error body header */
599 SSVAL(outbody, 0x00, 0x08 + 1);
600 SSVAL(outbody, 0x02, 0);
601 SIVAL(outbody, 0x04, 0);
604 req->out.vector = vector;
605 req->out.vector_count = count;
607 /* setup the length of the NBT packet */
608 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
610 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
615 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
617 const char *location)
619 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
621 exit_server_cleanly(reason);
624 static bool dup_smb2_vec3(TALLOC_CTX *ctx,
625 struct iovec *outvec,
626 const struct iovec *srcvec)
628 /* vec[0] is always boilerplate and must
629 * be allocated with size OUTVEC_ALLOC_SIZE. */
631 outvec[0].iov_base = talloc_memdup(ctx,
634 if (!outvec[0].iov_base) {
637 outvec[0].iov_len = SMB2_HDR_BODY;
640 * If this is a "standard" vec[1] of length 8,
641 * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
642 * then duplicate this. Else use talloc_memdup().
645 if (srcvec[1].iov_len == 8 &&
646 srcvec[1].iov_base ==
647 ((uint8_t *)srcvec[0].iov_base) +
649 outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
651 outvec[1].iov_len = 8;
653 outvec[1].iov_base = talloc_memdup(ctx,
656 if (!outvec[1].iov_base) {
659 outvec[1].iov_len = srcvec[1].iov_len;
663 * If this is a "standard" vec[2] of length 1,
664 * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
665 * then duplicate this. Else use talloc_memdup().
668 if (srcvec[2].iov_base &&
670 if (srcvec[2].iov_base ==
671 ((uint8_t *)srcvec[0].iov_base) +
672 (OUTVEC_ALLOC_SIZE - 1) &&
673 srcvec[2].iov_len == 1) {
674 /* Common SMB2 error packet case. */
675 outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
676 (OUTVEC_ALLOC_SIZE - 1);
678 outvec[2].iov_base = talloc_memdup(ctx,
681 if (!outvec[2].iov_base) {
685 outvec[2].iov_len = srcvec[2].iov_len;
687 outvec[2].iov_base = NULL;
688 outvec[2].iov_len = 0;
693 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
695 struct smbd_smb2_request *newreq = NULL;
696 struct iovec *outvec = NULL;
697 int count = req->out.vector_count;
700 newreq = smbd_smb2_request_allocate(req->sconn);
705 newreq->sconn = req->sconn;
706 newreq->session = req->session;
707 newreq->do_signing = req->do_signing;
708 newreq->current_idx = req->current_idx;
709 newreq->async = false;
710 newreq->cancelled = false;
711 /* Note we are leaving:
715 uninitialized as NULL here as
716 they're not used in the interim
717 response code. JRA. */
719 outvec = talloc_zero_array(newreq, struct iovec, count);
724 newreq->out.vector = outvec;
725 newreq->out.vector_count = count;
727 /* Setup the outvec's identically to req. */
728 outvec[0].iov_base = newreq->out.nbt_hdr;
729 outvec[0].iov_len = 4;
730 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
732 /* Setup the vectors identically to the ones in req. */
733 for (i = 1; i < count; i += 3) {
734 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
745 smb2_setup_nbt_length(newreq->out.vector,
746 newreq->out.vector_count);
751 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
753 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
756 uint8_t *outhdr = NULL;
757 struct smbd_smb2_request *nreq = NULL;
759 /* Create a new smb2 request we'll use
760 for the interim return. */
761 nreq = dup_smb2_req(req);
763 return NT_STATUS_NO_MEMORY;
766 /* Lose the last 3 out vectors. They're the
767 ones we'll be using for the async reply. */
768 nreq->out.vector_count -= 3;
770 smb2_setup_nbt_length(nreq->out.vector,
771 nreq->out.vector_count);
773 /* Step back to the previous reply. */
774 i = nreq->current_idx - 3;
775 outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
776 /* And end the chain. */
777 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
779 /* Calculate outgoing credits */
780 smb2_calculate_credits(req, nreq);
782 /* Re-sign if needed. */
783 if (nreq->do_signing) {
785 status = smb2_signing_sign_pdu(nreq->session->session_key,
786 &nreq->out.vector[i], 3);
787 if (!NT_STATUS_IS_OK(status)) {
791 if (DEBUGLEVEL >= 10) {
792 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
793 (unsigned int)nreq->current_idx );
794 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
795 (unsigned int)nreq->out.vector_count );
796 print_req_vectors(nreq);
798 nreq->subreq = tstream_writev_queue_send(nreq,
799 nreq->sconn->smb2.event_ctx,
800 nreq->sconn->smb2.stream,
801 nreq->sconn->smb2.send_queue,
803 nreq->out.vector_count);
805 if (nreq->subreq == NULL) {
806 return NT_STATUS_NO_MEMORY;
809 tevent_req_set_callback(nreq->subreq,
810 smbd_smb2_request_writev_done,
816 struct smbd_smb2_request_pending_state {
817 struct smbd_server_connection *sconn;
818 uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
819 struct iovec vector[3];
822 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
824 struct smbd_smb2_request_pending_state *state =
825 tevent_req_callback_data(subreq,
826 struct smbd_smb2_request_pending_state);
827 struct smbd_server_connection *sconn = state->sconn;
831 ret = tstream_writev_queue_recv(subreq, &sys_errno);
834 NTSTATUS status = map_nt_error_from_unix(sys_errno);
835 smbd_server_connection_terminate(sconn, nt_errstr(status));
842 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
843 struct tevent_req *subreq)
846 struct smbd_smb2_request_pending_state *state = NULL;
847 int i = req->current_idx;
848 uint8_t *reqhdr = NULL;
850 uint8_t *body = NULL;
852 uint64_t message_id = 0;
853 uint64_t async_id = 0;
854 struct iovec *outvec = NULL;
856 if (!tevent_req_is_in_progress(subreq)) {
860 req->subreq = subreq;
864 /* We're already async. */
868 if (req->in.vector_count > i + 3) {
870 * We're trying to go async in a compound
871 * request chain. This is not allowed.
872 * Cancel the outstanding request.
874 tevent_req_cancel(req->subreq);
875 return smbd_smb2_request_error(req,
876 NT_STATUS_INSUFFICIENT_RESOURCES);
879 if (DEBUGLEVEL >= 10) {
880 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
881 (unsigned int)req->current_idx );
882 print_req_vectors(req);
885 if (req->out.vector_count > 4) {
886 /* This is a compound reply. We
887 * must do an interim response
888 * followed by the async response
891 status = smb2_send_async_interim_response(req);
892 if (!NT_STATUS_IS_OK(status)) {
897 * We're splitting off the last SMB2
898 * request in a compound set, and the
899 * smb2_send_async_interim_response()
900 * call above just sent all the replies
901 * for the previous SMB2 requests in
902 * this compound set. So we're no longer
903 * in the "compound_related_in_progress"
904 * state, and this is no longer a compound
907 req->compound_related = false;
908 req->sconn->smb2.compound_related_in_progress = false;
911 /* Don't return an intermediate packet on a pipe read/write. */
912 if (req->tcon && req->tcon->compat_conn && IS_IPC(req->tcon->compat_conn)) {
916 reqhdr = (uint8_t *)req->out.vector[i].iov_base;
917 flags = (IVAL(reqhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
918 message_id = BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
919 async_id = message_id; /* keep it simple for now... */
922 * What we send is identical to a smbd_smb2_request_error
923 * packet with an error status of STATUS_PENDING. Make use
924 * of this fact sometime when refactoring. JRA.
927 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
929 return NT_STATUS_NO_MEMORY;
931 state->sconn = req->sconn;
933 state->vector[0].iov_base = (void *)state->buf;
934 state->vector[0].iov_len = 4;
936 state->vector[1].iov_base = state->buf + 4;
937 state->vector[1].iov_len = SMB2_HDR_BODY;
939 state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
940 state->vector[2].iov_len = 9;
942 smb2_setup_nbt_length(state->vector, 3);
944 hdr = (uint8_t *)state->vector[1].iov_base;
945 body = (uint8_t *)state->vector[2].iov_base;
947 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
948 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
949 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
950 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
951 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE));
953 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
954 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
955 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
956 SBVAL(hdr, SMB2_HDR_PID, async_id);
957 SBVAL(hdr, SMB2_HDR_SESSION_ID,
958 BVAL(reqhdr, SMB2_HDR_SESSION_ID));
959 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
961 SSVAL(body, 0x00, 0x08 + 1);
963 SCVAL(body, 0x02, 0);
964 SCVAL(body, 0x03, 0);
965 SIVAL(body, 0x04, 0);
966 /* Match W2K8R2... */
967 SCVAL(body, 0x08, 0x21);
969 /* Ensure we correctly go through crediting. Grant
970 the credits now, and zero credits on the final
972 smb2_set_operation_credit(req->sconn,
976 if (req->do_signing) {
977 status = smb2_signing_sign_pdu(req->session->session_key,
978 &state->vector[1], 2);
979 if (!NT_STATUS_IS_OK(status)) {
984 subreq = tstream_writev_queue_send(state,
985 req->sconn->smb2.event_ctx,
986 req->sconn->smb2.stream,
987 req->sconn->smb2.send_queue,
991 if (subreq == NULL) {
992 return NT_STATUS_NO_MEMORY;
995 tevent_req_set_callback(subreq,
996 smbd_smb2_request_pending_writev_done,
999 /* Note we're going async with this request. */
1005 * Now manipulate req so that the outstanding async request
1006 * is the only one left in the struct smbd_smb2_request.
1009 if (req->current_idx == 1) {
1010 /* There was only one. */
1014 /* Re-arrange the in.vectors. */
1015 req->in.vector[1] = req->in.vector[i];
1016 req->in.vector[2] = req->in.vector[i+1];
1017 req->in.vector[3] = req->in.vector[i+2];
1018 req->in.vector_count = 4;
1019 /* Reset the new in size. */
1020 smb2_setup_nbt_length(req->in.vector, 4);
1022 /* Now recreate the out.vectors. */
1023 outvec = talloc_zero_array(req, struct iovec, 4);
1025 return NT_STATUS_NO_MEMORY;
1028 /* 0 is always boilerplate and must
1029 * be of size 4 for the length field. */
1031 outvec[0].iov_base = req->out.nbt_hdr;
1032 outvec[0].iov_len = 4;
1033 SIVAL(req->out.nbt_hdr, 0, 0);
1035 if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
1036 return NT_STATUS_NO_MEMORY;
1039 TALLOC_FREE(req->out.vector);
1041 req->out.vector = outvec;
1043 req->current_idx = 1;
1044 req->out.vector_count = 4;
1048 smb2_setup_nbt_length(req->out.vector,
1049 req->out.vector_count);
1052 /* Ensure our final reply matches the interim one. */
1053 reqhdr = (uint8_t *)req->out.vector[1].iov_base;
1054 SIVAL(reqhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1055 SBVAL(reqhdr, SMB2_HDR_PID, async_id);
1058 const uint8_t *inhdr =
1059 (const uint8_t *)req->in.vector[1].iov_base;
1060 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1062 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1063 (unsigned long long)async_id ));
1067 return NT_STATUS_OK;
1070 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1072 struct smbd_server_connection *sconn = req->sconn;
1073 struct smbd_smb2_request *cur;
1074 const uint8_t *inhdr;
1075 int i = req->current_idx;
1077 uint64_t search_message_id;
1078 uint64_t search_async_id;
1081 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1083 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1084 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1085 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1088 * we don't need the request anymore
1089 * cancel requests never have a response
1091 DLIST_REMOVE(req->sconn->smb2.requests, req);
1094 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1095 const uint8_t *outhdr;
1096 uint64_t message_id;
1099 i = cur->current_idx;
1101 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
1103 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1104 async_id = BVAL(outhdr, SMB2_HDR_PID);
1106 if (flags & SMB2_HDR_FLAG_ASYNC) {
1107 if (search_async_id == async_id) {
1108 found_id = async_id;
1112 if (search_message_id == message_id) {
1113 found_id = message_id;
1119 if (cur && cur->subreq) {
1120 inhdr = (const uint8_t *)cur->in.vector[i].iov_base;
1121 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1122 "cancel opcode[%s] mid %llu\n",
1123 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1124 (unsigned long long)found_id ));
1125 tevent_req_cancel(cur->subreq);
1128 return NT_STATUS_OK;
1131 /*************************************************************
1132 Ensure an incoming tid is a valid one for us to access.
1133 Change to the associated uid credentials and chdir to the
1134 valid tid directory.
1135 *************************************************************/
1137 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1139 const uint8_t *inhdr;
1140 const uint8_t *outhdr;
1141 int i = req->current_idx;
1144 struct smbd_smb2_tcon *tcon;
1145 bool chained_fixup = false;
1147 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1149 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1151 if (in_tid == (0xFFFFFFFF)) {
1154 * async request - fill in tid from
1155 * already setup out.vector[].iov_base.
1157 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1158 in_tid = IVAL(outhdr, SMB2_HDR_TID);
1161 * Chained request - fill in tid from
1162 * the previous request out.vector[].iov_base.
1164 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1165 in_tid = IVAL(outhdr, SMB2_HDR_TID);
1166 chained_fixup = true;
1170 /* lookup an existing session */
1171 p = idr_find(req->session->tcons.idtree, in_tid);
1173 return NT_STATUS_NETWORK_NAME_DELETED;
1175 tcon = talloc_get_type_abort(p, struct smbd_smb2_tcon);
1177 if (!change_to_user(tcon->compat_conn,req->session->vuid)) {
1178 return NT_STATUS_ACCESS_DENIED;
1181 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1182 if (!set_current_service(tcon->compat_conn, 0, true)) {
1183 return NT_STATUS_ACCESS_DENIED;
1188 if (chained_fixup) {
1189 /* Fix up our own outhdr. */
1190 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1191 SIVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_TID, in_tid);
1194 return NT_STATUS_OK;
1197 /*************************************************************
1198 Ensure an incoming session_id is a valid one for us to access.
1199 *************************************************************/
1201 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1203 const uint8_t *inhdr;
1204 const uint8_t *outhdr;
1205 int i = req->current_idx;
1206 uint64_t in_session_id;
1208 struct smbd_smb2_session *session;
1209 bool chained_fixup = false;
1211 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1213 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1215 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
1218 * async request - fill in session_id from
1219 * already setup request out.vector[].iov_base.
1221 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1222 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1225 * Chained request - fill in session_id from
1226 * the previous request out.vector[].iov_base.
1228 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1229 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1230 chained_fixup = true;
1234 /* lookup an existing session */
1235 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
1237 return NT_STATUS_USER_SESSION_DELETED;
1239 session = talloc_get_type_abort(p, struct smbd_smb2_session);
1241 if (!NT_STATUS_IS_OK(session->status)) {
1242 return NT_STATUS_ACCESS_DENIED;
1245 set_current_user_info(session->session_info->unix_info->sanitized_username,
1246 session->session_info->unix_info->unix_name,
1247 session->session_info->info->domain_name);
1249 req->session = session;
1251 if (chained_fixup) {
1252 /* Fix up our own outhdr. */
1253 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1254 SBVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_SESSION_ID, in_session_id);
1256 return NT_STATUS_OK;
1259 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1260 size_t expected_body_size)
1262 const uint8_t *inhdr;
1264 const uint8_t *inbody;
1265 int i = req->current_idx;
1267 size_t min_dyn_size = expected_body_size & 0x00000001;
1270 * The following should be checked already.
1272 if ((i+2) > req->in.vector_count) {
1273 return NT_STATUS_INTERNAL_ERROR;
1275 if (req->in.vector[i+0].iov_len != SMB2_HDR_BODY) {
1276 return NT_STATUS_INTERNAL_ERROR;
1278 if (req->in.vector[i+1].iov_len < 2) {
1279 return NT_STATUS_INTERNAL_ERROR;
1282 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1283 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1286 case SMB2_OP_GETINFO:
1292 * Now check the expected body size,
1293 * where the last byte might be in the
1294 * dynnamic section..
1296 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1297 return NT_STATUS_INVALID_PARAMETER;
1299 if (req->in.vector[i+2].iov_len < min_dyn_size) {
1300 return NT_STATUS_INVALID_PARAMETER;
1303 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1305 body_size = SVAL(inbody, 0x00);
1306 if (body_size != expected_body_size) {
1307 return NT_STATUS_INVALID_PARAMETER;
1310 return NT_STATUS_OK;
1313 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1315 const uint8_t *inhdr;
1316 int i = req->current_idx;
1321 NTSTATUS session_status;
1322 uint32_t allowed_flags;
1323 NTSTATUS return_value;
1325 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1327 /* TODO: verify more things */
1329 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1330 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1331 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1332 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1333 smb2_opcode_name(opcode),
1334 (unsigned long long)mid));
1336 if (get_Protocol() >= PROTOCOL_SMB2_02) {
1338 * once the protocol is negotiated
1339 * SMB2_OP_NEGPROT is not allowed anymore
1341 if (opcode == SMB2_OP_NEGPROT) {
1342 /* drop the connection */
1343 return NT_STATUS_INVALID_PARAMETER;
1347 * if the protocol is not negotiated yet
1348 * only SMB2_OP_NEGPROT is allowed.
1350 if (opcode != SMB2_OP_NEGPROT) {
1351 /* drop the connection */
1352 return NT_STATUS_INVALID_PARAMETER;
1356 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1357 SMB2_HDR_FLAG_SIGNED |
1359 if (opcode == SMB2_OP_CANCEL) {
1360 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1362 if ((flags & ~allowed_flags) != 0) {
1363 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1367 * Check if the client provided a valid session id,
1368 * if so smbd_smb2_request_check_session() calls
1369 * set_current_user_info().
1371 * As some command don't require a valid session id
1372 * we defer the check of the session_status
1374 session_status = smbd_smb2_request_check_session(req);
1376 req->do_signing = false;
1377 if (flags & SMB2_HDR_FLAG_SIGNED) {
1378 if (!NT_STATUS_IS_OK(session_status)) {
1379 return smbd_smb2_request_error(req, session_status);
1382 req->do_signing = true;
1383 status = smb2_signing_check_pdu(req->session->session_key,
1384 &req->in.vector[i], 3);
1385 if (!NT_STATUS_IS_OK(status)) {
1386 return smbd_smb2_request_error(req, status);
1388 } else if (opcode == SMB2_OP_CANCEL) {
1389 /* Cancel requests are allowed to skip the signing */
1390 } else if (req->session && req->session->do_signing) {
1391 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1394 if (flags & SMB2_HDR_FLAG_CHAINED) {
1396 * This check is mostly for giving the correct error code
1397 * for compounded requests.
1399 * TODO: we may need to move this after the session
1402 if (!NT_STATUS_IS_OK(req->next_status)) {
1403 return smbd_smb2_request_error(req, req->next_status);
1406 req->compat_chain_fsp = NULL;
1409 if (req->compound_related) {
1410 req->sconn->smb2.compound_related_in_progress = true;
1414 case SMB2_OP_NEGPROT:
1415 /* This call needs to be run as root */
1416 change_to_root_user();
1419 START_PROFILE(smb2_negprot);
1420 return_value = smbd_smb2_request_process_negprot(req);
1421 END_PROFILE(smb2_negprot);
1425 case SMB2_OP_SESSSETUP:
1426 /* This call needs to be run as root */
1427 change_to_root_user();
1430 START_PROFILE(smb2_sesssetup);
1431 return_value = smbd_smb2_request_process_sesssetup(req);
1432 END_PROFILE(smb2_sesssetup);
1436 case SMB2_OP_LOGOFF:
1437 if (!NT_STATUS_IS_OK(session_status)) {
1438 return_value = smbd_smb2_request_error(req, session_status);
1442 /* This call needs to be run as root */
1443 change_to_root_user();
1446 START_PROFILE(smb2_logoff);
1447 return_value = smbd_smb2_request_process_logoff(req);
1448 END_PROFILE(smb2_logoff);
1453 if (!NT_STATUS_IS_OK(session_status)) {
1454 return_value = smbd_smb2_request_error(req, session_status);
1459 * This call needs to be run as root.
1461 * smbd_smb2_request_process_tcon()
1462 * calls make_connection_snum(), which will call
1463 * change_to_user(), when needed.
1465 change_to_root_user();
1468 START_PROFILE(smb2_tcon);
1469 return_value = smbd_smb2_request_process_tcon(req);
1470 END_PROFILE(smb2_tcon);
1475 if (!NT_STATUS_IS_OK(session_status)) {
1476 return_value = smbd_smb2_request_error(req, session_status);
1480 * This call needs to be run as user.
1482 * smbd_smb2_request_check_tcon()
1483 * calls change_to_user() on success.
1485 status = smbd_smb2_request_check_tcon(req);
1486 if (!NT_STATUS_IS_OK(status)) {
1487 return_value = smbd_smb2_request_error(req, status);
1490 /* This call needs to be run as root */
1491 change_to_root_user();
1495 START_PROFILE(smb2_tdis);
1496 return_value = smbd_smb2_request_process_tdis(req);
1497 END_PROFILE(smb2_tdis);
1501 case SMB2_OP_CREATE:
1502 if (!NT_STATUS_IS_OK(session_status)) {
1503 return_value = smbd_smb2_request_error(req, session_status);
1507 * This call needs to be run as user.
1509 * smbd_smb2_request_check_tcon()
1510 * calls change_to_user() on success.
1512 status = smbd_smb2_request_check_tcon(req);
1513 if (!NT_STATUS_IS_OK(status)) {
1514 return_value = smbd_smb2_request_error(req, status);
1519 START_PROFILE(smb2_create);
1520 return_value = smbd_smb2_request_process_create(req);
1521 END_PROFILE(smb2_create);
1526 if (!NT_STATUS_IS_OK(session_status)) {
1527 return_value = smbd_smb2_request_error(req, session_status);
1531 * This call needs to be run as user.
1533 * smbd_smb2_request_check_tcon()
1534 * calls change_to_user() on success.
1536 status = smbd_smb2_request_check_tcon(req);
1537 if (!NT_STATUS_IS_OK(status)) {
1538 return_value = smbd_smb2_request_error(req, status);
1543 START_PROFILE(smb2_close);
1544 return_value = smbd_smb2_request_process_close(req);
1545 END_PROFILE(smb2_close);
1550 if (!NT_STATUS_IS_OK(session_status)) {
1551 return_value = smbd_smb2_request_error(req, session_status);
1555 * This call needs to be run as user.
1557 * smbd_smb2_request_check_tcon()
1558 * calls change_to_user() on success.
1560 status = smbd_smb2_request_check_tcon(req);
1561 if (!NT_STATUS_IS_OK(status)) {
1562 return_value = smbd_smb2_request_error(req, status);
1567 START_PROFILE(smb2_flush);
1568 return_value = smbd_smb2_request_process_flush(req);
1569 END_PROFILE(smb2_flush);
1574 if (!NT_STATUS_IS_OK(session_status)) {
1575 return_value = smbd_smb2_request_error(req, session_status);
1579 * This call needs to be run as user.
1581 * smbd_smb2_request_check_tcon()
1582 * calls change_to_user() on success.
1584 status = smbd_smb2_request_check_tcon(req);
1585 if (!NT_STATUS_IS_OK(status)) {
1586 return_value = smbd_smb2_request_error(req, status);
1591 START_PROFILE(smb2_read);
1592 return_value = smbd_smb2_request_process_read(req);
1593 END_PROFILE(smb2_read);
1598 if (!NT_STATUS_IS_OK(session_status)) {
1599 return_value = smbd_smb2_request_error(req, session_status);
1603 * This call needs to be run as user.
1605 * smbd_smb2_request_check_tcon()
1606 * calls change_to_user() on success.
1608 status = smbd_smb2_request_check_tcon(req);
1609 if (!NT_STATUS_IS_OK(status)) {
1610 return_value = smbd_smb2_request_error(req, status);
1615 START_PROFILE(smb2_write);
1616 return_value = smbd_smb2_request_process_write(req);
1617 END_PROFILE(smb2_write);
1622 if (!NT_STATUS_IS_OK(session_status)) {
1623 /* Too ugly to live ? JRA. */
1624 if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
1625 session_status = NT_STATUS_FILE_CLOSED;
1627 return_value = smbd_smb2_request_error(req, session_status);
1631 * This call needs to be run as user.
1633 * smbd_smb2_request_check_tcon()
1634 * calls change_to_user() on success.
1636 status = smbd_smb2_request_check_tcon(req);
1637 if (!NT_STATUS_IS_OK(status)) {
1638 /* Too ugly to live ? JRA. */
1639 if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
1640 status = NT_STATUS_FILE_CLOSED;
1642 return_value = smbd_smb2_request_error(req, status);
1647 START_PROFILE(smb2_lock);
1648 return_value = smbd_smb2_request_process_lock(req);
1649 END_PROFILE(smb2_lock);
1654 if (!NT_STATUS_IS_OK(session_status)) {
1655 return_value = smbd_smb2_request_error(req, session_status);
1659 * This call needs to be run as user.
1661 * smbd_smb2_request_check_tcon()
1662 * calls change_to_user() on success.
1664 status = smbd_smb2_request_check_tcon(req);
1665 if (!NT_STATUS_IS_OK(status)) {
1666 return_value = smbd_smb2_request_error(req, status);
1671 START_PROFILE(smb2_ioctl);
1672 return_value = smbd_smb2_request_process_ioctl(req);
1673 END_PROFILE(smb2_ioctl);
1677 case SMB2_OP_CANCEL:
1679 * This call needs to be run as root
1681 * That is what we also do in the SMB1 case.
1683 change_to_root_user();
1686 START_PROFILE(smb2_cancel);
1687 return_value = smbd_smb2_request_process_cancel(req);
1688 END_PROFILE(smb2_cancel);
1692 case SMB2_OP_KEEPALIVE:
1693 /* This call needs to be run as root */
1694 change_to_root_user();
1697 START_PROFILE(smb2_keepalive);
1698 return_value = smbd_smb2_request_process_keepalive(req);
1699 END_PROFILE(smb2_keepalive);
1704 if (!NT_STATUS_IS_OK(session_status)) {
1705 return_value = smbd_smb2_request_error(req, session_status);
1709 * This call needs to be run as user.
1711 * smbd_smb2_request_check_tcon()
1712 * calls change_to_user() on success.
1714 status = smbd_smb2_request_check_tcon(req);
1715 if (!NT_STATUS_IS_OK(status)) {
1716 return_value = smbd_smb2_request_error(req, status);
1721 START_PROFILE(smb2_find);
1722 return_value = smbd_smb2_request_process_find(req);
1723 END_PROFILE(smb2_find);
1727 case SMB2_OP_NOTIFY:
1728 if (!NT_STATUS_IS_OK(session_status)) {
1729 return_value = smbd_smb2_request_error(req, session_status);
1733 * This call needs to be run as user.
1735 * smbd_smb2_request_check_tcon()
1736 * calls change_to_user() on success.
1738 status = smbd_smb2_request_check_tcon(req);
1739 if (!NT_STATUS_IS_OK(status)) {
1740 return_value = smbd_smb2_request_error(req, status);
1745 START_PROFILE(smb2_notify);
1746 return_value = smbd_smb2_request_process_notify(req);
1747 END_PROFILE(smb2_notify);
1751 case SMB2_OP_GETINFO:
1752 if (!NT_STATUS_IS_OK(session_status)) {
1753 return_value = smbd_smb2_request_error(req, session_status);
1757 * This call needs to be run as user.
1759 * smbd_smb2_request_check_tcon()
1760 * calls change_to_user() on success.
1762 status = smbd_smb2_request_check_tcon(req);
1763 if (!NT_STATUS_IS_OK(status)) {
1764 return_value = smbd_smb2_request_error(req, status);
1769 START_PROFILE(smb2_getinfo);
1770 return_value = smbd_smb2_request_process_getinfo(req);
1771 END_PROFILE(smb2_getinfo);
1775 case SMB2_OP_SETINFO:
1776 if (!NT_STATUS_IS_OK(session_status)) {
1777 return_value = smbd_smb2_request_error(req, session_status);
1781 * This call needs to be run as user.
1783 * smbd_smb2_request_check_tcon()
1784 * calls change_to_user() on success.
1786 status = smbd_smb2_request_check_tcon(req);
1787 if (!NT_STATUS_IS_OK(status)) {
1788 return_value = smbd_smb2_request_error(req, status);
1793 START_PROFILE(smb2_setinfo);
1794 return_value = smbd_smb2_request_process_setinfo(req);
1795 END_PROFILE(smb2_setinfo);
1800 if (!NT_STATUS_IS_OK(session_status)) {
1801 return_value = smbd_smb2_request_error(req, session_status);
1805 * This call needs to be run as user.
1807 * smbd_smb2_request_check_tcon()
1808 * calls change_to_user() on success.
1810 status = smbd_smb2_request_check_tcon(req);
1811 if (!NT_STATUS_IS_OK(status)) {
1812 return_value = smbd_smb2_request_error(req, status);
1817 START_PROFILE(smb2_break);
1818 return_value = smbd_smb2_request_process_break(req);
1819 END_PROFILE(smb2_break);
1824 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1827 return return_value;
1830 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
1832 struct tevent_req *subreq;
1833 int i = req->current_idx;
1837 req->current_idx += 3;
1839 if (req->current_idx < req->out.vector_count) {
1841 * We must process the remaining compound
1842 * SMB2 requests before any new incoming SMB2
1843 * requests. This is because incoming SMB2
1844 * requests may include a cancel for a
1845 * compound request we haven't processed
1848 struct tevent_immediate *im = tevent_create_immediate(req);
1850 return NT_STATUS_NO_MEMORY;
1852 tevent_schedule_immediate(im,
1853 req->sconn->smb2.event_ctx,
1854 smbd_smb2_request_dispatch_immediate,
1856 return NT_STATUS_OK;
1859 if (req->compound_related) {
1860 req->sconn->smb2.compound_related_in_progress = false;
1863 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
1865 /* Set credit for this operation (zero credits if this
1866 is a final reply for an async operation). */
1867 smb2_set_operation_credit(req->sconn,
1869 &req->out.vector[i]);
1871 if (req->do_signing) {
1873 status = smb2_signing_sign_pdu(req->session->session_key,
1874 &req->out.vector[i], 3);
1875 if (!NT_STATUS_IS_OK(status)) {
1880 if (DEBUGLEVEL >= 10) {
1881 dbgtext("smbd_smb2_request_reply: sending...\n");
1882 print_req_vectors(req);
1885 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
1886 if (req->out.vector_count == 4 &&
1887 req->out.vector[3].iov_base == NULL &&
1888 req->out.vector[3].iov_len != 0) {
1889 /* Dynamic part is NULL. Chop it off,
1890 We're going to send it via sendfile. */
1891 req->out.vector_count -= 1;
1894 subreq = tstream_writev_queue_send(req,
1895 req->sconn->smb2.event_ctx,
1896 req->sconn->smb2.stream,
1897 req->sconn->smb2.send_queue,
1899 req->out.vector_count);
1900 if (subreq == NULL) {
1901 return NT_STATUS_NO_MEMORY;
1903 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
1905 * We're done with this request -
1906 * move it off the "being processed" queue.
1908 DLIST_REMOVE(req->sconn->smb2.requests, req);
1910 return NT_STATUS_OK;
1913 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
1915 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
1916 struct tevent_immediate *im,
1919 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
1920 struct smbd_smb2_request);
1921 struct smbd_server_connection *sconn = req->sconn;
1926 if (DEBUGLEVEL >= 10) {
1927 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
1928 req->current_idx, req->in.vector_count));
1929 print_req_vectors(req);
1932 status = smbd_smb2_request_dispatch(req);
1933 if (!NT_STATUS_IS_OK(status)) {
1934 smbd_server_connection_terminate(sconn, nt_errstr(status));
1938 status = smbd_smb2_request_next_incoming(sconn);
1939 if (!NT_STATUS_IS_OK(status)) {
1940 smbd_server_connection_terminate(sconn, nt_errstr(status));
1945 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
1947 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
1948 struct smbd_smb2_request);
1949 struct smbd_server_connection *sconn = req->sconn;
1954 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1955 TALLOC_FREE(subreq);
1958 status = map_nt_error_from_unix(sys_errno);
1959 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
1960 nt_errstr(status)));
1961 smbd_server_connection_terminate(sconn, nt_errstr(status));
1965 status = smbd_smb2_request_next_incoming(sconn);
1966 if (!NT_STATUS_IS_OK(status)) {
1967 smbd_server_connection_terminate(sconn, nt_errstr(status));
1972 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
1974 DATA_BLOB body, DATA_BLOB *dyn,
1975 const char *location)
1978 int i = req->current_idx;
1979 uint32_t next_command_ofs;
1981 DEBUG(10,("smbd_smb2_request_done_ex: "
1982 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
1983 i, nt_errstr(status), (unsigned int)body.length,
1985 (unsigned int)(dyn ? dyn->length : 0),
1988 if (body.length < 2) {
1989 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1992 if ((body.length % 2) != 0) {
1993 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1996 outhdr = (uint8_t *)req->out.vector[i].iov_base;
1998 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
1999 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2001 req->out.vector[i+1].iov_base = (void *)body.data;
2002 req->out.vector[i+1].iov_len = body.length;
2005 req->out.vector[i+2].iov_base = (void *)dyn->data;
2006 req->out.vector[i+2].iov_len = dyn->length;
2008 req->out.vector[i+2].iov_base = NULL;
2009 req->out.vector[i+2].iov_len = 0;
2012 /* see if we need to recalculate the offset to the next response */
2013 if (next_command_ofs > 0) {
2014 next_command_ofs = SMB2_HDR_BODY;
2015 next_command_ofs += req->out.vector[i+1].iov_len;
2016 next_command_ofs += req->out.vector[i+2].iov_len;
2019 if ((next_command_ofs % 8) != 0) {
2020 size_t pad_size = 8 - (next_command_ofs % 8);
2021 if (req->out.vector[i+2].iov_len == 0) {
2023 * if the dyn buffer is empty
2024 * we can use it to add padding
2028 pad = talloc_zero_array(req->out.vector,
2031 return smbd_smb2_request_error(req,
2032 NT_STATUS_NO_MEMORY);
2035 req->out.vector[i+2].iov_base = (void *)pad;
2036 req->out.vector[i+2].iov_len = pad_size;
2039 * For now we copy the dynamic buffer
2040 * and add the padding to the new buffer
2047 old_size = req->out.vector[i+2].iov_len;
2048 old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
2050 new_size = old_size + pad_size;
2051 new_dyn = talloc_zero_array(req->out.vector,
2053 if (new_dyn == NULL) {
2054 return smbd_smb2_request_error(req,
2055 NT_STATUS_NO_MEMORY);
2058 memcpy(new_dyn, old_dyn, old_size);
2059 memset(new_dyn + old_size, 0, pad_size);
2061 req->out.vector[i+2].iov_base = (void *)new_dyn;
2062 req->out.vector[i+2].iov_len = new_size;
2064 next_command_ofs += pad_size;
2067 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2069 return smbd_smb2_request_reply(req);
2072 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2075 const char *location)
2078 int i = req->current_idx;
2079 uint8_t *outhdr = (uint8_t *)req->out.vector[i].iov_base;
2081 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2082 i, nt_errstr(status), info ? " +info" : "",
2085 body.data = outhdr + SMB2_HDR_BODY;
2087 SSVAL(body.data, 0, 9);
2090 SIVAL(body.data, 0x04, info->length);
2092 /* Allocated size of req->out.vector[i].iov_base
2093 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2094 * 1 byte without having to do an alloc.
2096 info = talloc_zero_array(req->out.vector,
2100 return NT_STATUS_NO_MEMORY;
2102 info->data = ((uint8_t *)outhdr) +
2103 OUTVEC_ALLOC_SIZE - 1;
2105 SCVAL(info->data, 0, 0);
2109 * if a request fails, all other remaining
2110 * compounded requests should fail too
2112 req->next_status = NT_STATUS_INVALID_PARAMETER;
2114 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2118 struct smbd_smb2_send_oplock_break_state {
2119 struct smbd_server_connection *sconn;
2120 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
2121 struct iovec vector;
2124 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2126 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2127 uint64_t file_id_persistent,
2128 uint64_t file_id_volatile,
2129 uint8_t oplock_level)
2131 struct smbd_smb2_send_oplock_break_state *state;
2132 struct tevent_req *subreq;
2136 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2137 if (state == NULL) {
2138 return NT_STATUS_NO_MEMORY;
2140 state->sconn = sconn;
2142 state->vector.iov_base = (void *)state->buf;
2143 state->vector.iov_len = sizeof(state->buf);
2145 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
2146 hdr = state->buf + 4;
2147 body = hdr + SMB2_HDR_BODY;
2149 SIVAL(hdr, 0, SMB2_MAGIC);
2150 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2151 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2152 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2153 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2154 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2155 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2156 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2157 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2158 SIVAL(hdr, SMB2_HDR_PID, 0);
2159 SIVAL(hdr, SMB2_HDR_TID, 0);
2160 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2161 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2163 SSVAL(body, 0x00, 0x18);
2165 SCVAL(body, 0x02, oplock_level);
2166 SCVAL(body, 0x03, 0); /* reserved */
2167 SIVAL(body, 0x04, 0); /* reserved */
2168 SBVAL(body, 0x08, file_id_persistent);
2169 SBVAL(body, 0x10, file_id_volatile);
2171 subreq = tstream_writev_queue_send(state,
2172 sconn->smb2.event_ctx,
2174 sconn->smb2.send_queue,
2176 if (subreq == NULL) {
2177 return NT_STATUS_NO_MEMORY;
2179 tevent_req_set_callback(subreq,
2180 smbd_smb2_oplock_break_writev_done,
2183 return NT_STATUS_OK;
2186 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2188 struct smbd_smb2_send_oplock_break_state *state =
2189 tevent_req_callback_data(subreq,
2190 struct smbd_smb2_send_oplock_break_state);
2191 struct smbd_server_connection *sconn = state->sconn;
2195 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2196 TALLOC_FREE(subreq);
2198 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2199 smbd_server_connection_terminate(sconn, nt_errstr(status));
2206 struct smbd_smb2_request_read_state {
2208 bool asked_for_header;
2209 struct smbd_smb2_request *smb2_req;
2212 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2214 TALLOC_CTX *mem_ctx,
2215 struct iovec **_vector,
2217 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2219 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2220 struct tevent_context *ev,
2221 struct smbd_server_connection *sconn)
2223 struct tevent_req *req;
2224 struct smbd_smb2_request_read_state *state;
2225 struct tevent_req *subreq;
2227 req = tevent_req_create(mem_ctx, &state,
2228 struct smbd_smb2_request_read_state);
2233 state->asked_for_header = false;
2235 state->smb2_req = smbd_smb2_request_allocate(state);
2236 if (tevent_req_nomem(state->smb2_req, req)) {
2237 return tevent_req_post(req, ev);
2239 state->smb2_req->sconn = sconn;
2241 subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
2242 sconn->smb2.recv_queue,
2243 smbd_smb2_request_next_vector,
2245 if (tevent_req_nomem(subreq, req)) {
2246 return tevent_req_post(req, ev);
2248 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2253 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2255 TALLOC_CTX *mem_ctx,
2256 struct iovec **_vector,
2259 struct smbd_smb2_request_read_state *state =
2260 talloc_get_type_abort(private_data,
2261 struct smbd_smb2_request_read_state);
2262 struct smbd_smb2_request *req = state->smb2_req;
2263 struct iovec *vector;
2264 int idx = req->in.vector_count;
2266 uint8_t *buf = NULL;
2268 if (req->in.vector_count == 0) {
2270 * first we need to get the NBT header
2272 req->in.vector = talloc_array(req, struct iovec,
2273 req->in.vector_count + 1);
2274 if (req->in.vector == NULL) {
2277 req->in.vector_count += 1;
2279 req->in.vector[idx].iov_base = (void *)req->in.nbt_hdr;
2280 req->in.vector[idx].iov_len = 4;
2282 vector = talloc_array(mem_ctx, struct iovec, 1);
2283 if (vector == NULL) {
2287 vector[0] = req->in.vector[idx];
2294 if (req->in.vector_count == 1) {
2296 * Now we analyze the NBT header
2298 state->missing = smb2_len(req->in.vector[0].iov_base);
2300 if (state->missing == 0) {
2301 /* if there're no remaining bytes, we're done */
2307 req->in.vector = talloc_realloc(req, req->in.vector,
2309 req->in.vector_count + 1);
2310 if (req->in.vector == NULL) {
2313 req->in.vector_count += 1;
2315 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
2317 * it's a special NBT message,
2318 * so get all remaining bytes
2320 len = state->missing;
2321 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
2323 * it's an invalid message, just read what we can get
2324 * and let the caller handle the error
2326 len = state->missing;
2329 * We assume it's a SMB2 request,
2330 * and we first get the header and the
2331 * first 2 bytes (the struct size) of the body
2333 len = SMB2_HDR_BODY + 2;
2335 state->asked_for_header = true;
2338 state->missing -= len;
2340 buf = talloc_array(req->in.vector, uint8_t, len);
2345 req->in.vector[idx].iov_base = (void *)buf;
2346 req->in.vector[idx].iov_len = len;
2348 vector = talloc_array(mem_ctx, struct iovec, 1);
2349 if (vector == NULL) {
2353 vector[0] = req->in.vector[idx];
2360 if (state->missing == 0) {
2361 /* if there're no remaining bytes, we're done */
2367 if (state->asked_for_header) {
2370 size_t next_command_ofs;
2375 bool invalid = false;
2377 state->asked_for_header = false;
2380 * We got the SMB2 header and the first 2 bytes
2381 * of the body. We fix the size to just the header
2382 * and manually copy the 2 first bytes to the body section
2384 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
2385 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
2387 /* allocate vectors for body and dynamic areas */
2388 req->in.vector = talloc_realloc(req, req->in.vector,
2390 req->in.vector_count + 2);
2391 if (req->in.vector == NULL) {
2394 req->in.vector_count += 2;
2396 full_size = state->missing + SMB2_HDR_BODY + 2;
2397 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
2398 body_size = SVAL(hdr, SMB2_HDR_BODY);
2400 if (next_command_ofs != 0) {
2401 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
2403 * this is invalid, just return a zero
2404 * body and let the caller deal with the error
2407 } else if (next_command_ofs > full_size) {
2409 * this is invalid, just return a zero
2410 * body and let the caller deal with the error
2414 full_size = next_command_ofs;
2419 if (body_size < 2) {
2421 * this is invalid, just return a zero
2422 * body and let the caller deal with the error
2428 * Mask out the lowest bit, the "dynamic" part
2433 if (body_size > (full_size - SMB2_HDR_BODY)) {
2435 * this is invalid, just return a zero
2436 * body and let the caller deal with the error
2443 /* the caller should check this */
2447 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
2449 state->missing -= (body_size - 2) + dyn_size;
2451 body = talloc_array(req->in.vector, uint8_t, body_size);
2456 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
2461 req->in.vector[idx].iov_base = (void *)body;
2462 req->in.vector[idx].iov_len = body_size;
2463 req->in.vector[idx+1].iov_base = (void *)dyn;
2464 req->in.vector[idx+1].iov_len = dyn_size;
2466 vector = talloc_array(mem_ctx, struct iovec, 2);
2467 if (vector == NULL) {
2472 * the first 2 bytes of the body were already fetched
2473 * together with the header
2475 memcpy(body, hdr + SMB2_HDR_BODY, 2);
2476 vector[0].iov_base = body + 2;
2477 vector[0].iov_len = body_size - 2;
2479 vector[1] = req->in.vector[idx+1];
2487 * when we endup here, we're looking for a new SMB2 request
2488 * next. And we ask for its header and the first 2 bytes of
2489 * the body (like we did for the first SMB2 request).
2492 req->in.vector = talloc_realloc(req, req->in.vector,
2494 req->in.vector_count + 1);
2495 if (req->in.vector == NULL) {
2498 req->in.vector_count += 1;
2501 * We assume it's a SMB2 request,
2502 * and we first get the header and the
2503 * first 2 bytes (the struct size) of the body
2505 len = SMB2_HDR_BODY + 2;
2507 if (len > state->missing) {
2508 /* let the caller handle the error */
2509 len = state->missing;
2512 state->missing -= len;
2513 state->asked_for_header = true;
2515 buf = talloc_array(req->in.vector, uint8_t, len);
2520 req->in.vector[idx].iov_base = (void *)buf;
2521 req->in.vector[idx].iov_len = len;
2523 vector = talloc_array(mem_ctx, struct iovec, 1);
2524 if (vector == NULL) {
2528 vector[0] = req->in.vector[idx];
2535 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2537 struct tevent_req *req =
2538 tevent_req_callback_data(subreq,
2544 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2546 status = map_nt_error_from_unix(sys_errno);
2547 tevent_req_nterror(req, status);
2551 tevent_req_done(req);
2554 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2555 TALLOC_CTX *mem_ctx,
2556 struct smbd_smb2_request **_smb2_req)
2558 struct smbd_smb2_request_read_state *state =
2559 tevent_req_data(req,
2560 struct smbd_smb2_request_read_state);
2563 if (tevent_req_is_nterror(req, &status)) {
2564 tevent_req_received(req);
2568 talloc_steal(mem_ctx, state->smb2_req->mem_pool);
2569 *_smb2_req = state->smb2_req;
2570 tevent_req_received(req);
2571 return NT_STATUS_OK;
2574 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2576 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2578 size_t max_send_queue_len;
2579 size_t cur_send_queue_len;
2580 struct tevent_req *subreq;
2582 if (sconn->smb2.compound_related_in_progress) {
2584 * Can't read another until the related
2587 return NT_STATUS_OK;
2590 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
2592 * if there is already a smbd_smb2_request_read
2593 * pending, we are done.
2595 return NT_STATUS_OK;
2598 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2599 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
2601 if (cur_send_queue_len > max_send_queue_len) {
2603 * if we have a lot of requests to send,
2604 * we wait until they are on the wire until we
2605 * ask for the next request.
2607 return NT_STATUS_OK;
2610 /* ask for the next request */
2611 subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
2612 if (subreq == NULL) {
2613 return NT_STATUS_NO_MEMORY;
2615 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2617 return NT_STATUS_OK;
2620 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2621 const uint8_t *inbuf, size_t size)
2624 struct smbd_smb2_request *req = NULL;
2626 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2627 (unsigned int)size));
2629 status = smbd_initialize_smb2(sconn);
2630 if (!NT_STATUS_IS_OK(status)) {
2631 smbd_server_connection_terminate(sconn, nt_errstr(status));
2635 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2636 if (!NT_STATUS_IS_OK(status)) {
2637 smbd_server_connection_terminate(sconn, nt_errstr(status));
2641 status = smbd_smb2_request_setup_out(req);
2642 if (!NT_STATUS_IS_OK(status)) {
2643 smbd_server_connection_terminate(sconn, nt_errstr(status));
2647 status = smbd_smb2_request_dispatch(req);
2648 if (!NT_STATUS_IS_OK(status)) {
2649 smbd_server_connection_terminate(sconn, nt_errstr(status));
2653 status = smbd_smb2_request_next_incoming(sconn);
2654 if (!NT_STATUS_IS_OK(status)) {
2655 smbd_server_connection_terminate(sconn, nt_errstr(status));
2659 sconn->num_requests++;
2662 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2664 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2665 struct smbd_server_connection);
2667 struct smbd_smb2_request *req = NULL;
2669 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2670 TALLOC_FREE(subreq);
2671 if (!NT_STATUS_IS_OK(status)) {
2672 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2673 nt_errstr(status)));
2674 smbd_server_connection_terminate(sconn, nt_errstr(status));
2678 if (req->in.nbt_hdr[0] != 0x00) {
2679 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
2680 req->in.nbt_hdr[0]));
2685 req->current_idx = 1;
2687 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2688 req->current_idx, req->in.vector_count));
2690 status = smbd_smb2_request_validate(req);
2691 if (!NT_STATUS_IS_OK(status)) {
2692 smbd_server_connection_terminate(sconn, nt_errstr(status));
2696 status = smbd_smb2_request_setup_out(req);
2697 if (!NT_STATUS_IS_OK(status)) {
2698 smbd_server_connection_terminate(sconn, nt_errstr(status));
2702 status = smbd_smb2_request_dispatch(req);
2703 if (!NT_STATUS_IS_OK(status)) {
2704 smbd_server_connection_terminate(sconn, nt_errstr(status));
2709 status = smbd_smb2_request_next_incoming(sconn);
2710 if (!NT_STATUS_IS_OK(status)) {
2711 smbd_server_connection_terminate(sconn, nt_errstr(status));
2715 sconn->num_requests++;
2717 /* The timeout_processing function isn't run nearly
2718 often enough to implement 'max log size' without
2719 overrunning the size of the file by many megabytes.
2720 This is especially true if we are running at debug
2721 level 10. Checking every 50 SMB2s is a nice
2722 tradeoff of performance vs log file size overrun. */
2724 if ((sconn->num_requests % 50) == 0 &&
2725 need_to_check_log_size()) {
2726 change_to_root_user();