s3-torture/denytest.c: replace cli_read_old() with cli_read()
[Samba/gebeck_regimport.git] / source3 / smbd / smb2_server.c
blob11b5ed8bf03d18378b75267fd655f88c6525fa04
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 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
448 uint16_t credits_requested = 0;
449 uint16_t credits_granted = 0;
451 if (in_vector != NULL) {
452 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
453 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
456 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
458 /* Remember what we gave out. */
459 credits_granted = MIN(credits_requested, (sconn->smb2.max_credits -
460 sconn->smb2.credits_granted));
462 if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
463 /* First negprot packet, or ensure the client credits can
464 never drop to zero. */
465 credits_granted = 1;
468 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
469 sconn->smb2.credits_granted += credits_granted;
471 DEBUG(10,("smb2_set_operation_credit: requested %u, "
472 "granted %u, total granted %u\n",
473 (unsigned int)credits_requested,
474 (unsigned int)credits_granted,
475 (unsigned int)sconn->smb2.credits_granted ));
478 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
479 struct smbd_smb2_request *outreq)
481 int count, idx;
483 count = outreq->out.vector_count;
485 for (idx=1; idx < count; idx += 3) {
486 smb2_set_operation_credit(outreq->sconn,
487 &inreq->in.vector[idx],
488 &outreq->out.vector[idx]);
492 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
494 struct iovec *vector;
495 int count;
496 int idx;
498 count = req->in.vector_count;
499 vector = talloc_zero_array(req, struct iovec, count);
500 if (vector == NULL) {
501 return NT_STATUS_NO_MEMORY;
504 vector[0].iov_base = req->out.nbt_hdr;
505 vector[0].iov_len = 4;
506 SIVAL(req->out.nbt_hdr, 0, 0);
508 for (idx=1; idx < count; idx += 3) {
509 const uint8_t *inhdr = NULL;
510 uint32_t in_flags;
511 uint8_t *outhdr = NULL;
512 uint8_t *outbody = NULL;
513 uint32_t next_command_ofs = 0;
514 struct iovec *current = &vector[idx];
516 if ((idx + 3) < count) {
517 /* we have a next command -
518 * setup for the error case. */
519 next_command_ofs = SMB2_HDR_BODY + 9;
522 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
523 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
525 outhdr = talloc_zero_array(vector, uint8_t,
526 OUTVEC_ALLOC_SIZE);
527 if (outhdr == NULL) {
528 return NT_STATUS_NO_MEMORY;
531 outbody = outhdr + SMB2_HDR_BODY;
533 current[0].iov_base = (void *)outhdr;
534 current[0].iov_len = SMB2_HDR_BODY;
536 current[1].iov_base = (void *)outbody;
537 current[1].iov_len = 8;
539 current[2].iov_base = NULL;
540 current[2].iov_len = 0;
542 /* setup the SMB2 header */
543 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
544 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
545 SSVAL(outhdr, SMB2_HDR_EPOCH, 0);
546 SIVAL(outhdr, SMB2_HDR_STATUS,
547 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
548 SSVAL(outhdr, SMB2_HDR_OPCODE,
549 SVAL(inhdr, SMB2_HDR_OPCODE));
550 SIVAL(outhdr, SMB2_HDR_FLAGS,
551 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
552 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
553 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
554 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
555 SIVAL(outhdr, SMB2_HDR_PID,
556 IVAL(inhdr, SMB2_HDR_PID));
557 SIVAL(outhdr, SMB2_HDR_TID,
558 IVAL(inhdr, SMB2_HDR_TID));
559 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
560 BVAL(inhdr, SMB2_HDR_SESSION_ID));
561 memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16);
563 /* setup error body header */
564 SSVAL(outbody, 0x00, 0x08 + 1);
565 SSVAL(outbody, 0x02, 0);
566 SIVAL(outbody, 0x04, 0);
569 req->out.vector = vector;
570 req->out.vector_count = count;
572 /* setup the length of the NBT packet */
573 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
575 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
577 return NT_STATUS_OK;
580 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
581 const char *reason,
582 const char *location)
584 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
585 reason, location));
586 exit_server_cleanly(reason);
589 static bool dup_smb2_vec3(TALLOC_CTX *ctx,
590 struct iovec *outvec,
591 const struct iovec *srcvec)
593 /* vec[0] is always boilerplate and must
594 * be allocated with size OUTVEC_ALLOC_SIZE. */
596 outvec[0].iov_base = talloc_memdup(ctx,
597 srcvec[0].iov_base,
598 OUTVEC_ALLOC_SIZE);
599 if (!outvec[0].iov_base) {
600 return false;
602 outvec[0].iov_len = SMB2_HDR_BODY;
605 * If this is a "standard" vec[1] of length 8,
606 * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
607 * then duplicate this. Else use talloc_memdup().
610 if (srcvec[1].iov_len == 8 &&
611 srcvec[1].iov_base ==
612 ((uint8_t *)srcvec[0].iov_base) +
613 SMB2_HDR_BODY) {
614 outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
615 SMB2_HDR_BODY;
616 outvec[1].iov_len = 8;
617 } else {
618 outvec[1].iov_base = talloc_memdup(ctx,
619 srcvec[1].iov_base,
620 srcvec[1].iov_len);
621 if (!outvec[1].iov_base) {
622 return false;
624 outvec[1].iov_len = srcvec[1].iov_len;
628 * If this is a "standard" vec[2] of length 1,
629 * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
630 * then duplicate this. Else use talloc_memdup().
633 if (srcvec[2].iov_base &&
634 srcvec[2].iov_len) {
635 if (srcvec[2].iov_base ==
636 ((uint8_t *)srcvec[0].iov_base) +
637 (OUTVEC_ALLOC_SIZE - 1) &&
638 srcvec[2].iov_len == 1) {
639 /* Common SMB2 error packet case. */
640 outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
641 (OUTVEC_ALLOC_SIZE - 1);
642 } else {
643 outvec[2].iov_base = talloc_memdup(ctx,
644 srcvec[2].iov_base,
645 srcvec[2].iov_len);
646 if (!outvec[2].iov_base) {
647 return false;
650 outvec[2].iov_len = srcvec[2].iov_len;
651 } else {
652 outvec[2].iov_base = NULL;
653 outvec[2].iov_len = 0;
655 return true;
658 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
660 struct smbd_smb2_request *newreq = NULL;
661 struct iovec *outvec = NULL;
662 int count = req->out.vector_count;
663 int i;
665 newreq = smbd_smb2_request_allocate(req->sconn);
666 if (!newreq) {
667 return NULL;
670 newreq->sconn = req->sconn;
671 newreq->session = req->session;
672 newreq->do_signing = req->do_signing;
673 newreq->current_idx = req->current_idx;
674 newreq->async = false;
675 newreq->cancelled = false;
676 /* Note we are leaving:
677 ->tcon
678 ->smb1req
679 ->compat_chain_fsp
680 uninitialized as NULL here as
681 they're not used in the interim
682 response code. JRA. */
684 outvec = talloc_zero_array(newreq, struct iovec, count);
685 if (!outvec) {
686 TALLOC_FREE(newreq);
687 return NULL;
689 newreq->out.vector = outvec;
690 newreq->out.vector_count = count;
692 /* Setup the outvec's identically to req. */
693 outvec[0].iov_base = newreq->out.nbt_hdr;
694 outvec[0].iov_len = 4;
695 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
697 /* Setup the vectors identically to the ones in req. */
698 for (i = 1; i < count; i += 3) {
699 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
700 break;
704 if (i < count) {
705 /* Alloc failed. */
706 TALLOC_FREE(newreq);
707 return NULL;
710 smb2_setup_nbt_length(newreq->out.vector,
711 newreq->out.vector_count);
713 return newreq;
716 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
718 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
720 int i = 0;
721 uint8_t *outhdr = NULL;
722 struct smbd_smb2_request *nreq = NULL;
724 /* Create a new smb2 request we'll use
725 for the interim return. */
726 nreq = dup_smb2_req(req);
727 if (!nreq) {
728 return NT_STATUS_NO_MEMORY;
731 /* Lose the last 3 out vectors. They're the
732 ones we'll be using for the async reply. */
733 nreq->out.vector_count -= 3;
735 smb2_setup_nbt_length(nreq->out.vector,
736 nreq->out.vector_count);
738 /* Step back to the previous reply. */
739 i = nreq->current_idx - 3;
740 outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
741 /* And end the chain. */
742 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
744 /* Calculate outgoing credits */
745 smb2_calculate_credits(req, nreq);
747 /* Re-sign if needed. */
748 if (nreq->do_signing) {
749 NTSTATUS status;
750 status = smb2_signing_sign_pdu(nreq->session->session_key,
751 &nreq->out.vector[i], 3);
752 if (!NT_STATUS_IS_OK(status)) {
753 return status;
756 if (DEBUGLEVEL >= 10) {
757 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
758 (unsigned int)nreq->current_idx );
759 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
760 (unsigned int)nreq->out.vector_count );
761 print_req_vectors(nreq);
763 nreq->subreq = tstream_writev_queue_send(nreq,
764 nreq->sconn->smb2.event_ctx,
765 nreq->sconn->smb2.stream,
766 nreq->sconn->smb2.send_queue,
767 nreq->out.vector,
768 nreq->out.vector_count);
770 if (nreq->subreq == NULL) {
771 return NT_STATUS_NO_MEMORY;
774 tevent_req_set_callback(nreq->subreq,
775 smbd_smb2_request_writev_done,
776 nreq);
778 return NT_STATUS_OK;
781 struct smbd_smb2_request_pending_state {
782 struct smbd_server_connection *sconn;
783 uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
784 struct iovec vector[3];
787 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
789 struct smbd_smb2_request_pending_state *state =
790 tevent_req_callback_data(subreq,
791 struct smbd_smb2_request_pending_state);
792 struct smbd_server_connection *sconn = state->sconn;
793 int ret;
794 int sys_errno;
796 ret = tstream_writev_queue_recv(subreq, &sys_errno);
797 TALLOC_FREE(subreq);
798 if (ret == -1) {
799 NTSTATUS status = map_nt_error_from_unix(sys_errno);
800 smbd_server_connection_terminate(sconn, nt_errstr(status));
801 return;
804 TALLOC_FREE(state);
807 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
808 struct tevent_req *subreq)
810 NTSTATUS status;
811 struct smbd_smb2_request_pending_state *state = NULL;
812 int i = req->current_idx;
813 uint8_t *reqhdr = NULL;
814 uint8_t *hdr = NULL;
815 uint8_t *body = NULL;
816 uint32_t flags = 0;
817 uint64_t message_id = 0;
818 uint64_t async_id = 0;
819 struct iovec *outvec = NULL;
821 if (!tevent_req_is_in_progress(subreq)) {
822 return NT_STATUS_OK;
825 req->subreq = subreq;
826 subreq = NULL;
828 if (req->async) {
829 /* We're already async. */
830 return NT_STATUS_OK;
833 if (req->in.vector_count > i + 3) {
835 * We're trying to go async in a compound
836 * request chain. This is not allowed.
837 * Cancel the outstanding request.
839 tevent_req_cancel(req->subreq);
840 return smbd_smb2_request_error(req,
841 NT_STATUS_INSUFFICIENT_RESOURCES);
844 if (DEBUGLEVEL >= 10) {
845 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
846 (unsigned int)req->current_idx );
847 print_req_vectors(req);
850 if (req->out.vector_count > 4) {
851 /* This is a compound reply. We
852 * must do an interim response
853 * followed by the async response
854 * to match W2K8R2.
856 status = smb2_send_async_interim_response(req);
857 if (!NT_STATUS_IS_OK(status)) {
858 return status;
862 /* Don't return an intermediate packet on a pipe read/write. */
863 if (req->tcon && req->tcon->compat_conn && IS_IPC(req->tcon->compat_conn)) {
864 return NT_STATUS_OK;
867 reqhdr = (uint8_t *)req->out.vector[i].iov_base;
868 flags = (IVAL(reqhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
869 message_id = BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
870 async_id = message_id; /* keep it simple for now... */
873 * What we send is identical to a smbd_smb2_request_error
874 * packet with an error status of STATUS_PENDING. Make use
875 * of this fact sometime when refactoring. JRA.
878 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
879 if (state == NULL) {
880 return NT_STATUS_NO_MEMORY;
882 state->sconn = req->sconn;
884 state->vector[0].iov_base = (void *)state->buf;
885 state->vector[0].iov_len = 4;
887 state->vector[1].iov_base = state->buf + 4;
888 state->vector[1].iov_len = SMB2_HDR_BODY;
890 state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
891 state->vector[2].iov_len = 9;
893 smb2_setup_nbt_length(state->vector, 3);
895 hdr = (uint8_t *)state->vector[1].iov_base;
896 body = (uint8_t *)state->vector[2].iov_base;
898 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
899 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
900 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
901 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
902 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE));
904 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
905 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
906 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
907 SBVAL(hdr, SMB2_HDR_PID, async_id);
908 SBVAL(hdr, SMB2_HDR_SESSION_ID,
909 BVAL(reqhdr, SMB2_HDR_SESSION_ID));
910 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
912 SSVAL(body, 0x00, 0x08 + 1);
914 SCVAL(body, 0x02, 0);
915 SCVAL(body, 0x03, 0);
916 SIVAL(body, 0x04, 0);
917 /* Match W2K8R2... */
918 SCVAL(body, 0x08, 0x21);
920 /* Ensure we correctly go through crediting. Grant
921 the credits now, and zero credits on the final
922 response. */
923 smb2_set_operation_credit(req->sconn,
924 &req->in.vector[i],
925 &state->vector[1]);
927 if (req->do_signing) {
928 status = smb2_signing_sign_pdu(req->session->session_key,
929 &state->vector[1], 2);
930 if (!NT_STATUS_IS_OK(status)) {
931 return status;
935 subreq = tstream_writev_queue_send(state,
936 req->sconn->smb2.event_ctx,
937 req->sconn->smb2.stream,
938 req->sconn->smb2.send_queue,
939 state->vector,
942 if (subreq == NULL) {
943 return NT_STATUS_NO_MEMORY;
946 tevent_req_set_callback(subreq,
947 smbd_smb2_request_pending_writev_done,
948 state);
950 /* Note we're going async with this request. */
951 req->async = true;
954 * Now manipulate req so that the outstanding async request
955 * is the only one left in the struct smbd_smb2_request.
958 if (req->current_idx == 1) {
959 /* There was only one. */
960 goto out;
963 /* Re-arrange the in.vectors. */
964 req->in.vector[1] = req->in.vector[i];
965 req->in.vector[2] = req->in.vector[i+1];
966 req->in.vector[3] = req->in.vector[i+2];
967 req->in.vector_count = 4;
968 /* Reset the new in size. */
969 smb2_setup_nbt_length(req->in.vector, 4);
971 /* Now recreate the out.vectors. */
972 outvec = talloc_zero_array(req, struct iovec, 4);
973 if (!outvec) {
974 return NT_STATUS_NO_MEMORY;
977 /* 0 is always boilerplate and must
978 * be of size 4 for the length field. */
980 outvec[0].iov_base = req->out.nbt_hdr;
981 outvec[0].iov_len = 4;
982 SIVAL(req->out.nbt_hdr, 0, 0);
984 if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
985 return NT_STATUS_NO_MEMORY;
988 TALLOC_FREE(req->out.vector);
990 req->out.vector = outvec;
992 req->current_idx = 1;
993 req->out.vector_count = 4;
995 out:
997 smb2_setup_nbt_length(req->out.vector,
998 req->out.vector_count);
1000 /* Ensure our final reply matches the interim one. */
1001 reqhdr = (uint8_t *)req->out.vector[1].iov_base;
1002 SIVAL(reqhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1003 SBVAL(reqhdr, SMB2_HDR_PID, async_id);
1006 const uint8_t *inhdr =
1007 (const uint8_t *)req->in.vector[1].iov_base;
1008 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1009 "going async\n",
1010 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1011 (unsigned long long)async_id ));
1013 return NT_STATUS_OK;
1016 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1018 struct smbd_server_connection *sconn = req->sconn;
1019 struct smbd_smb2_request *cur;
1020 const uint8_t *inhdr;
1021 int i = req->current_idx;
1022 uint32_t flags;
1023 uint64_t search_message_id;
1024 uint64_t search_async_id;
1025 uint64_t found_id;
1027 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1029 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1030 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1031 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1034 * we don't need the request anymore
1035 * cancel requests never have a response
1037 DLIST_REMOVE(req->sconn->smb2.requests, req);
1038 TALLOC_FREE(req);
1040 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1041 const uint8_t *outhdr;
1042 uint64_t message_id;
1043 uint64_t async_id;
1045 i = cur->current_idx;
1047 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
1049 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1050 async_id = BVAL(outhdr, SMB2_HDR_PID);
1052 if (flags & SMB2_HDR_FLAG_ASYNC) {
1053 if (search_async_id == async_id) {
1054 found_id = async_id;
1055 break;
1057 } else {
1058 if (search_message_id == message_id) {
1059 found_id = message_id;
1060 break;
1065 if (cur && cur->subreq) {
1066 inhdr = (const uint8_t *)cur->in.vector[i].iov_base;
1067 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1068 "cancel opcode[%s] mid %llu\n",
1069 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1070 (unsigned long long)found_id ));
1071 tevent_req_cancel(cur->subreq);
1074 return NT_STATUS_OK;
1077 /*************************************************************
1078 Ensure an incoming tid is a valid one for us to access.
1079 Change to the associated uid credentials and chdir to the
1080 valid tid directory.
1081 *************************************************************/
1083 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1085 const uint8_t *inhdr;
1086 const uint8_t *outhdr;
1087 int i = req->current_idx;
1088 uint32_t in_tid;
1089 void *p;
1090 struct smbd_smb2_tcon *tcon;
1091 bool chained_fixup = false;
1093 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1095 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1097 if (in_tid == (0xFFFFFFFF)) {
1098 if (req->async) {
1100 * async request - fill in tid from
1101 * already setup out.vector[].iov_base.
1103 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1104 in_tid = IVAL(outhdr, SMB2_HDR_TID);
1105 } else if (i > 2) {
1107 * Chained request - fill in tid from
1108 * the previous request out.vector[].iov_base.
1110 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1111 in_tid = IVAL(outhdr, SMB2_HDR_TID);
1112 chained_fixup = true;
1116 /* lookup an existing session */
1117 p = idr_find(req->session->tcons.idtree, in_tid);
1118 if (p == NULL) {
1119 return NT_STATUS_NETWORK_NAME_DELETED;
1121 tcon = talloc_get_type_abort(p, struct smbd_smb2_tcon);
1123 if (!change_to_user(tcon->compat_conn,req->session->vuid)) {
1124 return NT_STATUS_ACCESS_DENIED;
1127 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1128 if (!set_current_service(tcon->compat_conn, 0, true)) {
1129 return NT_STATUS_ACCESS_DENIED;
1132 req->tcon = tcon;
1134 if (chained_fixup) {
1135 /* Fix up our own outhdr. */
1136 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1137 SIVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_TID, in_tid);
1140 return NT_STATUS_OK;
1143 /*************************************************************
1144 Ensure an incoming session_id is a valid one for us to access.
1145 *************************************************************/
1147 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1149 const uint8_t *inhdr;
1150 const uint8_t *outhdr;
1151 int i = req->current_idx;
1152 uint64_t in_session_id;
1153 void *p;
1154 struct smbd_smb2_session *session;
1155 bool chained_fixup = false;
1157 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1159 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1161 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
1162 if (req->async) {
1164 * async request - fill in session_id from
1165 * already setup request out.vector[].iov_base.
1167 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1168 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1169 } else if (i > 2) {
1171 * Chained request - fill in session_id from
1172 * the previous request out.vector[].iov_base.
1174 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1175 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1176 chained_fixup = true;
1180 /* lookup an existing session */
1181 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
1182 if (p == NULL) {
1183 return NT_STATUS_USER_SESSION_DELETED;
1185 session = talloc_get_type_abort(p, struct smbd_smb2_session);
1187 if (!NT_STATUS_IS_OK(session->status)) {
1188 return NT_STATUS_ACCESS_DENIED;
1191 set_current_user_info(session->session_info->unix_info->sanitized_username,
1192 session->session_info->unix_info->unix_name,
1193 session->session_info->info->domain_name);
1195 req->session = session;
1197 if (chained_fixup) {
1198 /* Fix up our own outhdr. */
1199 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1200 SBVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_SESSION_ID, in_session_id);
1202 return NT_STATUS_OK;
1205 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1207 const uint8_t *inhdr;
1208 int i = req->current_idx;
1209 uint16_t opcode;
1210 uint32_t flags;
1211 uint64_t mid;
1212 NTSTATUS status;
1213 NTSTATUS session_status;
1214 uint32_t allowed_flags;
1215 NTSTATUS return_value;
1217 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1219 /* TODO: verify more things */
1221 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1222 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1223 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1224 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1225 smb2_opcode_name(opcode),
1226 (unsigned long long)mid));
1228 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1229 SMB2_HDR_FLAG_SIGNED |
1230 SMB2_HDR_FLAG_DFS;
1231 if (opcode == SMB2_OP_CANCEL) {
1232 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1234 if ((flags & ~allowed_flags) != 0) {
1235 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1239 * Check if the client provided a valid session id,
1240 * if so smbd_smb2_request_check_session() calls
1241 * set_current_user_info().
1243 * As some command don't require a valid session id
1244 * we defer the check of the session_status
1246 session_status = smbd_smb2_request_check_session(req);
1248 req->do_signing = false;
1249 if (flags & SMB2_HDR_FLAG_SIGNED) {
1250 if (!NT_STATUS_IS_OK(session_status)) {
1251 return smbd_smb2_request_error(req, session_status);
1254 req->do_signing = true;
1255 status = smb2_signing_check_pdu(req->session->session_key,
1256 &req->in.vector[i], 3);
1257 if (!NT_STATUS_IS_OK(status)) {
1258 return smbd_smb2_request_error(req, status);
1260 } else if (req->session && req->session->do_signing) {
1261 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1264 if (flags & SMB2_HDR_FLAG_CHAINED) {
1266 * This check is mostly for giving the correct error code
1267 * for compounded requests.
1269 * TODO: we may need to move this after the session
1270 * and tcon checks.
1272 if (!NT_STATUS_IS_OK(req->next_status)) {
1273 return smbd_smb2_request_error(req, req->next_status);
1275 } else {
1276 req->compat_chain_fsp = NULL;
1279 switch (opcode) {
1280 case SMB2_OP_NEGPROT:
1281 /* This call needs to be run as root */
1282 change_to_root_user();
1285 START_PROFILE(smb2_negprot);
1286 return_value = smbd_smb2_request_process_negprot(req);
1287 END_PROFILE(smb2_negprot);
1289 break;
1291 case SMB2_OP_SESSSETUP:
1292 /* This call needs to be run as root */
1293 change_to_root_user();
1296 START_PROFILE(smb2_sesssetup);
1297 return_value = smbd_smb2_request_process_sesssetup(req);
1298 END_PROFILE(smb2_sesssetup);
1300 break;
1302 case SMB2_OP_LOGOFF:
1303 if (!NT_STATUS_IS_OK(session_status)) {
1304 return_value = smbd_smb2_request_error(req, session_status);
1305 break;
1308 /* This call needs to be run as root */
1309 change_to_root_user();
1312 START_PROFILE(smb2_logoff);
1313 return_value = smbd_smb2_request_process_logoff(req);
1314 END_PROFILE(smb2_logoff);
1316 break;
1318 case SMB2_OP_TCON:
1319 if (!NT_STATUS_IS_OK(session_status)) {
1320 return_value = smbd_smb2_request_error(req, session_status);
1321 break;
1325 * This call needs to be run as root.
1327 * smbd_smb2_request_process_tcon()
1328 * calls make_connection_snum(), which will call
1329 * change_to_user(), when needed.
1331 change_to_root_user();
1334 START_PROFILE(smb2_tcon);
1335 return_value = smbd_smb2_request_process_tcon(req);
1336 END_PROFILE(smb2_tcon);
1338 break;
1340 case SMB2_OP_TDIS:
1341 if (!NT_STATUS_IS_OK(session_status)) {
1342 return_value = smbd_smb2_request_error(req, session_status);
1343 break;
1346 * This call needs to be run as user.
1348 * smbd_smb2_request_check_tcon()
1349 * calls change_to_user() on success.
1351 status = smbd_smb2_request_check_tcon(req);
1352 if (!NT_STATUS_IS_OK(status)) {
1353 return_value = smbd_smb2_request_error(req, status);
1354 break;
1356 /* This call needs to be run as root */
1357 change_to_root_user();
1361 START_PROFILE(smb2_tdis);
1362 return_value = smbd_smb2_request_process_tdis(req);
1363 END_PROFILE(smb2_tdis);
1365 break;
1367 case SMB2_OP_CREATE:
1368 if (!NT_STATUS_IS_OK(session_status)) {
1369 return_value = smbd_smb2_request_error(req, session_status);
1370 break;
1373 * This call needs to be run as user.
1375 * smbd_smb2_request_check_tcon()
1376 * calls change_to_user() on success.
1378 status = smbd_smb2_request_check_tcon(req);
1379 if (!NT_STATUS_IS_OK(status)) {
1380 return_value = smbd_smb2_request_error(req, status);
1381 break;
1385 START_PROFILE(smb2_create);
1386 return_value = smbd_smb2_request_process_create(req);
1387 END_PROFILE(smb2_create);
1389 break;
1391 case SMB2_OP_CLOSE:
1392 if (!NT_STATUS_IS_OK(session_status)) {
1393 return_value = smbd_smb2_request_error(req, session_status);
1394 break;
1397 * This call needs to be run as user.
1399 * smbd_smb2_request_check_tcon()
1400 * calls change_to_user() on success.
1402 status = smbd_smb2_request_check_tcon(req);
1403 if (!NT_STATUS_IS_OK(status)) {
1404 return_value = smbd_smb2_request_error(req, status);
1405 break;
1409 START_PROFILE(smb2_close);
1410 return_value = smbd_smb2_request_process_close(req);
1411 END_PROFILE(smb2_close);
1413 break;
1415 case SMB2_OP_FLUSH:
1416 if (!NT_STATUS_IS_OK(session_status)) {
1417 return_value = smbd_smb2_request_error(req, session_status);
1418 break;
1421 * This call needs to be run as user.
1423 * smbd_smb2_request_check_tcon()
1424 * calls change_to_user() on success.
1426 status = smbd_smb2_request_check_tcon(req);
1427 if (!NT_STATUS_IS_OK(status)) {
1428 return_value = smbd_smb2_request_error(req, status);
1429 break;
1433 START_PROFILE(smb2_flush);
1434 return_value = smbd_smb2_request_process_flush(req);
1435 END_PROFILE(smb2_flush);
1437 break;
1439 case SMB2_OP_READ:
1440 if (!NT_STATUS_IS_OK(session_status)) {
1441 return_value = smbd_smb2_request_error(req, session_status);
1442 break;
1445 * This call needs to be run as user.
1447 * smbd_smb2_request_check_tcon()
1448 * calls change_to_user() on success.
1450 status = smbd_smb2_request_check_tcon(req);
1451 if (!NT_STATUS_IS_OK(status)) {
1452 return_value = smbd_smb2_request_error(req, status);
1453 break;
1457 START_PROFILE(smb2_read);
1458 return_value = smbd_smb2_request_process_read(req);
1459 END_PROFILE(smb2_read);
1461 break;
1463 case SMB2_OP_WRITE:
1464 if (!NT_STATUS_IS_OK(session_status)) {
1465 return_value = smbd_smb2_request_error(req, session_status);
1466 break;
1469 * This call needs to be run as user.
1471 * smbd_smb2_request_check_tcon()
1472 * calls change_to_user() on success.
1474 status = smbd_smb2_request_check_tcon(req);
1475 if (!NT_STATUS_IS_OK(status)) {
1476 return_value = smbd_smb2_request_error(req, status);
1477 break;
1481 START_PROFILE(smb2_write);
1482 return_value = smbd_smb2_request_process_write(req);
1483 END_PROFILE(smb2_write);
1485 break;
1487 case SMB2_OP_LOCK:
1488 if (!NT_STATUS_IS_OK(session_status)) {
1489 /* Too ugly to live ? JRA. */
1490 if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
1491 session_status = NT_STATUS_FILE_CLOSED;
1493 return_value = smbd_smb2_request_error(req, session_status);
1494 break;
1497 * This call needs to be run as user.
1499 * smbd_smb2_request_check_tcon()
1500 * calls change_to_user() on success.
1502 status = smbd_smb2_request_check_tcon(req);
1503 if (!NT_STATUS_IS_OK(status)) {
1504 /* Too ugly to live ? JRA. */
1505 if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
1506 status = NT_STATUS_FILE_CLOSED;
1508 return_value = smbd_smb2_request_error(req, status);
1509 break;
1513 START_PROFILE(smb2_lock);
1514 return_value = smbd_smb2_request_process_lock(req);
1515 END_PROFILE(smb2_lock);
1517 break;
1519 case SMB2_OP_IOCTL:
1520 if (!NT_STATUS_IS_OK(session_status)) {
1521 return_value = smbd_smb2_request_error(req, session_status);
1522 break;
1525 * This call needs to be run as user.
1527 * smbd_smb2_request_check_tcon()
1528 * calls change_to_user() on success.
1530 status = smbd_smb2_request_check_tcon(req);
1531 if (!NT_STATUS_IS_OK(status)) {
1532 return_value = smbd_smb2_request_error(req, status);
1533 break;
1537 START_PROFILE(smb2_ioctl);
1538 return_value = smbd_smb2_request_process_ioctl(req);
1539 END_PROFILE(smb2_ioctl);
1541 break;
1543 case SMB2_OP_CANCEL:
1545 * This call needs to be run as root
1547 * That is what we also do in the SMB1 case.
1549 change_to_root_user();
1552 START_PROFILE(smb2_cancel);
1553 return_value = smbd_smb2_request_process_cancel(req);
1554 END_PROFILE(smb2_cancel);
1556 break;
1558 case SMB2_OP_KEEPALIVE:
1559 /* This call needs to be run as root */
1560 change_to_root_user();
1563 START_PROFILE(smb2_keepalive);
1564 return_value = smbd_smb2_request_process_keepalive(req);
1565 END_PROFILE(smb2_keepalive);
1567 break;
1569 case SMB2_OP_FIND:
1570 if (!NT_STATUS_IS_OK(session_status)) {
1571 return_value = smbd_smb2_request_error(req, session_status);
1572 break;
1575 * This call needs to be run as user.
1577 * smbd_smb2_request_check_tcon()
1578 * calls change_to_user() on success.
1580 status = smbd_smb2_request_check_tcon(req);
1581 if (!NT_STATUS_IS_OK(status)) {
1582 return_value = smbd_smb2_request_error(req, status);
1583 break;
1587 START_PROFILE(smb2_find);
1588 return_value = smbd_smb2_request_process_find(req);
1589 END_PROFILE(smb2_find);
1591 break;
1593 case SMB2_OP_NOTIFY:
1594 if (!NT_STATUS_IS_OK(session_status)) {
1595 return_value = smbd_smb2_request_error(req, session_status);
1596 break;
1599 * This call needs to be run as user.
1601 * smbd_smb2_request_check_tcon()
1602 * calls change_to_user() on success.
1604 status = smbd_smb2_request_check_tcon(req);
1605 if (!NT_STATUS_IS_OK(status)) {
1606 return_value = smbd_smb2_request_error(req, status);
1607 break;
1611 START_PROFILE(smb2_notify);
1612 return_value = smbd_smb2_request_process_notify(req);
1613 END_PROFILE(smb2_notify);
1615 break;
1617 case SMB2_OP_GETINFO:
1618 if (!NT_STATUS_IS_OK(session_status)) {
1619 return_value = smbd_smb2_request_error(req, session_status);
1620 break;
1623 * This call needs to be run as user.
1625 * smbd_smb2_request_check_tcon()
1626 * calls change_to_user() on success.
1628 status = smbd_smb2_request_check_tcon(req);
1629 if (!NT_STATUS_IS_OK(status)) {
1630 return_value = smbd_smb2_request_error(req, status);
1631 break;
1635 START_PROFILE(smb2_getinfo);
1636 return_value = smbd_smb2_request_process_getinfo(req);
1637 END_PROFILE(smb2_getinfo);
1639 break;
1641 case SMB2_OP_SETINFO:
1642 if (!NT_STATUS_IS_OK(session_status)) {
1643 return_value = smbd_smb2_request_error(req, session_status);
1644 break;
1647 * This call needs to be run as user.
1649 * smbd_smb2_request_check_tcon()
1650 * calls change_to_user() on success.
1652 status = smbd_smb2_request_check_tcon(req);
1653 if (!NT_STATUS_IS_OK(status)) {
1654 return_value = smbd_smb2_request_error(req, status);
1655 break;
1659 START_PROFILE(smb2_setinfo);
1660 return_value = smbd_smb2_request_process_setinfo(req);
1661 END_PROFILE(smb2_setinfo);
1663 break;
1665 case SMB2_OP_BREAK:
1666 if (!NT_STATUS_IS_OK(session_status)) {
1667 return_value = smbd_smb2_request_error(req, session_status);
1668 break;
1671 * This call needs to be run as user.
1673 * smbd_smb2_request_check_tcon()
1674 * calls change_to_user() on success.
1676 status = smbd_smb2_request_check_tcon(req);
1677 if (!NT_STATUS_IS_OK(status)) {
1678 return_value = smbd_smb2_request_error(req, status);
1679 break;
1683 START_PROFILE(smb2_break);
1684 return_value = smbd_smb2_request_process_break(req);
1685 END_PROFILE(smb2_break);
1687 break;
1689 default:
1690 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1691 break;
1693 return return_value;
1696 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
1698 struct tevent_req *subreq;
1699 int i = req->current_idx;
1701 req->subreq = NULL;
1703 req->current_idx += 3;
1705 if (req->current_idx < req->out.vector_count) {
1707 * We must process the remaining compound
1708 * SMB2 requests before any new incoming SMB2
1709 * requests. This is because incoming SMB2
1710 * requests may include a cancel for a
1711 * compound request we haven't processed
1712 * yet.
1714 struct tevent_immediate *im = tevent_create_immediate(req);
1715 if (!im) {
1716 return NT_STATUS_NO_MEMORY;
1718 tevent_schedule_immediate(im,
1719 req->sconn->smb2.event_ctx,
1720 smbd_smb2_request_dispatch_immediate,
1721 req);
1722 return NT_STATUS_OK;
1725 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
1727 /* Set credit for this operation (zero credits if this
1728 is a final reply for an async operation). */
1729 smb2_set_operation_credit(req->sconn,
1730 req->async ? NULL : &req->in.vector[i],
1731 &req->out.vector[i]);
1733 if (req->do_signing) {
1734 NTSTATUS status;
1735 status = smb2_signing_sign_pdu(req->session->session_key,
1736 &req->out.vector[i], 3);
1737 if (!NT_STATUS_IS_OK(status)) {
1738 return status;
1742 if (DEBUGLEVEL >= 10) {
1743 dbgtext("smbd_smb2_request_reply: sending...\n");
1744 print_req_vectors(req);
1747 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
1748 if (req->out.vector_count == 4 &&
1749 req->out.vector[3].iov_base == NULL &&
1750 req->out.vector[3].iov_len != 0) {
1751 /* Dynamic part is NULL. Chop it off,
1752 We're going to send it via sendfile. */
1753 req->out.vector_count -= 1;
1756 subreq = tstream_writev_queue_send(req,
1757 req->sconn->smb2.event_ctx,
1758 req->sconn->smb2.stream,
1759 req->sconn->smb2.send_queue,
1760 req->out.vector,
1761 req->out.vector_count);
1762 if (subreq == NULL) {
1763 return NT_STATUS_NO_MEMORY;
1765 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
1767 * We're done with this request -
1768 * move it off the "being processed" queue.
1770 DLIST_REMOVE(req->sconn->smb2.requests, req);
1772 return NT_STATUS_OK;
1775 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
1776 struct tevent_immediate *im,
1777 void *private_data)
1779 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
1780 struct smbd_smb2_request);
1781 struct smbd_server_connection *sconn = req->sconn;
1782 NTSTATUS status;
1784 TALLOC_FREE(im);
1786 if (DEBUGLEVEL >= 10) {
1787 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
1788 req->current_idx, req->in.vector_count));
1789 print_req_vectors(req);
1792 status = smbd_smb2_request_dispatch(req);
1793 if (!NT_STATUS_IS_OK(status)) {
1794 smbd_server_connection_terminate(sconn, nt_errstr(status));
1795 return;
1799 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
1801 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
1802 struct smbd_smb2_request);
1803 struct smbd_server_connection *sconn = req->sconn;
1804 int ret;
1805 int sys_errno;
1807 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1808 TALLOC_FREE(subreq);
1809 TALLOC_FREE(req);
1810 if (ret == -1) {
1811 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1812 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
1813 nt_errstr(status)));
1814 smbd_server_connection_terminate(sconn, nt_errstr(status));
1815 return;
1819 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
1820 NTSTATUS status,
1821 DATA_BLOB body, DATA_BLOB *dyn,
1822 const char *location)
1824 uint8_t *outhdr;
1825 int i = req->current_idx;
1826 uint32_t next_command_ofs;
1828 DEBUG(10,("smbd_smb2_request_done_ex: "
1829 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
1830 i, nt_errstr(status), (unsigned int)body.length,
1831 dyn ? "yes": "no",
1832 (unsigned int)(dyn ? dyn->length : 0),
1833 location));
1835 if (body.length < 2) {
1836 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1839 if ((body.length % 2) != 0) {
1840 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1843 outhdr = (uint8_t *)req->out.vector[i].iov_base;
1845 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
1846 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
1848 req->out.vector[i+1].iov_base = (void *)body.data;
1849 req->out.vector[i+1].iov_len = body.length;
1851 if (dyn) {
1852 req->out.vector[i+2].iov_base = (void *)dyn->data;
1853 req->out.vector[i+2].iov_len = dyn->length;
1854 } else {
1855 req->out.vector[i+2].iov_base = NULL;
1856 req->out.vector[i+2].iov_len = 0;
1859 /* see if we need to recalculate the offset to the next response */
1860 if (next_command_ofs > 0) {
1861 next_command_ofs = SMB2_HDR_BODY;
1862 next_command_ofs += req->out.vector[i+1].iov_len;
1863 next_command_ofs += req->out.vector[i+2].iov_len;
1866 if ((next_command_ofs % 8) != 0) {
1867 size_t pad_size = 8 - (next_command_ofs % 8);
1868 if (req->out.vector[i+2].iov_len == 0) {
1870 * if the dyn buffer is empty
1871 * we can use it to add padding
1873 uint8_t *pad;
1875 pad = talloc_zero_array(req->out.vector,
1876 uint8_t, pad_size);
1877 if (pad == NULL) {
1878 return smbd_smb2_request_error(req,
1879 NT_STATUS_NO_MEMORY);
1882 req->out.vector[i+2].iov_base = (void *)pad;
1883 req->out.vector[i+2].iov_len = pad_size;
1884 } else {
1886 * For now we copy the dynamic buffer
1887 * and add the padding to the new buffer
1889 size_t old_size;
1890 uint8_t *old_dyn;
1891 size_t new_size;
1892 uint8_t *new_dyn;
1894 old_size = req->out.vector[i+2].iov_len;
1895 old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
1897 new_size = old_size + pad_size;
1898 new_dyn = talloc_zero_array(req->out.vector,
1899 uint8_t, new_size);
1900 if (new_dyn == NULL) {
1901 return smbd_smb2_request_error(req,
1902 NT_STATUS_NO_MEMORY);
1905 memcpy(new_dyn, old_dyn, old_size);
1906 memset(new_dyn + old_size, 0, pad_size);
1908 req->out.vector[i+2].iov_base = (void *)new_dyn;
1909 req->out.vector[i+2].iov_len = new_size;
1911 next_command_ofs += pad_size;
1914 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
1916 return smbd_smb2_request_reply(req);
1919 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
1920 NTSTATUS status,
1921 DATA_BLOB *info,
1922 const char *location)
1924 DATA_BLOB body;
1925 int i = req->current_idx;
1926 uint8_t *outhdr = (uint8_t *)req->out.vector[i].iov_base;
1928 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
1929 i, nt_errstr(status), info ? " +info" : "",
1930 location));
1932 body.data = outhdr + SMB2_HDR_BODY;
1933 body.length = 8;
1934 SSVAL(body.data, 0, 9);
1936 if (info) {
1937 SIVAL(body.data, 0x04, info->length);
1938 } else {
1939 /* Allocated size of req->out.vector[i].iov_base
1940 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
1941 * 1 byte without having to do an alloc.
1943 info = talloc_zero_array(req->out.vector,
1944 DATA_BLOB,
1946 if (!info) {
1947 return NT_STATUS_NO_MEMORY;
1949 info->data = ((uint8_t *)outhdr) +
1950 OUTVEC_ALLOC_SIZE - 1;
1951 info->length = 1;
1952 SCVAL(info->data, 0, 0);
1956 * if a request fails, all other remaining
1957 * compounded requests should fail too
1959 req->next_status = NT_STATUS_INVALID_PARAMETER;
1961 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
1965 struct smbd_smb2_send_oplock_break_state {
1966 struct smbd_server_connection *sconn;
1967 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
1968 struct iovec vector;
1971 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
1973 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
1974 uint64_t file_id_persistent,
1975 uint64_t file_id_volatile,
1976 uint8_t oplock_level)
1978 struct smbd_smb2_send_oplock_break_state *state;
1979 struct tevent_req *subreq;
1980 uint8_t *hdr;
1981 uint8_t *body;
1983 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
1984 if (state == NULL) {
1985 return NT_STATUS_NO_MEMORY;
1987 state->sconn = sconn;
1989 state->vector.iov_base = (void *)state->buf;
1990 state->vector.iov_len = sizeof(state->buf);
1992 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
1993 hdr = state->buf + 4;
1994 body = hdr + SMB2_HDR_BODY;
1996 SIVAL(hdr, 0, SMB2_MAGIC);
1997 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1998 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1999 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2000 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2001 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2002 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2003 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2004 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2005 SIVAL(hdr, SMB2_HDR_PID, 0);
2006 SIVAL(hdr, SMB2_HDR_TID, 0);
2007 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2008 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2010 SSVAL(body, 0x00, 0x18);
2012 SCVAL(body, 0x02, oplock_level);
2013 SCVAL(body, 0x03, 0); /* reserved */
2014 SIVAL(body, 0x04, 0); /* reserved */
2015 SBVAL(body, 0x08, file_id_persistent);
2016 SBVAL(body, 0x10, file_id_volatile);
2018 subreq = tstream_writev_queue_send(state,
2019 sconn->smb2.event_ctx,
2020 sconn->smb2.stream,
2021 sconn->smb2.send_queue,
2022 &state->vector, 1);
2023 if (subreq == NULL) {
2024 return NT_STATUS_NO_MEMORY;
2026 tevent_req_set_callback(subreq,
2027 smbd_smb2_oplock_break_writev_done,
2028 state);
2030 return NT_STATUS_OK;
2033 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2035 struct smbd_smb2_send_oplock_break_state *state =
2036 tevent_req_callback_data(subreq,
2037 struct smbd_smb2_send_oplock_break_state);
2038 struct smbd_server_connection *sconn = state->sconn;
2039 int ret;
2040 int sys_errno;
2042 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2043 TALLOC_FREE(subreq);
2044 if (ret == -1) {
2045 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2046 smbd_server_connection_terminate(sconn, nt_errstr(status));
2047 return;
2050 TALLOC_FREE(state);
2053 struct smbd_smb2_request_read_state {
2054 size_t missing;
2055 bool asked_for_header;
2056 struct smbd_smb2_request *smb2_req;
2059 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2060 void *private_data,
2061 TALLOC_CTX *mem_ctx,
2062 struct iovec **_vector,
2063 size_t *_count);
2064 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2066 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2067 struct tevent_context *ev,
2068 struct smbd_server_connection *sconn)
2070 struct tevent_req *req;
2071 struct smbd_smb2_request_read_state *state;
2072 struct tevent_req *subreq;
2074 req = tevent_req_create(mem_ctx, &state,
2075 struct smbd_smb2_request_read_state);
2076 if (req == NULL) {
2077 return NULL;
2079 state->missing = 0;
2080 state->asked_for_header = false;
2082 state->smb2_req = smbd_smb2_request_allocate(state);
2083 if (tevent_req_nomem(state->smb2_req, req)) {
2084 return tevent_req_post(req, ev);
2086 state->smb2_req->sconn = sconn;
2088 subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
2089 sconn->smb2.recv_queue,
2090 smbd_smb2_request_next_vector,
2091 state);
2092 if (tevent_req_nomem(subreq, req)) {
2093 return tevent_req_post(req, ev);
2095 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2097 return req;
2100 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2101 void *private_data,
2102 TALLOC_CTX *mem_ctx,
2103 struct iovec **_vector,
2104 size_t *_count)
2106 struct smbd_smb2_request_read_state *state =
2107 talloc_get_type_abort(private_data,
2108 struct smbd_smb2_request_read_state);
2109 struct smbd_smb2_request *req = state->smb2_req;
2110 struct iovec *vector;
2111 int idx = req->in.vector_count;
2112 size_t len = 0;
2113 uint8_t *buf = NULL;
2115 if (req->in.vector_count == 0) {
2117 * first we need to get the NBT header
2119 req->in.vector = talloc_array(req, struct iovec,
2120 req->in.vector_count + 1);
2121 if (req->in.vector == NULL) {
2122 return -1;
2124 req->in.vector_count += 1;
2126 req->in.vector[idx].iov_base = (void *)req->in.nbt_hdr;
2127 req->in.vector[idx].iov_len = 4;
2129 vector = talloc_array(mem_ctx, struct iovec, 1);
2130 if (vector == NULL) {
2131 return -1;
2134 vector[0] = req->in.vector[idx];
2136 *_vector = vector;
2137 *_count = 1;
2138 return 0;
2141 if (req->in.vector_count == 1) {
2143 * Now we analyze the NBT header
2145 state->missing = smb2_len(req->in.vector[0].iov_base);
2147 if (state->missing == 0) {
2148 /* if there're no remaining bytes, we're done */
2149 *_vector = NULL;
2150 *_count = 0;
2151 return 0;
2154 req->in.vector = talloc_realloc(req, req->in.vector,
2155 struct iovec,
2156 req->in.vector_count + 1);
2157 if (req->in.vector == NULL) {
2158 return -1;
2160 req->in.vector_count += 1;
2162 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
2164 * it's a special NBT message,
2165 * so get all remaining bytes
2167 len = state->missing;
2168 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
2170 * it's an invalid message, just read what we can get
2171 * and let the caller handle the error
2173 len = state->missing;
2174 } else {
2176 * We assume it's a SMB2 request,
2177 * and we first get the header and the
2178 * first 2 bytes (the struct size) of the body
2180 len = SMB2_HDR_BODY + 2;
2182 state->asked_for_header = true;
2185 state->missing -= len;
2187 buf = talloc_array(req->in.vector, uint8_t, len);
2188 if (buf == NULL) {
2189 return -1;
2192 req->in.vector[idx].iov_base = (void *)buf;
2193 req->in.vector[idx].iov_len = len;
2195 vector = talloc_array(mem_ctx, struct iovec, 1);
2196 if (vector == NULL) {
2197 return -1;
2200 vector[0] = req->in.vector[idx];
2202 *_vector = vector;
2203 *_count = 1;
2204 return 0;
2207 if (state->missing == 0) {
2208 /* if there're no remaining bytes, we're done */
2209 *_vector = NULL;
2210 *_count = 0;
2211 return 0;
2214 if (state->asked_for_header) {
2215 const uint8_t *hdr;
2216 size_t full_size;
2217 size_t next_command_ofs;
2218 size_t body_size;
2219 uint8_t *body;
2220 size_t dyn_size;
2221 uint8_t *dyn;
2222 bool invalid = false;
2224 state->asked_for_header = false;
2227 * We got the SMB2 header and the first 2 bytes
2228 * of the body. We fix the size to just the header
2229 * and manually copy the 2 first bytes to the body section
2231 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
2232 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
2234 /* allocate vectors for body and dynamic areas */
2235 req->in.vector = talloc_realloc(req, req->in.vector,
2236 struct iovec,
2237 req->in.vector_count + 2);
2238 if (req->in.vector == NULL) {
2239 return -1;
2241 req->in.vector_count += 2;
2243 full_size = state->missing + SMB2_HDR_BODY + 2;
2244 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
2245 body_size = SVAL(hdr, SMB2_HDR_BODY);
2247 if (next_command_ofs != 0) {
2248 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
2250 * this is invalid, just return a zero
2251 * body and let the caller deal with the error
2253 invalid = true;
2254 } else if (next_command_ofs > full_size) {
2256 * this is invalid, just return a zero
2257 * body and let the caller deal with the error
2259 invalid = true;
2260 } else {
2261 full_size = next_command_ofs;
2265 if (!invalid) {
2266 if (body_size < 2) {
2268 * this is invalid, just return a zero
2269 * body and let the caller deal with the error
2271 invalid = true;
2275 * Mask out the lowest bit, the "dynamic" part
2276 * of body_size.
2278 body_size &= ~1;
2280 if (body_size > (full_size - SMB2_HDR_BODY)) {
2282 * this is invalid, just return a zero
2283 * body and let the caller deal with the error
2285 invalid = true;
2289 if (invalid) {
2290 /* the caller should check this */
2291 body_size = 2;
2294 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
2296 state->missing -= (body_size - 2) + dyn_size;
2298 body = talloc_array(req->in.vector, uint8_t, body_size);
2299 if (body == NULL) {
2300 return -1;
2303 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
2304 if (dyn == NULL) {
2305 return -1;
2308 req->in.vector[idx].iov_base = (void *)body;
2309 req->in.vector[idx].iov_len = body_size;
2310 req->in.vector[idx+1].iov_base = (void *)dyn;
2311 req->in.vector[idx+1].iov_len = dyn_size;
2313 vector = talloc_array(mem_ctx, struct iovec, 2);
2314 if (vector == NULL) {
2315 return -1;
2319 * the first 2 bytes of the body were already fetched
2320 * together with the header
2322 memcpy(body, hdr + SMB2_HDR_BODY, 2);
2323 vector[0].iov_base = body + 2;
2324 vector[0].iov_len = body_size - 2;
2326 vector[1] = req->in.vector[idx+1];
2328 *_vector = vector;
2329 *_count = 2;
2330 return 0;
2334 * when we endup here, we're looking for a new SMB2 request
2335 * next. And we ask for its header and the first 2 bytes of
2336 * the body (like we did for the first SMB2 request).
2339 req->in.vector = talloc_realloc(req, req->in.vector,
2340 struct iovec,
2341 req->in.vector_count + 1);
2342 if (req->in.vector == NULL) {
2343 return -1;
2345 req->in.vector_count += 1;
2348 * We assume it's a SMB2 request,
2349 * and we first get the header and the
2350 * first 2 bytes (the struct size) of the body
2352 len = SMB2_HDR_BODY + 2;
2354 if (len > state->missing) {
2355 /* let the caller handle the error */
2356 len = state->missing;
2359 state->missing -= len;
2360 state->asked_for_header = true;
2362 buf = talloc_array(req->in.vector, uint8_t, len);
2363 if (buf == NULL) {
2364 return -1;
2367 req->in.vector[idx].iov_base = (void *)buf;
2368 req->in.vector[idx].iov_len = len;
2370 vector = talloc_array(mem_ctx, struct iovec, 1);
2371 if (vector == NULL) {
2372 return -1;
2375 vector[0] = req->in.vector[idx];
2377 *_vector = vector;
2378 *_count = 1;
2379 return 0;
2382 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2384 struct tevent_req *req =
2385 tevent_req_callback_data(subreq,
2386 struct tevent_req);
2387 int ret;
2388 int sys_errno;
2389 NTSTATUS status;
2391 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2392 if (ret == -1) {
2393 status = map_nt_error_from_unix(sys_errno);
2394 tevent_req_nterror(req, status);
2395 return;
2398 tevent_req_done(req);
2401 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2402 TALLOC_CTX *mem_ctx,
2403 struct smbd_smb2_request **_smb2_req)
2405 struct smbd_smb2_request_read_state *state =
2406 tevent_req_data(req,
2407 struct smbd_smb2_request_read_state);
2408 NTSTATUS status;
2410 if (tevent_req_is_nterror(req, &status)) {
2411 tevent_req_received(req);
2412 return status;
2415 talloc_steal(mem_ctx, state->smb2_req->mem_pool);
2416 *_smb2_req = state->smb2_req;
2417 tevent_req_received(req);
2418 return NT_STATUS_OK;
2421 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2423 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2424 const uint8_t *inbuf, size_t size)
2426 NTSTATUS status;
2427 struct smbd_smb2_request *req = NULL;
2428 struct tevent_req *subreq;
2430 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2431 (unsigned int)size));
2433 status = smbd_initialize_smb2(sconn);
2434 if (!NT_STATUS_IS_OK(status)) {
2435 smbd_server_connection_terminate(sconn, nt_errstr(status));
2436 return;
2439 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2440 if (!NT_STATUS_IS_OK(status)) {
2441 smbd_server_connection_terminate(sconn, nt_errstr(status));
2442 return;
2445 status = smbd_smb2_request_setup_out(req);
2446 if (!NT_STATUS_IS_OK(status)) {
2447 smbd_server_connection_terminate(sconn, nt_errstr(status));
2448 return;
2451 status = smbd_smb2_request_dispatch(req);
2452 if (!NT_STATUS_IS_OK(status)) {
2453 smbd_server_connection_terminate(sconn, nt_errstr(status));
2454 return;
2457 /* ask for the next request */
2458 subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
2459 if (subreq == NULL) {
2460 smbd_server_connection_terminate(sconn, "no memory for reading");
2461 return;
2463 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2465 sconn->num_requests++;
2468 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2470 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2471 struct smbd_server_connection);
2472 NTSTATUS status;
2473 struct smbd_smb2_request *req = NULL;
2475 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2476 TALLOC_FREE(subreq);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2479 nt_errstr(status)));
2480 smbd_server_connection_terminate(sconn, nt_errstr(status));
2481 return;
2484 if (req->in.nbt_hdr[0] != 0x00) {
2485 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
2486 req->in.nbt_hdr[0]));
2487 TALLOC_FREE(req);
2488 goto next;
2491 req->current_idx = 1;
2493 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2494 req->current_idx, req->in.vector_count));
2496 status = smbd_smb2_request_validate(req);
2497 if (!NT_STATUS_IS_OK(status)) {
2498 smbd_server_connection_terminate(sconn, nt_errstr(status));
2499 return;
2502 status = smbd_smb2_request_setup_out(req);
2503 if (!NT_STATUS_IS_OK(status)) {
2504 smbd_server_connection_terminate(sconn, nt_errstr(status));
2505 return;
2508 status = smbd_smb2_request_dispatch(req);
2509 if (!NT_STATUS_IS_OK(status)) {
2510 smbd_server_connection_terminate(sconn, nt_errstr(status));
2511 return;
2514 next:
2515 /* ask for the next request (this constructs the main loop) */
2516 subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
2517 if (subreq == NULL) {
2518 smbd_server_connection_terminate(sconn, "no memory for reading");
2519 return;
2521 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2523 sconn->num_requests++;
2525 /* The timeout_processing function isn't run nearly
2526 often enough to implement 'max log size' without
2527 overrunning the size of the file by many megabytes.
2528 This is especially true if we are running at debug
2529 level 10. Checking every 50 SMB2s is a nice
2530 tradeoff of performance vs log file size overrun. */
2532 if ((sconn->num_requests % 50) == 0 &&
2533 need_to_check_log_size()) {
2534 change_to_root_user();
2535 check_log_size();