s3:smb2_server: add and use smbd_smb2_call()
[Samba.git] / source3 / smbd / smb2_server.c
blob4ee0e2f0b572dfc1a42f2ff3dca0acdbdb27d6e9
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 struct smbd_smb2_dispatch_table {
36 uint16_t opcode;
37 const char *name;
38 bool need_session;
39 bool need_tcon;
40 bool as_root;
41 } smbd_smb2_table[] = {
42 #define _OP(o) .opcode = o, .name = #o
44 _OP(SMB2_OP_NEGPROT),
45 .as_root = true,
46 },{
47 _OP(SMB2_OP_SESSSETUP),
48 .as_root = true,
49 },{
50 _OP(SMB2_OP_LOGOFF),
51 .need_session = true,
52 .as_root = true,
53 },{
54 _OP(SMB2_OP_TCON),
55 .need_session = true,
57 * This call needs to be run as root.
59 * smbd_smb2_request_process_tcon()
60 * calls make_connection_snum(), which will call
61 * change_to_user(), when needed.
63 .as_root = true,
64 },{
65 _OP(SMB2_OP_TDIS),
66 .need_session = true,
67 .need_tcon = true,
68 .as_root = true,
69 },{
70 _OP(SMB2_OP_CREATE),
71 .need_session = true,
72 .need_tcon = true,
73 },{
74 _OP(SMB2_OP_CLOSE),
75 .need_session = true,
76 .need_tcon = true,
77 },{
78 _OP(SMB2_OP_FLUSH),
79 .need_session = true,
80 .need_tcon = true,
81 },{
82 _OP(SMB2_OP_READ),
83 .need_session = true,
84 .need_tcon = true,
85 },{
86 _OP(SMB2_OP_WRITE),
87 .need_session = true,
88 .need_tcon = true,
89 },{
90 _OP(SMB2_OP_LOCK),
91 .need_session = true,
92 .need_tcon = true,
93 },{
94 _OP(SMB2_OP_IOCTL),
95 .need_session = true,
96 .need_tcon = true,
97 },{
98 _OP(SMB2_OP_CANCEL),
99 .as_root = true,
101 _OP(SMB2_OP_KEEPALIVE),
102 .as_root = true,
104 _OP(SMB2_OP_FIND),
105 .need_session = true,
106 .need_tcon = true,
108 _OP(SMB2_OP_NOTIFY),
109 .need_session = true,
110 .need_tcon = true,
112 _OP(SMB2_OP_GETINFO),
113 .need_session = true,
114 .need_tcon = true,
116 _OP(SMB2_OP_SETINFO),
117 .need_session = true,
118 .need_tcon = true,
120 _OP(SMB2_OP_BREAK),
121 .need_session = true,
122 .need_tcon = true,
126 const char *smb2_opcode_name(uint16_t opcode)
128 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
129 return "Bad SMB2 opcode";
131 return smbd_smb2_table[opcode].name;
134 static const struct smbd_smb2_dispatch_table *smbd_smb2_call(uint16_t opcode)
136 const struct smbd_smb2_dispatch_table *ret = NULL;
138 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
139 return NULL;
142 ret = &smbd_smb2_table[opcode];
144 SMB_ASSERT(ret->opcode == opcode);
146 return ret;
149 static void print_req_vectors(struct smbd_smb2_request *req)
151 int i;
153 for (i = 0; i < req->in.vector_count; i++) {
154 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
155 (unsigned int)i,
156 (unsigned int)req->in.vector[i].iov_len);
158 for (i = 0; i < req->out.vector_count; i++) {
159 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
160 (unsigned int)i,
161 (unsigned int)req->out.vector[i].iov_len);
165 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
167 if (size < (4 + SMB2_HDR_BODY)) {
168 return false;
171 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
172 return false;
175 return true;
178 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
180 NTSTATUS status;
181 int ret;
183 TALLOC_FREE(sconn->smb1.fde);
185 sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
186 if (sconn->smb2.recv_queue == NULL) {
187 return NT_STATUS_NO_MEMORY;
190 sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
191 if (sconn->smb2.send_queue == NULL) {
192 return NT_STATUS_NO_MEMORY;
195 sconn->smb2.seqnum_low = 0;
196 sconn->smb2.seqnum_range = 1;
197 sconn->smb2.credits_granted = 1;
198 sconn->smb2.max_credits = lp_smb2_max_credits();
199 sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
200 sconn->smb2.max_credits);
201 if (sconn->smb2.credits_bitmap == NULL) {
202 return NT_STATUS_NO_MEMORY;
205 ret = tstream_bsd_existing_socket(sconn, sconn->sock,
206 &sconn->smb2.stream);
207 if (ret == -1) {
208 status = map_nt_error_from_unix(errno);
209 return status;
212 /* Ensure child is set to non-blocking mode */
213 set_blocking(sconn->sock, false);
214 return NT_STATUS_OK;
217 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
218 #define _smb2_setlen(_buf,len) do { \
219 uint8_t *buf = (uint8_t *)_buf; \
220 buf[0] = 0; \
221 buf[1] = ((len)&0xFF0000)>>16; \
222 buf[2] = ((len)&0xFF00)>>8; \
223 buf[3] = (len)&0xFF; \
224 } while (0)
226 static void smb2_setup_nbt_length(struct iovec *vector, int count)
228 size_t len = 0;
229 int i;
231 for (i=1; i < count; i++) {
232 len += vector[i].iov_len;
235 _smb2_setlen(vector[0].iov_base, len);
238 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
240 TALLOC_CTX *mem_pool;
241 struct smbd_smb2_request *req;
243 #if 0
244 /* Enable this to find subtle valgrind errors. */
245 mem_pool = talloc_init("smbd_smb2_request_allocate");
246 #else
247 mem_pool = talloc_pool(mem_ctx, 8192);
248 #endif
249 if (mem_pool == NULL) {
250 return NULL;
253 req = talloc_zero(mem_pool, struct smbd_smb2_request);
254 if (req == NULL) {
255 talloc_free(mem_pool);
256 return NULL;
258 talloc_reparent(mem_pool, mem_ctx, req);
259 TALLOC_FREE(mem_pool);
261 req->last_session_id = UINT64_MAX;
262 req->last_tid = UINT32_MAX;
264 return req;
267 static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
268 NTTIME now,
269 uint8_t *buf,
270 size_t buflen,
271 TALLOC_CTX *mem_ctx,
272 struct iovec **piov,
273 int *pnum_iov)
275 struct iovec *iov;
276 int num_iov = 1;
277 size_t taken = 0;
278 uint8_t *first_hdr = buf;
281 * Note: index '0' is reserved for the transport protocol
283 iov = talloc_zero_array(mem_ctx, struct iovec, num_iov);
284 if (iov == NULL) {
285 return NT_STATUS_NO_MEMORY;
288 while (taken < buflen) {
289 size_t len = buflen - taken;
290 uint8_t *hdr = first_hdr + taken;
291 struct iovec *cur;
292 size_t full_size;
293 size_t next_command_ofs;
294 uint16_t body_size;
295 struct iovec *iov_tmp;
298 * We need the header plus the body length field
301 if (len < SMB2_HDR_BODY + 2) {
302 DEBUG(10, ("%d bytes left, expected at least %d\n",
303 (int)len, SMB2_HDR_BODY));
304 goto inval;
306 if (IVAL(hdr, 0) != SMB2_MAGIC) {
307 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
308 IVAL(hdr, 0)));
309 goto inval;
311 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
312 DEBUG(10, ("Got HDR len %d, expected %d\n",
313 SVAL(hdr, 4), SMB2_HDR_BODY));
314 goto inval;
317 full_size = len;
318 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
319 body_size = SVAL(hdr, SMB2_HDR_BODY);
321 if (next_command_ofs != 0) {
322 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
323 goto inval;
325 if (next_command_ofs > full_size) {
326 goto inval;
328 full_size = next_command_ofs;
330 if (body_size < 2) {
331 goto inval;
333 body_size &= 0xfffe;
335 if (body_size > (full_size - SMB2_HDR_BODY)) {
337 * let the caller handle the error
339 body_size = full_size - SMB2_HDR_BODY;
342 iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
343 num_iov + 3);
344 if (iov_tmp == NULL) {
345 TALLOC_FREE(iov);
346 return NT_STATUS_NO_MEMORY;
348 iov = iov_tmp;
349 cur = &iov[num_iov];
350 num_iov += 3;
352 cur[0].iov_base = hdr;
353 cur[0].iov_len = SMB2_HDR_BODY;
354 cur[1].iov_base = hdr + SMB2_HDR_BODY;
355 cur[1].iov_len = body_size;
356 cur[2].iov_base = hdr + SMB2_HDR_BODY + body_size;
357 cur[2].iov_len = full_size - (SMB2_HDR_BODY + body_size);
359 taken += full_size;
362 *piov = iov;
363 *pnum_iov = num_iov;
364 return NT_STATUS_OK;
366 inval:
367 TALLOC_FREE(iov);
368 return NT_STATUS_INVALID_PARAMETER;
371 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
372 uint8_t *inbuf, size_t size,
373 struct smbd_smb2_request **_req)
375 struct smbd_smb2_request *req;
376 uint32_t protocol_version;
377 const uint8_t *inhdr = NULL;
378 uint16_t cmd;
379 uint32_t next_command_ofs;
380 NTSTATUS status;
381 NTTIME now;
383 if (size < (4 + SMB2_HDR_BODY + 2)) {
384 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
385 return NT_STATUS_INVALID_PARAMETER;
388 inhdr = inbuf + 4;
390 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
391 if (protocol_version != SMB2_MAGIC) {
392 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
393 protocol_version));
394 return NT_STATUS_INVALID_PARAMETER;
397 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
398 if (cmd != SMB2_OP_NEGPROT) {
399 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
400 cmd));
401 return NT_STATUS_INVALID_PARAMETER;
404 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
405 if (next_command_ofs != 0) {
406 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
407 next_command_ofs));
408 return NT_STATUS_INVALID_PARAMETER;
411 req = smbd_smb2_request_allocate(sconn);
412 if (req == NULL) {
413 return NT_STATUS_NO_MEMORY;
415 req->sconn = sconn;
417 talloc_steal(req, inbuf);
419 req->request_time = timeval_current();
420 now = timeval_to_nttime(&req->request_time);
422 status = smbd_smb2_inbuf_parse_compound(sconn->conn,
423 now,
424 inbuf + NBT_HDR_SIZE,
425 size - NBT_HDR_SIZE,
426 req, &req->in.vector,
427 &req->in.vector_count);
428 if (!NT_STATUS_IS_OK(status)) {
429 TALLOC_FREE(req);
430 return status;
433 req->current_idx = 1;
435 *_req = req;
436 return NT_STATUS_OK;
439 static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
440 uint64_t message_id, uint64_t seq_id)
442 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
443 unsigned int offset;
445 if (seq_id < sconn->smb2.seqnum_low) {
446 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
447 "%llu (sequence id %llu) "
448 "(granted = %u, low = %llu, range = %u)\n",
449 (unsigned long long)message_id,
450 (unsigned long long)seq_id,
451 (unsigned int)sconn->smb2.credits_granted,
452 (unsigned long long)sconn->smb2.seqnum_low,
453 (unsigned int)sconn->smb2.seqnum_range));
454 return false;
457 if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
458 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
459 "%llu (sequence id %llu) "
460 "(granted = %u, low = %llu, range = %u)\n",
461 (unsigned long long)message_id,
462 (unsigned long long)seq_id,
463 (unsigned int)sconn->smb2.credits_granted,
464 (unsigned long long)sconn->smb2.seqnum_low,
465 (unsigned int)sconn->smb2.seqnum_range));
466 return false;
469 offset = seq_id % sconn->smb2.max_credits;
471 if (bitmap_query(credits_bm, offset)) {
472 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
473 "%llu (sequence id %llu) "
474 "(granted = %u, low = %llu, range = %u) "
475 "(bm offset %u)\n",
476 (unsigned long long)message_id,
477 (unsigned long long)seq_id,
478 (unsigned int)sconn->smb2.credits_granted,
479 (unsigned long long)sconn->smb2.seqnum_low,
480 (unsigned int)sconn->smb2.seqnum_range,
481 offset));
482 return false;
485 /* Mark the message_ids as seen in the bitmap. */
486 bitmap_set(credits_bm, offset);
488 if (seq_id != sconn->smb2.seqnum_low) {
489 return true;
493 * Move the window forward by all the message_id's
494 * already seen.
496 while (bitmap_query(credits_bm, offset)) {
497 DEBUG(10,("smb2_validate_sequence_number: clearing "
498 "id %llu (position %u) from bitmap\n",
499 (unsigned long long)(sconn->smb2.seqnum_low),
500 offset));
501 bitmap_clear(credits_bm, offset);
503 sconn->smb2.seqnum_low += 1;
504 sconn->smb2.seqnum_range -= 1;
505 offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
508 return true;
511 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
512 const uint8_t *inhdr)
514 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
515 uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
516 uint16_t credit_charge = 1;
517 uint64_t i;
519 if (opcode == SMB2_OP_CANCEL) {
520 /* SMB2_CANCEL requests by definition resend messageids. */
521 return true;
524 if (sconn->smb2.supports_multicredit) {
525 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
526 credit_charge = MAX(credit_charge, 1);
529 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
530 "credits_granted %llu, "
531 "seqnum low/range: %llu/%llu\n",
532 (unsigned long long) message_id,
533 (unsigned long long) credit_charge,
534 (unsigned long long) sconn->smb2.credits_granted,
535 (unsigned long long) sconn->smb2.seqnum_low,
536 (unsigned long long) sconn->smb2.seqnum_range));
538 if (sconn->smb2.credits_granted < credit_charge) {
539 DEBUG(0, ("smb2_validate_message_id: client used more "
540 "credits than granted, mid %llu, charge %llu, "
541 "credits_granted %llu, "
542 "seqnum low/range: %llu/%llu\n",
543 (unsigned long long) message_id,
544 (unsigned long long) credit_charge,
545 (unsigned long long) sconn->smb2.credits_granted,
546 (unsigned long long) sconn->smb2.seqnum_low,
547 (unsigned long long) sconn->smb2.seqnum_range));
548 return false;
552 * now check the message ids
554 * for multi-credit requests we need to check all current mid plus
555 * the implicit mids caused by the credit charge
556 * e.g. current mid = 15, charge 5 => mark 15-19 as used
559 for (i = 0; i <= (credit_charge-1); i++) {
560 uint64_t id = message_id + i;
561 bool ok;
563 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
564 (unsigned long long)message_id,
565 credit_charge,
566 (unsigned long long)id));
568 ok = smb2_validate_sequence_number(sconn, message_id, id);
569 if (!ok) {
570 return false;
574 /* substract used credits */
575 sconn->smb2.credits_granted -= credit_charge;
577 return true;
580 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
582 int count;
583 int idx;
585 count = req->in.vector_count;
587 if (count < 4) {
588 /* It's not a SMB2 request */
589 return NT_STATUS_INVALID_PARAMETER;
592 for (idx=1; idx < count; idx += 3) {
593 const uint8_t *inhdr = NULL;
594 uint32_t flags;
596 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
597 return NT_STATUS_INVALID_PARAMETER;
600 if (req->in.vector[idx+1].iov_len < 2) {
601 return NT_STATUS_INVALID_PARAMETER;
604 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
606 /* Check the SMB2 header */
607 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
608 return NT_STATUS_INVALID_PARAMETER;
611 if (!smb2_validate_message_id(req->sconn, inhdr)) {
612 return NT_STATUS_INVALID_PARAMETER;
615 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
616 if (idx == 1) {
618 * the 1st request should never have the
619 * SMB2_HDR_FLAG_CHAINED flag set
621 if (flags & SMB2_HDR_FLAG_CHAINED) {
622 req->next_status = NT_STATUS_INVALID_PARAMETER;
623 return NT_STATUS_OK;
625 } else if (idx == 4) {
627 * the 2nd request triggers related vs. unrelated
628 * compounded requests
630 if (flags & SMB2_HDR_FLAG_CHAINED) {
631 req->compound_related = true;
633 } else if (idx > 4) {
634 #if 0
636 * It seems the this tests are wrong
637 * see the SMB2-COMPOUND test
641 * all other requests should match the 2nd one
643 if (flags & SMB2_HDR_FLAG_CHAINED) {
644 if (!req->compound_related) {
645 req->next_status =
646 NT_STATUS_INVALID_PARAMETER;
647 return NT_STATUS_OK;
649 } else {
650 if (req->compound_related) {
651 req->next_status =
652 NT_STATUS_INVALID_PARAMETER;
653 return NT_STATUS_OK;
656 #endif
660 return NT_STATUS_OK;
663 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
664 const struct iovec *in_vector,
665 struct iovec *out_vector)
667 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
668 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
669 uint16_t credit_charge = 1;
670 uint16_t credits_requested;
671 uint32_t out_flags;
672 uint16_t cmd;
673 NTSTATUS out_status;
674 uint16_t credits_granted = 0;
675 uint64_t credits_possible;
676 uint16_t current_max_credits;
679 * first we grant only 1/16th of the max range.
681 * Windows also starts with the 1/16th and then grants
682 * more later. I was only able to trigger higher
683 * values, when using a verify high credit charge.
685 * TODO: scale up depending one load, free memory
686 * or other stuff.
687 * Maybe also on the relationship between number
688 * of requests and the used sequence number.
689 * Which means we would grant more credits
690 * for client which use multi credit requests.
692 current_max_credits = sconn->smb2.max_credits / 16;
693 current_max_credits = MAX(current_max_credits, 1);
695 if (sconn->smb2.supports_multicredit) {
696 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
697 credit_charge = MAX(credit_charge, 1);
700 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
701 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
702 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
703 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
705 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
706 SMB_ASSERT(sconn->smb2.max_credits >= credit_charge);
708 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
710 * In case we already send an async interim
711 * response, we should not grant
712 * credits on the final response.
714 credits_granted = 0;
715 } else if (credits_requested > 0) {
716 uint16_t additional_max = 0;
717 uint16_t additional_credits = credits_requested - 1;
719 switch (cmd) {
720 case SMB2_OP_NEGPROT:
721 break;
722 case SMB2_OP_SESSSETUP:
724 * Windows 2012 RC1 starts to grant
725 * additional credits
726 * with a successful session setup
728 if (NT_STATUS_IS_OK(out_status)) {
729 additional_max = 32;
731 break;
732 default:
734 * We match windows and only grant additional credits
735 * in chunks of 32.
737 additional_max = 32;
738 break;
741 additional_credits = MIN(additional_credits, additional_max);
743 credits_granted = credit_charge + additional_credits;
744 } else if (sconn->smb2.credits_granted == 0) {
746 * Make sure the client has always at least one credit
748 credits_granted = 1;
752 * sequence numbers should not wrap
754 * 1. calculate the possible credits until
755 * the sequence numbers start to wrap on 64-bit.
757 * 2. UINT64_MAX is used for Break Notifications.
759 * 2. truncate the possible credits to the maximum
760 * credits we want to grant to the client in total.
762 * 3. remove the range we'll already granted to the client
763 * this makes sure the client consumes the lowest sequence
764 * number, before we can grant additional credits.
766 credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
767 if (credits_possible > 0) {
768 /* remove UINT64_MAX */
769 credits_possible -= 1;
771 credits_possible = MIN(credits_possible, current_max_credits);
772 credits_possible -= sconn->smb2.seqnum_range;
774 credits_granted = MIN(credits_granted, credits_possible);
776 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
777 sconn->smb2.credits_granted += credits_granted;
778 sconn->smb2.seqnum_range += credits_granted;
780 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
781 "granted %u, current possible/max %u/%u, "
782 "total granted/max/low/range %u/%u/%llu/%u\n",
783 (unsigned int)credits_requested,
784 (unsigned int)credit_charge,
785 (unsigned int)credits_granted,
786 (unsigned int)credits_possible,
787 (unsigned int)current_max_credits,
788 (unsigned int)sconn->smb2.credits_granted,
789 (unsigned int)sconn->smb2.max_credits,
790 (unsigned long long)sconn->smb2.seqnum_low,
791 (unsigned int)sconn->smb2.seqnum_range));
794 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
795 struct smbd_smb2_request *outreq)
797 int count, idx;
798 uint16_t total_credits = 0;
800 count = outreq->out.vector_count;
802 for (idx=1; idx < count; idx += 3) {
803 uint8_t *outhdr = (uint8_t *)outreq->out.vector[idx].iov_base;
804 smb2_set_operation_credit(outreq->sconn,
805 &inreq->in.vector[idx],
806 &outreq->out.vector[idx]);
807 /* To match Windows, count up what we
808 just granted. */
809 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
810 /* Set to zero in all but the last reply. */
811 if (idx + 3 < count) {
812 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
813 } else {
814 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
819 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
821 struct iovec *vector;
822 int count;
823 int idx;
825 count = req->in.vector_count;
826 vector = talloc_zero_array(req, struct iovec, count);
827 if (vector == NULL) {
828 return NT_STATUS_NO_MEMORY;
831 vector[0].iov_base = req->out.nbt_hdr;
832 vector[0].iov_len = 4;
833 SIVAL(req->out.nbt_hdr, 0, 0);
835 for (idx=1; idx < count; idx += 3) {
836 const uint8_t *inhdr = NULL;
837 uint8_t *outhdr = NULL;
838 uint8_t *outbody = NULL;
839 uint32_t next_command_ofs = 0;
840 struct iovec *current = &vector[idx];
842 if ((idx + 3) < count) {
843 /* we have a next command -
844 * setup for the error case. */
845 next_command_ofs = SMB2_HDR_BODY + 9;
848 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
850 outhdr = talloc_zero_array(vector, uint8_t,
851 OUTVEC_ALLOC_SIZE);
852 if (outhdr == NULL) {
853 return NT_STATUS_NO_MEMORY;
856 outbody = outhdr + SMB2_HDR_BODY;
858 current[0].iov_base = (void *)outhdr;
859 current[0].iov_len = SMB2_HDR_BODY;
861 current[1].iov_base = (void *)outbody;
862 current[1].iov_len = 8;
864 current[2].iov_base = NULL;
865 current[2].iov_len = 0;
867 /* setup the SMB2 header */
868 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
869 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
870 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
871 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
872 SIVAL(outhdr, SMB2_HDR_STATUS,
873 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
874 SSVAL(outhdr, SMB2_HDR_OPCODE,
875 SVAL(inhdr, SMB2_HDR_OPCODE));
876 SIVAL(outhdr, SMB2_HDR_FLAGS,
877 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
878 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
879 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
880 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
881 SIVAL(outhdr, SMB2_HDR_PID,
882 IVAL(inhdr, SMB2_HDR_PID));
883 SIVAL(outhdr, SMB2_HDR_TID,
884 IVAL(inhdr, SMB2_HDR_TID));
885 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
886 BVAL(inhdr, SMB2_HDR_SESSION_ID));
887 memcpy(outhdr + SMB2_HDR_SIGNATURE,
888 inhdr + SMB2_HDR_SIGNATURE, 16);
890 /* setup error body header */
891 SSVAL(outbody, 0x00, 0x08 + 1);
892 SSVAL(outbody, 0x02, 0);
893 SIVAL(outbody, 0x04, 0);
896 req->out.vector = vector;
897 req->out.vector_count = count;
899 /* setup the length of the NBT packet */
900 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
902 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
904 return NT_STATUS_OK;
907 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
908 const char *reason,
909 const char *location)
911 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
912 reason, location));
913 exit_server_cleanly(reason);
916 static bool dup_smb2_vec3(TALLOC_CTX *ctx,
917 struct iovec *outvec,
918 const struct iovec *srcvec)
920 /* vec[0] is always boilerplate and must
921 * be allocated with size OUTVEC_ALLOC_SIZE. */
923 outvec[0].iov_base = talloc_memdup(ctx,
924 srcvec[0].iov_base,
925 OUTVEC_ALLOC_SIZE);
926 if (!outvec[0].iov_base) {
927 return false;
929 outvec[0].iov_len = SMB2_HDR_BODY;
932 * If this is a "standard" vec[1] of length 8,
933 * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
934 * then duplicate this. Else use talloc_memdup().
937 if (srcvec[1].iov_len == 8 &&
938 srcvec[1].iov_base ==
939 ((uint8_t *)srcvec[0].iov_base) +
940 SMB2_HDR_BODY) {
941 outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
942 SMB2_HDR_BODY;
943 outvec[1].iov_len = 8;
944 } else {
945 outvec[1].iov_base = talloc_memdup(ctx,
946 srcvec[1].iov_base,
947 srcvec[1].iov_len);
948 if (!outvec[1].iov_base) {
949 return false;
951 outvec[1].iov_len = srcvec[1].iov_len;
955 * If this is a "standard" vec[2] of length 1,
956 * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
957 * then duplicate this. Else use talloc_memdup().
960 if (srcvec[2].iov_base &&
961 srcvec[2].iov_len) {
962 if (srcvec[2].iov_base ==
963 ((uint8_t *)srcvec[0].iov_base) +
964 (OUTVEC_ALLOC_SIZE - 1) &&
965 srcvec[2].iov_len == 1) {
966 /* Common SMB2 error packet case. */
967 outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
968 (OUTVEC_ALLOC_SIZE - 1);
969 } else {
970 outvec[2].iov_base = talloc_memdup(ctx,
971 srcvec[2].iov_base,
972 srcvec[2].iov_len);
973 if (!outvec[2].iov_base) {
974 return false;
977 outvec[2].iov_len = srcvec[2].iov_len;
978 } else {
979 outvec[2].iov_base = NULL;
980 outvec[2].iov_len = 0;
982 return true;
985 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
987 struct smbd_smb2_request *newreq = NULL;
988 struct iovec *outvec = NULL;
989 int count = req->out.vector_count;
990 int i;
992 newreq = smbd_smb2_request_allocate(req->sconn);
993 if (!newreq) {
994 return NULL;
997 newreq->sconn = req->sconn;
998 newreq->session = req->session;
999 newreq->do_signing = req->do_signing;
1000 newreq->current_idx = req->current_idx;
1002 outvec = talloc_zero_array(newreq, struct iovec, count);
1003 if (!outvec) {
1004 TALLOC_FREE(newreq);
1005 return NULL;
1007 newreq->out.vector = outvec;
1008 newreq->out.vector_count = count;
1010 /* Setup the outvec's identically to req. */
1011 outvec[0].iov_base = newreq->out.nbt_hdr;
1012 outvec[0].iov_len = 4;
1013 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
1015 /* Setup the vectors identically to the ones in req. */
1016 for (i = 1; i < count; i += 3) {
1017 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
1018 break;
1022 if (i < count) {
1023 /* Alloc failed. */
1024 TALLOC_FREE(newreq);
1025 return NULL;
1028 smb2_setup_nbt_length(newreq->out.vector,
1029 newreq->out.vector_count);
1031 return newreq;
1034 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
1036 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1038 int i = 0;
1039 uint8_t *outhdr = NULL;
1040 struct smbd_smb2_request *nreq = NULL;
1042 /* Create a new smb2 request we'll use
1043 for the interim return. */
1044 nreq = dup_smb2_req(req);
1045 if (!nreq) {
1046 return NT_STATUS_NO_MEMORY;
1049 /* Lose the last 3 out vectors. They're the
1050 ones we'll be using for the async reply. */
1051 nreq->out.vector_count -= 3;
1053 smb2_setup_nbt_length(nreq->out.vector,
1054 nreq->out.vector_count);
1056 /* Step back to the previous reply. */
1057 i = nreq->current_idx - 3;
1058 outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
1059 /* And end the chain. */
1060 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1062 /* Calculate outgoing credits */
1063 smb2_calculate_credits(req, nreq);
1065 /* Re-sign if needed. */
1066 if (nreq->do_signing) {
1067 NTSTATUS status;
1068 struct smbXsrv_session *x = nreq->session;
1069 struct smbXsrv_connection *conn = x->connection;
1070 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1072 status = smb2_signing_sign_pdu(signing_key,
1073 conn->protocol,
1074 &nreq->out.vector[i], 3);
1075 if (!NT_STATUS_IS_OK(status)) {
1076 return status;
1079 if (DEBUGLEVEL >= 10) {
1080 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1081 (unsigned int)nreq->current_idx );
1082 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1083 (unsigned int)nreq->out.vector_count );
1084 print_req_vectors(nreq);
1086 nreq->subreq = tstream_writev_queue_send(nreq,
1087 nreq->sconn->ev_ctx,
1088 nreq->sconn->smb2.stream,
1089 nreq->sconn->smb2.send_queue,
1090 nreq->out.vector,
1091 nreq->out.vector_count);
1093 if (nreq->subreq == NULL) {
1094 return NT_STATUS_NO_MEMORY;
1097 tevent_req_set_callback(nreq->subreq,
1098 smbd_smb2_request_writev_done,
1099 nreq);
1101 return NT_STATUS_OK;
1104 struct smbd_smb2_request_pending_state {
1105 struct smbd_server_connection *sconn;
1106 uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
1107 struct iovec vector[3];
1110 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
1112 struct smbd_smb2_request_pending_state *state =
1113 tevent_req_callback_data(subreq,
1114 struct smbd_smb2_request_pending_state);
1115 struct smbd_server_connection *sconn = state->sconn;
1116 int ret;
1117 int sys_errno;
1119 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1120 TALLOC_FREE(subreq);
1121 if (ret == -1) {
1122 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1123 smbd_server_connection_terminate(sconn, nt_errstr(status));
1124 return;
1127 TALLOC_FREE(state);
1130 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1131 struct tevent_timer *te,
1132 struct timeval current_time,
1133 void *private_data);
1135 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1136 struct tevent_req *subreq,
1137 uint32_t defer_time)
1139 NTSTATUS status;
1140 int i = req->current_idx;
1141 struct timeval defer_endtime;
1142 uint8_t *outhdr = NULL;
1143 uint32_t flags;
1145 if (!tevent_req_is_in_progress(subreq)) {
1146 return NT_STATUS_OK;
1149 req->subreq = subreq;
1150 subreq = NULL;
1152 if (req->async_te) {
1153 /* We're already async. */
1154 return NT_STATUS_OK;
1157 outhdr = (uint8_t *)req->out.vector[i].iov_base;
1158 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1159 if (flags & SMB2_HDR_FLAG_ASYNC) {
1160 /* We're already async. */
1161 return NT_STATUS_OK;
1164 if (req->in.vector_count > i + 3) {
1166 * We're trying to go async in a compound
1167 * request chain. This is not allowed.
1168 * Cancel the outstanding request.
1170 tevent_req_cancel(req->subreq);
1171 return smbd_smb2_request_error(req,
1172 NT_STATUS_INSUFFICIENT_RESOURCES);
1175 if (DEBUGLEVEL >= 10) {
1176 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1177 (unsigned int)req->current_idx );
1178 print_req_vectors(req);
1181 if (req->out.vector_count > 4) {
1182 struct iovec *outvec = NULL;
1184 /* This is a compound reply. We
1185 * must do an interim response
1186 * followed by the async response
1187 * to match W2K8R2.
1189 status = smb2_send_async_interim_response(req);
1190 if (!NT_STATUS_IS_OK(status)) {
1191 return status;
1195 * We're splitting off the last SMB2
1196 * request in a compound set, and the
1197 * smb2_send_async_interim_response()
1198 * call above just sent all the replies
1199 * for the previous SMB2 requests in
1200 * this compound set. So we're no longer
1201 * in the "compound_related_in_progress"
1202 * state, and this is no longer a compound
1203 * request.
1205 req->compound_related = false;
1206 req->sconn->smb2.compound_related_in_progress = false;
1208 /* Re-arrange the in.vectors. */
1209 req->in.vector[1] = req->in.vector[i];
1210 req->in.vector[2] = req->in.vector[i+1];
1211 req->in.vector[3] = req->in.vector[i+2];
1212 req->in.vector_count = 4;
1214 /* Reset the new in size. */
1215 smb2_setup_nbt_length(req->in.vector, 4);
1217 /* Now recreate the out.vectors. */
1218 outvec = talloc_zero_array(req, struct iovec, 4);
1219 if (!outvec) {
1220 return NT_STATUS_NO_MEMORY;
1223 /* 0 is always boilerplate and must
1224 * be of size 4 for the length field. */
1226 outvec[0].iov_base = req->out.nbt_hdr;
1227 outvec[0].iov_len = 4;
1228 SIVAL(req->out.nbt_hdr, 0, 0);
1230 if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
1231 return NT_STATUS_NO_MEMORY;
1234 TALLOC_FREE(req->out.vector);
1236 req->out.vector = outvec;
1238 req->current_idx = 1;
1239 req->out.vector_count = 4;
1241 outhdr = (uint8_t *)req->out.vector[1].iov_base;
1242 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1243 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1246 defer_endtime = timeval_current_ofs_usec(defer_time);
1247 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1248 req, defer_endtime,
1249 smbd_smb2_request_pending_timer,
1250 req);
1251 if (req->async_te == NULL) {
1252 return NT_STATUS_NO_MEMORY;
1255 return NT_STATUS_OK;
1258 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1259 struct tevent_timer *te,
1260 struct timeval current_time,
1261 void *private_data)
1263 struct smbd_smb2_request *req =
1264 talloc_get_type_abort(private_data,
1265 struct smbd_smb2_request);
1266 struct smbd_smb2_request_pending_state *state = NULL;
1267 uint8_t *outhdr = NULL;
1268 const uint8_t *inhdr = NULL;
1269 uint8_t *hdr = NULL;
1270 uint8_t *body = NULL;
1271 uint32_t flags = 0;
1272 uint64_t message_id = 0;
1273 uint64_t async_id = 0;
1274 struct tevent_req *subreq = NULL;
1276 TALLOC_FREE(req->async_te);
1278 /* Ensure our final reply matches the interim one. */
1279 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1280 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1281 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1282 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1284 async_id = message_id; /* keep it simple for now... */
1286 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1287 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1289 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1290 "going async\n",
1291 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1292 (unsigned long long)async_id ));
1295 * What we send is identical to a smbd_smb2_request_error
1296 * packet with an error status of STATUS_PENDING. Make use
1297 * of this fact sometime when refactoring. JRA.
1300 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1301 if (state == NULL) {
1302 smbd_server_connection_terminate(req->sconn,
1303 nt_errstr(NT_STATUS_NO_MEMORY));
1304 return;
1306 state->sconn = req->sconn;
1308 state->vector[0].iov_base = (void *)state->buf;
1309 state->vector[0].iov_len = 4;
1311 state->vector[1].iov_base = state->buf + 4;
1312 state->vector[1].iov_len = SMB2_HDR_BODY;
1314 state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
1315 state->vector[2].iov_len = 9;
1317 smb2_setup_nbt_length(state->vector, 3);
1319 hdr = (uint8_t *)state->vector[1].iov_base;
1320 body = (uint8_t *)state->vector[2].iov_base;
1322 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1323 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1324 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1325 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1326 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1328 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1329 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1330 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1331 SBVAL(hdr, SMB2_HDR_PID, async_id);
1332 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1333 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1334 memcpy(hdr+SMB2_HDR_SIGNATURE,
1335 outhdr+SMB2_HDR_SIGNATURE, 16);
1337 SSVAL(body, 0x00, 0x08 + 1);
1339 SCVAL(body, 0x02, 0);
1340 SCVAL(body, 0x03, 0);
1341 SIVAL(body, 0x04, 0);
1342 /* Match W2K8R2... */
1343 SCVAL(body, 0x08, 0x21);
1345 /* Ensure we correctly go through crediting. Grant
1346 the credits now, and zero credits on the final
1347 response. */
1348 smb2_set_operation_credit(req->sconn,
1349 SMBD_SMB2_IN_HDR_IOV(req),
1350 &state->vector[1]);
1352 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1354 if (req->do_signing) {
1355 NTSTATUS status;
1356 struct smbXsrv_session *x = req->session;
1357 struct smbXsrv_connection *conn = x->connection;
1358 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1360 status = smb2_signing_sign_pdu(signing_key,
1361 conn->protocol,
1362 &state->vector[1], 2);
1363 if (!NT_STATUS_IS_OK(status)) {
1364 smbd_server_connection_terminate(req->sconn,
1365 nt_errstr(status));
1366 return;
1370 subreq = tstream_writev_queue_send(state,
1371 state->sconn->ev_ctx,
1372 state->sconn->smb2.stream,
1373 state->sconn->smb2.send_queue,
1374 state->vector,
1376 if (subreq == NULL) {
1377 smbd_server_connection_terminate(state->sconn,
1378 nt_errstr(NT_STATUS_NO_MEMORY));
1379 return;
1381 tevent_req_set_callback(subreq,
1382 smbd_smb2_request_pending_writev_done,
1383 state);
1386 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1388 struct smbd_server_connection *sconn = req->sconn;
1389 struct smbd_smb2_request *cur;
1390 const uint8_t *inhdr;
1391 uint32_t flags;
1392 uint64_t search_message_id;
1393 uint64_t search_async_id;
1394 uint64_t found_id;
1396 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1398 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1399 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1400 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1403 * we don't need the request anymore
1404 * cancel requests never have a response
1406 DLIST_REMOVE(req->sconn->smb2.requests, req);
1407 TALLOC_FREE(req);
1409 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1410 const uint8_t *outhdr;
1411 uint64_t message_id;
1412 uint64_t async_id;
1414 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1416 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1417 async_id = BVAL(outhdr, SMB2_HDR_PID);
1419 if (flags & SMB2_HDR_FLAG_ASYNC) {
1420 if (search_async_id == async_id) {
1421 found_id = async_id;
1422 break;
1424 } else {
1425 if (search_message_id == message_id) {
1426 found_id = message_id;
1427 break;
1432 if (cur && cur->subreq) {
1433 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1434 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1435 "cancel opcode[%s] mid %llu\n",
1436 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1437 (unsigned long long)found_id ));
1438 tevent_req_cancel(cur->subreq);
1441 return NT_STATUS_OK;
1444 /*************************************************************
1445 Ensure an incoming tid is a valid one for us to access.
1446 Change to the associated uid credentials and chdir to the
1447 valid tid directory.
1448 *************************************************************/
1450 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1452 const uint8_t *inhdr;
1453 uint32_t in_flags;
1454 uint32_t in_tid;
1455 struct smbXsrv_tcon *tcon;
1456 NTSTATUS status;
1457 NTTIME now = timeval_to_nttime(&req->request_time);
1459 req->tcon = NULL;
1461 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1463 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1464 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1466 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1467 in_tid = req->last_tid;
1470 status = smb2srv_tcon_lookup(req->session,
1471 in_tid, now, &tcon);
1472 if (!NT_STATUS_IS_OK(status)) {
1473 return status;
1476 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1477 return NT_STATUS_ACCESS_DENIED;
1480 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1481 if (!set_current_service(tcon->compat, 0, true)) {
1482 return NT_STATUS_ACCESS_DENIED;
1485 req->tcon = tcon;
1486 req->last_tid = in_tid;
1488 return NT_STATUS_OK;
1491 /*************************************************************
1492 Ensure an incoming session_id is a valid one for us to access.
1493 *************************************************************/
1495 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1497 const uint8_t *inhdr;
1498 uint32_t in_flags;
1499 uint16_t in_opcode;
1500 uint64_t in_session_id;
1501 struct smbXsrv_session *session = NULL;
1502 struct auth_session_info *session_info;
1503 NTSTATUS status;
1504 NTTIME now = timeval_to_nttime(&req->request_time);
1506 req->session = NULL;
1507 req->tcon = NULL;
1509 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1511 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1512 in_opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1513 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1515 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1516 in_session_id = req->last_session_id;
1519 /* lookup an existing session */
1520 status = smb2srv_session_lookup(req->sconn->conn,
1521 in_session_id, now,
1522 &session);
1523 if (session) {
1524 req->session = session;
1525 req->last_session_id = in_session_id;
1527 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1528 switch (in_opcode) {
1529 case SMB2_OP_SESSSETUP:
1530 status = NT_STATUS_OK;
1531 break;
1532 default:
1533 break;
1536 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1537 switch (in_opcode) {
1538 case SMB2_OP_TCON:
1539 case SMB2_OP_CREATE:
1540 case SMB2_OP_GETINFO:
1541 case SMB2_OP_SETINFO:
1542 return NT_STATUS_INVALID_HANDLE;
1543 default:
1545 * Notice the check for
1546 * (session_info == NULL)
1547 * below.
1549 status = NT_STATUS_OK;
1550 break;
1553 if (!NT_STATUS_IS_OK(status)) {
1554 return status;
1557 session_info = session->global->auth_session_info;
1558 if (session_info == NULL) {
1559 return NT_STATUS_INVALID_HANDLE;
1562 set_current_user_info(session_info->unix_info->sanitized_username,
1563 session_info->unix_info->unix_name,
1564 session_info->info->domain_name);
1566 return NT_STATUS_OK;
1569 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1570 uint32_t data_length)
1572 uint16_t needed_charge;
1573 uint16_t credit_charge = 1;
1574 const uint8_t *inhdr;
1576 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1578 if (req->sconn->smb2.supports_multicredit) {
1579 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1580 credit_charge = MAX(credit_charge, 1);
1583 needed_charge = (data_length - 1)/ 65536 + 1;
1585 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1586 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1587 credit_charge, needed_charge));
1589 if (needed_charge > credit_charge) {
1590 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1591 credit_charge, needed_charge));
1592 return NT_STATUS_INVALID_PARAMETER;
1595 return NT_STATUS_OK;
1598 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1599 size_t expected_body_size)
1601 const uint8_t *inhdr;
1602 uint16_t opcode;
1603 const uint8_t *inbody;
1604 int i = req->current_idx;
1605 size_t body_size;
1606 size_t min_dyn_size = expected_body_size & 0x00000001;
1609 * The following should be checked already.
1611 if ((i+2) > req->in.vector_count) {
1612 return NT_STATUS_INTERNAL_ERROR;
1614 if (req->in.vector[i+0].iov_len != SMB2_HDR_BODY) {
1615 return NT_STATUS_INTERNAL_ERROR;
1617 if (req->in.vector[i+1].iov_len < 2) {
1618 return NT_STATUS_INTERNAL_ERROR;
1621 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1622 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1624 switch (opcode) {
1625 case SMB2_OP_IOCTL:
1626 case SMB2_OP_GETINFO:
1627 min_dyn_size = 0;
1628 break;
1632 * Now check the expected body size,
1633 * where the last byte might be in the
1634 * dynamic section..
1636 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1637 return NT_STATUS_INVALID_PARAMETER;
1639 if (req->in.vector[i+2].iov_len < min_dyn_size) {
1640 return NT_STATUS_INVALID_PARAMETER;
1643 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1645 body_size = SVAL(inbody, 0x00);
1646 if (body_size != expected_body_size) {
1647 return NT_STATUS_INVALID_PARAMETER;
1650 return NT_STATUS_OK;
1653 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1655 struct smbXsrv_connection *conn = req->sconn->conn;
1656 const struct smbd_smb2_dispatch_table *call = NULL;
1657 const uint8_t *inhdr;
1658 uint16_t opcode;
1659 uint32_t flags;
1660 uint64_t mid;
1661 NTSTATUS status;
1662 NTSTATUS session_status;
1663 uint32_t allowed_flags;
1664 NTSTATUS return_value;
1665 struct smbXsrv_session *x = NULL;
1666 bool signing_required = false;
1668 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1670 /* TODO: verify more things */
1672 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1673 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1674 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1675 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1676 smb2_opcode_name(opcode),
1677 (unsigned long long)mid));
1679 if (conn->protocol >= PROTOCOL_SMB2_02) {
1681 * once the protocol is negotiated
1682 * SMB2_OP_NEGPROT is not allowed anymore
1684 if (opcode == SMB2_OP_NEGPROT) {
1685 /* drop the connection */
1686 return NT_STATUS_INVALID_PARAMETER;
1688 } else {
1690 * if the protocol is not negotiated yet
1691 * only SMB2_OP_NEGPROT is allowed.
1693 if (opcode != SMB2_OP_NEGPROT) {
1694 /* drop the connection */
1695 return NT_STATUS_INVALID_PARAMETER;
1699 call = smbd_smb2_call(opcode);
1700 if (call == NULL) {
1701 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1704 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1705 SMB2_HDR_FLAG_SIGNED |
1706 SMB2_HDR_FLAG_DFS;
1707 if (opcode == SMB2_OP_CANCEL) {
1708 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1710 if ((flags & ~allowed_flags) != 0) {
1711 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1715 * Check if the client provided a valid session id,
1716 * if so smbd_smb2_request_check_session() calls
1717 * set_current_user_info().
1719 * As some command don't require a valid session id
1720 * we defer the check of the session_status
1722 session_status = smbd_smb2_request_check_session(req);
1723 x = req->session;
1725 if (x != NULL) {
1726 signing_required = x->global->signing_required;
1728 if (opcode == SMB2_OP_SESSSETUP &&
1729 x->global->channels[0].signing_key.length) {
1730 signing_required = true;
1734 req->do_signing = false;
1735 if (flags & SMB2_HDR_FLAG_SIGNED) {
1736 DATA_BLOB signing_key;
1738 if (x == NULL) {
1739 return smbd_smb2_request_error(
1740 req, NT_STATUS_ACCESS_DENIED);
1743 signing_key = x->global->channels[0].signing_key;
1745 if (!NT_STATUS_IS_OK(session_status)) {
1746 return smbd_smb2_request_error(req, session_status);
1749 req->do_signing = true;
1750 status = smb2_signing_check_pdu(signing_key,
1751 conn->protocol,
1752 SMBD_SMB2_IN_HDR_IOV(req), 3);
1753 if (!NT_STATUS_IS_OK(status)) {
1754 return smbd_smb2_request_error(req, status);
1756 } else if (opcode == SMB2_OP_CANCEL) {
1757 /* Cancel requests are allowed to skip the signing */
1758 } else if (signing_required) {
1759 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1762 if (flags & SMB2_HDR_FLAG_CHAINED) {
1764 * This check is mostly for giving the correct error code
1765 * for compounded requests.
1767 * TODO: we may need to move this after the session
1768 * and tcon checks.
1770 if (!NT_STATUS_IS_OK(req->next_status)) {
1771 return smbd_smb2_request_error(req, req->next_status);
1773 } else {
1774 req->compat_chain_fsp = NULL;
1777 if (req->compound_related) {
1778 req->sconn->smb2.compound_related_in_progress = true;
1781 switch (opcode) {
1782 case SMB2_OP_NEGPROT:
1783 /* This call needs to be run as root */
1784 change_to_root_user();
1787 START_PROFILE(smb2_negprot);
1788 return_value = smbd_smb2_request_process_negprot(req);
1789 END_PROFILE(smb2_negprot);
1791 break;
1793 case SMB2_OP_SESSSETUP:
1794 /* This call needs to be run as root */
1795 change_to_root_user();
1798 START_PROFILE(smb2_sesssetup);
1799 return_value = smbd_smb2_request_process_sesssetup(req);
1800 END_PROFILE(smb2_sesssetup);
1802 break;
1804 case SMB2_OP_LOGOFF:
1805 if (!NT_STATUS_IS_OK(session_status)) {
1806 return_value = smbd_smb2_request_error(req, session_status);
1807 break;
1810 /* This call needs to be run as root */
1811 change_to_root_user();
1814 START_PROFILE(smb2_logoff);
1815 return_value = smbd_smb2_request_process_logoff(req);
1816 END_PROFILE(smb2_logoff);
1818 break;
1820 case SMB2_OP_TCON:
1821 if (!NT_STATUS_IS_OK(session_status)) {
1822 return_value = smbd_smb2_request_error(req, session_status);
1823 break;
1827 * This call needs to be run as root.
1829 * smbd_smb2_request_process_tcon()
1830 * calls make_connection_snum(), which will call
1831 * change_to_user(), when needed.
1833 change_to_root_user();
1836 START_PROFILE(smb2_tcon);
1837 return_value = smbd_smb2_request_process_tcon(req);
1838 END_PROFILE(smb2_tcon);
1840 break;
1842 case SMB2_OP_TDIS:
1843 if (!NT_STATUS_IS_OK(session_status)) {
1844 return_value = smbd_smb2_request_error(req, session_status);
1845 break;
1848 * This call needs to be run as user.
1850 * smbd_smb2_request_check_tcon()
1851 * calls change_to_user() on success.
1853 status = smbd_smb2_request_check_tcon(req);
1854 if (!NT_STATUS_IS_OK(status)) {
1855 return_value = smbd_smb2_request_error(req, status);
1856 break;
1858 /* This call needs to be run as root */
1859 change_to_root_user();
1863 START_PROFILE(smb2_tdis);
1864 return_value = smbd_smb2_request_process_tdis(req);
1865 END_PROFILE(smb2_tdis);
1867 break;
1869 case SMB2_OP_CREATE:
1870 if (!NT_STATUS_IS_OK(session_status)) {
1871 return_value = smbd_smb2_request_error(req, session_status);
1872 break;
1875 * This call needs to be run as user.
1877 * smbd_smb2_request_check_tcon()
1878 * calls change_to_user() on success.
1880 status = smbd_smb2_request_check_tcon(req);
1881 if (!NT_STATUS_IS_OK(status)) {
1882 return_value = smbd_smb2_request_error(req, status);
1883 break;
1887 START_PROFILE(smb2_create);
1888 return_value = smbd_smb2_request_process_create(req);
1889 END_PROFILE(smb2_create);
1891 break;
1893 case SMB2_OP_CLOSE:
1894 if (!NT_STATUS_IS_OK(session_status)) {
1895 return_value = smbd_smb2_request_error(req, session_status);
1896 break;
1899 * This call needs to be run as user.
1901 * smbd_smb2_request_check_tcon()
1902 * calls change_to_user() on success.
1904 status = smbd_smb2_request_check_tcon(req);
1905 if (!NT_STATUS_IS_OK(status)) {
1906 return_value = smbd_smb2_request_error(req, status);
1907 break;
1911 START_PROFILE(smb2_close);
1912 return_value = smbd_smb2_request_process_close(req);
1913 END_PROFILE(smb2_close);
1915 break;
1917 case SMB2_OP_FLUSH:
1918 if (!NT_STATUS_IS_OK(session_status)) {
1919 return_value = smbd_smb2_request_error(req, session_status);
1920 break;
1923 * This call needs to be run as user.
1925 * smbd_smb2_request_check_tcon()
1926 * calls change_to_user() on success.
1928 status = smbd_smb2_request_check_tcon(req);
1929 if (!NT_STATUS_IS_OK(status)) {
1930 return_value = smbd_smb2_request_error(req, status);
1931 break;
1935 START_PROFILE(smb2_flush);
1936 return_value = smbd_smb2_request_process_flush(req);
1937 END_PROFILE(smb2_flush);
1939 break;
1941 case SMB2_OP_READ:
1942 if (!NT_STATUS_IS_OK(session_status)) {
1943 return_value = smbd_smb2_request_error(req, session_status);
1944 break;
1947 * This call needs to be run as user.
1949 * smbd_smb2_request_check_tcon()
1950 * calls change_to_user() on success.
1952 status = smbd_smb2_request_check_tcon(req);
1953 if (!NT_STATUS_IS_OK(status)) {
1954 return_value = smbd_smb2_request_error(req, status);
1955 break;
1959 START_PROFILE(smb2_read);
1960 return_value = smbd_smb2_request_process_read(req);
1961 END_PROFILE(smb2_read);
1963 break;
1965 case SMB2_OP_WRITE:
1966 if (!NT_STATUS_IS_OK(session_status)) {
1967 return_value = smbd_smb2_request_error(req, session_status);
1968 break;
1971 * This call needs to be run as user.
1973 * smbd_smb2_request_check_tcon()
1974 * calls change_to_user() on success.
1976 status = smbd_smb2_request_check_tcon(req);
1977 if (!NT_STATUS_IS_OK(status)) {
1978 return_value = smbd_smb2_request_error(req, status);
1979 break;
1983 START_PROFILE(smb2_write);
1984 return_value = smbd_smb2_request_process_write(req);
1985 END_PROFILE(smb2_write);
1987 break;
1989 case SMB2_OP_LOCK:
1990 if (!NT_STATUS_IS_OK(session_status)) {
1991 /* Too ugly to live ? JRA. */
1992 if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
1993 session_status = NT_STATUS_FILE_CLOSED;
1995 return_value = smbd_smb2_request_error(req, session_status);
1996 break;
1999 * This call needs to be run as user.
2001 * smbd_smb2_request_check_tcon()
2002 * calls change_to_user() on success.
2004 status = smbd_smb2_request_check_tcon(req);
2005 if (!NT_STATUS_IS_OK(status)) {
2006 /* Too ugly to live ? JRA. */
2007 if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
2008 status = NT_STATUS_FILE_CLOSED;
2010 return_value = smbd_smb2_request_error(req, status);
2011 break;
2015 START_PROFILE(smb2_lock);
2016 return_value = smbd_smb2_request_process_lock(req);
2017 END_PROFILE(smb2_lock);
2019 break;
2021 case SMB2_OP_IOCTL:
2022 if (!NT_STATUS_IS_OK(session_status)) {
2023 return_value = smbd_smb2_request_error(req, session_status);
2024 break;
2027 * This call needs to be run as user.
2029 * smbd_smb2_request_check_tcon()
2030 * calls change_to_user() on success.
2032 status = smbd_smb2_request_check_tcon(req);
2033 if (!NT_STATUS_IS_OK(status)) {
2034 return_value = smbd_smb2_request_error(req, status);
2035 break;
2039 START_PROFILE(smb2_ioctl);
2040 return_value = smbd_smb2_request_process_ioctl(req);
2041 END_PROFILE(smb2_ioctl);
2043 break;
2045 case SMB2_OP_CANCEL:
2047 * This call needs to be run as root
2049 * That is what we also do in the SMB1 case.
2051 change_to_root_user();
2054 START_PROFILE(smb2_cancel);
2055 return_value = smbd_smb2_request_process_cancel(req);
2056 END_PROFILE(smb2_cancel);
2058 break;
2060 case SMB2_OP_KEEPALIVE:
2061 /* This call needs to be run as root */
2062 change_to_root_user();
2065 START_PROFILE(smb2_keepalive);
2066 return_value = smbd_smb2_request_process_keepalive(req);
2067 END_PROFILE(smb2_keepalive);
2069 break;
2071 case SMB2_OP_FIND:
2072 if (!NT_STATUS_IS_OK(session_status)) {
2073 return_value = smbd_smb2_request_error(req, session_status);
2074 break;
2077 * This call needs to be run as user.
2079 * smbd_smb2_request_check_tcon()
2080 * calls change_to_user() on success.
2082 status = smbd_smb2_request_check_tcon(req);
2083 if (!NT_STATUS_IS_OK(status)) {
2084 return_value = smbd_smb2_request_error(req, status);
2085 break;
2089 START_PROFILE(smb2_find);
2090 return_value = smbd_smb2_request_process_find(req);
2091 END_PROFILE(smb2_find);
2093 break;
2095 case SMB2_OP_NOTIFY:
2096 if (!NT_STATUS_IS_OK(session_status)) {
2097 return_value = smbd_smb2_request_error(req, session_status);
2098 break;
2101 * This call needs to be run as user.
2103 * smbd_smb2_request_check_tcon()
2104 * calls change_to_user() on success.
2106 status = smbd_smb2_request_check_tcon(req);
2107 if (!NT_STATUS_IS_OK(status)) {
2108 return_value = smbd_smb2_request_error(req, status);
2109 break;
2113 START_PROFILE(smb2_notify);
2114 return_value = smbd_smb2_request_process_notify(req);
2115 END_PROFILE(smb2_notify);
2117 break;
2119 case SMB2_OP_GETINFO:
2120 if (!NT_STATUS_IS_OK(session_status)) {
2121 return_value = smbd_smb2_request_error(req, session_status);
2122 break;
2125 * This call needs to be run as user.
2127 * smbd_smb2_request_check_tcon()
2128 * calls change_to_user() on success.
2130 status = smbd_smb2_request_check_tcon(req);
2131 if (!NT_STATUS_IS_OK(status)) {
2132 return_value = smbd_smb2_request_error(req, status);
2133 break;
2137 START_PROFILE(smb2_getinfo);
2138 return_value = smbd_smb2_request_process_getinfo(req);
2139 END_PROFILE(smb2_getinfo);
2141 break;
2143 case SMB2_OP_SETINFO:
2144 if (!NT_STATUS_IS_OK(session_status)) {
2145 return_value = smbd_smb2_request_error(req, session_status);
2146 break;
2149 * This call needs to be run as user.
2151 * smbd_smb2_request_check_tcon()
2152 * calls change_to_user() on success.
2154 status = smbd_smb2_request_check_tcon(req);
2155 if (!NT_STATUS_IS_OK(status)) {
2156 return_value = smbd_smb2_request_error(req, status);
2157 break;
2161 START_PROFILE(smb2_setinfo);
2162 return_value = smbd_smb2_request_process_setinfo(req);
2163 END_PROFILE(smb2_setinfo);
2165 break;
2167 case SMB2_OP_BREAK:
2168 if (!NT_STATUS_IS_OK(session_status)) {
2169 return_value = smbd_smb2_request_error(req, session_status);
2170 break;
2173 * This call needs to be run as user.
2175 * smbd_smb2_request_check_tcon()
2176 * calls change_to_user() on success.
2178 status = smbd_smb2_request_check_tcon(req);
2179 if (!NT_STATUS_IS_OK(status)) {
2180 return_value = smbd_smb2_request_error(req, status);
2181 break;
2185 START_PROFILE(smb2_break);
2186 return_value = smbd_smb2_request_process_break(req);
2187 END_PROFILE(smb2_break);
2189 break;
2191 default:
2192 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2193 break;
2195 return return_value;
2198 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2200 struct tevent_req *subreq;
2201 int i = req->current_idx;
2203 req->subreq = NULL;
2204 TALLOC_FREE(req->async_te);
2206 req->current_idx += 3;
2208 if (req->current_idx < req->out.vector_count) {
2210 * We must process the remaining compound
2211 * SMB2 requests before any new incoming SMB2
2212 * requests. This is because incoming SMB2
2213 * requests may include a cancel for a
2214 * compound request we haven't processed
2215 * yet.
2217 struct tevent_immediate *im = tevent_create_immediate(req);
2218 if (!im) {
2219 return NT_STATUS_NO_MEMORY;
2221 tevent_schedule_immediate(im,
2222 req->sconn->ev_ctx,
2223 smbd_smb2_request_dispatch_immediate,
2224 req);
2225 return NT_STATUS_OK;
2228 if (req->compound_related) {
2229 req->sconn->smb2.compound_related_in_progress = false;
2232 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2234 /* Set credit for these operations (zero credits if this
2235 is a final reply for an async operation). */
2236 smb2_calculate_credits(req, req);
2238 if (req->do_signing) {
2239 NTSTATUS status;
2240 struct smbXsrv_session *x = req->session;
2241 struct smbXsrv_connection *conn = x->connection;
2242 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2244 status = smb2_signing_sign_pdu(signing_key,
2245 conn->protocol,
2246 &req->out.vector[i], 3);
2247 if (!NT_STATUS_IS_OK(status)) {
2248 return status;
2252 if (DEBUGLEVEL >= 10) {
2253 dbgtext("smbd_smb2_request_reply: sending...\n");
2254 print_req_vectors(req);
2257 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2258 if (req->out.vector_count == 4 &&
2259 req->out.vector[3].iov_base == NULL &&
2260 req->out.vector[3].iov_len != 0) {
2261 /* Dynamic part is NULL. Chop it off,
2262 We're going to send it via sendfile. */
2263 req->out.vector_count -= 1;
2266 subreq = tstream_writev_queue_send(req,
2267 req->sconn->ev_ctx,
2268 req->sconn->smb2.stream,
2269 req->sconn->smb2.send_queue,
2270 req->out.vector,
2271 req->out.vector_count);
2272 if (subreq == NULL) {
2273 return NT_STATUS_NO_MEMORY;
2275 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
2277 * We're done with this request -
2278 * move it off the "being processed" queue.
2280 DLIST_REMOVE(req->sconn->smb2.requests, req);
2282 return NT_STATUS_OK;
2285 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2287 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2288 struct tevent_immediate *im,
2289 void *private_data)
2291 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2292 struct smbd_smb2_request);
2293 struct smbd_server_connection *sconn = req->sconn;
2294 NTSTATUS status;
2296 TALLOC_FREE(im);
2298 if (DEBUGLEVEL >= 10) {
2299 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2300 req->current_idx, req->in.vector_count));
2301 print_req_vectors(req);
2304 status = smbd_smb2_request_dispatch(req);
2305 if (!NT_STATUS_IS_OK(status)) {
2306 smbd_server_connection_terminate(sconn, nt_errstr(status));
2307 return;
2310 status = smbd_smb2_request_next_incoming(sconn);
2311 if (!NT_STATUS_IS_OK(status)) {
2312 smbd_server_connection_terminate(sconn, nt_errstr(status));
2313 return;
2317 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
2319 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
2320 struct smbd_smb2_request);
2321 struct smbd_server_connection *sconn = req->sconn;
2322 int ret;
2323 int sys_errno;
2324 NTSTATUS status;
2326 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2327 TALLOC_FREE(subreq);
2328 TALLOC_FREE(req);
2329 if (ret == -1) {
2330 status = map_nt_error_from_unix(sys_errno);
2331 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
2332 nt_errstr(status)));
2333 smbd_server_connection_terminate(sconn, nt_errstr(status));
2334 return;
2337 status = smbd_smb2_request_next_incoming(sconn);
2338 if (!NT_STATUS_IS_OK(status)) {
2339 smbd_server_connection_terminate(sconn, nt_errstr(status));
2340 return;
2344 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2345 NTSTATUS status,
2346 DATA_BLOB body, DATA_BLOB *dyn,
2347 const char *location)
2349 uint8_t *outhdr;
2350 int i = req->current_idx;
2351 uint32_t next_command_ofs;
2353 DEBUG(10,("smbd_smb2_request_done_ex: "
2354 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2355 i, nt_errstr(status), (unsigned int)body.length,
2356 dyn ? "yes": "no",
2357 (unsigned int)(dyn ? dyn->length : 0),
2358 location));
2360 if (body.length < 2) {
2361 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2364 if ((body.length % 2) != 0) {
2365 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2368 outhdr = (uint8_t *)req->out.vector[i].iov_base;
2370 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2371 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2373 req->out.vector[i+1].iov_base = (void *)body.data;
2374 req->out.vector[i+1].iov_len = body.length;
2376 if (dyn) {
2377 req->out.vector[i+2].iov_base = (void *)dyn->data;
2378 req->out.vector[i+2].iov_len = dyn->length;
2379 } else {
2380 req->out.vector[i+2].iov_base = NULL;
2381 req->out.vector[i+2].iov_len = 0;
2384 /* see if we need to recalculate the offset to the next response */
2385 if (next_command_ofs > 0) {
2386 next_command_ofs = SMB2_HDR_BODY;
2387 next_command_ofs += req->out.vector[i+1].iov_len;
2388 next_command_ofs += req->out.vector[i+2].iov_len;
2391 if ((next_command_ofs % 8) != 0) {
2392 size_t pad_size = 8 - (next_command_ofs % 8);
2393 if (req->out.vector[i+2].iov_len == 0) {
2395 * if the dyn buffer is empty
2396 * we can use it to add padding
2398 uint8_t *pad;
2400 pad = talloc_zero_array(req->out.vector,
2401 uint8_t, pad_size);
2402 if (pad == NULL) {
2403 return smbd_smb2_request_error(req,
2404 NT_STATUS_NO_MEMORY);
2407 req->out.vector[i+2].iov_base = (void *)pad;
2408 req->out.vector[i+2].iov_len = pad_size;
2409 } else {
2411 * For now we copy the dynamic buffer
2412 * and add the padding to the new buffer
2414 size_t old_size;
2415 uint8_t *old_dyn;
2416 size_t new_size;
2417 uint8_t *new_dyn;
2419 old_size = req->out.vector[i+2].iov_len;
2420 old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
2422 new_size = old_size + pad_size;
2423 new_dyn = talloc_zero_array(req->out.vector,
2424 uint8_t, new_size);
2425 if (new_dyn == NULL) {
2426 return smbd_smb2_request_error(req,
2427 NT_STATUS_NO_MEMORY);
2430 memcpy(new_dyn, old_dyn, old_size);
2431 memset(new_dyn + old_size, 0, pad_size);
2433 req->out.vector[i+2].iov_base = (void *)new_dyn;
2434 req->out.vector[i+2].iov_len = new_size;
2436 next_command_ofs += pad_size;
2439 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2441 return smbd_smb2_request_reply(req);
2444 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2445 NTSTATUS status,
2446 DATA_BLOB *info,
2447 const char *location)
2449 DATA_BLOB body;
2450 int i = req->current_idx;
2451 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2453 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2454 i, nt_errstr(status), info ? " +info" : "",
2455 location));
2457 body.data = outhdr + SMB2_HDR_BODY;
2458 body.length = 8;
2459 SSVAL(body.data, 0, 9);
2461 if (info) {
2462 SIVAL(body.data, 0x04, info->length);
2463 } else {
2464 /* Allocated size of req->out.vector[i].iov_base
2465 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2466 * 1 byte without having to do an alloc.
2468 info = talloc_zero_array(req->out.vector,
2469 DATA_BLOB,
2471 if (!info) {
2472 return NT_STATUS_NO_MEMORY;
2474 info->data = ((uint8_t *)outhdr) +
2475 OUTVEC_ALLOC_SIZE - 1;
2476 info->length = 1;
2477 SCVAL(info->data, 0, 0);
2481 * if a request fails, all other remaining
2482 * compounded requests should fail too
2484 req->next_status = NT_STATUS_INVALID_PARAMETER;
2486 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2490 struct smbd_smb2_send_oplock_break_state {
2491 struct smbd_server_connection *sconn;
2492 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
2493 struct iovec vector;
2496 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2498 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2499 uint64_t file_id_persistent,
2500 uint64_t file_id_volatile,
2501 uint8_t oplock_level)
2503 struct smbd_smb2_send_oplock_break_state *state;
2504 struct tevent_req *subreq;
2505 uint8_t *hdr;
2506 uint8_t *body;
2508 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2509 if (state == NULL) {
2510 return NT_STATUS_NO_MEMORY;
2512 state->sconn = sconn;
2514 state->vector.iov_base = (void *)state->buf;
2515 state->vector.iov_len = sizeof(state->buf);
2517 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
2518 hdr = state->buf + 4;
2519 body = hdr + SMB2_HDR_BODY;
2521 SIVAL(hdr, 0, SMB2_MAGIC);
2522 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2523 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2524 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2525 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2526 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2527 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2528 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2529 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2530 SIVAL(hdr, SMB2_HDR_PID, 0);
2531 SIVAL(hdr, SMB2_HDR_TID, 0);
2532 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2533 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2535 SSVAL(body, 0x00, 0x18);
2537 SCVAL(body, 0x02, oplock_level);
2538 SCVAL(body, 0x03, 0); /* reserved */
2539 SIVAL(body, 0x04, 0); /* reserved */
2540 SBVAL(body, 0x08, file_id_persistent);
2541 SBVAL(body, 0x10, file_id_volatile);
2543 subreq = tstream_writev_queue_send(state,
2544 sconn->ev_ctx,
2545 sconn->smb2.stream,
2546 sconn->smb2.send_queue,
2547 &state->vector, 1);
2548 if (subreq == NULL) {
2549 return NT_STATUS_NO_MEMORY;
2551 tevent_req_set_callback(subreq,
2552 smbd_smb2_oplock_break_writev_done,
2553 state);
2555 return NT_STATUS_OK;
2558 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2560 struct smbd_smb2_send_oplock_break_state *state =
2561 tevent_req_callback_data(subreq,
2562 struct smbd_smb2_send_oplock_break_state);
2563 struct smbd_server_connection *sconn = state->sconn;
2564 int ret;
2565 int sys_errno;
2567 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2568 TALLOC_FREE(subreq);
2569 if (ret == -1) {
2570 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2571 smbd_server_connection_terminate(sconn, nt_errstr(status));
2572 return;
2575 TALLOC_FREE(state);
2578 struct smbd_smb2_request_read_state {
2579 struct tevent_context *ev;
2580 struct smbd_server_connection *sconn;
2581 struct smbd_smb2_request *smb2_req;
2582 struct {
2583 uint8_t nbt[NBT_HDR_SIZE];
2584 bool done;
2585 } hdr;
2586 size_t pktlen;
2587 uint8_t *pktbuf;
2590 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2591 void *private_data,
2592 TALLOC_CTX *mem_ctx,
2593 struct iovec **_vector,
2594 size_t *_count);
2595 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2597 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2598 struct tevent_context *ev,
2599 struct smbd_server_connection *sconn)
2601 struct tevent_req *req;
2602 struct smbd_smb2_request_read_state *state;
2603 struct tevent_req *subreq;
2605 req = tevent_req_create(mem_ctx, &state,
2606 struct smbd_smb2_request_read_state);
2607 if (req == NULL) {
2608 return NULL;
2610 state->ev = ev;
2611 state->sconn = sconn;
2613 state->smb2_req = smbd_smb2_request_allocate(state);
2614 if (tevent_req_nomem(state->smb2_req, req)) {
2615 return tevent_req_post(req, ev);
2617 state->smb2_req->sconn = sconn;
2619 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2620 state->ev,
2621 state->sconn->smb2.stream,
2622 state->sconn->smb2.recv_queue,
2623 smbd_smb2_request_next_vector,
2624 state);
2625 if (tevent_req_nomem(subreq, req)) {
2626 return tevent_req_post(req, ev);
2628 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2630 return req;
2633 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2634 void *private_data,
2635 TALLOC_CTX *mem_ctx,
2636 struct iovec **_vector,
2637 size_t *_count)
2639 struct smbd_smb2_request_read_state *state =
2640 talloc_get_type_abort(private_data,
2641 struct smbd_smb2_request_read_state);
2642 struct iovec *vector;
2644 if (state->pktlen > 0) {
2645 /* if there're no remaining bytes, we're done */
2646 *_vector = NULL;
2647 *_count = 0;
2648 return 0;
2651 if (!state->hdr.done) {
2653 * first we need to get the NBT header
2655 vector = talloc_array(mem_ctx, struct iovec, 1);
2656 if (vector == NULL) {
2657 return -1;
2660 vector[0].iov_base = (void *)state->hdr.nbt;
2661 vector[0].iov_len = NBT_HDR_SIZE;
2663 *_vector = vector;
2664 *_count = 1;
2666 state->hdr.done = true;
2667 return 0;
2671 * Now we analyze the NBT header
2673 state->pktlen = smb2_len(state->hdr.nbt);
2675 if (state->pktlen == 0) {
2676 /* if there're no remaining bytes, we're done */
2677 *_vector = NULL;
2678 *_count = 0;
2679 return 0;
2682 state->pktbuf = talloc_array(state->smb2_req, uint8_t, state->pktlen);
2683 if (state->pktbuf == NULL) {
2684 return -1;
2687 vector = talloc_array(mem_ctx, struct iovec, 1);
2688 if (vector == NULL) {
2689 return -1;
2692 vector[0].iov_base = (void *)state->pktbuf;
2693 vector[0].iov_len = state->pktlen;
2695 *_vector = vector;
2696 *_count = 1;
2697 return 0;
2700 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2702 struct tevent_req *req =
2703 tevent_req_callback_data(subreq,
2704 struct tevent_req);
2705 struct smbd_smb2_request_read_state *state =
2706 tevent_req_data(req,
2707 struct smbd_smb2_request_read_state);
2708 int ret;
2709 int sys_errno;
2710 NTSTATUS status;
2711 NTTIME now;
2713 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2714 TALLOC_FREE(subreq);
2715 if (ret == -1) {
2716 status = map_nt_error_from_unix(sys_errno);
2717 tevent_req_nterror(req, status);
2718 return;
2721 if (state->hdr.nbt[0] != 0x00) {
2722 DEBUG(1,("smbd_smb2_request_read_done: ignore NBT[0x%02X] msg\n",
2723 state->hdr.nbt[0]));
2725 ZERO_STRUCT(state->hdr);
2726 TALLOC_FREE(state->pktbuf);
2727 state->pktlen = 0;
2729 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2730 state->ev,
2731 state->sconn->smb2.stream,
2732 state->sconn->smb2.recv_queue,
2733 smbd_smb2_request_next_vector,
2734 state);
2735 if (tevent_req_nomem(subreq, req)) {
2736 return;
2738 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2739 return;
2742 state->smb2_req->request_time = timeval_current();
2743 now = timeval_to_nttime(&state->smb2_req->request_time);
2745 status = smbd_smb2_inbuf_parse_compound(state->smb2_req->sconn->conn,
2746 now,
2747 state->pktbuf,
2748 state->pktlen,
2749 state->smb2_req,
2750 &state->smb2_req->in.vector,
2751 &state->smb2_req->in.vector_count);
2752 if (tevent_req_nterror(req, status)) {
2753 return;
2756 state->smb2_req->current_idx = 1;
2758 tevent_req_done(req);
2761 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2762 TALLOC_CTX *mem_ctx,
2763 struct smbd_smb2_request **_smb2_req)
2765 struct smbd_smb2_request_read_state *state =
2766 tevent_req_data(req,
2767 struct smbd_smb2_request_read_state);
2768 NTSTATUS status;
2770 if (tevent_req_is_nterror(req, &status)) {
2771 tevent_req_received(req);
2772 return status;
2775 *_smb2_req = talloc_move(mem_ctx, &state->smb2_req);
2776 tevent_req_received(req);
2777 return NT_STATUS_OK;
2780 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2782 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2784 size_t max_send_queue_len;
2785 size_t cur_send_queue_len;
2786 struct tevent_req *subreq;
2788 if (sconn->smb2.compound_related_in_progress) {
2790 * Can't read another until the related
2791 * compound is done.
2793 return NT_STATUS_OK;
2796 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
2798 * if there is already a smbd_smb2_request_read
2799 * pending, we are done.
2801 return NT_STATUS_OK;
2804 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2805 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
2807 if (cur_send_queue_len > max_send_queue_len) {
2809 * if we have a lot of requests to send,
2810 * we wait until they are on the wire until we
2811 * ask for the next request.
2813 return NT_STATUS_OK;
2816 /* ask for the next request */
2817 subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn);
2818 if (subreq == NULL) {
2819 return NT_STATUS_NO_MEMORY;
2821 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2823 return NT_STATUS_OK;
2826 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2827 uint8_t *inbuf, size_t size)
2829 NTSTATUS status;
2830 struct smbd_smb2_request *req = NULL;
2832 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2833 (unsigned int)size));
2835 status = smbd_initialize_smb2(sconn);
2836 if (!NT_STATUS_IS_OK(status)) {
2837 smbd_server_connection_terminate(sconn, nt_errstr(status));
2838 return;
2841 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2842 if (!NT_STATUS_IS_OK(status)) {
2843 smbd_server_connection_terminate(sconn, nt_errstr(status));
2844 return;
2847 status = smbd_smb2_request_validate(req);
2848 if (!NT_STATUS_IS_OK(status)) {
2849 smbd_server_connection_terminate(sconn, nt_errstr(status));
2850 return;
2853 status = smbd_smb2_request_setup_out(req);
2854 if (!NT_STATUS_IS_OK(status)) {
2855 smbd_server_connection_terminate(sconn, nt_errstr(status));
2856 return;
2859 status = smbd_smb2_request_dispatch(req);
2860 if (!NT_STATUS_IS_OK(status)) {
2861 smbd_server_connection_terminate(sconn, nt_errstr(status));
2862 return;
2865 status = smbd_smb2_request_next_incoming(sconn);
2866 if (!NT_STATUS_IS_OK(status)) {
2867 smbd_server_connection_terminate(sconn, nt_errstr(status));
2868 return;
2871 sconn->num_requests++;
2874 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2876 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2877 struct smbd_server_connection);
2878 NTSTATUS status;
2879 struct smbd_smb2_request *req = NULL;
2881 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2882 TALLOC_FREE(subreq);
2883 if (!NT_STATUS_IS_OK(status)) {
2884 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2885 nt_errstr(status)));
2886 smbd_server_connection_terminate(sconn, nt_errstr(status));
2887 return;
2890 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2891 req->current_idx, req->in.vector_count));
2893 status = smbd_smb2_request_validate(req);
2894 if (!NT_STATUS_IS_OK(status)) {
2895 smbd_server_connection_terminate(sconn, nt_errstr(status));
2896 return;
2899 status = smbd_smb2_request_setup_out(req);
2900 if (!NT_STATUS_IS_OK(status)) {
2901 smbd_server_connection_terminate(sconn, nt_errstr(status));
2902 return;
2905 status = smbd_smb2_request_dispatch(req);
2906 if (!NT_STATUS_IS_OK(status)) {
2907 smbd_server_connection_terminate(sconn, nt_errstr(status));
2908 return;
2911 status = smbd_smb2_request_next_incoming(sconn);
2912 if (!NT_STATUS_IS_OK(status)) {
2913 smbd_server_connection_terminate(sconn, nt_errstr(status));
2914 return;
2917 sconn->num_requests++;
2919 /* The timeout_processing function isn't run nearly
2920 often enough to implement 'max log size' without
2921 overrunning the size of the file by many megabytes.
2922 This is especially true if we are running at debug
2923 level 10. Checking every 50 SMB2s is a nice
2924 tradeoff of performance vs log file size overrun. */
2926 if ((sconn->num_requests % 50) == 0 &&
2927 need_to_check_log_size()) {
2928 change_to_root_user();
2929 check_log_size();