s3:smb2_server: make sure we don't grant more credits than we allow
[Samba/gebeck_regimport.git] / source3 / smbd / smb2_server.c
blob320923a4cfeceedca3c2c69c4589f305b3c4d9bd
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.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
102 if (sconn->smb2.recv_queue == NULL) {
103 return NT_STATUS_NO_MEMORY;
106 sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
107 if (sconn->smb2.send_queue == NULL) {
108 return NT_STATUS_NO_MEMORY;
111 sconn->smb2.seqnum_low = 0;
112 sconn->smb2.seqnum_range = 1;
113 sconn->smb2.credits_granted = 1;
114 sconn->smb2.max_credits = lp_smb2_max_credits();
115 sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
116 sconn->smb2.max_credits);
117 if (sconn->smb2.credits_bitmap == NULL) {
118 return NT_STATUS_NO_MEMORY;
121 ret = tstream_bsd_existing_socket(sconn, sconn->sock,
122 &sconn->smb2.stream);
123 if (ret == -1) {
124 status = map_nt_error_from_unix(errno);
125 return status;
128 /* Ensure child is set to non-blocking mode */
129 set_blocking(sconn->sock, false);
130 return NT_STATUS_OK;
133 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
134 #define _smb2_setlen(_buf,len) do { \
135 uint8_t *buf = (uint8_t *)_buf; \
136 buf[0] = 0; \
137 buf[1] = ((len)&0xFF0000)>>16; \
138 buf[2] = ((len)&0xFF00)>>8; \
139 buf[3] = (len)&0xFF; \
140 } while (0)
142 static void smb2_setup_nbt_length(struct iovec *vector, int count)
144 size_t len = 0;
145 int i;
147 for (i=1; i < count; i++) {
148 len += vector[i].iov_len;
151 _smb2_setlen(vector[0].iov_base, len);
154 static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request **req)
156 if (*req) {
157 (*req)->parent = NULL;
158 (*req)->mem_pool = NULL;
161 return 0;
164 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
166 if (req->parent) {
167 *req->parent = NULL;
168 talloc_free(req->mem_pool);
171 return 0;
174 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
176 TALLOC_CTX *mem_pool;
177 struct smbd_smb2_request **parent;
178 struct smbd_smb2_request *req;
180 #if 0
181 /* Enable this to find subtle valgrind errors. */
182 mem_pool = talloc_init("smbd_smb2_request_allocate");
183 #else
184 mem_pool = talloc_pool(mem_ctx, 8192);
185 #endif
186 if (mem_pool == NULL) {
187 return NULL;
190 parent = talloc(mem_pool, struct smbd_smb2_request *);
191 if (parent == NULL) {
192 talloc_free(mem_pool);
193 return NULL;
196 req = talloc_zero(parent, struct smbd_smb2_request);
197 if (req == NULL) {
198 talloc_free(mem_pool);
199 return NULL;
201 *parent = req;
202 req->mem_pool = mem_pool;
203 req->parent = parent;
205 req->last_session_id = UINT64_MAX;
206 req->last_tid = UINT32_MAX;
208 talloc_set_destructor(parent, smbd_smb2_request_parent_destructor);
209 talloc_set_destructor(req, smbd_smb2_request_destructor);
211 return req;
214 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
215 const uint8_t *inbuf, size_t size,
216 struct smbd_smb2_request **_req)
218 struct smbd_smb2_request *req;
219 uint32_t protocol_version;
220 const uint8_t *inhdr = NULL;
221 off_t ofs = 0;
222 uint16_t cmd;
223 uint32_t next_command_ofs;
225 if (size < (4 + SMB2_HDR_BODY + 2)) {
226 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
227 return NT_STATUS_INVALID_PARAMETER;
230 inhdr = inbuf + 4;
232 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
233 if (protocol_version != SMB2_MAGIC) {
234 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
235 protocol_version));
236 return NT_STATUS_INVALID_PARAMETER;
239 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
240 if (cmd != SMB2_OP_NEGPROT) {
241 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
242 cmd));
243 return NT_STATUS_INVALID_PARAMETER;
246 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
247 if (next_command_ofs != 0) {
248 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
249 next_command_ofs));
250 return NT_STATUS_INVALID_PARAMETER;
253 req = smbd_smb2_request_allocate(sconn);
254 if (req == NULL) {
255 return NT_STATUS_NO_MEMORY;
257 req->sconn = sconn;
259 talloc_steal(req, inbuf);
261 req->in.vector = talloc_array(req, struct iovec, 4);
262 if (req->in.vector == NULL) {
263 TALLOC_FREE(req);
264 return NT_STATUS_NO_MEMORY;
266 req->in.vector_count = 4;
268 memcpy(req->in.nbt_hdr, inbuf, 4);
270 ofs = 0;
271 req->in.vector[0].iov_base = discard_const_p(void, req->in.nbt_hdr);
272 req->in.vector[0].iov_len = 4;
273 ofs += req->in.vector[0].iov_len;
275 req->in.vector[1].iov_base = discard_const_p(void, (inbuf + ofs));
276 req->in.vector[1].iov_len = SMB2_HDR_BODY;
277 ofs += req->in.vector[1].iov_len;
279 req->in.vector[2].iov_base = discard_const_p(void, (inbuf + ofs));
280 req->in.vector[2].iov_len = SVAL(inbuf, ofs) & 0xFFFE;
281 ofs += req->in.vector[2].iov_len;
283 if (ofs > size) {
284 return NT_STATUS_INVALID_PARAMETER;
287 req->in.vector[3].iov_base = discard_const_p(void, (inbuf + ofs));
288 req->in.vector[3].iov_len = size - ofs;
289 ofs += req->in.vector[3].iov_len;
291 req->current_idx = 1;
293 *_req = req;
294 return NT_STATUS_OK;
297 static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
298 uint64_t message_id, uint64_t seq_id)
300 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
301 unsigned int offset;
303 if (seq_id < sconn->smb2.seqnum_low) {
304 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
305 "%llu (sequence id %llu) "
306 "(granted = %u, low = %llu, range = %u)\n",
307 (unsigned long long)message_id,
308 (unsigned long long)seq_id,
309 (unsigned int)sconn->smb2.credits_granted,
310 (unsigned long long)sconn->smb2.seqnum_low,
311 (unsigned int)sconn->smb2.seqnum_range));
312 return false;
315 if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
316 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
317 "%llu (sequence id %llu) "
318 "(granted = %u, low = %llu, range = %u)\n",
319 (unsigned long long)message_id,
320 (unsigned long long)seq_id,
321 (unsigned int)sconn->smb2.credits_granted,
322 (unsigned long long)sconn->smb2.seqnum_low,
323 (unsigned int)sconn->smb2.seqnum_range));
324 return false;
327 offset = seq_id % sconn->smb2.max_credits;
329 if (bitmap_query(credits_bm, offset)) {
330 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
331 "%llu (sequence id %llu) "
332 "(granted = %u, low = %llu, range = %u) "
333 "(bm offset %u)\n",
334 (unsigned long long)message_id,
335 (unsigned long long)seq_id,
336 (unsigned int)sconn->smb2.credits_granted,
337 (unsigned long long)sconn->smb2.seqnum_low,
338 (unsigned int)sconn->smb2.seqnum_range,
339 offset));
340 return false;
343 /* Mark the message_ids as seen in the bitmap. */
344 bitmap_set(credits_bm, offset);
346 if (seq_id != sconn->smb2.seqnum_low) {
347 return true;
351 * Move the window forward by all the message_id's
352 * already seen.
354 while (bitmap_query(credits_bm, offset)) {
355 DEBUG(10,("smb2_validate_sequence_number: clearing "
356 "id %llu (position %u) from bitmap\n",
357 (unsigned long long)(sconn->smb2.seqnum_low),
358 offset));
359 bitmap_clear(credits_bm, offset);
361 sconn->smb2.seqnum_low += 1;
362 sconn->smb2.seqnum_range -= 1;
363 offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
366 return true;
369 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
370 const uint8_t *inhdr)
372 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
373 uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
374 uint16_t credit_charge = 1;
375 uint64_t i;
377 if (opcode == SMB2_OP_CANCEL) {
378 /* SMB2_CANCEL requests by definition resend messageids. */
379 return true;
382 if (sconn->smb2.supports_multicredit) {
383 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
384 credit_charge = MAX(credit_charge, 1);
387 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
388 "credits_granted %llu, "
389 "seqnum low/range: %llu/%llu\n",
390 (unsigned long long) message_id,
391 (unsigned long long) credit_charge,
392 (unsigned long long) sconn->smb2.credits_granted,
393 (unsigned long long) sconn->smb2.seqnum_low,
394 (unsigned long long) sconn->smb2.seqnum_range));
396 if (sconn->smb2.credits_granted < credit_charge) {
397 DEBUG(0, ("smb2_validate_message_id: client used more "
398 "credits than granted, mid %llu, charge %llu, "
399 "credits_granted %llu, "
400 "seqnum low/range: %llu/%llu\n",
401 (unsigned long long) message_id,
402 (unsigned long long) credit_charge,
403 (unsigned long long) sconn->smb2.credits_granted,
404 (unsigned long long) sconn->smb2.seqnum_low,
405 (unsigned long long) sconn->smb2.seqnum_range));
406 return false;
410 * now check the message ids
412 * for multi-credit requests we need to check all current mid plus
413 * the implicit mids caused by the credit charge
414 * e.g. current mid = 15, charge 5 => mark 15-19 as used
417 for (i = 0; i <= (credit_charge-1); i++) {
418 uint64_t id = message_id + i;
419 bool ok;
421 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
422 (unsigned long long)message_id,
423 credit_charge,
424 (unsigned long long)id));
426 ok = smb2_validate_sequence_number(sconn, message_id, id);
427 if (!ok) {
428 return false;
432 /* substract used credits */
433 sconn->smb2.credits_granted -= credit_charge;
435 return true;
438 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
440 int count;
441 int idx;
443 count = req->in.vector_count;
445 if (count < 4) {
446 /* It's not a SMB2 request */
447 return NT_STATUS_INVALID_PARAMETER;
450 for (idx=1; idx < count; idx += 3) {
451 const uint8_t *inhdr = NULL;
452 uint32_t flags;
454 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
455 return NT_STATUS_INVALID_PARAMETER;
458 if (req->in.vector[idx+1].iov_len < 2) {
459 return NT_STATUS_INVALID_PARAMETER;
462 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
464 /* Check the SMB2 header */
465 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
466 return NT_STATUS_INVALID_PARAMETER;
469 if (!smb2_validate_message_id(req->sconn, inhdr)) {
470 return NT_STATUS_INVALID_PARAMETER;
473 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
474 if (idx == 1) {
476 * the 1st request should never have the
477 * SMB2_HDR_FLAG_CHAINED flag set
479 if (flags & SMB2_HDR_FLAG_CHAINED) {
480 req->next_status = NT_STATUS_INVALID_PARAMETER;
481 return NT_STATUS_OK;
483 } else if (idx == 4) {
485 * the 2nd request triggers related vs. unrelated
486 * compounded requests
488 if (flags & SMB2_HDR_FLAG_CHAINED) {
489 req->compound_related = true;
491 } else if (idx > 4) {
492 #if 0
494 * It seems the this tests are wrong
495 * see the SMB2-COMPOUND test
499 * all other requests should match the 2nd one
501 if (flags & SMB2_HDR_FLAG_CHAINED) {
502 if (!req->compound_related) {
503 req->next_status =
504 NT_STATUS_INVALID_PARAMETER;
505 return NT_STATUS_OK;
507 } else {
508 if (req->compound_related) {
509 req->next_status =
510 NT_STATUS_INVALID_PARAMETER;
511 return NT_STATUS_OK;
514 #endif
518 return NT_STATUS_OK;
521 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
522 const struct iovec *in_vector,
523 struct iovec *out_vector)
525 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
526 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
527 uint16_t credits_requested;
528 uint32_t out_flags;
529 uint16_t credits_granted = 0;
530 uint64_t credits_possible;
532 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
533 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
535 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
537 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
539 * In case we already send an async interim
540 * response, we should not grant
541 * credits on the final response.
543 credits_granted = 0;
544 } else if (credits_requested > 0) {
545 uint16_t modified_credits_requested;
546 uint32_t multiplier;
549 * Split up max_credits into 1/16ths, and then scale
550 * the requested credits by how many 16ths have been
551 * currently granted. Less than 1/16th == grant all
552 * requested (100%), scale down as more have been
553 * granted. Never ask for less than 1 as the client
554 * asked for at least 1. JRA.
557 multiplier = 16 - (((sconn->smb2.credits_granted * 16) / sconn->smb2.max_credits) % 16);
559 modified_credits_requested = (multiplier * credits_requested) / 16;
560 if (modified_credits_requested == 0) {
561 modified_credits_requested = 1;
564 credits_granted = modified_credits_requested;
565 } else if (sconn->smb2.credits_granted == 0) {
567 * Make sure the client has always at least one credit
569 credits_granted = 1;
573 * remove the range we'll already granted to the client
574 * this makes sure the client consumes the lowest sequence
575 * number, before we can grant additional credits.
577 credits_possible = sconn->smb2.max_credits;
578 credits_possible -= sconn->smb2.seqnum_range;
580 credits_granted = MIN(credits_granted, credits_possible);
582 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
583 sconn->smb2.credits_granted += credits_granted;
584 sconn->smb2.seqnum_range += credits_granted;
586 DEBUG(10,("smb2_set_operation_credit: requested %u, "
587 "granted %u, current possible %u, "
588 "total granted/max/low/range %u/%u/%llu/%u\n",
589 (unsigned int)credits_requested,
590 (unsigned int)credits_granted,
591 (unsigned int)credits_possible,
592 (unsigned int)sconn->smb2.credits_granted,
593 (unsigned int)sconn->smb2.max_credits,
594 (unsigned long long)sconn->smb2.seqnum_low,
595 (unsigned int)sconn->smb2.seqnum_range));
598 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
599 struct smbd_smb2_request *outreq)
601 int count, idx;
602 uint16_t total_credits = 0;
604 count = outreq->out.vector_count;
606 for (idx=1; idx < count; idx += 3) {
607 uint8_t *outhdr = (uint8_t *)outreq->out.vector[idx].iov_base;
608 smb2_set_operation_credit(outreq->sconn,
609 &inreq->in.vector[idx],
610 &outreq->out.vector[idx]);
611 /* To match Windows, count up what we
612 just granted. */
613 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
614 /* Set to zero in all but the last reply. */
615 if (idx + 3 < count) {
616 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
617 } else {
618 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
623 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
625 struct iovec *vector;
626 int count;
627 int idx;
629 req->request_time = timeval_current();
631 count = req->in.vector_count;
632 vector = talloc_zero_array(req, struct iovec, count);
633 if (vector == NULL) {
634 return NT_STATUS_NO_MEMORY;
637 vector[0].iov_base = req->out.nbt_hdr;
638 vector[0].iov_len = 4;
639 SIVAL(req->out.nbt_hdr, 0, 0);
641 for (idx=1; idx < count; idx += 3) {
642 const uint8_t *inhdr = NULL;
643 uint8_t *outhdr = NULL;
644 uint8_t *outbody = NULL;
645 uint32_t next_command_ofs = 0;
646 struct iovec *current = &vector[idx];
648 if ((idx + 3) < count) {
649 /* we have a next command -
650 * setup for the error case. */
651 next_command_ofs = SMB2_HDR_BODY + 9;
654 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
656 outhdr = talloc_zero_array(vector, uint8_t,
657 OUTVEC_ALLOC_SIZE);
658 if (outhdr == NULL) {
659 return NT_STATUS_NO_MEMORY;
662 outbody = outhdr + SMB2_HDR_BODY;
664 current[0].iov_base = (void *)outhdr;
665 current[0].iov_len = SMB2_HDR_BODY;
667 current[1].iov_base = (void *)outbody;
668 current[1].iov_len = 8;
670 current[2].iov_base = NULL;
671 current[2].iov_len = 0;
673 /* setup the SMB2 header */
674 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
675 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
676 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
677 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
678 SIVAL(outhdr, SMB2_HDR_STATUS,
679 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
680 SSVAL(outhdr, SMB2_HDR_OPCODE,
681 SVAL(inhdr, SMB2_HDR_OPCODE));
682 SIVAL(outhdr, SMB2_HDR_FLAGS,
683 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
684 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
685 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
686 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
687 SIVAL(outhdr, SMB2_HDR_PID,
688 IVAL(inhdr, SMB2_HDR_PID));
689 SIVAL(outhdr, SMB2_HDR_TID,
690 IVAL(inhdr, SMB2_HDR_TID));
691 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
692 BVAL(inhdr, SMB2_HDR_SESSION_ID));
693 memcpy(outhdr + SMB2_HDR_SIGNATURE,
694 inhdr + SMB2_HDR_SIGNATURE, 16);
696 /* setup error body header */
697 SSVAL(outbody, 0x00, 0x08 + 1);
698 SSVAL(outbody, 0x02, 0);
699 SIVAL(outbody, 0x04, 0);
702 req->out.vector = vector;
703 req->out.vector_count = count;
705 /* setup the length of the NBT packet */
706 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
708 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
710 return NT_STATUS_OK;
713 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
714 const char *reason,
715 const char *location)
717 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
718 reason, location));
719 exit_server_cleanly(reason);
722 static bool dup_smb2_vec3(TALLOC_CTX *ctx,
723 struct iovec *outvec,
724 const struct iovec *srcvec)
726 /* vec[0] is always boilerplate and must
727 * be allocated with size OUTVEC_ALLOC_SIZE. */
729 outvec[0].iov_base = talloc_memdup(ctx,
730 srcvec[0].iov_base,
731 OUTVEC_ALLOC_SIZE);
732 if (!outvec[0].iov_base) {
733 return false;
735 outvec[0].iov_len = SMB2_HDR_BODY;
738 * If this is a "standard" vec[1] of length 8,
739 * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
740 * then duplicate this. Else use talloc_memdup().
743 if (srcvec[1].iov_len == 8 &&
744 srcvec[1].iov_base ==
745 ((uint8_t *)srcvec[0].iov_base) +
746 SMB2_HDR_BODY) {
747 outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
748 SMB2_HDR_BODY;
749 outvec[1].iov_len = 8;
750 } else {
751 outvec[1].iov_base = talloc_memdup(ctx,
752 srcvec[1].iov_base,
753 srcvec[1].iov_len);
754 if (!outvec[1].iov_base) {
755 return false;
757 outvec[1].iov_len = srcvec[1].iov_len;
761 * If this is a "standard" vec[2] of length 1,
762 * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
763 * then duplicate this. Else use talloc_memdup().
766 if (srcvec[2].iov_base &&
767 srcvec[2].iov_len) {
768 if (srcvec[2].iov_base ==
769 ((uint8_t *)srcvec[0].iov_base) +
770 (OUTVEC_ALLOC_SIZE - 1) &&
771 srcvec[2].iov_len == 1) {
772 /* Common SMB2 error packet case. */
773 outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
774 (OUTVEC_ALLOC_SIZE - 1);
775 } else {
776 outvec[2].iov_base = talloc_memdup(ctx,
777 srcvec[2].iov_base,
778 srcvec[2].iov_len);
779 if (!outvec[2].iov_base) {
780 return false;
783 outvec[2].iov_len = srcvec[2].iov_len;
784 } else {
785 outvec[2].iov_base = NULL;
786 outvec[2].iov_len = 0;
788 return true;
791 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
793 struct smbd_smb2_request *newreq = NULL;
794 struct iovec *outvec = NULL;
795 int count = req->out.vector_count;
796 int i;
798 newreq = smbd_smb2_request_allocate(req->sconn);
799 if (!newreq) {
800 return NULL;
803 newreq->sconn = req->sconn;
804 newreq->session = req->session;
805 newreq->do_signing = req->do_signing;
806 newreq->current_idx = req->current_idx;
808 outvec = talloc_zero_array(newreq, struct iovec, count);
809 if (!outvec) {
810 TALLOC_FREE(newreq);
811 return NULL;
813 newreq->out.vector = outvec;
814 newreq->out.vector_count = count;
816 /* Setup the outvec's identically to req. */
817 outvec[0].iov_base = newreq->out.nbt_hdr;
818 outvec[0].iov_len = 4;
819 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
821 /* Setup the vectors identically to the ones in req. */
822 for (i = 1; i < count; i += 3) {
823 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
824 break;
828 if (i < count) {
829 /* Alloc failed. */
830 TALLOC_FREE(newreq);
831 return NULL;
834 smb2_setup_nbt_length(newreq->out.vector,
835 newreq->out.vector_count);
837 return newreq;
840 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
842 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
844 int i = 0;
845 uint8_t *outhdr = NULL;
846 struct smbd_smb2_request *nreq = NULL;
848 /* Create a new smb2 request we'll use
849 for the interim return. */
850 nreq = dup_smb2_req(req);
851 if (!nreq) {
852 return NT_STATUS_NO_MEMORY;
855 /* Lose the last 3 out vectors. They're the
856 ones we'll be using for the async reply. */
857 nreq->out.vector_count -= 3;
859 smb2_setup_nbt_length(nreq->out.vector,
860 nreq->out.vector_count);
862 /* Step back to the previous reply. */
863 i = nreq->current_idx - 3;
864 outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
865 /* And end the chain. */
866 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
868 /* Calculate outgoing credits */
869 smb2_calculate_credits(req, nreq);
871 /* Re-sign if needed. */
872 if (nreq->do_signing) {
873 NTSTATUS status;
874 struct smbXsrv_session *x = nreq->session;
875 struct smbXsrv_connection *conn = x->connection;
876 DATA_BLOB signing_key = x->global->channels[0].signing_key;
878 status = smb2_signing_sign_pdu(signing_key,
879 conn->protocol,
880 &nreq->out.vector[i], 3);
881 if (!NT_STATUS_IS_OK(status)) {
882 return status;
885 if (DEBUGLEVEL >= 10) {
886 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
887 (unsigned int)nreq->current_idx );
888 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
889 (unsigned int)nreq->out.vector_count );
890 print_req_vectors(nreq);
892 nreq->subreq = tstream_writev_queue_send(nreq,
893 nreq->sconn->ev_ctx,
894 nreq->sconn->smb2.stream,
895 nreq->sconn->smb2.send_queue,
896 nreq->out.vector,
897 nreq->out.vector_count);
899 if (nreq->subreq == NULL) {
900 return NT_STATUS_NO_MEMORY;
903 tevent_req_set_callback(nreq->subreq,
904 smbd_smb2_request_writev_done,
905 nreq);
907 return NT_STATUS_OK;
910 struct smbd_smb2_request_pending_state {
911 struct smbd_server_connection *sconn;
912 uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
913 struct iovec vector[3];
916 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
918 struct smbd_smb2_request_pending_state *state =
919 tevent_req_callback_data(subreq,
920 struct smbd_smb2_request_pending_state);
921 struct smbd_server_connection *sconn = state->sconn;
922 int ret;
923 int sys_errno;
925 ret = tstream_writev_queue_recv(subreq, &sys_errno);
926 TALLOC_FREE(subreq);
927 if (ret == -1) {
928 NTSTATUS status = map_nt_error_from_unix(sys_errno);
929 smbd_server_connection_terminate(sconn, nt_errstr(status));
930 return;
933 TALLOC_FREE(state);
936 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
937 struct tevent_timer *te,
938 struct timeval current_time,
939 void *private_data);
941 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
942 struct tevent_req *subreq,
943 uint32_t defer_time)
945 NTSTATUS status;
946 int i = req->current_idx;
947 struct timeval defer_endtime;
948 uint8_t *outhdr = NULL;
949 uint32_t flags;
951 if (!tevent_req_is_in_progress(subreq)) {
952 return NT_STATUS_OK;
955 req->subreq = subreq;
956 subreq = NULL;
958 if (req->async_te) {
959 /* We're already async. */
960 return NT_STATUS_OK;
963 outhdr = (uint8_t *)req->out.vector[i].iov_base;
964 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
965 if (flags & SMB2_HDR_FLAG_ASYNC) {
966 /* We're already async. */
967 return NT_STATUS_OK;
970 if (req->in.vector_count > i + 3) {
972 * We're trying to go async in a compound
973 * request chain. This is not allowed.
974 * Cancel the outstanding request.
976 tevent_req_cancel(req->subreq);
977 return smbd_smb2_request_error(req,
978 NT_STATUS_INSUFFICIENT_RESOURCES);
981 if (DEBUGLEVEL >= 10) {
982 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
983 (unsigned int)req->current_idx );
984 print_req_vectors(req);
987 if (req->out.vector_count > 4) {
988 struct iovec *outvec = NULL;
990 /* This is a compound reply. We
991 * must do an interim response
992 * followed by the async response
993 * to match W2K8R2.
995 status = smb2_send_async_interim_response(req);
996 if (!NT_STATUS_IS_OK(status)) {
997 return status;
1001 * We're splitting off the last SMB2
1002 * request in a compound set, and the
1003 * smb2_send_async_interim_response()
1004 * call above just sent all the replies
1005 * for the previous SMB2 requests in
1006 * this compound set. So we're no longer
1007 * in the "compound_related_in_progress"
1008 * state, and this is no longer a compound
1009 * request.
1011 req->compound_related = false;
1012 req->sconn->smb2.compound_related_in_progress = false;
1014 /* Re-arrange the in.vectors. */
1015 req->in.vector[1] = req->in.vector[i];
1016 req->in.vector[2] = req->in.vector[i+1];
1017 req->in.vector[3] = req->in.vector[i+2];
1018 req->in.vector_count = 4;
1020 /* Reset the new in size. */
1021 smb2_setup_nbt_length(req->in.vector, 4);
1023 /* Now recreate the out.vectors. */
1024 outvec = talloc_zero_array(req, struct iovec, 4);
1025 if (!outvec) {
1026 return NT_STATUS_NO_MEMORY;
1029 /* 0 is always boilerplate and must
1030 * be of size 4 for the length field. */
1032 outvec[0].iov_base = req->out.nbt_hdr;
1033 outvec[0].iov_len = 4;
1034 SIVAL(req->out.nbt_hdr, 0, 0);
1036 if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
1037 return NT_STATUS_NO_MEMORY;
1040 TALLOC_FREE(req->out.vector);
1042 req->out.vector = outvec;
1044 req->current_idx = 1;
1045 req->out.vector_count = 4;
1047 outhdr = (uint8_t *)req->out.vector[1].iov_base;
1048 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1049 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1052 defer_endtime = timeval_current_ofs_usec(defer_time);
1053 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1054 req, defer_endtime,
1055 smbd_smb2_request_pending_timer,
1056 req);
1057 if (req->async_te == NULL) {
1058 return NT_STATUS_NO_MEMORY;
1061 return NT_STATUS_OK;
1064 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1065 struct tevent_timer *te,
1066 struct timeval current_time,
1067 void *private_data)
1069 struct smbd_smb2_request *req =
1070 talloc_get_type_abort(private_data,
1071 struct smbd_smb2_request);
1072 struct smbd_smb2_request_pending_state *state = NULL;
1073 int i = req->current_idx;
1074 uint8_t *outhdr = NULL;
1075 const uint8_t *inhdr = NULL;
1076 uint8_t *hdr = NULL;
1077 uint8_t *body = NULL;
1078 uint32_t flags = 0;
1079 uint64_t message_id = 0;
1080 uint64_t async_id = 0;
1081 struct tevent_req *subreq = NULL;
1083 TALLOC_FREE(req->async_te);
1085 /* Ensure our final reply matches the interim one. */
1086 inhdr = (const uint8_t *)req->in.vector[1].iov_base;
1087 outhdr = (uint8_t *)req->out.vector[1].iov_base;
1088 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1089 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1091 async_id = message_id; /* keep it simple for now... */
1093 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1094 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1096 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1097 "going async\n",
1098 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1099 (unsigned long long)async_id ));
1102 * What we send is identical to a smbd_smb2_request_error
1103 * packet with an error status of STATUS_PENDING. Make use
1104 * of this fact sometime when refactoring. JRA.
1107 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1108 if (state == NULL) {
1109 smbd_server_connection_terminate(req->sconn,
1110 nt_errstr(NT_STATUS_NO_MEMORY));
1111 return;
1113 state->sconn = req->sconn;
1115 state->vector[0].iov_base = (void *)state->buf;
1116 state->vector[0].iov_len = 4;
1118 state->vector[1].iov_base = state->buf + 4;
1119 state->vector[1].iov_len = SMB2_HDR_BODY;
1121 state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
1122 state->vector[2].iov_len = 9;
1124 smb2_setup_nbt_length(state->vector, 3);
1126 hdr = (uint8_t *)state->vector[1].iov_base;
1127 body = (uint8_t *)state->vector[2].iov_base;
1129 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1130 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1131 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1132 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1133 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1135 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1136 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1137 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1138 SBVAL(hdr, SMB2_HDR_PID, async_id);
1139 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1140 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1141 memcpy(hdr+SMB2_HDR_SIGNATURE,
1142 outhdr+SMB2_HDR_SIGNATURE, 16);
1144 SSVAL(body, 0x00, 0x08 + 1);
1146 SCVAL(body, 0x02, 0);
1147 SCVAL(body, 0x03, 0);
1148 SIVAL(body, 0x04, 0);
1149 /* Match W2K8R2... */
1150 SCVAL(body, 0x08, 0x21);
1152 /* Ensure we correctly go through crediting. Grant
1153 the credits now, and zero credits on the final
1154 response. */
1155 smb2_set_operation_credit(req->sconn,
1156 &req->in.vector[i],
1157 &state->vector[1]);
1159 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1161 if (req->do_signing) {
1162 NTSTATUS status;
1163 struct smbXsrv_session *x = req->session;
1164 struct smbXsrv_connection *conn = x->connection;
1165 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1167 status = smb2_signing_sign_pdu(signing_key,
1168 conn->protocol,
1169 &state->vector[1], 2);
1170 if (!NT_STATUS_IS_OK(status)) {
1171 smbd_server_connection_terminate(req->sconn,
1172 nt_errstr(status));
1173 return;
1177 subreq = tstream_writev_queue_send(state,
1178 state->sconn->ev_ctx,
1179 state->sconn->smb2.stream,
1180 state->sconn->smb2.send_queue,
1181 state->vector,
1183 if (subreq == NULL) {
1184 smbd_server_connection_terminate(state->sconn,
1185 nt_errstr(NT_STATUS_NO_MEMORY));
1186 return;
1188 tevent_req_set_callback(subreq,
1189 smbd_smb2_request_pending_writev_done,
1190 state);
1193 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1195 struct smbd_server_connection *sconn = req->sconn;
1196 struct smbd_smb2_request *cur;
1197 const uint8_t *inhdr;
1198 int i = req->current_idx;
1199 uint32_t flags;
1200 uint64_t search_message_id;
1201 uint64_t search_async_id;
1202 uint64_t found_id;
1204 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1206 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1207 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1208 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1211 * we don't need the request anymore
1212 * cancel requests never have a response
1214 DLIST_REMOVE(req->sconn->smb2.requests, req);
1215 TALLOC_FREE(req);
1217 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1218 const uint8_t *outhdr;
1219 uint64_t message_id;
1220 uint64_t async_id;
1222 i = cur->current_idx;
1224 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
1226 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1227 async_id = BVAL(outhdr, SMB2_HDR_PID);
1229 if (flags & SMB2_HDR_FLAG_ASYNC) {
1230 if (search_async_id == async_id) {
1231 found_id = async_id;
1232 break;
1234 } else {
1235 if (search_message_id == message_id) {
1236 found_id = message_id;
1237 break;
1242 if (cur && cur->subreq) {
1243 inhdr = (const uint8_t *)cur->in.vector[i].iov_base;
1244 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1245 "cancel opcode[%s] mid %llu\n",
1246 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1247 (unsigned long long)found_id ));
1248 tevent_req_cancel(cur->subreq);
1251 return NT_STATUS_OK;
1254 /*************************************************************
1255 Ensure an incoming tid is a valid one for us to access.
1256 Change to the associated uid credentials and chdir to the
1257 valid tid directory.
1258 *************************************************************/
1260 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1262 const uint8_t *inhdr;
1263 int i = req->current_idx;
1264 uint32_t in_flags;
1265 uint32_t in_tid;
1266 struct smbXsrv_tcon0 *tcon;
1267 NTSTATUS status;
1268 NTTIME now = timeval_to_nttime(&req->request_time);
1270 req->tcon = NULL;
1272 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1274 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1275 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1277 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1278 in_tid = req->last_tid;
1281 status = smb2srv_tcon_lookup(req->session,
1282 in_tid, now, &tcon);
1283 if (!NT_STATUS_IS_OK(status)) {
1284 return status;
1287 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1288 return NT_STATUS_ACCESS_DENIED;
1291 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1292 if (!set_current_service(tcon->compat, 0, true)) {
1293 return NT_STATUS_ACCESS_DENIED;
1296 req->tcon = tcon;
1297 req->last_tid = in_tid;
1299 return NT_STATUS_OK;
1302 /*************************************************************
1303 Ensure an incoming session_id is a valid one for us to access.
1304 *************************************************************/
1306 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1308 const uint8_t *inhdr;
1309 int i = req->current_idx;
1310 uint32_t in_flags;
1311 uint16_t in_opcode;
1312 uint64_t in_session_id;
1313 struct smbXsrv_session *session = NULL;
1314 struct auth_session_info *session_info;
1315 NTSTATUS status;
1316 NTTIME now = timeval_to_nttime(&req->request_time);
1318 req->session = NULL;
1319 req->tcon = NULL;
1321 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1323 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1324 in_opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1325 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1327 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1328 in_session_id = req->last_session_id;
1331 /* lookup an existing session */
1332 status = smb2srv_session_lookup(req->sconn->conn,
1333 in_session_id, now,
1334 &session);
1335 if (session) {
1336 req->session = session;
1337 req->last_session_id = in_session_id;
1339 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1340 switch (in_opcode) {
1341 case SMB2_OP_SESSSETUP:
1342 status = NT_STATUS_OK;
1343 break;
1344 default:
1345 break;
1348 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1349 switch (in_opcode) {
1350 case SMB2_OP_TCON:
1351 case SMB2_OP_CREATE:
1352 case SMB2_OP_GETINFO:
1353 case SMB2_OP_SETINFO:
1354 return NT_STATUS_INVALID_HANDLE;
1355 default:
1357 * Notice the check for
1358 * (session_info == NULL)
1359 * below.
1361 status = NT_STATUS_OK;
1362 break;
1365 if (!NT_STATUS_IS_OK(status)) {
1366 return status;
1369 session_info = session->global->auth_session_info;
1370 if (session_info == NULL) {
1371 return NT_STATUS_INVALID_HANDLE;
1374 set_current_user_info(session_info->unix_info->sanitized_username,
1375 session_info->unix_info->unix_name,
1376 session_info->info->domain_name);
1378 return NT_STATUS_OK;
1381 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1382 uint32_t data_length)
1384 uint16_t needed_charge;
1385 uint16_t credit_charge;
1386 const uint8_t *inhdr;
1387 int i = req->current_idx;
1389 if (!req->sconn->smb2.supports_multicredit) {
1390 if (data_length > 65536) {
1391 return NT_STATUS_INVALID_PARAMETER;
1393 return NT_STATUS_OK;
1396 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1397 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1399 /* requests larger than 64 KB need credit charge */
1400 if (credit_charge == 0 && data_length > 65536) {
1401 DEBUG(2, ("Request larger than 64KB w/o creditcharge\n"));
1402 return NT_STATUS_INVALID_PARAMETER;
1405 needed_charge = (data_length - 1)/ 65536 + 1;
1407 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1408 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1409 credit_charge, needed_charge));
1411 if (needed_charge > credit_charge) {
1412 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1413 credit_charge, needed_charge));
1414 return NT_STATUS_INVALID_PARAMETER;
1417 return NT_STATUS_OK;
1420 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1421 size_t expected_body_size)
1423 const uint8_t *inhdr;
1424 uint16_t opcode;
1425 const uint8_t *inbody;
1426 int i = req->current_idx;
1427 size_t body_size;
1428 size_t min_dyn_size = expected_body_size & 0x00000001;
1431 * The following should be checked already.
1433 if ((i+2) > req->in.vector_count) {
1434 return NT_STATUS_INTERNAL_ERROR;
1436 if (req->in.vector[i+0].iov_len != SMB2_HDR_BODY) {
1437 return NT_STATUS_INTERNAL_ERROR;
1439 if (req->in.vector[i+1].iov_len < 2) {
1440 return NT_STATUS_INTERNAL_ERROR;
1443 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1444 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1446 switch (opcode) {
1447 case SMB2_OP_IOCTL:
1448 case SMB2_OP_GETINFO:
1449 min_dyn_size = 0;
1450 break;
1454 * Now check the expected body size,
1455 * where the last byte might be in the
1456 * dynamic section..
1458 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1459 return NT_STATUS_INVALID_PARAMETER;
1461 if (req->in.vector[i+2].iov_len < min_dyn_size) {
1462 return NT_STATUS_INVALID_PARAMETER;
1465 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1467 body_size = SVAL(inbody, 0x00);
1468 if (body_size != expected_body_size) {
1469 return NT_STATUS_INVALID_PARAMETER;
1472 return NT_STATUS_OK;
1475 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1477 const uint8_t *inhdr;
1478 int i = req->current_idx;
1479 uint16_t opcode;
1480 uint32_t flags;
1481 uint64_t mid;
1482 NTSTATUS status;
1483 NTSTATUS session_status;
1484 uint32_t allowed_flags;
1485 NTSTATUS return_value;
1486 struct smbXsrv_session *x = NULL;
1487 bool signing_required = false;
1489 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
1491 /* TODO: verify more things */
1493 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1494 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1495 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1496 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1497 smb2_opcode_name(opcode),
1498 (unsigned long long)mid));
1500 if (get_Protocol() >= PROTOCOL_SMB2_02) {
1502 * once the protocol is negotiated
1503 * SMB2_OP_NEGPROT is not allowed anymore
1505 if (opcode == SMB2_OP_NEGPROT) {
1506 /* drop the connection */
1507 return NT_STATUS_INVALID_PARAMETER;
1509 } else {
1511 * if the protocol is not negotiated yet
1512 * only SMB2_OP_NEGPROT is allowed.
1514 if (opcode != SMB2_OP_NEGPROT) {
1515 /* drop the connection */
1516 return NT_STATUS_INVALID_PARAMETER;
1520 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1521 SMB2_HDR_FLAG_SIGNED |
1522 SMB2_HDR_FLAG_DFS;
1523 if (opcode == SMB2_OP_CANCEL) {
1524 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1526 if ((flags & ~allowed_flags) != 0) {
1527 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1531 * Check if the client provided a valid session id,
1532 * if so smbd_smb2_request_check_session() calls
1533 * set_current_user_info().
1535 * As some command don't require a valid session id
1536 * we defer the check of the session_status
1538 session_status = smbd_smb2_request_check_session(req);
1539 x = req->session;
1541 if (x != NULL) {
1542 signing_required = x->global->signing_required;
1544 if (opcode == SMB2_OP_SESSSETUP &&
1545 x->global->channels[0].signing_key.length) {
1546 signing_required = true;
1550 req->do_signing = false;
1551 if (flags & SMB2_HDR_FLAG_SIGNED) {
1552 struct smbXsrv_connection *conn = x->connection;
1553 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1555 if (!NT_STATUS_IS_OK(session_status)) {
1556 return smbd_smb2_request_error(req, session_status);
1559 req->do_signing = true;
1560 status = smb2_signing_check_pdu(signing_key,
1561 conn->protocol,
1562 &req->in.vector[i], 3);
1563 if (!NT_STATUS_IS_OK(status)) {
1564 return smbd_smb2_request_error(req, status);
1566 } else if (opcode == SMB2_OP_CANCEL) {
1567 /* Cancel requests are allowed to skip the signing */
1568 } else if (signing_required) {
1569 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1572 if (flags & SMB2_HDR_FLAG_CHAINED) {
1574 * This check is mostly for giving the correct error code
1575 * for compounded requests.
1577 * TODO: we may need to move this after the session
1578 * and tcon checks.
1580 if (!NT_STATUS_IS_OK(req->next_status)) {
1581 return smbd_smb2_request_error(req, req->next_status);
1583 } else {
1584 req->compat_chain_fsp = NULL;
1587 if (req->compound_related) {
1588 req->sconn->smb2.compound_related_in_progress = true;
1591 switch (opcode) {
1592 case SMB2_OP_NEGPROT:
1593 /* This call needs to be run as root */
1594 change_to_root_user();
1597 START_PROFILE(smb2_negprot);
1598 return_value = smbd_smb2_request_process_negprot(req);
1599 END_PROFILE(smb2_negprot);
1601 break;
1603 case SMB2_OP_SESSSETUP:
1604 /* This call needs to be run as root */
1605 change_to_root_user();
1608 START_PROFILE(smb2_sesssetup);
1609 return_value = smbd_smb2_request_process_sesssetup(req);
1610 END_PROFILE(smb2_sesssetup);
1612 break;
1614 case SMB2_OP_LOGOFF:
1615 if (!NT_STATUS_IS_OK(session_status)) {
1616 return_value = smbd_smb2_request_error(req, session_status);
1617 break;
1620 /* This call needs to be run as root */
1621 change_to_root_user();
1624 START_PROFILE(smb2_logoff);
1625 return_value = smbd_smb2_request_process_logoff(req);
1626 END_PROFILE(smb2_logoff);
1628 break;
1630 case SMB2_OP_TCON:
1631 if (!NT_STATUS_IS_OK(session_status)) {
1632 return_value = smbd_smb2_request_error(req, session_status);
1633 break;
1637 * This call needs to be run as root.
1639 * smbd_smb2_request_process_tcon()
1640 * calls make_connection_snum(), which will call
1641 * change_to_user(), when needed.
1643 change_to_root_user();
1646 START_PROFILE(smb2_tcon);
1647 return_value = smbd_smb2_request_process_tcon(req);
1648 END_PROFILE(smb2_tcon);
1650 break;
1652 case SMB2_OP_TDIS:
1653 if (!NT_STATUS_IS_OK(session_status)) {
1654 return_value = smbd_smb2_request_error(req, session_status);
1655 break;
1658 * This call needs to be run as user.
1660 * smbd_smb2_request_check_tcon()
1661 * calls change_to_user() on success.
1663 status = smbd_smb2_request_check_tcon(req);
1664 if (!NT_STATUS_IS_OK(status)) {
1665 return_value = smbd_smb2_request_error(req, status);
1666 break;
1668 /* This call needs to be run as root */
1669 change_to_root_user();
1673 START_PROFILE(smb2_tdis);
1674 return_value = smbd_smb2_request_process_tdis(req);
1675 END_PROFILE(smb2_tdis);
1677 break;
1679 case SMB2_OP_CREATE:
1680 if (!NT_STATUS_IS_OK(session_status)) {
1681 return_value = smbd_smb2_request_error(req, session_status);
1682 break;
1685 * This call needs to be run as user.
1687 * smbd_smb2_request_check_tcon()
1688 * calls change_to_user() on success.
1690 status = smbd_smb2_request_check_tcon(req);
1691 if (!NT_STATUS_IS_OK(status)) {
1692 return_value = smbd_smb2_request_error(req, status);
1693 break;
1697 START_PROFILE(smb2_create);
1698 return_value = smbd_smb2_request_process_create(req);
1699 END_PROFILE(smb2_create);
1701 break;
1703 case SMB2_OP_CLOSE:
1704 if (!NT_STATUS_IS_OK(session_status)) {
1705 return_value = smbd_smb2_request_error(req, session_status);
1706 break;
1709 * This call needs to be run as user.
1711 * smbd_smb2_request_check_tcon()
1712 * calls change_to_user() on success.
1714 status = smbd_smb2_request_check_tcon(req);
1715 if (!NT_STATUS_IS_OK(status)) {
1716 return_value = smbd_smb2_request_error(req, status);
1717 break;
1721 START_PROFILE(smb2_close);
1722 return_value = smbd_smb2_request_process_close(req);
1723 END_PROFILE(smb2_close);
1725 break;
1727 case SMB2_OP_FLUSH:
1728 if (!NT_STATUS_IS_OK(session_status)) {
1729 return_value = smbd_smb2_request_error(req, session_status);
1730 break;
1733 * This call needs to be run as user.
1735 * smbd_smb2_request_check_tcon()
1736 * calls change_to_user() on success.
1738 status = smbd_smb2_request_check_tcon(req);
1739 if (!NT_STATUS_IS_OK(status)) {
1740 return_value = smbd_smb2_request_error(req, status);
1741 break;
1745 START_PROFILE(smb2_flush);
1746 return_value = smbd_smb2_request_process_flush(req);
1747 END_PROFILE(smb2_flush);
1749 break;
1751 case SMB2_OP_READ:
1752 if (!NT_STATUS_IS_OK(session_status)) {
1753 return_value = smbd_smb2_request_error(req, session_status);
1754 break;
1757 * This call needs to be run as user.
1759 * smbd_smb2_request_check_tcon()
1760 * calls change_to_user() on success.
1762 status = smbd_smb2_request_check_tcon(req);
1763 if (!NT_STATUS_IS_OK(status)) {
1764 return_value = smbd_smb2_request_error(req, status);
1765 break;
1769 START_PROFILE(smb2_read);
1770 return_value = smbd_smb2_request_process_read(req);
1771 END_PROFILE(smb2_read);
1773 break;
1775 case SMB2_OP_WRITE:
1776 if (!NT_STATUS_IS_OK(session_status)) {
1777 return_value = smbd_smb2_request_error(req, session_status);
1778 break;
1781 * This call needs to be run as user.
1783 * smbd_smb2_request_check_tcon()
1784 * calls change_to_user() on success.
1786 status = smbd_smb2_request_check_tcon(req);
1787 if (!NT_STATUS_IS_OK(status)) {
1788 return_value = smbd_smb2_request_error(req, status);
1789 break;
1793 START_PROFILE(smb2_write);
1794 return_value = smbd_smb2_request_process_write(req);
1795 END_PROFILE(smb2_write);
1797 break;
1799 case SMB2_OP_LOCK:
1800 if (!NT_STATUS_IS_OK(session_status)) {
1801 /* Too ugly to live ? JRA. */
1802 if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
1803 session_status = NT_STATUS_FILE_CLOSED;
1805 return_value = smbd_smb2_request_error(req, session_status);
1806 break;
1809 * This call needs to be run as user.
1811 * smbd_smb2_request_check_tcon()
1812 * calls change_to_user() on success.
1814 status = smbd_smb2_request_check_tcon(req);
1815 if (!NT_STATUS_IS_OK(status)) {
1816 /* Too ugly to live ? JRA. */
1817 if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
1818 status = NT_STATUS_FILE_CLOSED;
1820 return_value = smbd_smb2_request_error(req, status);
1821 break;
1825 START_PROFILE(smb2_lock);
1826 return_value = smbd_smb2_request_process_lock(req);
1827 END_PROFILE(smb2_lock);
1829 break;
1831 case SMB2_OP_IOCTL:
1832 if (!NT_STATUS_IS_OK(session_status)) {
1833 return_value = smbd_smb2_request_error(req, session_status);
1834 break;
1837 * This call needs to be run as user.
1839 * smbd_smb2_request_check_tcon()
1840 * calls change_to_user() on success.
1842 status = smbd_smb2_request_check_tcon(req);
1843 if (!NT_STATUS_IS_OK(status)) {
1844 return_value = smbd_smb2_request_error(req, status);
1845 break;
1849 START_PROFILE(smb2_ioctl);
1850 return_value = smbd_smb2_request_process_ioctl(req);
1851 END_PROFILE(smb2_ioctl);
1853 break;
1855 case SMB2_OP_CANCEL:
1857 * This call needs to be run as root
1859 * That is what we also do in the SMB1 case.
1861 change_to_root_user();
1864 START_PROFILE(smb2_cancel);
1865 return_value = smbd_smb2_request_process_cancel(req);
1866 END_PROFILE(smb2_cancel);
1868 break;
1870 case SMB2_OP_KEEPALIVE:
1871 /* This call needs to be run as root */
1872 change_to_root_user();
1875 START_PROFILE(smb2_keepalive);
1876 return_value = smbd_smb2_request_process_keepalive(req);
1877 END_PROFILE(smb2_keepalive);
1879 break;
1881 case SMB2_OP_FIND:
1882 if (!NT_STATUS_IS_OK(session_status)) {
1883 return_value = smbd_smb2_request_error(req, session_status);
1884 break;
1887 * This call needs to be run as user.
1889 * smbd_smb2_request_check_tcon()
1890 * calls change_to_user() on success.
1892 status = smbd_smb2_request_check_tcon(req);
1893 if (!NT_STATUS_IS_OK(status)) {
1894 return_value = smbd_smb2_request_error(req, status);
1895 break;
1899 START_PROFILE(smb2_find);
1900 return_value = smbd_smb2_request_process_find(req);
1901 END_PROFILE(smb2_find);
1903 break;
1905 case SMB2_OP_NOTIFY:
1906 if (!NT_STATUS_IS_OK(session_status)) {
1907 return_value = smbd_smb2_request_error(req, session_status);
1908 break;
1911 * This call needs to be run as user.
1913 * smbd_smb2_request_check_tcon()
1914 * calls change_to_user() on success.
1916 status = smbd_smb2_request_check_tcon(req);
1917 if (!NT_STATUS_IS_OK(status)) {
1918 return_value = smbd_smb2_request_error(req, status);
1919 break;
1923 START_PROFILE(smb2_notify);
1924 return_value = smbd_smb2_request_process_notify(req);
1925 END_PROFILE(smb2_notify);
1927 break;
1929 case SMB2_OP_GETINFO:
1930 if (!NT_STATUS_IS_OK(session_status)) {
1931 return_value = smbd_smb2_request_error(req, session_status);
1932 break;
1935 * This call needs to be run as user.
1937 * smbd_smb2_request_check_tcon()
1938 * calls change_to_user() on success.
1940 status = smbd_smb2_request_check_tcon(req);
1941 if (!NT_STATUS_IS_OK(status)) {
1942 return_value = smbd_smb2_request_error(req, status);
1943 break;
1947 START_PROFILE(smb2_getinfo);
1948 return_value = smbd_smb2_request_process_getinfo(req);
1949 END_PROFILE(smb2_getinfo);
1951 break;
1953 case SMB2_OP_SETINFO:
1954 if (!NT_STATUS_IS_OK(session_status)) {
1955 return_value = smbd_smb2_request_error(req, session_status);
1956 break;
1959 * This call needs to be run as user.
1961 * smbd_smb2_request_check_tcon()
1962 * calls change_to_user() on success.
1964 status = smbd_smb2_request_check_tcon(req);
1965 if (!NT_STATUS_IS_OK(status)) {
1966 return_value = smbd_smb2_request_error(req, status);
1967 break;
1971 START_PROFILE(smb2_setinfo);
1972 return_value = smbd_smb2_request_process_setinfo(req);
1973 END_PROFILE(smb2_setinfo);
1975 break;
1977 case SMB2_OP_BREAK:
1978 if (!NT_STATUS_IS_OK(session_status)) {
1979 return_value = smbd_smb2_request_error(req, session_status);
1980 break;
1983 * This call needs to be run as user.
1985 * smbd_smb2_request_check_tcon()
1986 * calls change_to_user() on success.
1988 status = smbd_smb2_request_check_tcon(req);
1989 if (!NT_STATUS_IS_OK(status)) {
1990 return_value = smbd_smb2_request_error(req, status);
1991 break;
1995 START_PROFILE(smb2_break);
1996 return_value = smbd_smb2_request_process_break(req);
1997 END_PROFILE(smb2_break);
1999 break;
2001 default:
2002 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2003 break;
2005 return return_value;
2008 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2010 struct tevent_req *subreq;
2011 int i = req->current_idx;
2013 req->subreq = NULL;
2014 TALLOC_FREE(req->async_te);
2016 req->current_idx += 3;
2018 if (req->current_idx < req->out.vector_count) {
2020 * We must process the remaining compound
2021 * SMB2 requests before any new incoming SMB2
2022 * requests. This is because incoming SMB2
2023 * requests may include a cancel for a
2024 * compound request we haven't processed
2025 * yet.
2027 struct tevent_immediate *im = tevent_create_immediate(req);
2028 if (!im) {
2029 return NT_STATUS_NO_MEMORY;
2031 tevent_schedule_immediate(im,
2032 req->sconn->ev_ctx,
2033 smbd_smb2_request_dispatch_immediate,
2034 req);
2035 return NT_STATUS_OK;
2038 if (req->compound_related) {
2039 req->sconn->smb2.compound_related_in_progress = false;
2042 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2044 /* Set credit for these operations (zero credits if this
2045 is a final reply for an async operation). */
2046 smb2_calculate_credits(req, req);
2048 if (req->do_signing) {
2049 NTSTATUS status;
2050 struct smbXsrv_session *x = req->session;
2051 struct smbXsrv_connection *conn = x->connection;
2052 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2054 status = smb2_signing_sign_pdu(signing_key,
2055 conn->protocol,
2056 &req->out.vector[i], 3);
2057 if (!NT_STATUS_IS_OK(status)) {
2058 return status;
2062 if (DEBUGLEVEL >= 10) {
2063 dbgtext("smbd_smb2_request_reply: sending...\n");
2064 print_req_vectors(req);
2067 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2068 if (req->out.vector_count == 4 &&
2069 req->out.vector[3].iov_base == NULL &&
2070 req->out.vector[3].iov_len != 0) {
2071 /* Dynamic part is NULL. Chop it off,
2072 We're going to send it via sendfile. */
2073 req->out.vector_count -= 1;
2076 subreq = tstream_writev_queue_send(req,
2077 req->sconn->ev_ctx,
2078 req->sconn->smb2.stream,
2079 req->sconn->smb2.send_queue,
2080 req->out.vector,
2081 req->out.vector_count);
2082 if (subreq == NULL) {
2083 return NT_STATUS_NO_MEMORY;
2085 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
2087 * We're done with this request -
2088 * move it off the "being processed" queue.
2090 DLIST_REMOVE(req->sconn->smb2.requests, req);
2092 return NT_STATUS_OK;
2095 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2097 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2098 struct tevent_immediate *im,
2099 void *private_data)
2101 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2102 struct smbd_smb2_request);
2103 struct smbd_server_connection *sconn = req->sconn;
2104 NTSTATUS status;
2106 TALLOC_FREE(im);
2108 if (DEBUGLEVEL >= 10) {
2109 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2110 req->current_idx, req->in.vector_count));
2111 print_req_vectors(req);
2114 status = smbd_smb2_request_dispatch(req);
2115 if (!NT_STATUS_IS_OK(status)) {
2116 smbd_server_connection_terminate(sconn, nt_errstr(status));
2117 return;
2120 status = smbd_smb2_request_next_incoming(sconn);
2121 if (!NT_STATUS_IS_OK(status)) {
2122 smbd_server_connection_terminate(sconn, nt_errstr(status));
2123 return;
2127 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
2129 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
2130 struct smbd_smb2_request);
2131 struct smbd_server_connection *sconn = req->sconn;
2132 int ret;
2133 int sys_errno;
2134 NTSTATUS status;
2136 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2137 TALLOC_FREE(subreq);
2138 TALLOC_FREE(req);
2139 if (ret == -1) {
2140 status = map_nt_error_from_unix(sys_errno);
2141 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
2142 nt_errstr(status)));
2143 smbd_server_connection_terminate(sconn, nt_errstr(status));
2144 return;
2147 status = smbd_smb2_request_next_incoming(sconn);
2148 if (!NT_STATUS_IS_OK(status)) {
2149 smbd_server_connection_terminate(sconn, nt_errstr(status));
2150 return;
2154 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2155 NTSTATUS status,
2156 DATA_BLOB body, DATA_BLOB *dyn,
2157 const char *location)
2159 uint8_t *outhdr;
2160 int i = req->current_idx;
2161 uint32_t next_command_ofs;
2163 DEBUG(10,("smbd_smb2_request_done_ex: "
2164 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2165 i, nt_errstr(status), (unsigned int)body.length,
2166 dyn ? "yes": "no",
2167 (unsigned int)(dyn ? dyn->length : 0),
2168 location));
2170 if (body.length < 2) {
2171 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2174 if ((body.length % 2) != 0) {
2175 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2178 outhdr = (uint8_t *)req->out.vector[i].iov_base;
2180 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2181 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2183 req->out.vector[i+1].iov_base = (void *)body.data;
2184 req->out.vector[i+1].iov_len = body.length;
2186 if (dyn) {
2187 req->out.vector[i+2].iov_base = (void *)dyn->data;
2188 req->out.vector[i+2].iov_len = dyn->length;
2189 } else {
2190 req->out.vector[i+2].iov_base = NULL;
2191 req->out.vector[i+2].iov_len = 0;
2194 /* see if we need to recalculate the offset to the next response */
2195 if (next_command_ofs > 0) {
2196 next_command_ofs = SMB2_HDR_BODY;
2197 next_command_ofs += req->out.vector[i+1].iov_len;
2198 next_command_ofs += req->out.vector[i+2].iov_len;
2201 if ((next_command_ofs % 8) != 0) {
2202 size_t pad_size = 8 - (next_command_ofs % 8);
2203 if (req->out.vector[i+2].iov_len == 0) {
2205 * if the dyn buffer is empty
2206 * we can use it to add padding
2208 uint8_t *pad;
2210 pad = talloc_zero_array(req->out.vector,
2211 uint8_t, pad_size);
2212 if (pad == NULL) {
2213 return smbd_smb2_request_error(req,
2214 NT_STATUS_NO_MEMORY);
2217 req->out.vector[i+2].iov_base = (void *)pad;
2218 req->out.vector[i+2].iov_len = pad_size;
2219 } else {
2221 * For now we copy the dynamic buffer
2222 * and add the padding to the new buffer
2224 size_t old_size;
2225 uint8_t *old_dyn;
2226 size_t new_size;
2227 uint8_t *new_dyn;
2229 old_size = req->out.vector[i+2].iov_len;
2230 old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
2232 new_size = old_size + pad_size;
2233 new_dyn = talloc_zero_array(req->out.vector,
2234 uint8_t, new_size);
2235 if (new_dyn == NULL) {
2236 return smbd_smb2_request_error(req,
2237 NT_STATUS_NO_MEMORY);
2240 memcpy(new_dyn, old_dyn, old_size);
2241 memset(new_dyn + old_size, 0, pad_size);
2243 req->out.vector[i+2].iov_base = (void *)new_dyn;
2244 req->out.vector[i+2].iov_len = new_size;
2246 next_command_ofs += pad_size;
2249 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2251 return smbd_smb2_request_reply(req);
2254 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2255 NTSTATUS status,
2256 DATA_BLOB *info,
2257 const char *location)
2259 DATA_BLOB body;
2260 int i = req->current_idx;
2261 uint8_t *outhdr = (uint8_t *)req->out.vector[i].iov_base;
2263 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2264 i, nt_errstr(status), info ? " +info" : "",
2265 location));
2267 body.data = outhdr + SMB2_HDR_BODY;
2268 body.length = 8;
2269 SSVAL(body.data, 0, 9);
2271 if (info) {
2272 SIVAL(body.data, 0x04, info->length);
2273 } else {
2274 /* Allocated size of req->out.vector[i].iov_base
2275 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2276 * 1 byte without having to do an alloc.
2278 info = talloc_zero_array(req->out.vector,
2279 DATA_BLOB,
2281 if (!info) {
2282 return NT_STATUS_NO_MEMORY;
2284 info->data = ((uint8_t *)outhdr) +
2285 OUTVEC_ALLOC_SIZE - 1;
2286 info->length = 1;
2287 SCVAL(info->data, 0, 0);
2291 * if a request fails, all other remaining
2292 * compounded requests should fail too
2294 req->next_status = NT_STATUS_INVALID_PARAMETER;
2296 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2300 struct smbd_smb2_send_oplock_break_state {
2301 struct smbd_server_connection *sconn;
2302 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
2303 struct iovec vector;
2306 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2308 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2309 uint64_t file_id_persistent,
2310 uint64_t file_id_volatile,
2311 uint8_t oplock_level)
2313 struct smbd_smb2_send_oplock_break_state *state;
2314 struct tevent_req *subreq;
2315 uint8_t *hdr;
2316 uint8_t *body;
2318 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2319 if (state == NULL) {
2320 return NT_STATUS_NO_MEMORY;
2322 state->sconn = sconn;
2324 state->vector.iov_base = (void *)state->buf;
2325 state->vector.iov_len = sizeof(state->buf);
2327 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
2328 hdr = state->buf + 4;
2329 body = hdr + SMB2_HDR_BODY;
2331 SIVAL(hdr, 0, SMB2_MAGIC);
2332 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2333 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2334 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2335 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2336 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2337 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2338 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2339 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2340 SIVAL(hdr, SMB2_HDR_PID, 0);
2341 SIVAL(hdr, SMB2_HDR_TID, 0);
2342 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2343 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2345 SSVAL(body, 0x00, 0x18);
2347 SCVAL(body, 0x02, oplock_level);
2348 SCVAL(body, 0x03, 0); /* reserved */
2349 SIVAL(body, 0x04, 0); /* reserved */
2350 SBVAL(body, 0x08, file_id_persistent);
2351 SBVAL(body, 0x10, file_id_volatile);
2353 subreq = tstream_writev_queue_send(state,
2354 sconn->ev_ctx,
2355 sconn->smb2.stream,
2356 sconn->smb2.send_queue,
2357 &state->vector, 1);
2358 if (subreq == NULL) {
2359 return NT_STATUS_NO_MEMORY;
2361 tevent_req_set_callback(subreq,
2362 smbd_smb2_oplock_break_writev_done,
2363 state);
2365 return NT_STATUS_OK;
2368 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2370 struct smbd_smb2_send_oplock_break_state *state =
2371 tevent_req_callback_data(subreq,
2372 struct smbd_smb2_send_oplock_break_state);
2373 struct smbd_server_connection *sconn = state->sconn;
2374 int ret;
2375 int sys_errno;
2377 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2378 TALLOC_FREE(subreq);
2379 if (ret == -1) {
2380 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2381 smbd_server_connection_terminate(sconn, nt_errstr(status));
2382 return;
2385 TALLOC_FREE(state);
2388 struct smbd_smb2_request_read_state {
2389 size_t missing;
2390 bool asked_for_header;
2391 struct smbd_smb2_request *smb2_req;
2394 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2395 void *private_data,
2396 TALLOC_CTX *mem_ctx,
2397 struct iovec **_vector,
2398 size_t *_count);
2399 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2401 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2402 struct tevent_context *ev,
2403 struct smbd_server_connection *sconn)
2405 struct tevent_req *req;
2406 struct smbd_smb2_request_read_state *state;
2407 struct tevent_req *subreq;
2409 req = tevent_req_create(mem_ctx, &state,
2410 struct smbd_smb2_request_read_state);
2411 if (req == NULL) {
2412 return NULL;
2414 state->missing = 0;
2415 state->asked_for_header = false;
2417 state->smb2_req = smbd_smb2_request_allocate(state);
2418 if (tevent_req_nomem(state->smb2_req, req)) {
2419 return tevent_req_post(req, ev);
2421 state->smb2_req->sconn = sconn;
2423 subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
2424 sconn->smb2.recv_queue,
2425 smbd_smb2_request_next_vector,
2426 state);
2427 if (tevent_req_nomem(subreq, req)) {
2428 return tevent_req_post(req, ev);
2430 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2432 return req;
2435 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2436 void *private_data,
2437 TALLOC_CTX *mem_ctx,
2438 struct iovec **_vector,
2439 size_t *_count)
2441 struct smbd_smb2_request_read_state *state =
2442 talloc_get_type_abort(private_data,
2443 struct smbd_smb2_request_read_state);
2444 struct smbd_smb2_request *req = state->smb2_req;
2445 struct iovec *vector;
2446 int idx = req->in.vector_count;
2447 size_t len = 0;
2448 uint8_t *buf = NULL;
2450 if (req->in.vector_count == 0) {
2452 * first we need to get the NBT header
2454 req->in.vector = talloc_array(req, struct iovec,
2455 req->in.vector_count + 1);
2456 if (req->in.vector == NULL) {
2457 return -1;
2459 req->in.vector_count += 1;
2461 req->in.vector[idx].iov_base = (void *)req->in.nbt_hdr;
2462 req->in.vector[idx].iov_len = 4;
2464 vector = talloc_array(mem_ctx, struct iovec, 1);
2465 if (vector == NULL) {
2466 return -1;
2469 vector[0] = req->in.vector[idx];
2471 *_vector = vector;
2472 *_count = 1;
2473 return 0;
2476 if (req->in.vector_count == 1) {
2478 * Now we analyze the NBT header
2480 state->missing = smb2_len(req->in.vector[0].iov_base);
2482 if (state->missing == 0) {
2483 /* if there're no remaining bytes, we're done */
2484 *_vector = NULL;
2485 *_count = 0;
2486 return 0;
2489 req->in.vector = talloc_realloc(req, req->in.vector,
2490 struct iovec,
2491 req->in.vector_count + 1);
2492 if (req->in.vector == NULL) {
2493 return -1;
2495 req->in.vector_count += 1;
2497 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
2499 * it's a special NBT message,
2500 * so get all remaining bytes
2502 len = state->missing;
2503 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
2505 * it's an invalid message, just read what we can get
2506 * and let the caller handle the error
2508 len = state->missing;
2509 } else {
2511 * We assume it's a SMB2 request,
2512 * and we first get the header and the
2513 * first 2 bytes (the struct size) of the body
2515 len = SMB2_HDR_BODY + 2;
2517 state->asked_for_header = true;
2520 state->missing -= len;
2522 buf = talloc_array(req->in.vector, uint8_t, len);
2523 if (buf == NULL) {
2524 return -1;
2527 req->in.vector[idx].iov_base = (void *)buf;
2528 req->in.vector[idx].iov_len = len;
2530 vector = talloc_array(mem_ctx, struct iovec, 1);
2531 if (vector == NULL) {
2532 return -1;
2535 vector[0] = req->in.vector[idx];
2537 *_vector = vector;
2538 *_count = 1;
2539 return 0;
2542 if (state->missing == 0) {
2543 /* if there're no remaining bytes, we're done */
2544 *_vector = NULL;
2545 *_count = 0;
2546 return 0;
2549 if (state->asked_for_header) {
2550 const uint8_t *hdr;
2551 size_t full_size;
2552 size_t next_command_ofs;
2553 size_t body_size;
2554 uint8_t *body;
2555 size_t dyn_size;
2556 uint8_t *dyn;
2557 bool invalid = false;
2559 state->asked_for_header = false;
2562 * We got the SMB2 header and the first 2 bytes
2563 * of the body. We fix the size to just the header
2564 * and manually copy the 2 first bytes to the body section
2566 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
2567 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
2569 /* allocate vectors for body and dynamic areas */
2570 req->in.vector = talloc_realloc(req, req->in.vector,
2571 struct iovec,
2572 req->in.vector_count + 2);
2573 if (req->in.vector == NULL) {
2574 return -1;
2576 req->in.vector_count += 2;
2578 full_size = state->missing + SMB2_HDR_BODY + 2;
2579 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
2580 body_size = SVAL(hdr, SMB2_HDR_BODY);
2582 if (next_command_ofs != 0) {
2583 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
2585 * this is invalid, just return a zero
2586 * body and let the caller deal with the error
2588 invalid = true;
2589 } else if (next_command_ofs > full_size) {
2591 * this is invalid, just return a zero
2592 * body and let the caller deal with the error
2594 invalid = true;
2595 } else {
2596 full_size = next_command_ofs;
2600 if (!invalid) {
2601 if (body_size < 2) {
2603 * this is invalid, just return a zero
2604 * body and let the caller deal with the error
2606 invalid = true;
2610 * Mask out the lowest bit, the "dynamic" part
2611 * of body_size.
2613 body_size &= ~1;
2615 if (body_size > (full_size - SMB2_HDR_BODY)) {
2617 * this is invalid, just return a zero
2618 * body and let the caller deal with the error
2620 invalid = true;
2624 if (invalid) {
2625 /* the caller should check this */
2626 body_size = 2;
2629 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
2631 state->missing -= (body_size - 2) + dyn_size;
2633 body = talloc_array(req->in.vector, uint8_t, body_size);
2634 if (body == NULL) {
2635 return -1;
2638 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
2639 if (dyn == NULL) {
2640 return -1;
2643 req->in.vector[idx].iov_base = (void *)body;
2644 req->in.vector[idx].iov_len = body_size;
2645 req->in.vector[idx+1].iov_base = (void *)dyn;
2646 req->in.vector[idx+1].iov_len = dyn_size;
2648 vector = talloc_array(mem_ctx, struct iovec, 2);
2649 if (vector == NULL) {
2650 return -1;
2654 * the first 2 bytes of the body were already fetched
2655 * together with the header
2657 memcpy(body, hdr + SMB2_HDR_BODY, 2);
2658 vector[0].iov_base = body + 2;
2659 vector[0].iov_len = body_size - 2;
2661 vector[1] = req->in.vector[idx+1];
2663 *_vector = vector;
2664 *_count = 2;
2665 return 0;
2669 * when we endup here, we're looking for a new SMB2 request
2670 * next. And we ask for its header and the first 2 bytes of
2671 * the body (like we did for the first SMB2 request).
2674 req->in.vector = talloc_realloc(req, req->in.vector,
2675 struct iovec,
2676 req->in.vector_count + 1);
2677 if (req->in.vector == NULL) {
2678 return -1;
2680 req->in.vector_count += 1;
2683 * We assume it's a SMB2 request,
2684 * and we first get the header and the
2685 * first 2 bytes (the struct size) of the body
2687 len = SMB2_HDR_BODY + 2;
2689 if (len > state->missing) {
2690 /* let the caller handle the error */
2691 len = state->missing;
2694 state->missing -= len;
2695 state->asked_for_header = true;
2697 buf = talloc_array(req->in.vector, uint8_t, len);
2698 if (buf == NULL) {
2699 return -1;
2702 req->in.vector[idx].iov_base = (void *)buf;
2703 req->in.vector[idx].iov_len = len;
2705 vector = talloc_array(mem_ctx, struct iovec, 1);
2706 if (vector == NULL) {
2707 return -1;
2710 vector[0] = req->in.vector[idx];
2712 *_vector = vector;
2713 *_count = 1;
2714 return 0;
2717 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2719 struct tevent_req *req =
2720 tevent_req_callback_data(subreq,
2721 struct tevent_req);
2722 int ret;
2723 int sys_errno;
2724 NTSTATUS status;
2726 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2727 if (ret == -1) {
2728 status = map_nt_error_from_unix(sys_errno);
2729 tevent_req_nterror(req, status);
2730 return;
2733 tevent_req_done(req);
2736 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2737 TALLOC_CTX *mem_ctx,
2738 struct smbd_smb2_request **_smb2_req)
2740 struct smbd_smb2_request_read_state *state =
2741 tevent_req_data(req,
2742 struct smbd_smb2_request_read_state);
2743 NTSTATUS status;
2745 if (tevent_req_is_nterror(req, &status)) {
2746 tevent_req_received(req);
2747 return status;
2750 talloc_steal(mem_ctx, state->smb2_req->mem_pool);
2751 *_smb2_req = state->smb2_req;
2752 tevent_req_received(req);
2753 return NT_STATUS_OK;
2756 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2758 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2760 size_t max_send_queue_len;
2761 size_t cur_send_queue_len;
2762 struct tevent_req *subreq;
2764 if (sconn->smb2.compound_related_in_progress) {
2766 * Can't read another until the related
2767 * compound is done.
2769 return NT_STATUS_OK;
2772 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
2774 * if there is already a smbd_smb2_request_read
2775 * pending, we are done.
2777 return NT_STATUS_OK;
2780 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2781 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
2783 if (cur_send_queue_len > max_send_queue_len) {
2785 * if we have a lot of requests to send,
2786 * we wait until they are on the wire until we
2787 * ask for the next request.
2789 return NT_STATUS_OK;
2792 /* ask for the next request */
2793 subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn);
2794 if (subreq == NULL) {
2795 return NT_STATUS_NO_MEMORY;
2797 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2799 return NT_STATUS_OK;
2802 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2803 const uint8_t *inbuf, size_t size)
2805 NTSTATUS status;
2806 struct smbd_smb2_request *req = NULL;
2808 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2809 (unsigned int)size));
2811 status = smbd_initialize_smb2(sconn);
2812 if (!NT_STATUS_IS_OK(status)) {
2813 smbd_server_connection_terminate(sconn, nt_errstr(status));
2814 return;
2817 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2818 if (!NT_STATUS_IS_OK(status)) {
2819 smbd_server_connection_terminate(sconn, nt_errstr(status));
2820 return;
2823 status = smbd_smb2_request_validate(req);
2824 if (!NT_STATUS_IS_OK(status)) {
2825 smbd_server_connection_terminate(sconn, nt_errstr(status));
2826 return;
2829 status = smbd_smb2_request_setup_out(req);
2830 if (!NT_STATUS_IS_OK(status)) {
2831 smbd_server_connection_terminate(sconn, nt_errstr(status));
2832 return;
2835 status = smbd_smb2_request_dispatch(req);
2836 if (!NT_STATUS_IS_OK(status)) {
2837 smbd_server_connection_terminate(sconn, nt_errstr(status));
2838 return;
2841 status = smbd_smb2_request_next_incoming(sconn);
2842 if (!NT_STATUS_IS_OK(status)) {
2843 smbd_server_connection_terminate(sconn, nt_errstr(status));
2844 return;
2847 sconn->num_requests++;
2850 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2852 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2853 struct smbd_server_connection);
2854 NTSTATUS status;
2855 struct smbd_smb2_request *req = NULL;
2857 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2858 TALLOC_FREE(subreq);
2859 if (!NT_STATUS_IS_OK(status)) {
2860 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2861 nt_errstr(status)));
2862 smbd_server_connection_terminate(sconn, nt_errstr(status));
2863 return;
2866 if (req->in.nbt_hdr[0] != 0x00) {
2867 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
2868 req->in.nbt_hdr[0]));
2869 TALLOC_FREE(req);
2870 goto next;
2873 req->current_idx = 1;
2875 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2876 req->current_idx, req->in.vector_count));
2878 status = smbd_smb2_request_validate(req);
2879 if (!NT_STATUS_IS_OK(status)) {
2880 smbd_server_connection_terminate(sconn, nt_errstr(status));
2881 return;
2884 status = smbd_smb2_request_setup_out(req);
2885 if (!NT_STATUS_IS_OK(status)) {
2886 smbd_server_connection_terminate(sconn, nt_errstr(status));
2887 return;
2890 status = smbd_smb2_request_dispatch(req);
2891 if (!NT_STATUS_IS_OK(status)) {
2892 smbd_server_connection_terminate(sconn, nt_errstr(status));
2893 return;
2896 next:
2897 status = smbd_smb2_request_next_incoming(sconn);
2898 if (!NT_STATUS_IS_OK(status)) {
2899 smbd_server_connection_terminate(sconn, nt_errstr(status));
2900 return;
2903 sconn->num_requests++;
2905 /* The timeout_processing function isn't run nearly
2906 often enough to implement 'max log size' without
2907 overrunning the size of the file by many megabytes.
2908 This is especially true if we are running at debug
2909 level 10. Checking every 50 SMB2s is a nice
2910 tradeoff of performance vs log file size overrun. */
2912 if ((sconn->num_requests % 50) == 0 &&
2913 need_to_check_log_size()) {
2914 change_to_root_user();
2915 check_log_size();