Fix bug #8476 - Samba asserts when SMB2 client breaks the crediting rules.
[Samba/id10ts.git] / source3 / smbd / smb2_server.c
blob0ffeb4818d04786df57f76d6b65453e18db892f5
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
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/>.
22 #include "includes.h"
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 "auth.h"
33 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
35 static const char *smb2_names[] = {
36 "SMB2_NEGPROT",
37 "SMB2_SESSSETUP",
38 "SMB2_LOGOFF",
39 "SMB2_TCON",
40 "SMB2_TDIS",
41 "SMB2_CREATE",
42 "SMB2_CLOSE",
43 "SMB2_FLUSH",
44 "SMB2_READ",
45 "SMB2_WRITE",
46 "SMB2_LOCK",
47 "SMB2_IOCTL",
48 "SMB2_CANCEL",
49 "SMB2_KEEPALIVE",
50 "SMB2_FIND",
51 "SMB2_NOTIFY",
52 "SMB2_GETINFO",
53 "SMB2_SETINFO",
54 "SMB2_BREAK"
57 const char *smb2_opcode_name(uint16_t opcode)
59 if (opcode > 0x12) {
60 return "Bad SMB2 opcode";
62 return smb2_names[opcode];
65 static void print_req_vectors(struct smbd_smb2_request *req)
67 int i;
69 for (i = 0; i < req->in.vector_count; i++) {
70 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
71 (unsigned int)i,
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",
76 (unsigned int)i,
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)) {
84 return false;
87 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
88 return false;
91 return true;
94 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
96 NTSTATUS status;
97 int ret;
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);
130 if (ret == -1) {
131 status = map_nt_error_from_unix(errno);
132 return status;
135 /* Ensure child is set to non-blocking mode */
136 set_blocking(sconn->sock, false);
137 return NT_STATUS_OK;
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; \
143 buf[0] = 0; \
144 buf[1] = ((len)&0xFF0000)>>16; \
145 buf[2] = ((len)&0xFF00)>>8; \
146 buf[3] = (len)&0xFF; \
147 } while (0)
149 static void smb2_setup_nbt_length(struct iovec *vector, int count)
151 size_t len = 0;
152 int i;
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)
163 if (*req) {
164 (*req)->parent = NULL;
165 (*req)->mem_pool = NULL;
168 return 0;
171 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
173 if (req->parent) {
174 *req->parent = NULL;
175 talloc_free(req->mem_pool);
178 return 0;
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;
187 #if 0
188 /* Enable this to find subtle valgrind errors. */
189 mem_pool = talloc_init("smbd_smb2_request_allocate");
190 #else
191 mem_pool = talloc_pool(mem_ctx, 8192);
192 #endif
193 if (mem_pool == NULL) {
194 return NULL;
197 parent = talloc(mem_pool, struct smbd_smb2_request *);
198 if (parent == NULL) {
199 talloc_free(mem_pool);
200 return NULL;
203 req = talloc_zero(parent, struct smbd_smb2_request);
204 if (req == NULL) {
205 talloc_free(mem_pool);
206 return NULL;
208 *parent = req;
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);
215 return req;
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;
225 off_t ofs = 0;
226 uint16_t cmd;
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;
234 inhdr = inbuf + 4;
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",
239 protocol_version));
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",
246 cmd));
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",
253 next_command_ofs));
254 return NT_STATUS_INVALID_PARAMETER;
257 req = smbd_smb2_request_allocate(sconn);
258 if (req == NULL) {
259 return NT_STATUS_NO_MEMORY;
261 req->sconn = sconn;
263 talloc_steal(req, inbuf);
265 req->in.vector = talloc_array(req, struct iovec, 4);
266 if (req->in.vector == NULL) {
267 TALLOC_FREE(req);
268 return NT_STATUS_NO_MEMORY;
270 req->in.vector_count = 4;
272 memcpy(req->in.nbt_hdr, inbuf, 4);
274 ofs = 0;
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;
287 if (ofs > size) {
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;
297 *_req = req;
298 return NT_STATUS_OK;
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. */
311 return true;
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 ));
322 return false;
325 if (sconn->smb2.credits_granted == 0) {
326 smbd_server_connection_terminate(sconn, "smb2_validate_message_id: "
327 "terminating connection: client used more credits than granted\n");
328 return false;
331 /* client just used a credit. */
332 sconn->smb2.credits_granted -= 1;
334 /* Mark the message_id as seen in the bitmap. */
335 bitmap_offset = (unsigned int)(message_id %
336 (uint64_t)(sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR));
337 if (bitmap_query(credits_bm, bitmap_offset)) {
338 DEBUG(0,("smb2_validate_message_id: duplicate message_id "
339 "%llu (bm offset %u)\n",
340 (unsigned long long)message_id,
341 bitmap_offset));
342 return false;
344 bitmap_set(credits_bm, bitmap_offset);
346 if (message_id == sconn->smb2.seqnum_low + 1) {
347 /* Move the window forward by all the message_id's
348 already seen. */
349 while (bitmap_query(credits_bm, bitmap_offset)) {
350 DEBUG(10,("smb2_validate_message_id: clearing "
351 "id %llu (position %u) from bitmap\n",
352 (unsigned long long)(sconn->smb2.seqnum_low + 1),
353 bitmap_offset ));
354 bitmap_clear(credits_bm, bitmap_offset);
355 sconn->smb2.seqnum_low += 1;
356 bitmap_offset = (bitmap_offset + 1) %
357 (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR);
361 return true;
364 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
366 int count;
367 int idx;
369 count = req->in.vector_count;
371 if (count < 4) {
372 /* It's not a SMB2 request */
373 return NT_STATUS_INVALID_PARAMETER;
376 for (idx=1; idx < count; idx += 3) {
377 const uint8_t *inhdr = NULL;
378 uint32_t flags;
380 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
381 return NT_STATUS_INVALID_PARAMETER;
384 if (req->in.vector[idx+1].iov_len < 2) {
385 return NT_STATUS_INVALID_PARAMETER;
388 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
390 /* Check the SMB2 header */
391 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
392 return NT_STATUS_INVALID_PARAMETER;
395 if (!smb2_validate_message_id(req->sconn, inhdr)) {
396 return NT_STATUS_INVALID_PARAMETER;
399 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
400 if (idx == 1) {
402 * the 1st request should never have the
403 * SMB2_HDR_FLAG_CHAINED flag set
405 if (flags & SMB2_HDR_FLAG_CHAINED) {
406 req->next_status = NT_STATUS_INVALID_PARAMETER;
407 return NT_STATUS_OK;
409 } else if (idx == 4) {
411 * the 2nd request triggers related vs. unrelated
412 * compounded requests
414 if (flags & SMB2_HDR_FLAG_CHAINED) {
415 req->compound_related = true;
417 } else if (idx > 4) {
418 #if 0
420 * It seems the this tests are wrong
421 * see the SMB2-COMPOUND test
425 * all other requests should match the 2nd one
427 if (flags & SMB2_HDR_FLAG_CHAINED) {
428 if (!req->compound_related) {
429 req->next_status =
430 NT_STATUS_INVALID_PARAMETER;
431 return NT_STATUS_OK;
433 } else {
434 if (req->compound_related) {
435 req->next_status =
436 NT_STATUS_INVALID_PARAMETER;
437 return NT_STATUS_OK;
440 #endif
444 return NT_STATUS_OK;
447 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
448 const struct iovec *in_vector,
449 struct iovec *out_vector)
451 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
452 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
453 uint16_t credits_requested;
454 uint32_t out_flags;
455 uint16_t credits_granted = 0;
457 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
458 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
460 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
462 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
464 * In case we already send an async interim
465 * response, we should not grant
466 * credits on the final response.
468 credits_requested = 0;
471 if (credits_requested) {
472 uint16_t modified_credits_requested;
473 uint32_t multiplier;
476 * Split up max_credits into 1/16ths, and then scale
477 * the requested credits by how many 16ths have been
478 * currently granted. Less than 1/16th == grant all
479 * requested (100%), scale down as more have been
480 * granted. Never ask for less than 1 as the client
481 * asked for at least 1. JRA.
484 multiplier = 16 - (((sconn->smb2.credits_granted * 16) / sconn->smb2.max_credits) % 16);
486 modified_credits_requested = (multiplier * credits_requested) / 16;
487 if (modified_credits_requested == 0) {
488 modified_credits_requested = 1;
491 /* Remember what we gave out. */
492 credits_granted = MIN(modified_credits_requested,
493 (sconn->smb2.max_credits - sconn->smb2.credits_granted));
496 if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
497 /* First negprot packet, or ensure the client credits can
498 never drop to zero. */
499 credits_granted = 1;
502 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
503 sconn->smb2.credits_granted += credits_granted;
505 DEBUG(10,("smb2_set_operation_credit: requested %u, "
506 "granted %u, total granted %u\n",
507 (unsigned int)credits_requested,
508 (unsigned int)credits_granted,
509 (unsigned int)sconn->smb2.credits_granted ));
512 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
513 struct smbd_smb2_request *outreq)
515 int count, idx;
517 count = outreq->out.vector_count;
519 for (idx=1; idx < count; idx += 3) {
520 smb2_set_operation_credit(outreq->sconn,
521 &inreq->in.vector[idx],
522 &outreq->out.vector[idx]);
526 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
528 struct iovec *vector;
529 int count;
530 int idx;
532 count = req->in.vector_count;
533 vector = talloc_zero_array(req, struct iovec, count);
534 if (vector == NULL) {
535 return NT_STATUS_NO_MEMORY;
538 vector[0].iov_base = req->out.nbt_hdr;
539 vector[0].iov_len = 4;
540 SIVAL(req->out.nbt_hdr, 0, 0);
542 for (idx=1; idx < count; idx += 3) {
543 const uint8_t *inhdr = NULL;
544 uint32_t in_flags;
545 uint8_t *outhdr = NULL;
546 uint8_t *outbody = NULL;
547 uint32_t next_command_ofs = 0;
548 struct iovec *current = &vector[idx];
550 if ((idx + 3) < count) {
551 /* we have a next command -
552 * setup for the error case. */
553 next_command_ofs = SMB2_HDR_BODY + 9;
556 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
557 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
559 outhdr = talloc_zero_array(vector, uint8_t,
560 OUTVEC_ALLOC_SIZE);
561 if (outhdr == NULL) {
562 return NT_STATUS_NO_MEMORY;
565 outbody = outhdr + SMB2_HDR_BODY;
567 current[0].iov_base = (void *)outhdr;
568 current[0].iov_len = SMB2_HDR_BODY;
570 current[1].iov_base = (void *)outbody;
571 current[1].iov_len = 8;
573 current[2].iov_base = NULL;
574 current[2].iov_len = 0;
576 /* setup the SMB2 header */
577 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
578 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
579 SSVAL(outhdr, SMB2_HDR_EPOCH, 0);
580 SIVAL(outhdr, SMB2_HDR_STATUS,
581 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
582 SSVAL(outhdr, SMB2_HDR_OPCODE,
583 SVAL(inhdr, SMB2_HDR_OPCODE));
584 SIVAL(outhdr, SMB2_HDR_FLAGS,
585 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
586 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
587 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
588 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
589 SIVAL(outhdr, SMB2_HDR_PID,
590 IVAL(inhdr, SMB2_HDR_PID));
591 SIVAL(outhdr, SMB2_HDR_TID,
592 IVAL(inhdr, SMB2_HDR_TID));
593 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
594 BVAL(inhdr, SMB2_HDR_SESSION_ID));
595 memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16);
597 /* setup error body header */
598 SSVAL(outbody, 0x00, 0x08 + 1);
599 SSVAL(outbody, 0x02, 0);
600 SIVAL(outbody, 0x04, 0);
603 req->out.vector = vector;
604 req->out.vector_count = count;
606 /* setup the length of the NBT packet */
607 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
609 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
611 return NT_STATUS_OK;
614 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
615 const char *reason,
616 const char *location)
618 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
619 reason, location));
620 exit_server_cleanly(reason);
623 static bool dup_smb2_vec3(TALLOC_CTX *ctx,
624 struct iovec *outvec,
625 const struct iovec *srcvec)
627 /* vec[0] is always boilerplate and must
628 * be allocated with size OUTVEC_ALLOC_SIZE. */
630 outvec[0].iov_base = talloc_memdup(ctx,
631 srcvec[0].iov_base,
632 OUTVEC_ALLOC_SIZE);
633 if (!outvec[0].iov_base) {
634 return false;
636 outvec[0].iov_len = SMB2_HDR_BODY;
639 * If this is a "standard" vec[1] of length 8,
640 * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
641 * then duplicate this. Else use talloc_memdup().
644 if (srcvec[1].iov_len == 8 &&
645 srcvec[1].iov_base ==
646 ((uint8_t *)srcvec[0].iov_base) +
647 SMB2_HDR_BODY) {
648 outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
649 SMB2_HDR_BODY;
650 outvec[1].iov_len = 8;
651 } else {
652 outvec[1].iov_base = talloc_memdup(ctx,
653 srcvec[1].iov_base,
654 srcvec[1].iov_len);
655 if (!outvec[1].iov_base) {
656 return false;
658 outvec[1].iov_len = srcvec[1].iov_len;
662 * If this is a "standard" vec[2] of length 1,
663 * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
664 * then duplicate this. Else use talloc_memdup().
667 if (srcvec[2].iov_base &&
668 srcvec[2].iov_len) {
669 if (srcvec[2].iov_base ==
670 ((uint8_t *)srcvec[0].iov_base) +
671 (OUTVEC_ALLOC_SIZE - 1) &&
672 srcvec[2].iov_len == 1) {
673 /* Common SMB2 error packet case. */
674 outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
675 (OUTVEC_ALLOC_SIZE - 1);
676 } else {
677 outvec[2].iov_base = talloc_memdup(ctx,
678 srcvec[2].iov_base,
679 srcvec[2].iov_len);
680 if (!outvec[2].iov_base) {
681 return false;
684 outvec[2].iov_len = srcvec[2].iov_len;
685 } else {
686 outvec[2].iov_base = NULL;
687 outvec[2].iov_len = 0;
689 return true;
692 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
694 struct smbd_smb2_request *newreq = NULL;
695 struct iovec *outvec = NULL;
696 int count = req->out.vector_count;
697 int i;
699 newreq = smbd_smb2_request_allocate(req->sconn);
700 if (!newreq) {
701 return NULL;
704 newreq->sconn = req->sconn;
705 newreq->session = req->session;
706 newreq->do_signing = req->do_signing;
707 newreq->current_idx = req->current_idx;
708 newreq->async = false;
709 newreq->cancelled = false;
710 /* Note we are leaving:
711 ->tcon
712 ->smb1req
713 ->compat_chain_fsp
714 uninitialized as NULL here as
715 they're not used in the interim
716 response code. JRA. */
718 outvec = talloc_zero_array(newreq, struct iovec, count);
719 if (!outvec) {
720 TALLOC_FREE(newreq);
721 return NULL;
723 newreq->out.vector = outvec;
724 newreq->out.vector_count = count;
726 /* Setup the outvec's identically to req. */
727 outvec[0].iov_base = newreq->out.nbt_hdr;
728 outvec[0].iov_len = 4;
729 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
731 /* Setup the vectors identically to the ones in req. */
732 for (i = 1; i < count; i += 3) {
733 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
734 break;
738 if (i < count) {
739 /* Alloc failed. */
740 TALLOC_FREE(newreq);
741 return NULL;
744 smb2_setup_nbt_length(newreq->out.vector,
745 newreq->out.vector_count);
747 return newreq;
750 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
752 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
754 int i = 0;
755 uint8_t *outhdr = NULL;
756 struct smbd_smb2_request *nreq = NULL;
758 /* Create a new smb2 request we'll use
759 for the interim return. */
760 nreq = dup_smb2_req(req);
761 if (!nreq) {
762 return NT_STATUS_NO_MEMORY;
765 /* Lose the last 3 out vectors. They're the
766 ones we'll be using for the async reply. */
767 nreq->out.vector_count -= 3;
769 smb2_setup_nbt_length(nreq->out.vector,
770 nreq->out.vector_count);
772 /* Step back to the previous reply. */
773 i = nreq->current_idx - 3;
774 outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
775 /* And end the chain. */
776 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
778 /* Calculate outgoing credits */
779 smb2_calculate_credits(req, nreq);
781 /* Re-sign if needed. */
782 if (nreq->do_signing) {
783 NTSTATUS status;
784 status = smb2_signing_sign_pdu(nreq->session->session_key,
785 &nreq->out.vector[i], 3);
786 if (!NT_STATUS_IS_OK(status)) {
787 return status;
790 if (DEBUGLEVEL >= 10) {
791 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
792 (unsigned int)nreq->current_idx );
793 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
794 (unsigned int)nreq->out.vector_count );
795 print_req_vectors(nreq);
797 nreq->subreq = tstream_writev_queue_send(nreq,
798 nreq->sconn->smb2.event_ctx,
799 nreq->sconn->smb2.stream,
800 nreq->sconn->smb2.send_queue,
801 nreq->out.vector,
802 nreq->out.vector_count);
804 if (nreq->subreq == NULL) {
805 return NT_STATUS_NO_MEMORY;
808 tevent_req_set_callback(nreq->subreq,
809 smbd_smb2_request_writev_done,
810 nreq);
812 return NT_STATUS_OK;
815 struct smbd_smb2_request_pending_state {
816 struct smbd_server_connection *sconn;
817 uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
818 struct iovec vector[3];
821 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
823 struct smbd_smb2_request_pending_state *state =
824 tevent_req_callback_data(subreq,
825 struct smbd_smb2_request_pending_state);
826 struct smbd_server_connection *sconn = state->sconn;
827 int ret;
828 int sys_errno;
830 ret = tstream_writev_queue_recv(subreq, &sys_errno);
831 TALLOC_FREE(subreq);
832 if (ret == -1) {
833 NTSTATUS status = map_nt_error_from_unix(sys_errno);
834 smbd_server_connection_terminate(sconn, nt_errstr(status));
835 return;
838 TALLOC_FREE(state);
841 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
842 struct tevent_req *subreq)
844 NTSTATUS status;
845 struct smbd_smb2_request_pending_state *state = NULL;
846 int i = req->current_idx;
847 uint8_t *reqhdr = NULL;
848 uint8_t *hdr = NULL;
849 uint8_t *body = NULL;
850 uint32_t flags = 0;
851 uint64_t message_id = 0;
852 uint64_t async_id = 0;
853 struct iovec *outvec = NULL;
855 if (!tevent_req_is_in_progress(subreq)) {
856 return NT_STATUS_OK;
859 req->subreq = subreq;
860 subreq = NULL;
862 if (req->async) {
863 /* We're already async. */
864 return NT_STATUS_OK;
867 if (req->in.vector_count > i + 3) {
869 * We're trying to go async in a compound
870 * request chain. This is not allowed.
871 * Cancel the outstanding request.
873 tevent_req_cancel(req->subreq);
874 return smbd_smb2_request_error(req,
875 NT_STATUS_INSUFFICIENT_RESOURCES);
878 if (DEBUGLEVEL >= 10) {
879 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
880 (unsigned int)req->current_idx );
881 print_req_vectors(req);
884 if (req->out.vector_count > 4) {
885 /* This is a compound reply. We
886 * must do an interim response
887 * followed by the async response
888 * to match W2K8R2.
890 status = smb2_send_async_interim_response(req);
891 if (!NT_STATUS_IS_OK(status)) {
892 return status;
896 * We're splitting off the last SMB2
897 * request in a compound set, and the
898 * smb2_send_async_interim_response()
899 * call above just sent all the replies
900 * for the previous SMB2 requests in
901 * this compound set. So we're no longer
902 * in the "compound_related_in_progress"
903 * state, and this is no longer a compound
904 * request.
906 req->compound_related = false;
907 req->sconn->smb2.compound_related_in_progress = false;
910 /* Don't return an intermediate packet on a pipe read/write. */
911 if (req->tcon && req->tcon->compat_conn && IS_IPC(req->tcon->compat_conn)) {
912 goto ipc_out;
915 reqhdr = (uint8_t *)req->out.vector[i].iov_base;
916 flags = (IVAL(reqhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
917 message_id = BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
918 async_id = message_id; /* keep it simple for now... */
921 * What we send is identical to a smbd_smb2_request_error
922 * packet with an error status of STATUS_PENDING. Make use
923 * of this fact sometime when refactoring. JRA.
926 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
927 if (state == NULL) {
928 return NT_STATUS_NO_MEMORY;
930 state->sconn = req->sconn;
932 state->vector[0].iov_base = (void *)state->buf;
933 state->vector[0].iov_len = 4;
935 state->vector[1].iov_base = state->buf + 4;
936 state->vector[1].iov_len = SMB2_HDR_BODY;
938 state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
939 state->vector[2].iov_len = 9;
941 smb2_setup_nbt_length(state->vector, 3);
943 hdr = (uint8_t *)state->vector[1].iov_base;
944 body = (uint8_t *)state->vector[2].iov_base;
946 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
947 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
948 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
949 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
950 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE));
952 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
953 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
954 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
955 SBVAL(hdr, SMB2_HDR_PID, async_id);
956 SBVAL(hdr, SMB2_HDR_SESSION_ID,
957 BVAL(reqhdr, SMB2_HDR_SESSION_ID));
958 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
960 SSVAL(body, 0x00, 0x08 + 1);
962 SCVAL(body, 0x02, 0);
963 SCVAL(body, 0x03, 0);
964 SIVAL(body, 0x04, 0);
965 /* Match W2K8R2... */
966 SCVAL(body, 0x08, 0x21);
968 /* Ensure we correctly go through crediting. Grant
969 the credits now, and zero credits on the final
970 response. */
971 smb2_set_operation_credit(req->sconn,
972 &req->in.vector[i],
973 &state->vector[1]);
975 if (req->do_signing) {
976 status = smb2_signing_sign_pdu(req->session->session_key,
977 &state->vector[1], 2);
978 if (!NT_STATUS_IS_OK(status)) {
979 return status;
983 subreq = tstream_writev_queue_send(state,
984 req->sconn->smb2.event_ctx,
985 req->sconn->smb2.stream,
986 req->sconn->smb2.send_queue,
987 state->vector,
990 if (subreq == NULL) {
991 return NT_STATUS_NO_MEMORY;
994 tevent_req_set_callback(subreq,
995 smbd_smb2_request_pending_writev_done,
996 state);
998 /* Note we're going async with this request. */
999 req->async = true;
1001 ipc_out:
1004 * Now manipulate req so that the outstanding async request
1005 * is the only one left in the struct smbd_smb2_request.
1008 if (req->current_idx == 1) {
1009 /* There was only one. */
1010 goto out;
1013 /* Re-arrange the in.vectors. */
1014 req->in.vector[1] = req->in.vector[i];
1015 req->in.vector[2] = req->in.vector[i+1];
1016 req->in.vector[3] = req->in.vector[i+2];
1017 req->in.vector_count = 4;
1018 /* Reset the new in size. */
1019 smb2_setup_nbt_length(req->in.vector, 4);
1021 /* Now recreate the out.vectors. */
1022 outvec = talloc_zero_array(req, struct iovec, 4);
1023 if (!outvec) {
1024 return NT_STATUS_NO_MEMORY;
1027 /* 0 is always boilerplate and must
1028 * be of size 4 for the length field. */
1030 outvec[0].iov_base = req->out.nbt_hdr;
1031 outvec[0].iov_len = 4;
1032 SIVAL(req->out.nbt_hdr, 0, 0);
1034 if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
1035 return NT_STATUS_NO_MEMORY;
1038 TALLOC_FREE(req->out.vector);
1040 req->out.vector = outvec;
1042 req->current_idx = 1;
1043 req->out.vector_count = 4;
1045 out:
1047 smb2_setup_nbt_length(req->out.vector,
1048 req->out.vector_count);
1050 if (req->async) {
1051 /* Ensure our final reply matches the interim one. */
1052 reqhdr = (uint8_t *)req->out.vector[1].iov_base;
1053 SIVAL(reqhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1054 SBVAL(reqhdr, SMB2_HDR_PID, async_id);
1057 const uint8_t *inhdr =
1058 (const uint8_t *)req->in.vector[1].iov_base;
1059 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1060 "going async\n",
1061 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1062 (unsigned long long)async_id ));
1066 return NT_STATUS_OK;
1069 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1071 struct smbd_server_connection *sconn = req->sconn;
1072 struct smbd_smb2_request *cur;
1073 const uint8_t *inhdr;
1074 int i = req->current_idx;
1075 uint32_t flags;
1076 uint64_t search_message_id;
1077 uint64_t search_async_id;
1078 uint64_t found_id;
1080 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1082 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1083 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1084 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1087 * we don't need the request anymore
1088 * cancel requests never have a response
1090 DLIST_REMOVE(req->sconn->smb2.requests, req);
1091 TALLOC_FREE(req);
1093 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1094 const uint8_t *outhdr;
1095 uint64_t message_id;
1096 uint64_t async_id;
1098 i = cur->current_idx;
1100 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
1102 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1103 async_id = BVAL(outhdr, SMB2_HDR_PID);
1105 if (flags & SMB2_HDR_FLAG_ASYNC) {
1106 if (search_async_id == async_id) {
1107 found_id = async_id;
1108 break;
1110 } else {
1111 if (search_message_id == message_id) {
1112 found_id = message_id;
1113 break;
1118 if (cur && cur->subreq) {
1119 inhdr = (const uint8_t *)cur->in.vector[i].iov_base;
1120 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1121 "cancel opcode[%s] mid %llu\n",
1122 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1123 (unsigned long long)found_id ));
1124 tevent_req_cancel(cur->subreq);
1127 return NT_STATUS_OK;
1130 /*************************************************************
1131 Ensure an incoming tid is a valid one for us to access.
1132 Change to the associated uid credentials and chdir to the
1133 valid tid directory.
1134 *************************************************************/
1136 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1138 const uint8_t *inhdr;
1139 const uint8_t *outhdr;
1140 int i = req->current_idx;
1141 uint32_t in_tid;
1142 void *p;
1143 struct smbd_smb2_tcon *tcon;
1144 bool chained_fixup = false;
1146 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1148 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1150 if (in_tid == (0xFFFFFFFF)) {
1151 if (req->async) {
1153 * async request - fill in tid from
1154 * already setup out.vector[].iov_base.
1156 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1157 in_tid = IVAL(outhdr, SMB2_HDR_TID);
1158 } else if (i > 2) {
1160 * Chained request - fill in tid from
1161 * the previous request out.vector[].iov_base.
1163 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1164 in_tid = IVAL(outhdr, SMB2_HDR_TID);
1165 chained_fixup = true;
1169 /* lookup an existing session */
1170 p = idr_find(req->session->tcons.idtree, in_tid);
1171 if (p == NULL) {
1172 return NT_STATUS_NETWORK_NAME_DELETED;
1174 tcon = talloc_get_type_abort(p, struct smbd_smb2_tcon);
1176 if (!change_to_user(tcon->compat_conn,req->session->vuid)) {
1177 return NT_STATUS_ACCESS_DENIED;
1180 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1181 if (!set_current_service(tcon->compat_conn, 0, true)) {
1182 return NT_STATUS_ACCESS_DENIED;
1185 req->tcon = tcon;
1187 if (chained_fixup) {
1188 /* Fix up our own outhdr. */
1189 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1190 SIVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_TID, in_tid);
1193 return NT_STATUS_OK;
1196 /*************************************************************
1197 Ensure an incoming session_id is a valid one for us to access.
1198 *************************************************************/
1200 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1202 const uint8_t *inhdr;
1203 const uint8_t *outhdr;
1204 int i = req->current_idx;
1205 uint64_t in_session_id;
1206 void *p;
1207 struct smbd_smb2_session *session;
1208 bool chained_fixup = false;
1210 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1212 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1214 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
1215 if (req->async) {
1217 * async request - fill in session_id from
1218 * already setup request out.vector[].iov_base.
1220 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1221 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1222 } else if (i > 2) {
1224 * Chained request - fill in session_id from
1225 * the previous request out.vector[].iov_base.
1227 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1228 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1229 chained_fixup = true;
1233 /* lookup an existing session */
1234 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
1235 if (p == NULL) {
1236 return NT_STATUS_USER_SESSION_DELETED;
1238 session = talloc_get_type_abort(p, struct smbd_smb2_session);
1240 if (!NT_STATUS_IS_OK(session->status)) {
1241 return NT_STATUS_ACCESS_DENIED;
1244 set_current_user_info(session->session_info->unix_info->sanitized_username,
1245 session->session_info->unix_info->unix_name,
1246 session->session_info->info->domain_name);
1248 req->session = session;
1250 if (chained_fixup) {
1251 /* Fix up our own outhdr. */
1252 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1253 SBVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_SESSION_ID, in_session_id);
1255 return NT_STATUS_OK;
1258 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1259 size_t expected_body_size)
1261 const uint8_t *inhdr;
1262 uint16_t opcode;
1263 const uint8_t *inbody;
1264 int i = req->current_idx;
1265 size_t body_size;
1266 size_t min_dyn_size = expected_body_size & 0x00000001;
1269 * The following should be checked already.
1271 if ((i+2) > req->in.vector_count) {
1272 return NT_STATUS_INTERNAL_ERROR;
1274 if (req->in.vector[i+0].iov_len != SMB2_HDR_BODY) {
1275 return NT_STATUS_INTERNAL_ERROR;
1277 if (req->in.vector[i+1].iov_len < 2) {
1278 return NT_STATUS_INTERNAL_ERROR;
1281 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1282 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1284 switch (opcode) {
1285 case SMB2_OP_GETINFO:
1286 min_dyn_size = 0;
1287 break;
1291 * Now check the expected body size,
1292 * where the last byte might be in the
1293 * dynnamic section..
1295 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1296 return NT_STATUS_INVALID_PARAMETER;
1298 if (req->in.vector[i+2].iov_len < min_dyn_size) {
1299 return NT_STATUS_INVALID_PARAMETER;
1302 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1304 body_size = SVAL(inbody, 0x00);
1305 if (body_size != expected_body_size) {
1306 return NT_STATUS_INVALID_PARAMETER;
1309 return NT_STATUS_OK;
1312 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1314 const uint8_t *inhdr;
1315 int i = req->current_idx;
1316 uint16_t opcode;
1317 uint32_t flags;
1318 uint64_t mid;
1319 NTSTATUS status;
1320 NTSTATUS session_status;
1321 uint32_t allowed_flags;
1322 NTSTATUS return_value;
1324 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1326 /* TODO: verify more things */
1328 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1329 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1330 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1331 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1332 smb2_opcode_name(opcode),
1333 (unsigned long long)mid));
1335 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1336 SMB2_HDR_FLAG_SIGNED |
1337 SMB2_HDR_FLAG_DFS;
1338 if (opcode == SMB2_OP_CANCEL) {
1339 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1341 if ((flags & ~allowed_flags) != 0) {
1342 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1346 * Check if the client provided a valid session id,
1347 * if so smbd_smb2_request_check_session() calls
1348 * set_current_user_info().
1350 * As some command don't require a valid session id
1351 * we defer the check of the session_status
1353 session_status = smbd_smb2_request_check_session(req);
1355 req->do_signing = false;
1356 if (flags & SMB2_HDR_FLAG_SIGNED) {
1357 if (!NT_STATUS_IS_OK(session_status)) {
1358 return smbd_smb2_request_error(req, session_status);
1361 req->do_signing = true;
1362 status = smb2_signing_check_pdu(req->session->session_key,
1363 &req->in.vector[i], 3);
1364 if (!NT_STATUS_IS_OK(status)) {
1365 return smbd_smb2_request_error(req, status);
1367 } else if (req->session && req->session->do_signing) {
1368 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1371 if (flags & SMB2_HDR_FLAG_CHAINED) {
1373 * This check is mostly for giving the correct error code
1374 * for compounded requests.
1376 * TODO: we may need to move this after the session
1377 * and tcon checks.
1379 if (!NT_STATUS_IS_OK(req->next_status)) {
1380 return smbd_smb2_request_error(req, req->next_status);
1382 } else {
1383 req->compat_chain_fsp = NULL;
1386 if (req->compound_related) {
1387 req->sconn->smb2.compound_related_in_progress = true;
1390 switch (opcode) {
1391 case SMB2_OP_NEGPROT:
1392 /* This call needs to be run as root */
1393 change_to_root_user();
1396 START_PROFILE(smb2_negprot);
1397 return_value = smbd_smb2_request_process_negprot(req);
1398 END_PROFILE(smb2_negprot);
1400 break;
1402 case SMB2_OP_SESSSETUP:
1403 /* This call needs to be run as root */
1404 change_to_root_user();
1407 START_PROFILE(smb2_sesssetup);
1408 return_value = smbd_smb2_request_process_sesssetup(req);
1409 END_PROFILE(smb2_sesssetup);
1411 break;
1413 case SMB2_OP_LOGOFF:
1414 if (!NT_STATUS_IS_OK(session_status)) {
1415 return_value = smbd_smb2_request_error(req, session_status);
1416 break;
1419 /* This call needs to be run as root */
1420 change_to_root_user();
1423 START_PROFILE(smb2_logoff);
1424 return_value = smbd_smb2_request_process_logoff(req);
1425 END_PROFILE(smb2_logoff);
1427 break;
1429 case SMB2_OP_TCON:
1430 if (!NT_STATUS_IS_OK(session_status)) {
1431 return_value = smbd_smb2_request_error(req, session_status);
1432 break;
1436 * This call needs to be run as root.
1438 * smbd_smb2_request_process_tcon()
1439 * calls make_connection_snum(), which will call
1440 * change_to_user(), when needed.
1442 change_to_root_user();
1445 START_PROFILE(smb2_tcon);
1446 return_value = smbd_smb2_request_process_tcon(req);
1447 END_PROFILE(smb2_tcon);
1449 break;
1451 case SMB2_OP_TDIS:
1452 if (!NT_STATUS_IS_OK(session_status)) {
1453 return_value = smbd_smb2_request_error(req, session_status);
1454 break;
1457 * This call needs to be run as user.
1459 * smbd_smb2_request_check_tcon()
1460 * calls change_to_user() on success.
1462 status = smbd_smb2_request_check_tcon(req);
1463 if (!NT_STATUS_IS_OK(status)) {
1464 return_value = smbd_smb2_request_error(req, status);
1465 break;
1467 /* This call needs to be run as root */
1468 change_to_root_user();
1472 START_PROFILE(smb2_tdis);
1473 return_value = smbd_smb2_request_process_tdis(req);
1474 END_PROFILE(smb2_tdis);
1476 break;
1478 case SMB2_OP_CREATE:
1479 if (!NT_STATUS_IS_OK(session_status)) {
1480 return_value = smbd_smb2_request_error(req, session_status);
1481 break;
1484 * This call needs to be run as user.
1486 * smbd_smb2_request_check_tcon()
1487 * calls change_to_user() on success.
1489 status = smbd_smb2_request_check_tcon(req);
1490 if (!NT_STATUS_IS_OK(status)) {
1491 return_value = smbd_smb2_request_error(req, status);
1492 break;
1496 START_PROFILE(smb2_create);
1497 return_value = smbd_smb2_request_process_create(req);
1498 END_PROFILE(smb2_create);
1500 break;
1502 case SMB2_OP_CLOSE:
1503 if (!NT_STATUS_IS_OK(session_status)) {
1504 return_value = smbd_smb2_request_error(req, session_status);
1505 break;
1508 * This call needs to be run as user.
1510 * smbd_smb2_request_check_tcon()
1511 * calls change_to_user() on success.
1513 status = smbd_smb2_request_check_tcon(req);
1514 if (!NT_STATUS_IS_OK(status)) {
1515 return_value = smbd_smb2_request_error(req, status);
1516 break;
1520 START_PROFILE(smb2_close);
1521 return_value = smbd_smb2_request_process_close(req);
1522 END_PROFILE(smb2_close);
1524 break;
1526 case SMB2_OP_FLUSH:
1527 if (!NT_STATUS_IS_OK(session_status)) {
1528 return_value = smbd_smb2_request_error(req, session_status);
1529 break;
1532 * This call needs to be run as user.
1534 * smbd_smb2_request_check_tcon()
1535 * calls change_to_user() on success.
1537 status = smbd_smb2_request_check_tcon(req);
1538 if (!NT_STATUS_IS_OK(status)) {
1539 return_value = smbd_smb2_request_error(req, status);
1540 break;
1544 START_PROFILE(smb2_flush);
1545 return_value = smbd_smb2_request_process_flush(req);
1546 END_PROFILE(smb2_flush);
1548 break;
1550 case SMB2_OP_READ:
1551 if (!NT_STATUS_IS_OK(session_status)) {
1552 return_value = smbd_smb2_request_error(req, session_status);
1553 break;
1556 * This call needs to be run as user.
1558 * smbd_smb2_request_check_tcon()
1559 * calls change_to_user() on success.
1561 status = smbd_smb2_request_check_tcon(req);
1562 if (!NT_STATUS_IS_OK(status)) {
1563 return_value = smbd_smb2_request_error(req, status);
1564 break;
1568 START_PROFILE(smb2_read);
1569 return_value = smbd_smb2_request_process_read(req);
1570 END_PROFILE(smb2_read);
1572 break;
1574 case SMB2_OP_WRITE:
1575 if (!NT_STATUS_IS_OK(session_status)) {
1576 return_value = smbd_smb2_request_error(req, session_status);
1577 break;
1580 * This call needs to be run as user.
1582 * smbd_smb2_request_check_tcon()
1583 * calls change_to_user() on success.
1585 status = smbd_smb2_request_check_tcon(req);
1586 if (!NT_STATUS_IS_OK(status)) {
1587 return_value = smbd_smb2_request_error(req, status);
1588 break;
1592 START_PROFILE(smb2_write);
1593 return_value = smbd_smb2_request_process_write(req);
1594 END_PROFILE(smb2_write);
1596 break;
1598 case SMB2_OP_LOCK:
1599 if (!NT_STATUS_IS_OK(session_status)) {
1600 /* Too ugly to live ? JRA. */
1601 if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
1602 session_status = NT_STATUS_FILE_CLOSED;
1604 return_value = smbd_smb2_request_error(req, session_status);
1605 break;
1608 * This call needs to be run as user.
1610 * smbd_smb2_request_check_tcon()
1611 * calls change_to_user() on success.
1613 status = smbd_smb2_request_check_tcon(req);
1614 if (!NT_STATUS_IS_OK(status)) {
1615 /* Too ugly to live ? JRA. */
1616 if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
1617 status = NT_STATUS_FILE_CLOSED;
1619 return_value = smbd_smb2_request_error(req, status);
1620 break;
1624 START_PROFILE(smb2_lock);
1625 return_value = smbd_smb2_request_process_lock(req);
1626 END_PROFILE(smb2_lock);
1628 break;
1630 case SMB2_OP_IOCTL:
1631 if (!NT_STATUS_IS_OK(session_status)) {
1632 return_value = smbd_smb2_request_error(req, session_status);
1633 break;
1636 * This call needs to be run as user.
1638 * smbd_smb2_request_check_tcon()
1639 * calls change_to_user() on success.
1641 status = smbd_smb2_request_check_tcon(req);
1642 if (!NT_STATUS_IS_OK(status)) {
1643 return_value = smbd_smb2_request_error(req, status);
1644 break;
1648 START_PROFILE(smb2_ioctl);
1649 return_value = smbd_smb2_request_process_ioctl(req);
1650 END_PROFILE(smb2_ioctl);
1652 break;
1654 case SMB2_OP_CANCEL:
1656 * This call needs to be run as root
1658 * That is what we also do in the SMB1 case.
1660 change_to_root_user();
1663 START_PROFILE(smb2_cancel);
1664 return_value = smbd_smb2_request_process_cancel(req);
1665 END_PROFILE(smb2_cancel);
1667 break;
1669 case SMB2_OP_KEEPALIVE:
1670 /* This call needs to be run as root */
1671 change_to_root_user();
1674 START_PROFILE(smb2_keepalive);
1675 return_value = smbd_smb2_request_process_keepalive(req);
1676 END_PROFILE(smb2_keepalive);
1678 break;
1680 case SMB2_OP_FIND:
1681 if (!NT_STATUS_IS_OK(session_status)) {
1682 return_value = smbd_smb2_request_error(req, session_status);
1683 break;
1686 * This call needs to be run as user.
1688 * smbd_smb2_request_check_tcon()
1689 * calls change_to_user() on success.
1691 status = smbd_smb2_request_check_tcon(req);
1692 if (!NT_STATUS_IS_OK(status)) {
1693 return_value = smbd_smb2_request_error(req, status);
1694 break;
1698 START_PROFILE(smb2_find);
1699 return_value = smbd_smb2_request_process_find(req);
1700 END_PROFILE(smb2_find);
1702 break;
1704 case SMB2_OP_NOTIFY:
1705 if (!NT_STATUS_IS_OK(session_status)) {
1706 return_value = smbd_smb2_request_error(req, session_status);
1707 break;
1710 * This call needs to be run as user.
1712 * smbd_smb2_request_check_tcon()
1713 * calls change_to_user() on success.
1715 status = smbd_smb2_request_check_tcon(req);
1716 if (!NT_STATUS_IS_OK(status)) {
1717 return_value = smbd_smb2_request_error(req, status);
1718 break;
1722 START_PROFILE(smb2_notify);
1723 return_value = smbd_smb2_request_process_notify(req);
1724 END_PROFILE(smb2_notify);
1726 break;
1728 case SMB2_OP_GETINFO:
1729 if (!NT_STATUS_IS_OK(session_status)) {
1730 return_value = smbd_smb2_request_error(req, session_status);
1731 break;
1734 * This call needs to be run as user.
1736 * smbd_smb2_request_check_tcon()
1737 * calls change_to_user() on success.
1739 status = smbd_smb2_request_check_tcon(req);
1740 if (!NT_STATUS_IS_OK(status)) {
1741 return_value = smbd_smb2_request_error(req, status);
1742 break;
1746 START_PROFILE(smb2_getinfo);
1747 return_value = smbd_smb2_request_process_getinfo(req);
1748 END_PROFILE(smb2_getinfo);
1750 break;
1752 case SMB2_OP_SETINFO:
1753 if (!NT_STATUS_IS_OK(session_status)) {
1754 return_value = smbd_smb2_request_error(req, session_status);
1755 break;
1758 * This call needs to be run as user.
1760 * smbd_smb2_request_check_tcon()
1761 * calls change_to_user() on success.
1763 status = smbd_smb2_request_check_tcon(req);
1764 if (!NT_STATUS_IS_OK(status)) {
1765 return_value = smbd_smb2_request_error(req, status);
1766 break;
1770 START_PROFILE(smb2_setinfo);
1771 return_value = smbd_smb2_request_process_setinfo(req);
1772 END_PROFILE(smb2_setinfo);
1774 break;
1776 case SMB2_OP_BREAK:
1777 if (!NT_STATUS_IS_OK(session_status)) {
1778 return_value = smbd_smb2_request_error(req, session_status);
1779 break;
1782 * This call needs to be run as user.
1784 * smbd_smb2_request_check_tcon()
1785 * calls change_to_user() on success.
1787 status = smbd_smb2_request_check_tcon(req);
1788 if (!NT_STATUS_IS_OK(status)) {
1789 return_value = smbd_smb2_request_error(req, status);
1790 break;
1794 START_PROFILE(smb2_break);
1795 return_value = smbd_smb2_request_process_break(req);
1796 END_PROFILE(smb2_break);
1798 break;
1800 default:
1801 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1802 break;
1804 return return_value;
1807 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
1809 struct tevent_req *subreq;
1810 int i = req->current_idx;
1812 req->subreq = NULL;
1814 req->current_idx += 3;
1816 if (req->current_idx < req->out.vector_count) {
1818 * We must process the remaining compound
1819 * SMB2 requests before any new incoming SMB2
1820 * requests. This is because incoming SMB2
1821 * requests may include a cancel for a
1822 * compound request we haven't processed
1823 * yet.
1825 struct tevent_immediate *im = tevent_create_immediate(req);
1826 if (!im) {
1827 return NT_STATUS_NO_MEMORY;
1829 tevent_schedule_immediate(im,
1830 req->sconn->smb2.event_ctx,
1831 smbd_smb2_request_dispatch_immediate,
1832 req);
1833 return NT_STATUS_OK;
1836 if (req->compound_related) {
1837 req->sconn->smb2.compound_related_in_progress = false;
1840 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
1842 /* Set credit for this operation (zero credits if this
1843 is a final reply for an async operation). */
1844 smb2_set_operation_credit(req->sconn,
1845 &req->in.vector[i],
1846 &req->out.vector[i]);
1848 if (req->do_signing) {
1849 NTSTATUS status;
1850 status = smb2_signing_sign_pdu(req->session->session_key,
1851 &req->out.vector[i], 3);
1852 if (!NT_STATUS_IS_OK(status)) {
1853 return status;
1857 if (DEBUGLEVEL >= 10) {
1858 dbgtext("smbd_smb2_request_reply: sending...\n");
1859 print_req_vectors(req);
1862 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
1863 if (req->out.vector_count == 4 &&
1864 req->out.vector[3].iov_base == NULL &&
1865 req->out.vector[3].iov_len != 0) {
1866 /* Dynamic part is NULL. Chop it off,
1867 We're going to send it via sendfile. */
1868 req->out.vector_count -= 1;
1871 subreq = tstream_writev_queue_send(req,
1872 req->sconn->smb2.event_ctx,
1873 req->sconn->smb2.stream,
1874 req->sconn->smb2.send_queue,
1875 req->out.vector,
1876 req->out.vector_count);
1877 if (subreq == NULL) {
1878 return NT_STATUS_NO_MEMORY;
1880 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
1882 * We're done with this request -
1883 * move it off the "being processed" queue.
1885 DLIST_REMOVE(req->sconn->smb2.requests, req);
1887 return NT_STATUS_OK;
1890 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
1892 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
1893 struct tevent_immediate *im,
1894 void *private_data)
1896 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
1897 struct smbd_smb2_request);
1898 struct smbd_server_connection *sconn = req->sconn;
1899 NTSTATUS status;
1901 TALLOC_FREE(im);
1903 if (DEBUGLEVEL >= 10) {
1904 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
1905 req->current_idx, req->in.vector_count));
1906 print_req_vectors(req);
1909 status = smbd_smb2_request_dispatch(req);
1910 if (!NT_STATUS_IS_OK(status)) {
1911 smbd_server_connection_terminate(sconn, nt_errstr(status));
1912 return;
1915 status = smbd_smb2_request_next_incoming(sconn);
1916 if (!NT_STATUS_IS_OK(status)) {
1917 smbd_server_connection_terminate(sconn, nt_errstr(status));
1918 return;
1922 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
1924 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
1925 struct smbd_smb2_request);
1926 struct smbd_server_connection *sconn = req->sconn;
1927 int ret;
1928 int sys_errno;
1929 NTSTATUS status;
1931 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1932 TALLOC_FREE(subreq);
1933 TALLOC_FREE(req);
1934 if (ret == -1) {
1935 status = map_nt_error_from_unix(sys_errno);
1936 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
1937 nt_errstr(status)));
1938 smbd_server_connection_terminate(sconn, nt_errstr(status));
1939 return;
1942 status = smbd_smb2_request_next_incoming(sconn);
1943 if (!NT_STATUS_IS_OK(status)) {
1944 smbd_server_connection_terminate(sconn, nt_errstr(status));
1945 return;
1949 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
1950 NTSTATUS status,
1951 DATA_BLOB body, DATA_BLOB *dyn,
1952 const char *location)
1954 uint8_t *outhdr;
1955 int i = req->current_idx;
1956 uint32_t next_command_ofs;
1958 DEBUG(10,("smbd_smb2_request_done_ex: "
1959 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
1960 i, nt_errstr(status), (unsigned int)body.length,
1961 dyn ? "yes": "no",
1962 (unsigned int)(dyn ? dyn->length : 0),
1963 location));
1965 if (body.length < 2) {
1966 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1969 if ((body.length % 2) != 0) {
1970 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1973 outhdr = (uint8_t *)req->out.vector[i].iov_base;
1975 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
1976 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
1978 req->out.vector[i+1].iov_base = (void *)body.data;
1979 req->out.vector[i+1].iov_len = body.length;
1981 if (dyn) {
1982 req->out.vector[i+2].iov_base = (void *)dyn->data;
1983 req->out.vector[i+2].iov_len = dyn->length;
1984 } else {
1985 req->out.vector[i+2].iov_base = NULL;
1986 req->out.vector[i+2].iov_len = 0;
1989 /* see if we need to recalculate the offset to the next response */
1990 if (next_command_ofs > 0) {
1991 next_command_ofs = SMB2_HDR_BODY;
1992 next_command_ofs += req->out.vector[i+1].iov_len;
1993 next_command_ofs += req->out.vector[i+2].iov_len;
1996 if ((next_command_ofs % 8) != 0) {
1997 size_t pad_size = 8 - (next_command_ofs % 8);
1998 if (req->out.vector[i+2].iov_len == 0) {
2000 * if the dyn buffer is empty
2001 * we can use it to add padding
2003 uint8_t *pad;
2005 pad = talloc_zero_array(req->out.vector,
2006 uint8_t, pad_size);
2007 if (pad == NULL) {
2008 return smbd_smb2_request_error(req,
2009 NT_STATUS_NO_MEMORY);
2012 req->out.vector[i+2].iov_base = (void *)pad;
2013 req->out.vector[i+2].iov_len = pad_size;
2014 } else {
2016 * For now we copy the dynamic buffer
2017 * and add the padding to the new buffer
2019 size_t old_size;
2020 uint8_t *old_dyn;
2021 size_t new_size;
2022 uint8_t *new_dyn;
2024 old_size = req->out.vector[i+2].iov_len;
2025 old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
2027 new_size = old_size + pad_size;
2028 new_dyn = talloc_zero_array(req->out.vector,
2029 uint8_t, new_size);
2030 if (new_dyn == NULL) {
2031 return smbd_smb2_request_error(req,
2032 NT_STATUS_NO_MEMORY);
2035 memcpy(new_dyn, old_dyn, old_size);
2036 memset(new_dyn + old_size, 0, pad_size);
2038 req->out.vector[i+2].iov_base = (void *)new_dyn;
2039 req->out.vector[i+2].iov_len = new_size;
2041 next_command_ofs += pad_size;
2044 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2046 return smbd_smb2_request_reply(req);
2049 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2050 NTSTATUS status,
2051 DATA_BLOB *info,
2052 const char *location)
2054 DATA_BLOB body;
2055 int i = req->current_idx;
2056 uint8_t *outhdr = (uint8_t *)req->out.vector[i].iov_base;
2058 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2059 i, nt_errstr(status), info ? " +info" : "",
2060 location));
2062 body.data = outhdr + SMB2_HDR_BODY;
2063 body.length = 8;
2064 SSVAL(body.data, 0, 9);
2066 if (info) {
2067 SIVAL(body.data, 0x04, info->length);
2068 } else {
2069 /* Allocated size of req->out.vector[i].iov_base
2070 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2071 * 1 byte without having to do an alloc.
2073 info = talloc_zero_array(req->out.vector,
2074 DATA_BLOB,
2076 if (!info) {
2077 return NT_STATUS_NO_MEMORY;
2079 info->data = ((uint8_t *)outhdr) +
2080 OUTVEC_ALLOC_SIZE - 1;
2081 info->length = 1;
2082 SCVAL(info->data, 0, 0);
2086 * if a request fails, all other remaining
2087 * compounded requests should fail too
2089 req->next_status = NT_STATUS_INVALID_PARAMETER;
2091 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2095 struct smbd_smb2_send_oplock_break_state {
2096 struct smbd_server_connection *sconn;
2097 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
2098 struct iovec vector;
2101 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2103 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2104 uint64_t file_id_persistent,
2105 uint64_t file_id_volatile,
2106 uint8_t oplock_level)
2108 struct smbd_smb2_send_oplock_break_state *state;
2109 struct tevent_req *subreq;
2110 uint8_t *hdr;
2111 uint8_t *body;
2113 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2114 if (state == NULL) {
2115 return NT_STATUS_NO_MEMORY;
2117 state->sconn = sconn;
2119 state->vector.iov_base = (void *)state->buf;
2120 state->vector.iov_len = sizeof(state->buf);
2122 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
2123 hdr = state->buf + 4;
2124 body = hdr + SMB2_HDR_BODY;
2126 SIVAL(hdr, 0, SMB2_MAGIC);
2127 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2128 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2129 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2130 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2131 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2132 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2133 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2134 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2135 SIVAL(hdr, SMB2_HDR_PID, 0);
2136 SIVAL(hdr, SMB2_HDR_TID, 0);
2137 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2138 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2140 SSVAL(body, 0x00, 0x18);
2142 SCVAL(body, 0x02, oplock_level);
2143 SCVAL(body, 0x03, 0); /* reserved */
2144 SIVAL(body, 0x04, 0); /* reserved */
2145 SBVAL(body, 0x08, file_id_persistent);
2146 SBVAL(body, 0x10, file_id_volatile);
2148 subreq = tstream_writev_queue_send(state,
2149 sconn->smb2.event_ctx,
2150 sconn->smb2.stream,
2151 sconn->smb2.send_queue,
2152 &state->vector, 1);
2153 if (subreq == NULL) {
2154 return NT_STATUS_NO_MEMORY;
2156 tevent_req_set_callback(subreq,
2157 smbd_smb2_oplock_break_writev_done,
2158 state);
2160 return NT_STATUS_OK;
2163 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2165 struct smbd_smb2_send_oplock_break_state *state =
2166 tevent_req_callback_data(subreq,
2167 struct smbd_smb2_send_oplock_break_state);
2168 struct smbd_server_connection *sconn = state->sconn;
2169 int ret;
2170 int sys_errno;
2172 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2173 TALLOC_FREE(subreq);
2174 if (ret == -1) {
2175 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2176 smbd_server_connection_terminate(sconn, nt_errstr(status));
2177 return;
2180 TALLOC_FREE(state);
2183 struct smbd_smb2_request_read_state {
2184 size_t missing;
2185 bool asked_for_header;
2186 struct smbd_smb2_request *smb2_req;
2189 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2190 void *private_data,
2191 TALLOC_CTX *mem_ctx,
2192 struct iovec **_vector,
2193 size_t *_count);
2194 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2196 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2197 struct tevent_context *ev,
2198 struct smbd_server_connection *sconn)
2200 struct tevent_req *req;
2201 struct smbd_smb2_request_read_state *state;
2202 struct tevent_req *subreq;
2204 req = tevent_req_create(mem_ctx, &state,
2205 struct smbd_smb2_request_read_state);
2206 if (req == NULL) {
2207 return NULL;
2209 state->missing = 0;
2210 state->asked_for_header = false;
2212 state->smb2_req = smbd_smb2_request_allocate(state);
2213 if (tevent_req_nomem(state->smb2_req, req)) {
2214 return tevent_req_post(req, ev);
2216 state->smb2_req->sconn = sconn;
2218 subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
2219 sconn->smb2.recv_queue,
2220 smbd_smb2_request_next_vector,
2221 state);
2222 if (tevent_req_nomem(subreq, req)) {
2223 return tevent_req_post(req, ev);
2225 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2227 return req;
2230 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2231 void *private_data,
2232 TALLOC_CTX *mem_ctx,
2233 struct iovec **_vector,
2234 size_t *_count)
2236 struct smbd_smb2_request_read_state *state =
2237 talloc_get_type_abort(private_data,
2238 struct smbd_smb2_request_read_state);
2239 struct smbd_smb2_request *req = state->smb2_req;
2240 struct iovec *vector;
2241 int idx = req->in.vector_count;
2242 size_t len = 0;
2243 uint8_t *buf = NULL;
2245 if (req->in.vector_count == 0) {
2247 * first we need to get the NBT header
2249 req->in.vector = talloc_array(req, struct iovec,
2250 req->in.vector_count + 1);
2251 if (req->in.vector == NULL) {
2252 return -1;
2254 req->in.vector_count += 1;
2256 req->in.vector[idx].iov_base = (void *)req->in.nbt_hdr;
2257 req->in.vector[idx].iov_len = 4;
2259 vector = talloc_array(mem_ctx, struct iovec, 1);
2260 if (vector == NULL) {
2261 return -1;
2264 vector[0] = req->in.vector[idx];
2266 *_vector = vector;
2267 *_count = 1;
2268 return 0;
2271 if (req->in.vector_count == 1) {
2273 * Now we analyze the NBT header
2275 state->missing = smb2_len(req->in.vector[0].iov_base);
2277 if (state->missing == 0) {
2278 /* if there're no remaining bytes, we're done */
2279 *_vector = NULL;
2280 *_count = 0;
2281 return 0;
2284 req->in.vector = talloc_realloc(req, req->in.vector,
2285 struct iovec,
2286 req->in.vector_count + 1);
2287 if (req->in.vector == NULL) {
2288 return -1;
2290 req->in.vector_count += 1;
2292 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
2294 * it's a special NBT message,
2295 * so get all remaining bytes
2297 len = state->missing;
2298 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
2300 * it's an invalid message, just read what we can get
2301 * and let the caller handle the error
2303 len = state->missing;
2304 } else {
2306 * We assume it's a SMB2 request,
2307 * and we first get the header and the
2308 * first 2 bytes (the struct size) of the body
2310 len = SMB2_HDR_BODY + 2;
2312 state->asked_for_header = true;
2315 state->missing -= len;
2317 buf = talloc_array(req->in.vector, uint8_t, len);
2318 if (buf == NULL) {
2319 return -1;
2322 req->in.vector[idx].iov_base = (void *)buf;
2323 req->in.vector[idx].iov_len = len;
2325 vector = talloc_array(mem_ctx, struct iovec, 1);
2326 if (vector == NULL) {
2327 return -1;
2330 vector[0] = req->in.vector[idx];
2332 *_vector = vector;
2333 *_count = 1;
2334 return 0;
2337 if (state->missing == 0) {
2338 /* if there're no remaining bytes, we're done */
2339 *_vector = NULL;
2340 *_count = 0;
2341 return 0;
2344 if (state->asked_for_header) {
2345 const uint8_t *hdr;
2346 size_t full_size;
2347 size_t next_command_ofs;
2348 size_t body_size;
2349 uint8_t *body;
2350 size_t dyn_size;
2351 uint8_t *dyn;
2352 bool invalid = false;
2354 state->asked_for_header = false;
2357 * We got the SMB2 header and the first 2 bytes
2358 * of the body. We fix the size to just the header
2359 * and manually copy the 2 first bytes to the body section
2361 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
2362 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
2364 /* allocate vectors for body and dynamic areas */
2365 req->in.vector = talloc_realloc(req, req->in.vector,
2366 struct iovec,
2367 req->in.vector_count + 2);
2368 if (req->in.vector == NULL) {
2369 return -1;
2371 req->in.vector_count += 2;
2373 full_size = state->missing + SMB2_HDR_BODY + 2;
2374 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
2375 body_size = SVAL(hdr, SMB2_HDR_BODY);
2377 if (next_command_ofs != 0) {
2378 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
2380 * this is invalid, just return a zero
2381 * body and let the caller deal with the error
2383 invalid = true;
2384 } else if (next_command_ofs > full_size) {
2386 * this is invalid, just return a zero
2387 * body and let the caller deal with the error
2389 invalid = true;
2390 } else {
2391 full_size = next_command_ofs;
2395 if (!invalid) {
2396 if (body_size < 2) {
2398 * this is invalid, just return a zero
2399 * body and let the caller deal with the error
2401 invalid = true;
2405 * Mask out the lowest bit, the "dynamic" part
2406 * of body_size.
2408 body_size &= ~1;
2410 if (body_size > (full_size - SMB2_HDR_BODY)) {
2412 * this is invalid, just return a zero
2413 * body and let the caller deal with the error
2415 invalid = true;
2419 if (invalid) {
2420 /* the caller should check this */
2421 body_size = 2;
2424 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
2426 state->missing -= (body_size - 2) + dyn_size;
2428 body = talloc_array(req->in.vector, uint8_t, body_size);
2429 if (body == NULL) {
2430 return -1;
2433 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
2434 if (dyn == NULL) {
2435 return -1;
2438 req->in.vector[idx].iov_base = (void *)body;
2439 req->in.vector[idx].iov_len = body_size;
2440 req->in.vector[idx+1].iov_base = (void *)dyn;
2441 req->in.vector[idx+1].iov_len = dyn_size;
2443 vector = talloc_array(mem_ctx, struct iovec, 2);
2444 if (vector == NULL) {
2445 return -1;
2449 * the first 2 bytes of the body were already fetched
2450 * together with the header
2452 memcpy(body, hdr + SMB2_HDR_BODY, 2);
2453 vector[0].iov_base = body + 2;
2454 vector[0].iov_len = body_size - 2;
2456 vector[1] = req->in.vector[idx+1];
2458 *_vector = vector;
2459 *_count = 2;
2460 return 0;
2464 * when we endup here, we're looking for a new SMB2 request
2465 * next. And we ask for its header and the first 2 bytes of
2466 * the body (like we did for the first SMB2 request).
2469 req->in.vector = talloc_realloc(req, req->in.vector,
2470 struct iovec,
2471 req->in.vector_count + 1);
2472 if (req->in.vector == NULL) {
2473 return -1;
2475 req->in.vector_count += 1;
2478 * We assume it's a SMB2 request,
2479 * and we first get the header and the
2480 * first 2 bytes (the struct size) of the body
2482 len = SMB2_HDR_BODY + 2;
2484 if (len > state->missing) {
2485 /* let the caller handle the error */
2486 len = state->missing;
2489 state->missing -= len;
2490 state->asked_for_header = true;
2492 buf = talloc_array(req->in.vector, uint8_t, len);
2493 if (buf == NULL) {
2494 return -1;
2497 req->in.vector[idx].iov_base = (void *)buf;
2498 req->in.vector[idx].iov_len = len;
2500 vector = talloc_array(mem_ctx, struct iovec, 1);
2501 if (vector == NULL) {
2502 return -1;
2505 vector[0] = req->in.vector[idx];
2507 *_vector = vector;
2508 *_count = 1;
2509 return 0;
2512 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2514 struct tevent_req *req =
2515 tevent_req_callback_data(subreq,
2516 struct tevent_req);
2517 int ret;
2518 int sys_errno;
2519 NTSTATUS status;
2521 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2522 if (ret == -1) {
2523 status = map_nt_error_from_unix(sys_errno);
2524 tevent_req_nterror(req, status);
2525 return;
2528 tevent_req_done(req);
2531 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2532 TALLOC_CTX *mem_ctx,
2533 struct smbd_smb2_request **_smb2_req)
2535 struct smbd_smb2_request_read_state *state =
2536 tevent_req_data(req,
2537 struct smbd_smb2_request_read_state);
2538 NTSTATUS status;
2540 if (tevent_req_is_nterror(req, &status)) {
2541 tevent_req_received(req);
2542 return status;
2545 talloc_steal(mem_ctx, state->smb2_req->mem_pool);
2546 *_smb2_req = state->smb2_req;
2547 tevent_req_received(req);
2548 return NT_STATUS_OK;
2551 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2553 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2555 size_t max_send_queue_len;
2556 size_t cur_send_queue_len;
2557 struct tevent_req *subreq;
2559 if (sconn->smb2.compound_related_in_progress) {
2561 * Can't read another until the related
2562 * compound is done.
2564 return NT_STATUS_OK;
2567 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
2569 * if there is already a smbd_smb2_request_read
2570 * pending, we are done.
2572 return NT_STATUS_OK;
2575 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2576 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
2578 if (cur_send_queue_len > max_send_queue_len) {
2580 * if we have a lot of requests to send,
2581 * we wait until they are on the wire until we
2582 * ask for the next request.
2584 return NT_STATUS_OK;
2587 /* ask for the next request */
2588 subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
2589 if (subreq == NULL) {
2590 return NT_STATUS_NO_MEMORY;
2592 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2594 return NT_STATUS_OK;
2597 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2598 const uint8_t *inbuf, size_t size)
2600 NTSTATUS status;
2601 struct smbd_smb2_request *req = NULL;
2603 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2604 (unsigned int)size));
2606 status = smbd_initialize_smb2(sconn);
2607 if (!NT_STATUS_IS_OK(status)) {
2608 smbd_server_connection_terminate(sconn, nt_errstr(status));
2609 return;
2612 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2613 if (!NT_STATUS_IS_OK(status)) {
2614 smbd_server_connection_terminate(sconn, nt_errstr(status));
2615 return;
2618 status = smbd_smb2_request_setup_out(req);
2619 if (!NT_STATUS_IS_OK(status)) {
2620 smbd_server_connection_terminate(sconn, nt_errstr(status));
2621 return;
2624 status = smbd_smb2_request_dispatch(req);
2625 if (!NT_STATUS_IS_OK(status)) {
2626 smbd_server_connection_terminate(sconn, nt_errstr(status));
2627 return;
2630 status = smbd_smb2_request_next_incoming(sconn);
2631 if (!NT_STATUS_IS_OK(status)) {
2632 smbd_server_connection_terminate(sconn, nt_errstr(status));
2633 return;
2636 sconn->num_requests++;
2639 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2641 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2642 struct smbd_server_connection);
2643 NTSTATUS status;
2644 struct smbd_smb2_request *req = NULL;
2646 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2647 TALLOC_FREE(subreq);
2648 if (!NT_STATUS_IS_OK(status)) {
2649 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2650 nt_errstr(status)));
2651 smbd_server_connection_terminate(sconn, nt_errstr(status));
2652 return;
2655 if (req->in.nbt_hdr[0] != 0x00) {
2656 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
2657 req->in.nbt_hdr[0]));
2658 TALLOC_FREE(req);
2659 goto next;
2662 req->current_idx = 1;
2664 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2665 req->current_idx, req->in.vector_count));
2667 status = smbd_smb2_request_validate(req);
2668 if (!NT_STATUS_IS_OK(status)) {
2669 smbd_server_connection_terminate(sconn, nt_errstr(status));
2670 return;
2673 status = smbd_smb2_request_setup_out(req);
2674 if (!NT_STATUS_IS_OK(status)) {
2675 smbd_server_connection_terminate(sconn, nt_errstr(status));
2676 return;
2679 status = smbd_smb2_request_dispatch(req);
2680 if (!NT_STATUS_IS_OK(status)) {
2681 smbd_server_connection_terminate(sconn, nt_errstr(status));
2682 return;
2685 next:
2686 status = smbd_smb2_request_next_incoming(sconn);
2687 if (!NT_STATUS_IS_OK(status)) {
2688 smbd_server_connection_terminate(sconn, nt_errstr(status));
2689 return;
2692 sconn->num_requests++;
2694 /* The timeout_processing function isn't run nearly
2695 often enough to implement 'max log size' without
2696 overrunning the size of the file by many megabytes.
2697 This is especially true if we are running at debug
2698 level 10. Checking every 50 SMB2s is a nice
2699 tradeoff of performance vs log file size overrun. */
2701 if ((sconn->num_requests % 50) == 0 &&
2702 need_to_check_log_size()) {
2703 change_to_root_user();
2704 check_log_size();