s3-id_cache: Move id caches mgmt out of smbd
[Samba.git] / source3 / smbd / smb2_server.c
blob6fc4b5d702eeb1e5a6d666ce8c9dac150210d0d2
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 /* client just used a credit. */
326 SMB_ASSERT(sconn->smb2.credits_granted > 0);
327 sconn->smb2.credits_granted -= 1;
329 /* Mark the message_id as seen in the bitmap. */
330 bitmap_offset = (unsigned int)(message_id %
331 (uint64_t)(sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR));
332 if (bitmap_query(credits_bm, bitmap_offset)) {
333 DEBUG(0,("smb2_validate_message_id: duplicate message_id "
334 "%llu (bm offset %u)\n",
335 (unsigned long long)message_id,
336 bitmap_offset));
337 return false;
339 bitmap_set(credits_bm, bitmap_offset);
341 if (message_id == sconn->smb2.seqnum_low + 1) {
342 /* Move the window forward by all the message_id's
343 already seen. */
344 while (bitmap_query(credits_bm, bitmap_offset)) {
345 DEBUG(10,("smb2_validate_message_id: clearing "
346 "id %llu (position %u) from bitmap\n",
347 (unsigned long long)(sconn->smb2.seqnum_low + 1),
348 bitmap_offset ));
349 bitmap_clear(credits_bm, bitmap_offset);
350 sconn->smb2.seqnum_low += 1;
351 bitmap_offset = (bitmap_offset + 1) %
352 (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR);
356 return true;
359 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
361 int count;
362 int idx;
363 bool compound_related = false;
365 count = req->in.vector_count;
367 if (count < 4) {
368 /* It's not a SMB2 request */
369 return NT_STATUS_INVALID_PARAMETER;
372 for (idx=1; idx < count; idx += 3) {
373 const uint8_t *inhdr = NULL;
374 uint32_t flags;
376 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
377 return NT_STATUS_INVALID_PARAMETER;
380 if (req->in.vector[idx+1].iov_len < 2) {
381 return NT_STATUS_INVALID_PARAMETER;
384 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
386 /* Check the SMB2 header */
387 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
388 return NT_STATUS_INVALID_PARAMETER;
391 if (!smb2_validate_message_id(req->sconn, inhdr)) {
392 return NT_STATUS_INVALID_PARAMETER;
395 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
396 if (idx == 1) {
398 * the 1st request should never have the
399 * SMB2_HDR_FLAG_CHAINED flag set
401 if (flags & SMB2_HDR_FLAG_CHAINED) {
402 req->next_status = NT_STATUS_INVALID_PARAMETER;
403 return NT_STATUS_OK;
405 } else if (idx == 4) {
407 * the 2nd request triggers related vs. unrelated
408 * compounded requests
410 if (flags & SMB2_HDR_FLAG_CHAINED) {
411 compound_related = true;
413 } else if (idx > 4) {
414 #if 0
416 * It seems the this tests are wrong
417 * see the SMB2-COMPOUND test
421 * all other requests should match the 2nd one
423 if (flags & SMB2_HDR_FLAG_CHAINED) {
424 if (!compound_related) {
425 req->next_status =
426 NT_STATUS_INVALID_PARAMETER;
427 return NT_STATUS_OK;
429 } else {
430 if (compound_related) {
431 req->next_status =
432 NT_STATUS_INVALID_PARAMETER;
433 return NT_STATUS_OK;
436 #endif
440 return NT_STATUS_OK;
443 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
444 const struct iovec *in_vector,
445 struct iovec *out_vector)
447 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
448 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
449 uint16_t credits_requested;
450 uint32_t out_flags;
451 uint16_t credits_granted = 0;
453 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
454 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
456 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
458 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
460 * In case we already send an async interim
461 * response, we should not grant
462 * credits on the final response.
464 credits_requested = 0;
467 if (credits_requested) {
468 uint16_t modified_credits_requested;
469 uint32_t multiplier;
472 * Split up max_credits into 1/16ths, and then scale
473 * the requested credits by how many 16ths have been
474 * currently granted. Less than 1/16th == grant all
475 * requested (100%), scale down as more have been
476 * granted. Never ask for less than 1 as the client
477 * asked for at least 1. JRA.
480 multiplier = 16 - (((sconn->smb2.credits_granted * 16) / sconn->smb2.max_credits) % 16);
482 modified_credits_requested = (multiplier * credits_requested) / 16;
483 if (modified_credits_requested == 0) {
484 modified_credits_requested = 1;
487 /* Remember what we gave out. */
488 credits_granted = MIN(modified_credits_requested,
489 (sconn->smb2.max_credits - sconn->smb2.credits_granted));
492 if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
493 /* First negprot packet, or ensure the client credits can
494 never drop to zero. */
495 credits_granted = 1;
498 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
499 sconn->smb2.credits_granted += credits_granted;
501 DEBUG(10,("smb2_set_operation_credit: requested %u, "
502 "granted %u, total granted %u\n",
503 (unsigned int)credits_requested,
504 (unsigned int)credits_granted,
505 (unsigned int)sconn->smb2.credits_granted ));
508 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
509 struct smbd_smb2_request *outreq)
511 int count, idx;
513 count = outreq->out.vector_count;
515 for (idx=1; idx < count; idx += 3) {
516 smb2_set_operation_credit(outreq->sconn,
517 &inreq->in.vector[idx],
518 &outreq->out.vector[idx]);
522 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
524 struct iovec *vector;
525 int count;
526 int idx;
528 count = req->in.vector_count;
529 vector = talloc_zero_array(req, struct iovec, count);
530 if (vector == NULL) {
531 return NT_STATUS_NO_MEMORY;
534 vector[0].iov_base = req->out.nbt_hdr;
535 vector[0].iov_len = 4;
536 SIVAL(req->out.nbt_hdr, 0, 0);
538 for (idx=1; idx < count; idx += 3) {
539 const uint8_t *inhdr = NULL;
540 uint32_t in_flags;
541 uint8_t *outhdr = NULL;
542 uint8_t *outbody = NULL;
543 uint32_t next_command_ofs = 0;
544 struct iovec *current = &vector[idx];
546 if ((idx + 3) < count) {
547 /* we have a next command -
548 * setup for the error case. */
549 next_command_ofs = SMB2_HDR_BODY + 9;
552 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
553 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
555 outhdr = talloc_zero_array(vector, uint8_t,
556 OUTVEC_ALLOC_SIZE);
557 if (outhdr == NULL) {
558 return NT_STATUS_NO_MEMORY;
561 outbody = outhdr + SMB2_HDR_BODY;
563 current[0].iov_base = (void *)outhdr;
564 current[0].iov_len = SMB2_HDR_BODY;
566 current[1].iov_base = (void *)outbody;
567 current[1].iov_len = 8;
569 current[2].iov_base = NULL;
570 current[2].iov_len = 0;
572 /* setup the SMB2 header */
573 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
574 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
575 SSVAL(outhdr, SMB2_HDR_EPOCH, 0);
576 SIVAL(outhdr, SMB2_HDR_STATUS,
577 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
578 SSVAL(outhdr, SMB2_HDR_OPCODE,
579 SVAL(inhdr, SMB2_HDR_OPCODE));
580 SIVAL(outhdr, SMB2_HDR_FLAGS,
581 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
582 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
583 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
584 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
585 SIVAL(outhdr, SMB2_HDR_PID,
586 IVAL(inhdr, SMB2_HDR_PID));
587 SIVAL(outhdr, SMB2_HDR_TID,
588 IVAL(inhdr, SMB2_HDR_TID));
589 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
590 BVAL(inhdr, SMB2_HDR_SESSION_ID));
591 memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16);
593 /* setup error body header */
594 SSVAL(outbody, 0x00, 0x08 + 1);
595 SSVAL(outbody, 0x02, 0);
596 SIVAL(outbody, 0x04, 0);
599 req->out.vector = vector;
600 req->out.vector_count = count;
602 /* setup the length of the NBT packet */
603 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
605 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
607 return NT_STATUS_OK;
610 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
611 const char *reason,
612 const char *location)
614 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
615 reason, location));
616 exit_server_cleanly(reason);
619 static bool dup_smb2_vec3(TALLOC_CTX *ctx,
620 struct iovec *outvec,
621 const struct iovec *srcvec)
623 /* vec[0] is always boilerplate and must
624 * be allocated with size OUTVEC_ALLOC_SIZE. */
626 outvec[0].iov_base = talloc_memdup(ctx,
627 srcvec[0].iov_base,
628 OUTVEC_ALLOC_SIZE);
629 if (!outvec[0].iov_base) {
630 return false;
632 outvec[0].iov_len = SMB2_HDR_BODY;
635 * If this is a "standard" vec[1] of length 8,
636 * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
637 * then duplicate this. Else use talloc_memdup().
640 if (srcvec[1].iov_len == 8 &&
641 srcvec[1].iov_base ==
642 ((uint8_t *)srcvec[0].iov_base) +
643 SMB2_HDR_BODY) {
644 outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
645 SMB2_HDR_BODY;
646 outvec[1].iov_len = 8;
647 } else {
648 outvec[1].iov_base = talloc_memdup(ctx,
649 srcvec[1].iov_base,
650 srcvec[1].iov_len);
651 if (!outvec[1].iov_base) {
652 return false;
654 outvec[1].iov_len = srcvec[1].iov_len;
658 * If this is a "standard" vec[2] of length 1,
659 * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
660 * then duplicate this. Else use talloc_memdup().
663 if (srcvec[2].iov_base &&
664 srcvec[2].iov_len) {
665 if (srcvec[2].iov_base ==
666 ((uint8_t *)srcvec[0].iov_base) +
667 (OUTVEC_ALLOC_SIZE - 1) &&
668 srcvec[2].iov_len == 1) {
669 /* Common SMB2 error packet case. */
670 outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
671 (OUTVEC_ALLOC_SIZE - 1);
672 } else {
673 outvec[2].iov_base = talloc_memdup(ctx,
674 srcvec[2].iov_base,
675 srcvec[2].iov_len);
676 if (!outvec[2].iov_base) {
677 return false;
680 outvec[2].iov_len = srcvec[2].iov_len;
681 } else {
682 outvec[2].iov_base = NULL;
683 outvec[2].iov_len = 0;
685 return true;
688 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
690 struct smbd_smb2_request *newreq = NULL;
691 struct iovec *outvec = NULL;
692 int count = req->out.vector_count;
693 int i;
695 newreq = smbd_smb2_request_allocate(req->sconn);
696 if (!newreq) {
697 return NULL;
700 newreq->sconn = req->sconn;
701 newreq->session = req->session;
702 newreq->do_signing = req->do_signing;
703 newreq->current_idx = req->current_idx;
704 newreq->async = false;
705 newreq->cancelled = false;
706 /* Note we are leaving:
707 ->tcon
708 ->smb1req
709 ->compat_chain_fsp
710 uninitialized as NULL here as
711 they're not used in the interim
712 response code. JRA. */
714 outvec = talloc_zero_array(newreq, struct iovec, count);
715 if (!outvec) {
716 TALLOC_FREE(newreq);
717 return NULL;
719 newreq->out.vector = outvec;
720 newreq->out.vector_count = count;
722 /* Setup the outvec's identically to req. */
723 outvec[0].iov_base = newreq->out.nbt_hdr;
724 outvec[0].iov_len = 4;
725 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
727 /* Setup the vectors identically to the ones in req. */
728 for (i = 1; i < count; i += 3) {
729 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
730 break;
734 if (i < count) {
735 /* Alloc failed. */
736 TALLOC_FREE(newreq);
737 return NULL;
740 smb2_setup_nbt_length(newreq->out.vector,
741 newreq->out.vector_count);
743 return newreq;
746 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
748 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
750 int i = 0;
751 uint8_t *outhdr = NULL;
752 struct smbd_smb2_request *nreq = NULL;
754 /* Create a new smb2 request we'll use
755 for the interim return. */
756 nreq = dup_smb2_req(req);
757 if (!nreq) {
758 return NT_STATUS_NO_MEMORY;
761 /* Lose the last 3 out vectors. They're the
762 ones we'll be using for the async reply. */
763 nreq->out.vector_count -= 3;
765 smb2_setup_nbt_length(nreq->out.vector,
766 nreq->out.vector_count);
768 /* Step back to the previous reply. */
769 i = nreq->current_idx - 3;
770 outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
771 /* And end the chain. */
772 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
774 /* Calculate outgoing credits */
775 smb2_calculate_credits(req, nreq);
777 /* Re-sign if needed. */
778 if (nreq->do_signing) {
779 NTSTATUS status;
780 status = smb2_signing_sign_pdu(nreq->session->session_key,
781 &nreq->out.vector[i], 3);
782 if (!NT_STATUS_IS_OK(status)) {
783 return status;
786 if (DEBUGLEVEL >= 10) {
787 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
788 (unsigned int)nreq->current_idx );
789 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
790 (unsigned int)nreq->out.vector_count );
791 print_req_vectors(nreq);
793 nreq->subreq = tstream_writev_queue_send(nreq,
794 nreq->sconn->smb2.event_ctx,
795 nreq->sconn->smb2.stream,
796 nreq->sconn->smb2.send_queue,
797 nreq->out.vector,
798 nreq->out.vector_count);
800 if (nreq->subreq == NULL) {
801 return NT_STATUS_NO_MEMORY;
804 tevent_req_set_callback(nreq->subreq,
805 smbd_smb2_request_writev_done,
806 nreq);
808 return NT_STATUS_OK;
811 struct smbd_smb2_request_pending_state {
812 struct smbd_server_connection *sconn;
813 uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
814 struct iovec vector[3];
817 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
819 struct smbd_smb2_request_pending_state *state =
820 tevent_req_callback_data(subreq,
821 struct smbd_smb2_request_pending_state);
822 struct smbd_server_connection *sconn = state->sconn;
823 int ret;
824 int sys_errno;
826 ret = tstream_writev_queue_recv(subreq, &sys_errno);
827 TALLOC_FREE(subreq);
828 if (ret == -1) {
829 NTSTATUS status = map_nt_error_from_unix(sys_errno);
830 smbd_server_connection_terminate(sconn, nt_errstr(status));
831 return;
834 TALLOC_FREE(state);
837 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
838 struct tevent_req *subreq)
840 NTSTATUS status;
841 struct smbd_smb2_request_pending_state *state = NULL;
842 int i = req->current_idx;
843 uint8_t *reqhdr = NULL;
844 uint8_t *hdr = NULL;
845 uint8_t *body = NULL;
846 uint32_t flags = 0;
847 uint64_t message_id = 0;
848 uint64_t async_id = 0;
849 struct iovec *outvec = NULL;
851 if (!tevent_req_is_in_progress(subreq)) {
852 return NT_STATUS_OK;
855 req->subreq = subreq;
856 subreq = NULL;
858 if (req->async) {
859 /* We're already async. */
860 return NT_STATUS_OK;
863 if (req->in.vector_count > i + 3) {
865 * We're trying to go async in a compound
866 * request chain. This is not allowed.
867 * Cancel the outstanding request.
869 tevent_req_cancel(req->subreq);
870 return smbd_smb2_request_error(req,
871 NT_STATUS_INSUFFICIENT_RESOURCES);
874 if (DEBUGLEVEL >= 10) {
875 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
876 (unsigned int)req->current_idx );
877 print_req_vectors(req);
880 if (req->out.vector_count > 4) {
881 /* This is a compound reply. We
882 * must do an interim response
883 * followed by the async response
884 * to match W2K8R2.
886 status = smb2_send_async_interim_response(req);
887 if (!NT_STATUS_IS_OK(status)) {
888 return status;
892 /* Don't return an intermediate packet on a pipe read/write. */
893 if (req->tcon && req->tcon->compat_conn && IS_IPC(req->tcon->compat_conn)) {
894 return NT_STATUS_OK;
897 reqhdr = (uint8_t *)req->out.vector[i].iov_base;
898 flags = (IVAL(reqhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
899 message_id = BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
900 async_id = message_id; /* keep it simple for now... */
903 * What we send is identical to a smbd_smb2_request_error
904 * packet with an error status of STATUS_PENDING. Make use
905 * of this fact sometime when refactoring. JRA.
908 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
909 if (state == NULL) {
910 return NT_STATUS_NO_MEMORY;
912 state->sconn = req->sconn;
914 state->vector[0].iov_base = (void *)state->buf;
915 state->vector[0].iov_len = 4;
917 state->vector[1].iov_base = state->buf + 4;
918 state->vector[1].iov_len = SMB2_HDR_BODY;
920 state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
921 state->vector[2].iov_len = 9;
923 smb2_setup_nbt_length(state->vector, 3);
925 hdr = (uint8_t *)state->vector[1].iov_base;
926 body = (uint8_t *)state->vector[2].iov_base;
928 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
929 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
930 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
931 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
932 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE));
934 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
935 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
936 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
937 SBVAL(hdr, SMB2_HDR_PID, async_id);
938 SBVAL(hdr, SMB2_HDR_SESSION_ID,
939 BVAL(reqhdr, SMB2_HDR_SESSION_ID));
940 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
942 SSVAL(body, 0x00, 0x08 + 1);
944 SCVAL(body, 0x02, 0);
945 SCVAL(body, 0x03, 0);
946 SIVAL(body, 0x04, 0);
947 /* Match W2K8R2... */
948 SCVAL(body, 0x08, 0x21);
950 /* Ensure we correctly go through crediting. Grant
951 the credits now, and zero credits on the final
952 response. */
953 smb2_set_operation_credit(req->sconn,
954 &req->in.vector[i],
955 &state->vector[1]);
957 if (req->do_signing) {
958 status = smb2_signing_sign_pdu(req->session->session_key,
959 &state->vector[1], 2);
960 if (!NT_STATUS_IS_OK(status)) {
961 return status;
965 subreq = tstream_writev_queue_send(state,
966 req->sconn->smb2.event_ctx,
967 req->sconn->smb2.stream,
968 req->sconn->smb2.send_queue,
969 state->vector,
972 if (subreq == NULL) {
973 return NT_STATUS_NO_MEMORY;
976 tevent_req_set_callback(subreq,
977 smbd_smb2_request_pending_writev_done,
978 state);
980 /* Note we're going async with this request. */
981 req->async = true;
984 * Now manipulate req so that the outstanding async request
985 * is the only one left in the struct smbd_smb2_request.
988 if (req->current_idx == 1) {
989 /* There was only one. */
990 goto out;
993 /* Re-arrange the in.vectors. */
994 req->in.vector[1] = req->in.vector[i];
995 req->in.vector[2] = req->in.vector[i+1];
996 req->in.vector[3] = req->in.vector[i+2];
997 req->in.vector_count = 4;
998 /* Reset the new in size. */
999 smb2_setup_nbt_length(req->in.vector, 4);
1001 /* Now recreate the out.vectors. */
1002 outvec = talloc_zero_array(req, struct iovec, 4);
1003 if (!outvec) {
1004 return NT_STATUS_NO_MEMORY;
1007 /* 0 is always boilerplate and must
1008 * be of size 4 for the length field. */
1010 outvec[0].iov_base = req->out.nbt_hdr;
1011 outvec[0].iov_len = 4;
1012 SIVAL(req->out.nbt_hdr, 0, 0);
1014 if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
1015 return NT_STATUS_NO_MEMORY;
1018 TALLOC_FREE(req->out.vector);
1020 req->out.vector = outvec;
1022 req->current_idx = 1;
1023 req->out.vector_count = 4;
1025 out:
1027 smb2_setup_nbt_length(req->out.vector,
1028 req->out.vector_count);
1030 /* Ensure our final reply matches the interim one. */
1031 reqhdr = (uint8_t *)req->out.vector[1].iov_base;
1032 SIVAL(reqhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1033 SBVAL(reqhdr, SMB2_HDR_PID, async_id);
1036 const uint8_t *inhdr =
1037 (const uint8_t *)req->in.vector[1].iov_base;
1038 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1039 "going async\n",
1040 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1041 (unsigned long long)async_id ));
1043 return NT_STATUS_OK;
1046 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1048 struct smbd_server_connection *sconn = req->sconn;
1049 struct smbd_smb2_request *cur;
1050 const uint8_t *inhdr;
1051 int i = req->current_idx;
1052 uint32_t flags;
1053 uint64_t search_message_id;
1054 uint64_t search_async_id;
1055 uint64_t found_id;
1057 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1059 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1060 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1061 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1064 * we don't need the request anymore
1065 * cancel requests never have a response
1067 DLIST_REMOVE(req->sconn->smb2.requests, req);
1068 TALLOC_FREE(req);
1070 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1071 const uint8_t *outhdr;
1072 uint64_t message_id;
1073 uint64_t async_id;
1075 i = cur->current_idx;
1077 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
1079 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1080 async_id = BVAL(outhdr, SMB2_HDR_PID);
1082 if (flags & SMB2_HDR_FLAG_ASYNC) {
1083 if (search_async_id == async_id) {
1084 found_id = async_id;
1085 break;
1087 } else {
1088 if (search_message_id == message_id) {
1089 found_id = message_id;
1090 break;
1095 if (cur && cur->subreq) {
1096 inhdr = (const uint8_t *)cur->in.vector[i].iov_base;
1097 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1098 "cancel opcode[%s] mid %llu\n",
1099 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1100 (unsigned long long)found_id ));
1101 tevent_req_cancel(cur->subreq);
1104 return NT_STATUS_OK;
1107 /*************************************************************
1108 Ensure an incoming tid is a valid one for us to access.
1109 Change to the associated uid credentials and chdir to the
1110 valid tid directory.
1111 *************************************************************/
1113 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1115 const uint8_t *inhdr;
1116 const uint8_t *outhdr;
1117 int i = req->current_idx;
1118 uint32_t in_tid;
1119 void *p;
1120 struct smbd_smb2_tcon *tcon;
1121 bool chained_fixup = false;
1123 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1125 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1127 if (in_tid == (0xFFFFFFFF)) {
1128 if (req->async) {
1130 * async request - fill in tid from
1131 * already setup out.vector[].iov_base.
1133 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1134 in_tid = IVAL(outhdr, SMB2_HDR_TID);
1135 } else if (i > 2) {
1137 * Chained request - fill in tid from
1138 * the previous request out.vector[].iov_base.
1140 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1141 in_tid = IVAL(outhdr, SMB2_HDR_TID);
1142 chained_fixup = true;
1146 /* lookup an existing session */
1147 p = idr_find(req->session->tcons.idtree, in_tid);
1148 if (p == NULL) {
1149 return NT_STATUS_NETWORK_NAME_DELETED;
1151 tcon = talloc_get_type_abort(p, struct smbd_smb2_tcon);
1153 if (!change_to_user(tcon->compat_conn,req->session->vuid)) {
1154 return NT_STATUS_ACCESS_DENIED;
1157 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1158 if (!set_current_service(tcon->compat_conn, 0, true)) {
1159 return NT_STATUS_ACCESS_DENIED;
1162 req->tcon = tcon;
1164 if (chained_fixup) {
1165 /* Fix up our own outhdr. */
1166 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1167 SIVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_TID, in_tid);
1170 return NT_STATUS_OK;
1173 /*************************************************************
1174 Ensure an incoming session_id is a valid one for us to access.
1175 *************************************************************/
1177 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1179 const uint8_t *inhdr;
1180 const uint8_t *outhdr;
1181 int i = req->current_idx;
1182 uint64_t in_session_id;
1183 void *p;
1184 struct smbd_smb2_session *session;
1185 bool chained_fixup = false;
1187 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1189 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1191 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
1192 if (req->async) {
1194 * async request - fill in session_id from
1195 * already setup request out.vector[].iov_base.
1197 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1198 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1199 } else if (i > 2) {
1201 * Chained request - fill in session_id from
1202 * the previous request out.vector[].iov_base.
1204 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1205 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1206 chained_fixup = true;
1210 /* lookup an existing session */
1211 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
1212 if (p == NULL) {
1213 return NT_STATUS_USER_SESSION_DELETED;
1215 session = talloc_get_type_abort(p, struct smbd_smb2_session);
1217 if (!NT_STATUS_IS_OK(session->status)) {
1218 return NT_STATUS_ACCESS_DENIED;
1221 set_current_user_info(session->session_info->unix_info->sanitized_username,
1222 session->session_info->unix_info->unix_name,
1223 session->session_info->info->domain_name);
1225 req->session = session;
1227 if (chained_fixup) {
1228 /* Fix up our own outhdr. */
1229 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1230 SBVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_SESSION_ID, in_session_id);
1232 return NT_STATUS_OK;
1235 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1237 const uint8_t *inhdr;
1238 int i = req->current_idx;
1239 uint16_t opcode;
1240 uint32_t flags;
1241 uint64_t mid;
1242 NTSTATUS status;
1243 NTSTATUS session_status;
1244 uint32_t allowed_flags;
1245 NTSTATUS return_value;
1247 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1249 /* TODO: verify more things */
1251 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1252 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1253 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1254 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1255 smb2_opcode_name(opcode),
1256 (unsigned long long)mid));
1258 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1259 SMB2_HDR_FLAG_SIGNED |
1260 SMB2_HDR_FLAG_DFS;
1261 if (opcode == SMB2_OP_CANCEL) {
1262 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1264 if ((flags & ~allowed_flags) != 0) {
1265 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1269 * Check if the client provided a valid session id,
1270 * if so smbd_smb2_request_check_session() calls
1271 * set_current_user_info().
1273 * As some command don't require a valid session id
1274 * we defer the check of the session_status
1276 session_status = smbd_smb2_request_check_session(req);
1278 req->do_signing = false;
1279 if (flags & SMB2_HDR_FLAG_SIGNED) {
1280 if (!NT_STATUS_IS_OK(session_status)) {
1281 return smbd_smb2_request_error(req, session_status);
1284 req->do_signing = true;
1285 status = smb2_signing_check_pdu(req->session->session_key,
1286 &req->in.vector[i], 3);
1287 if (!NT_STATUS_IS_OK(status)) {
1288 return smbd_smb2_request_error(req, status);
1290 } else if (req->session && req->session->do_signing) {
1291 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1294 if (flags & SMB2_HDR_FLAG_CHAINED) {
1296 * This check is mostly for giving the correct error code
1297 * for compounded requests.
1299 * TODO: we may need to move this after the session
1300 * and tcon checks.
1302 if (!NT_STATUS_IS_OK(req->next_status)) {
1303 return smbd_smb2_request_error(req, req->next_status);
1305 } else {
1306 req->compat_chain_fsp = NULL;
1309 switch (opcode) {
1310 case SMB2_OP_NEGPROT:
1311 /* This call needs to be run as root */
1312 change_to_root_user();
1315 START_PROFILE(smb2_negprot);
1316 return_value = smbd_smb2_request_process_negprot(req);
1317 END_PROFILE(smb2_negprot);
1319 break;
1321 case SMB2_OP_SESSSETUP:
1322 /* This call needs to be run as root */
1323 change_to_root_user();
1326 START_PROFILE(smb2_sesssetup);
1327 return_value = smbd_smb2_request_process_sesssetup(req);
1328 END_PROFILE(smb2_sesssetup);
1330 break;
1332 case SMB2_OP_LOGOFF:
1333 if (!NT_STATUS_IS_OK(session_status)) {
1334 return_value = smbd_smb2_request_error(req, session_status);
1335 break;
1338 /* This call needs to be run as root */
1339 change_to_root_user();
1342 START_PROFILE(smb2_logoff);
1343 return_value = smbd_smb2_request_process_logoff(req);
1344 END_PROFILE(smb2_logoff);
1346 break;
1348 case SMB2_OP_TCON:
1349 if (!NT_STATUS_IS_OK(session_status)) {
1350 return_value = smbd_smb2_request_error(req, session_status);
1351 break;
1355 * This call needs to be run as root.
1357 * smbd_smb2_request_process_tcon()
1358 * calls make_connection_snum(), which will call
1359 * change_to_user(), when needed.
1361 change_to_root_user();
1364 START_PROFILE(smb2_tcon);
1365 return_value = smbd_smb2_request_process_tcon(req);
1366 END_PROFILE(smb2_tcon);
1368 break;
1370 case SMB2_OP_TDIS:
1371 if (!NT_STATUS_IS_OK(session_status)) {
1372 return_value = smbd_smb2_request_error(req, session_status);
1373 break;
1376 * This call needs to be run as user.
1378 * smbd_smb2_request_check_tcon()
1379 * calls change_to_user() on success.
1381 status = smbd_smb2_request_check_tcon(req);
1382 if (!NT_STATUS_IS_OK(status)) {
1383 return_value = smbd_smb2_request_error(req, status);
1384 break;
1386 /* This call needs to be run as root */
1387 change_to_root_user();
1391 START_PROFILE(smb2_tdis);
1392 return_value = smbd_smb2_request_process_tdis(req);
1393 END_PROFILE(smb2_tdis);
1395 break;
1397 case SMB2_OP_CREATE:
1398 if (!NT_STATUS_IS_OK(session_status)) {
1399 return_value = smbd_smb2_request_error(req, session_status);
1400 break;
1403 * This call needs to be run as user.
1405 * smbd_smb2_request_check_tcon()
1406 * calls change_to_user() on success.
1408 status = smbd_smb2_request_check_tcon(req);
1409 if (!NT_STATUS_IS_OK(status)) {
1410 return_value = smbd_smb2_request_error(req, status);
1411 break;
1415 START_PROFILE(smb2_create);
1416 return_value = smbd_smb2_request_process_create(req);
1417 END_PROFILE(smb2_create);
1419 break;
1421 case SMB2_OP_CLOSE:
1422 if (!NT_STATUS_IS_OK(session_status)) {
1423 return_value = smbd_smb2_request_error(req, session_status);
1424 break;
1427 * This call needs to be run as user.
1429 * smbd_smb2_request_check_tcon()
1430 * calls change_to_user() on success.
1432 status = smbd_smb2_request_check_tcon(req);
1433 if (!NT_STATUS_IS_OK(status)) {
1434 return_value = smbd_smb2_request_error(req, status);
1435 break;
1439 START_PROFILE(smb2_close);
1440 return_value = smbd_smb2_request_process_close(req);
1441 END_PROFILE(smb2_close);
1443 break;
1445 case SMB2_OP_FLUSH:
1446 if (!NT_STATUS_IS_OK(session_status)) {
1447 return_value = smbd_smb2_request_error(req, session_status);
1448 break;
1451 * This call needs to be run as user.
1453 * smbd_smb2_request_check_tcon()
1454 * calls change_to_user() on success.
1456 status = smbd_smb2_request_check_tcon(req);
1457 if (!NT_STATUS_IS_OK(status)) {
1458 return_value = smbd_smb2_request_error(req, status);
1459 break;
1463 START_PROFILE(smb2_flush);
1464 return_value = smbd_smb2_request_process_flush(req);
1465 END_PROFILE(smb2_flush);
1467 break;
1469 case SMB2_OP_READ:
1470 if (!NT_STATUS_IS_OK(session_status)) {
1471 return_value = smbd_smb2_request_error(req, session_status);
1472 break;
1475 * This call needs to be run as user.
1477 * smbd_smb2_request_check_tcon()
1478 * calls change_to_user() on success.
1480 status = smbd_smb2_request_check_tcon(req);
1481 if (!NT_STATUS_IS_OK(status)) {
1482 return_value = smbd_smb2_request_error(req, status);
1483 break;
1487 START_PROFILE(smb2_read);
1488 return_value = smbd_smb2_request_process_read(req);
1489 END_PROFILE(smb2_read);
1491 break;
1493 case SMB2_OP_WRITE:
1494 if (!NT_STATUS_IS_OK(session_status)) {
1495 return_value = smbd_smb2_request_error(req, session_status);
1496 break;
1499 * This call needs to be run as user.
1501 * smbd_smb2_request_check_tcon()
1502 * calls change_to_user() on success.
1504 status = smbd_smb2_request_check_tcon(req);
1505 if (!NT_STATUS_IS_OK(status)) {
1506 return_value = smbd_smb2_request_error(req, status);
1507 break;
1511 START_PROFILE(smb2_write);
1512 return_value = smbd_smb2_request_process_write(req);
1513 END_PROFILE(smb2_write);
1515 break;
1517 case SMB2_OP_LOCK:
1518 if (!NT_STATUS_IS_OK(session_status)) {
1519 /* Too ugly to live ? JRA. */
1520 if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
1521 session_status = NT_STATUS_FILE_CLOSED;
1523 return_value = smbd_smb2_request_error(req, session_status);
1524 break;
1527 * This call needs to be run as user.
1529 * smbd_smb2_request_check_tcon()
1530 * calls change_to_user() on success.
1532 status = smbd_smb2_request_check_tcon(req);
1533 if (!NT_STATUS_IS_OK(status)) {
1534 /* Too ugly to live ? JRA. */
1535 if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
1536 status = NT_STATUS_FILE_CLOSED;
1538 return_value = smbd_smb2_request_error(req, status);
1539 break;
1543 START_PROFILE(smb2_lock);
1544 return_value = smbd_smb2_request_process_lock(req);
1545 END_PROFILE(smb2_lock);
1547 break;
1549 case SMB2_OP_IOCTL:
1550 if (!NT_STATUS_IS_OK(session_status)) {
1551 return_value = smbd_smb2_request_error(req, session_status);
1552 break;
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);
1563 break;
1567 START_PROFILE(smb2_ioctl);
1568 return_value = smbd_smb2_request_process_ioctl(req);
1569 END_PROFILE(smb2_ioctl);
1571 break;
1573 case SMB2_OP_CANCEL:
1575 * This call needs to be run as root
1577 * That is what we also do in the SMB1 case.
1579 change_to_root_user();
1582 START_PROFILE(smb2_cancel);
1583 return_value = smbd_smb2_request_process_cancel(req);
1584 END_PROFILE(smb2_cancel);
1586 break;
1588 case SMB2_OP_KEEPALIVE:
1589 /* This call needs to be run as root */
1590 change_to_root_user();
1593 START_PROFILE(smb2_keepalive);
1594 return_value = smbd_smb2_request_process_keepalive(req);
1595 END_PROFILE(smb2_keepalive);
1597 break;
1599 case SMB2_OP_FIND:
1600 if (!NT_STATUS_IS_OK(session_status)) {
1601 return_value = smbd_smb2_request_error(req, session_status);
1602 break;
1605 * This call needs to be run as user.
1607 * smbd_smb2_request_check_tcon()
1608 * calls change_to_user() on success.
1610 status = smbd_smb2_request_check_tcon(req);
1611 if (!NT_STATUS_IS_OK(status)) {
1612 return_value = smbd_smb2_request_error(req, status);
1613 break;
1617 START_PROFILE(smb2_find);
1618 return_value = smbd_smb2_request_process_find(req);
1619 END_PROFILE(smb2_find);
1621 break;
1623 case SMB2_OP_NOTIFY:
1624 if (!NT_STATUS_IS_OK(session_status)) {
1625 return_value = smbd_smb2_request_error(req, session_status);
1626 break;
1629 * This call needs to be run as user.
1631 * smbd_smb2_request_check_tcon()
1632 * calls change_to_user() on success.
1634 status = smbd_smb2_request_check_tcon(req);
1635 if (!NT_STATUS_IS_OK(status)) {
1636 return_value = smbd_smb2_request_error(req, status);
1637 break;
1641 START_PROFILE(smb2_notify);
1642 return_value = smbd_smb2_request_process_notify(req);
1643 END_PROFILE(smb2_notify);
1645 break;
1647 case SMB2_OP_GETINFO:
1648 if (!NT_STATUS_IS_OK(session_status)) {
1649 return_value = smbd_smb2_request_error(req, session_status);
1650 break;
1653 * This call needs to be run as user.
1655 * smbd_smb2_request_check_tcon()
1656 * calls change_to_user() on success.
1658 status = smbd_smb2_request_check_tcon(req);
1659 if (!NT_STATUS_IS_OK(status)) {
1660 return_value = smbd_smb2_request_error(req, status);
1661 break;
1665 START_PROFILE(smb2_getinfo);
1666 return_value = smbd_smb2_request_process_getinfo(req);
1667 END_PROFILE(smb2_getinfo);
1669 break;
1671 case SMB2_OP_SETINFO:
1672 if (!NT_STATUS_IS_OK(session_status)) {
1673 return_value = smbd_smb2_request_error(req, session_status);
1674 break;
1677 * This call needs to be run as user.
1679 * smbd_smb2_request_check_tcon()
1680 * calls change_to_user() on success.
1682 status = smbd_smb2_request_check_tcon(req);
1683 if (!NT_STATUS_IS_OK(status)) {
1684 return_value = smbd_smb2_request_error(req, status);
1685 break;
1689 START_PROFILE(smb2_setinfo);
1690 return_value = smbd_smb2_request_process_setinfo(req);
1691 END_PROFILE(smb2_setinfo);
1693 break;
1695 case SMB2_OP_BREAK:
1696 if (!NT_STATUS_IS_OK(session_status)) {
1697 return_value = smbd_smb2_request_error(req, session_status);
1698 break;
1701 * This call needs to be run as user.
1703 * smbd_smb2_request_check_tcon()
1704 * calls change_to_user() on success.
1706 status = smbd_smb2_request_check_tcon(req);
1707 if (!NT_STATUS_IS_OK(status)) {
1708 return_value = smbd_smb2_request_error(req, status);
1709 break;
1713 START_PROFILE(smb2_break);
1714 return_value = smbd_smb2_request_process_break(req);
1715 END_PROFILE(smb2_break);
1717 break;
1719 default:
1720 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1721 break;
1723 return return_value;
1726 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
1728 struct tevent_req *subreq;
1729 int i = req->current_idx;
1731 req->subreq = NULL;
1733 req->current_idx += 3;
1735 if (req->current_idx < req->out.vector_count) {
1737 * We must process the remaining compound
1738 * SMB2 requests before any new incoming SMB2
1739 * requests. This is because incoming SMB2
1740 * requests may include a cancel for a
1741 * compound request we haven't processed
1742 * yet.
1744 struct tevent_immediate *im = tevent_create_immediate(req);
1745 if (!im) {
1746 return NT_STATUS_NO_MEMORY;
1748 tevent_schedule_immediate(im,
1749 req->sconn->smb2.event_ctx,
1750 smbd_smb2_request_dispatch_immediate,
1751 req);
1752 return NT_STATUS_OK;
1755 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
1757 /* Set credit for this operation (zero credits if this
1758 is a final reply for an async operation). */
1759 smb2_set_operation_credit(req->sconn,
1760 &req->in.vector[i],
1761 &req->out.vector[i]);
1763 if (req->do_signing) {
1764 NTSTATUS status;
1765 status = smb2_signing_sign_pdu(req->session->session_key,
1766 &req->out.vector[i], 3);
1767 if (!NT_STATUS_IS_OK(status)) {
1768 return status;
1772 if (DEBUGLEVEL >= 10) {
1773 dbgtext("smbd_smb2_request_reply: sending...\n");
1774 print_req_vectors(req);
1777 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
1778 if (req->out.vector_count == 4 &&
1779 req->out.vector[3].iov_base == NULL &&
1780 req->out.vector[3].iov_len != 0) {
1781 /* Dynamic part is NULL. Chop it off,
1782 We're going to send it via sendfile. */
1783 req->out.vector_count -= 1;
1786 subreq = tstream_writev_queue_send(req,
1787 req->sconn->smb2.event_ctx,
1788 req->sconn->smb2.stream,
1789 req->sconn->smb2.send_queue,
1790 req->out.vector,
1791 req->out.vector_count);
1792 if (subreq == NULL) {
1793 return NT_STATUS_NO_MEMORY;
1795 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
1797 * We're done with this request -
1798 * move it off the "being processed" queue.
1800 DLIST_REMOVE(req->sconn->smb2.requests, req);
1802 return NT_STATUS_OK;
1805 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
1806 struct tevent_immediate *im,
1807 void *private_data)
1809 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
1810 struct smbd_smb2_request);
1811 struct smbd_server_connection *sconn = req->sconn;
1812 NTSTATUS status;
1814 TALLOC_FREE(im);
1816 if (DEBUGLEVEL >= 10) {
1817 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
1818 req->current_idx, req->in.vector_count));
1819 print_req_vectors(req);
1822 status = smbd_smb2_request_dispatch(req);
1823 if (!NT_STATUS_IS_OK(status)) {
1824 smbd_server_connection_terminate(sconn, nt_errstr(status));
1825 return;
1829 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
1831 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
1833 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
1834 struct smbd_smb2_request);
1835 struct smbd_server_connection *sconn = req->sconn;
1836 int ret;
1837 int sys_errno;
1838 NTSTATUS status;
1840 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1841 TALLOC_FREE(subreq);
1842 TALLOC_FREE(req);
1843 if (ret == -1) {
1844 status = map_nt_error_from_unix(sys_errno);
1845 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
1846 nt_errstr(status)));
1847 smbd_server_connection_terminate(sconn, nt_errstr(status));
1848 return;
1851 status = smbd_smb2_request_next_incoming(sconn);
1852 if (!NT_STATUS_IS_OK(status)) {
1853 smbd_server_connection_terminate(sconn, nt_errstr(status));
1854 return;
1858 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
1859 NTSTATUS status,
1860 DATA_BLOB body, DATA_BLOB *dyn,
1861 const char *location)
1863 uint8_t *outhdr;
1864 int i = req->current_idx;
1865 uint32_t next_command_ofs;
1867 DEBUG(10,("smbd_smb2_request_done_ex: "
1868 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
1869 i, nt_errstr(status), (unsigned int)body.length,
1870 dyn ? "yes": "no",
1871 (unsigned int)(dyn ? dyn->length : 0),
1872 location));
1874 if (body.length < 2) {
1875 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1878 if ((body.length % 2) != 0) {
1879 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1882 outhdr = (uint8_t *)req->out.vector[i].iov_base;
1884 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
1885 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
1887 req->out.vector[i+1].iov_base = (void *)body.data;
1888 req->out.vector[i+1].iov_len = body.length;
1890 if (dyn) {
1891 req->out.vector[i+2].iov_base = (void *)dyn->data;
1892 req->out.vector[i+2].iov_len = dyn->length;
1893 } else {
1894 req->out.vector[i+2].iov_base = NULL;
1895 req->out.vector[i+2].iov_len = 0;
1898 /* see if we need to recalculate the offset to the next response */
1899 if (next_command_ofs > 0) {
1900 next_command_ofs = SMB2_HDR_BODY;
1901 next_command_ofs += req->out.vector[i+1].iov_len;
1902 next_command_ofs += req->out.vector[i+2].iov_len;
1905 if ((next_command_ofs % 8) != 0) {
1906 size_t pad_size = 8 - (next_command_ofs % 8);
1907 if (req->out.vector[i+2].iov_len == 0) {
1909 * if the dyn buffer is empty
1910 * we can use it to add padding
1912 uint8_t *pad;
1914 pad = talloc_zero_array(req->out.vector,
1915 uint8_t, pad_size);
1916 if (pad == NULL) {
1917 return smbd_smb2_request_error(req,
1918 NT_STATUS_NO_MEMORY);
1921 req->out.vector[i+2].iov_base = (void *)pad;
1922 req->out.vector[i+2].iov_len = pad_size;
1923 } else {
1925 * For now we copy the dynamic buffer
1926 * and add the padding to the new buffer
1928 size_t old_size;
1929 uint8_t *old_dyn;
1930 size_t new_size;
1931 uint8_t *new_dyn;
1933 old_size = req->out.vector[i+2].iov_len;
1934 old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
1936 new_size = old_size + pad_size;
1937 new_dyn = talloc_zero_array(req->out.vector,
1938 uint8_t, new_size);
1939 if (new_dyn == NULL) {
1940 return smbd_smb2_request_error(req,
1941 NT_STATUS_NO_MEMORY);
1944 memcpy(new_dyn, old_dyn, old_size);
1945 memset(new_dyn + old_size, 0, pad_size);
1947 req->out.vector[i+2].iov_base = (void *)new_dyn;
1948 req->out.vector[i+2].iov_len = new_size;
1950 next_command_ofs += pad_size;
1953 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
1955 return smbd_smb2_request_reply(req);
1958 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
1959 NTSTATUS status,
1960 DATA_BLOB *info,
1961 const char *location)
1963 DATA_BLOB body;
1964 int i = req->current_idx;
1965 uint8_t *outhdr = (uint8_t *)req->out.vector[i].iov_base;
1967 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
1968 i, nt_errstr(status), info ? " +info" : "",
1969 location));
1971 body.data = outhdr + SMB2_HDR_BODY;
1972 body.length = 8;
1973 SSVAL(body.data, 0, 9);
1975 if (info) {
1976 SIVAL(body.data, 0x04, info->length);
1977 } else {
1978 /* Allocated size of req->out.vector[i].iov_base
1979 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
1980 * 1 byte without having to do an alloc.
1982 info = talloc_zero_array(req->out.vector,
1983 DATA_BLOB,
1985 if (!info) {
1986 return NT_STATUS_NO_MEMORY;
1988 info->data = ((uint8_t *)outhdr) +
1989 OUTVEC_ALLOC_SIZE - 1;
1990 info->length = 1;
1991 SCVAL(info->data, 0, 0);
1995 * if a request fails, all other remaining
1996 * compounded requests should fail too
1998 req->next_status = NT_STATUS_INVALID_PARAMETER;
2000 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2004 struct smbd_smb2_send_oplock_break_state {
2005 struct smbd_server_connection *sconn;
2006 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
2007 struct iovec vector;
2010 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2012 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2013 uint64_t file_id_persistent,
2014 uint64_t file_id_volatile,
2015 uint8_t oplock_level)
2017 struct smbd_smb2_send_oplock_break_state *state;
2018 struct tevent_req *subreq;
2019 uint8_t *hdr;
2020 uint8_t *body;
2022 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2023 if (state == NULL) {
2024 return NT_STATUS_NO_MEMORY;
2026 state->sconn = sconn;
2028 state->vector.iov_base = (void *)state->buf;
2029 state->vector.iov_len = sizeof(state->buf);
2031 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
2032 hdr = state->buf + 4;
2033 body = hdr + SMB2_HDR_BODY;
2035 SIVAL(hdr, 0, SMB2_MAGIC);
2036 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2037 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2038 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2039 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2040 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2041 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2042 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2043 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2044 SIVAL(hdr, SMB2_HDR_PID, 0);
2045 SIVAL(hdr, SMB2_HDR_TID, 0);
2046 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2047 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2049 SSVAL(body, 0x00, 0x18);
2051 SCVAL(body, 0x02, oplock_level);
2052 SCVAL(body, 0x03, 0); /* reserved */
2053 SIVAL(body, 0x04, 0); /* reserved */
2054 SBVAL(body, 0x08, file_id_persistent);
2055 SBVAL(body, 0x10, file_id_volatile);
2057 subreq = tstream_writev_queue_send(state,
2058 sconn->smb2.event_ctx,
2059 sconn->smb2.stream,
2060 sconn->smb2.send_queue,
2061 &state->vector, 1);
2062 if (subreq == NULL) {
2063 return NT_STATUS_NO_MEMORY;
2065 tevent_req_set_callback(subreq,
2066 smbd_smb2_oplock_break_writev_done,
2067 state);
2069 return NT_STATUS_OK;
2072 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2074 struct smbd_smb2_send_oplock_break_state *state =
2075 tevent_req_callback_data(subreq,
2076 struct smbd_smb2_send_oplock_break_state);
2077 struct smbd_server_connection *sconn = state->sconn;
2078 int ret;
2079 int sys_errno;
2081 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2082 TALLOC_FREE(subreq);
2083 if (ret == -1) {
2084 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2085 smbd_server_connection_terminate(sconn, nt_errstr(status));
2086 return;
2089 TALLOC_FREE(state);
2092 struct smbd_smb2_request_read_state {
2093 size_t missing;
2094 bool asked_for_header;
2095 struct smbd_smb2_request *smb2_req;
2098 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2099 void *private_data,
2100 TALLOC_CTX *mem_ctx,
2101 struct iovec **_vector,
2102 size_t *_count);
2103 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2105 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2106 struct tevent_context *ev,
2107 struct smbd_server_connection *sconn)
2109 struct tevent_req *req;
2110 struct smbd_smb2_request_read_state *state;
2111 struct tevent_req *subreq;
2113 req = tevent_req_create(mem_ctx, &state,
2114 struct smbd_smb2_request_read_state);
2115 if (req == NULL) {
2116 return NULL;
2118 state->missing = 0;
2119 state->asked_for_header = false;
2121 state->smb2_req = smbd_smb2_request_allocate(state);
2122 if (tevent_req_nomem(state->smb2_req, req)) {
2123 return tevent_req_post(req, ev);
2125 state->smb2_req->sconn = sconn;
2127 subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
2128 sconn->smb2.recv_queue,
2129 smbd_smb2_request_next_vector,
2130 state);
2131 if (tevent_req_nomem(subreq, req)) {
2132 return tevent_req_post(req, ev);
2134 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2136 return req;
2139 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2140 void *private_data,
2141 TALLOC_CTX *mem_ctx,
2142 struct iovec **_vector,
2143 size_t *_count)
2145 struct smbd_smb2_request_read_state *state =
2146 talloc_get_type_abort(private_data,
2147 struct smbd_smb2_request_read_state);
2148 struct smbd_smb2_request *req = state->smb2_req;
2149 struct iovec *vector;
2150 int idx = req->in.vector_count;
2151 size_t len = 0;
2152 uint8_t *buf = NULL;
2154 if (req->in.vector_count == 0) {
2156 * first we need to get the NBT header
2158 req->in.vector = talloc_array(req, struct iovec,
2159 req->in.vector_count + 1);
2160 if (req->in.vector == NULL) {
2161 return -1;
2163 req->in.vector_count += 1;
2165 req->in.vector[idx].iov_base = (void *)req->in.nbt_hdr;
2166 req->in.vector[idx].iov_len = 4;
2168 vector = talloc_array(mem_ctx, struct iovec, 1);
2169 if (vector == NULL) {
2170 return -1;
2173 vector[0] = req->in.vector[idx];
2175 *_vector = vector;
2176 *_count = 1;
2177 return 0;
2180 if (req->in.vector_count == 1) {
2182 * Now we analyze the NBT header
2184 state->missing = smb2_len(req->in.vector[0].iov_base);
2186 if (state->missing == 0) {
2187 /* if there're no remaining bytes, we're done */
2188 *_vector = NULL;
2189 *_count = 0;
2190 return 0;
2193 req->in.vector = talloc_realloc(req, req->in.vector,
2194 struct iovec,
2195 req->in.vector_count + 1);
2196 if (req->in.vector == NULL) {
2197 return -1;
2199 req->in.vector_count += 1;
2201 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
2203 * it's a special NBT message,
2204 * so get all remaining bytes
2206 len = state->missing;
2207 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
2209 * it's an invalid message, just read what we can get
2210 * and let the caller handle the error
2212 len = state->missing;
2213 } else {
2215 * We assume it's a SMB2 request,
2216 * and we first get the header and the
2217 * first 2 bytes (the struct size) of the body
2219 len = SMB2_HDR_BODY + 2;
2221 state->asked_for_header = true;
2224 state->missing -= len;
2226 buf = talloc_array(req->in.vector, uint8_t, len);
2227 if (buf == NULL) {
2228 return -1;
2231 req->in.vector[idx].iov_base = (void *)buf;
2232 req->in.vector[idx].iov_len = len;
2234 vector = talloc_array(mem_ctx, struct iovec, 1);
2235 if (vector == NULL) {
2236 return -1;
2239 vector[0] = req->in.vector[idx];
2241 *_vector = vector;
2242 *_count = 1;
2243 return 0;
2246 if (state->missing == 0) {
2247 /* if there're no remaining bytes, we're done */
2248 *_vector = NULL;
2249 *_count = 0;
2250 return 0;
2253 if (state->asked_for_header) {
2254 const uint8_t *hdr;
2255 size_t full_size;
2256 size_t next_command_ofs;
2257 size_t body_size;
2258 uint8_t *body;
2259 size_t dyn_size;
2260 uint8_t *dyn;
2261 bool invalid = false;
2263 state->asked_for_header = false;
2266 * We got the SMB2 header and the first 2 bytes
2267 * of the body. We fix the size to just the header
2268 * and manually copy the 2 first bytes to the body section
2270 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
2271 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
2273 /* allocate vectors for body and dynamic areas */
2274 req->in.vector = talloc_realloc(req, req->in.vector,
2275 struct iovec,
2276 req->in.vector_count + 2);
2277 if (req->in.vector == NULL) {
2278 return -1;
2280 req->in.vector_count += 2;
2282 full_size = state->missing + SMB2_HDR_BODY + 2;
2283 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
2284 body_size = SVAL(hdr, SMB2_HDR_BODY);
2286 if (next_command_ofs != 0) {
2287 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
2289 * this is invalid, just return a zero
2290 * body and let the caller deal with the error
2292 invalid = true;
2293 } else if (next_command_ofs > full_size) {
2295 * this is invalid, just return a zero
2296 * body and let the caller deal with the error
2298 invalid = true;
2299 } else {
2300 full_size = next_command_ofs;
2304 if (!invalid) {
2305 if (body_size < 2) {
2307 * this is invalid, just return a zero
2308 * body and let the caller deal with the error
2310 invalid = true;
2314 * Mask out the lowest bit, the "dynamic" part
2315 * of body_size.
2317 body_size &= ~1;
2319 if (body_size > (full_size - SMB2_HDR_BODY)) {
2321 * this is invalid, just return a zero
2322 * body and let the caller deal with the error
2324 invalid = true;
2328 if (invalid) {
2329 /* the caller should check this */
2330 body_size = 2;
2333 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
2335 state->missing -= (body_size - 2) + dyn_size;
2337 body = talloc_array(req->in.vector, uint8_t, body_size);
2338 if (body == NULL) {
2339 return -1;
2342 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
2343 if (dyn == NULL) {
2344 return -1;
2347 req->in.vector[idx].iov_base = (void *)body;
2348 req->in.vector[idx].iov_len = body_size;
2349 req->in.vector[idx+1].iov_base = (void *)dyn;
2350 req->in.vector[idx+1].iov_len = dyn_size;
2352 vector = talloc_array(mem_ctx, struct iovec, 2);
2353 if (vector == NULL) {
2354 return -1;
2358 * the first 2 bytes of the body were already fetched
2359 * together with the header
2361 memcpy(body, hdr + SMB2_HDR_BODY, 2);
2362 vector[0].iov_base = body + 2;
2363 vector[0].iov_len = body_size - 2;
2365 vector[1] = req->in.vector[idx+1];
2367 *_vector = vector;
2368 *_count = 2;
2369 return 0;
2373 * when we endup here, we're looking for a new SMB2 request
2374 * next. And we ask for its header and the first 2 bytes of
2375 * the body (like we did for the first SMB2 request).
2378 req->in.vector = talloc_realloc(req, req->in.vector,
2379 struct iovec,
2380 req->in.vector_count + 1);
2381 if (req->in.vector == NULL) {
2382 return -1;
2384 req->in.vector_count += 1;
2387 * We assume it's a SMB2 request,
2388 * and we first get the header and the
2389 * first 2 bytes (the struct size) of the body
2391 len = SMB2_HDR_BODY + 2;
2393 if (len > state->missing) {
2394 /* let the caller handle the error */
2395 len = state->missing;
2398 state->missing -= len;
2399 state->asked_for_header = true;
2401 buf = talloc_array(req->in.vector, uint8_t, len);
2402 if (buf == NULL) {
2403 return -1;
2406 req->in.vector[idx].iov_base = (void *)buf;
2407 req->in.vector[idx].iov_len = len;
2409 vector = talloc_array(mem_ctx, struct iovec, 1);
2410 if (vector == NULL) {
2411 return -1;
2414 vector[0] = req->in.vector[idx];
2416 *_vector = vector;
2417 *_count = 1;
2418 return 0;
2421 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2423 struct tevent_req *req =
2424 tevent_req_callback_data(subreq,
2425 struct tevent_req);
2426 int ret;
2427 int sys_errno;
2428 NTSTATUS status;
2430 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2431 if (ret == -1) {
2432 status = map_nt_error_from_unix(sys_errno);
2433 tevent_req_nterror(req, status);
2434 return;
2437 tevent_req_done(req);
2440 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2441 TALLOC_CTX *mem_ctx,
2442 struct smbd_smb2_request **_smb2_req)
2444 struct smbd_smb2_request_read_state *state =
2445 tevent_req_data(req,
2446 struct smbd_smb2_request_read_state);
2447 NTSTATUS status;
2449 if (tevent_req_is_nterror(req, &status)) {
2450 tevent_req_received(req);
2451 return status;
2454 talloc_steal(mem_ctx, state->smb2_req->mem_pool);
2455 *_smb2_req = state->smb2_req;
2456 tevent_req_received(req);
2457 return NT_STATUS_OK;
2460 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2462 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2464 size_t max_send_queue_len;
2465 size_t cur_send_queue_len;
2466 struct tevent_req *subreq;
2468 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
2470 * if there is already a smbd_smb2_request_read
2471 * pending, we are done.
2473 return NT_STATUS_OK;
2476 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2477 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
2479 if (cur_send_queue_len > max_send_queue_len) {
2481 * if we have a lot of requests to send,
2482 * we wait until they are on the wire until we
2483 * ask for the next request.
2485 return NT_STATUS_OK;
2488 /* ask for the next request */
2489 subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
2490 if (subreq == NULL) {
2491 return NT_STATUS_NO_MEMORY;
2493 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2495 return NT_STATUS_OK;
2498 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2499 const uint8_t *inbuf, size_t size)
2501 NTSTATUS status;
2502 struct smbd_smb2_request *req = NULL;
2504 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2505 (unsigned int)size));
2507 status = smbd_initialize_smb2(sconn);
2508 if (!NT_STATUS_IS_OK(status)) {
2509 smbd_server_connection_terminate(sconn, nt_errstr(status));
2510 return;
2513 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2514 if (!NT_STATUS_IS_OK(status)) {
2515 smbd_server_connection_terminate(sconn, nt_errstr(status));
2516 return;
2519 status = smbd_smb2_request_setup_out(req);
2520 if (!NT_STATUS_IS_OK(status)) {
2521 smbd_server_connection_terminate(sconn, nt_errstr(status));
2522 return;
2525 status = smbd_smb2_request_dispatch(req);
2526 if (!NT_STATUS_IS_OK(status)) {
2527 smbd_server_connection_terminate(sconn, nt_errstr(status));
2528 return;
2531 status = smbd_smb2_request_next_incoming(sconn);
2532 if (!NT_STATUS_IS_OK(status)) {
2533 smbd_server_connection_terminate(sconn, nt_errstr(status));
2534 return;
2537 sconn->num_requests++;
2540 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2542 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2543 struct smbd_server_connection);
2544 NTSTATUS status;
2545 struct smbd_smb2_request *req = NULL;
2547 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2548 TALLOC_FREE(subreq);
2549 if (!NT_STATUS_IS_OK(status)) {
2550 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2551 nt_errstr(status)));
2552 smbd_server_connection_terminate(sconn, nt_errstr(status));
2553 return;
2556 if (req->in.nbt_hdr[0] != 0x00) {
2557 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
2558 req->in.nbt_hdr[0]));
2559 TALLOC_FREE(req);
2560 goto next;
2563 req->current_idx = 1;
2565 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2566 req->current_idx, req->in.vector_count));
2568 status = smbd_smb2_request_validate(req);
2569 if (!NT_STATUS_IS_OK(status)) {
2570 smbd_server_connection_terminate(sconn, nt_errstr(status));
2571 return;
2574 status = smbd_smb2_request_setup_out(req);
2575 if (!NT_STATUS_IS_OK(status)) {
2576 smbd_server_connection_terminate(sconn, nt_errstr(status));
2577 return;
2580 status = smbd_smb2_request_dispatch(req);
2581 if (!NT_STATUS_IS_OK(status)) {
2582 smbd_server_connection_terminate(sconn, nt_errstr(status));
2583 return;
2586 next:
2587 status = smbd_smb2_request_next_incoming(sconn);
2588 if (!NT_STATUS_IS_OK(status)) {
2589 smbd_server_connection_terminate(sconn, nt_errstr(status));
2590 return;
2593 sconn->num_requests++;
2595 /* The timeout_processing function isn't run nearly
2596 often enough to implement 'max log size' without
2597 overrunning the size of the file by many megabytes.
2598 This is especially true if we are running at debug
2599 level 10. Checking every 50 SMB2s is a nice
2600 tradeoff of performance vs log file size overrun. */
2602 if ((sconn->num_requests % 50) == 0 &&
2603 need_to_check_log_size()) {
2604 change_to_root_user();
2605 check_log_size();