s3:smb2_server: make use of SMBD_SMB2_OUT_HDR_PTR() smbd_smb2_request_pending_queue()
[Samba.git] / source3 / smbd / smb2_server.c
blob171c999255a100ac7ab8c802440965219290f9f9
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 uint8_t *body = NULL;
296 uint32_t dyn_size;
297 uint8_t *dyn = NULL;
298 struct iovec *iov_tmp;
301 * We need the header plus the body length field
304 if (len < SMB2_HDR_BODY + 2) {
305 DEBUG(10, ("%d bytes left, expected at least %d\n",
306 (int)len, SMB2_HDR_BODY));
307 goto inval;
309 if (IVAL(hdr, 0) != SMB2_MAGIC) {
310 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
311 IVAL(hdr, 0)));
312 goto inval;
314 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
315 DEBUG(10, ("Got HDR len %d, expected %d\n",
316 SVAL(hdr, 4), SMB2_HDR_BODY));
317 goto inval;
320 full_size = len;
321 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
322 body_size = SVAL(hdr, SMB2_HDR_BODY);
324 if (next_command_ofs != 0) {
325 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
326 goto inval;
328 if (next_command_ofs > full_size) {
329 goto inval;
331 full_size = next_command_ofs;
333 if (body_size < 2) {
334 goto inval;
336 body_size &= 0xfffe;
338 if (body_size > (full_size - SMB2_HDR_BODY)) {
340 * let the caller handle the error
342 body_size = full_size - SMB2_HDR_BODY;
344 body = hdr + SMB2_HDR_BODY;
345 dyn = body + body_size;
346 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
348 iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
349 num_iov + SMBD_SMB2_NUM_IOV_PER_REQ);
350 if (iov_tmp == NULL) {
351 TALLOC_FREE(iov);
352 return NT_STATUS_NO_MEMORY;
354 iov = iov_tmp;
355 cur = &iov[num_iov];
356 num_iov += SMBD_SMB2_NUM_IOV_PER_REQ;
358 cur[SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
359 cur[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
360 cur[SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
361 cur[SMBD_SMB2_BODY_IOV_OFS].iov_len = body_size;
362 cur[SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
363 cur[SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_size;
365 taken += full_size;
368 *piov = iov;
369 *pnum_iov = num_iov;
370 return NT_STATUS_OK;
372 inval:
373 TALLOC_FREE(iov);
374 return NT_STATUS_INVALID_PARAMETER;
377 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
378 uint8_t *inbuf, size_t size,
379 struct smbd_smb2_request **_req)
381 struct smbd_smb2_request *req;
382 uint32_t protocol_version;
383 const uint8_t *inhdr = NULL;
384 uint16_t cmd;
385 uint32_t next_command_ofs;
386 NTSTATUS status;
387 NTTIME now;
389 if (size < (4 + SMB2_HDR_BODY + 2)) {
390 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
391 return NT_STATUS_INVALID_PARAMETER;
394 inhdr = inbuf + 4;
396 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
397 if (protocol_version != SMB2_MAGIC) {
398 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
399 protocol_version));
400 return NT_STATUS_INVALID_PARAMETER;
403 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
404 if (cmd != SMB2_OP_NEGPROT) {
405 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
406 cmd));
407 return NT_STATUS_INVALID_PARAMETER;
410 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
411 if (next_command_ofs != 0) {
412 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
413 next_command_ofs));
414 return NT_STATUS_INVALID_PARAMETER;
417 req = smbd_smb2_request_allocate(sconn);
418 if (req == NULL) {
419 return NT_STATUS_NO_MEMORY;
421 req->sconn = sconn;
423 talloc_steal(req, inbuf);
425 req->request_time = timeval_current();
426 now = timeval_to_nttime(&req->request_time);
428 status = smbd_smb2_inbuf_parse_compound(sconn->conn,
429 now,
430 inbuf + NBT_HDR_SIZE,
431 size - NBT_HDR_SIZE,
432 req, &req->in.vector,
433 &req->in.vector_count);
434 if (!NT_STATUS_IS_OK(status)) {
435 TALLOC_FREE(req);
436 return status;
439 req->current_idx = 1;
441 *_req = req;
442 return NT_STATUS_OK;
445 static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
446 uint64_t message_id, uint64_t seq_id)
448 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
449 unsigned int offset;
451 if (seq_id < sconn->smb2.seqnum_low) {
452 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
453 "%llu (sequence id %llu) "
454 "(granted = %u, low = %llu, range = %u)\n",
455 (unsigned long long)message_id,
456 (unsigned long long)seq_id,
457 (unsigned int)sconn->smb2.credits_granted,
458 (unsigned long long)sconn->smb2.seqnum_low,
459 (unsigned int)sconn->smb2.seqnum_range));
460 return false;
463 if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
464 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
465 "%llu (sequence id %llu) "
466 "(granted = %u, low = %llu, range = %u)\n",
467 (unsigned long long)message_id,
468 (unsigned long long)seq_id,
469 (unsigned int)sconn->smb2.credits_granted,
470 (unsigned long long)sconn->smb2.seqnum_low,
471 (unsigned int)sconn->smb2.seqnum_range));
472 return false;
475 offset = seq_id % sconn->smb2.max_credits;
477 if (bitmap_query(credits_bm, offset)) {
478 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
479 "%llu (sequence id %llu) "
480 "(granted = %u, low = %llu, range = %u) "
481 "(bm offset %u)\n",
482 (unsigned long long)message_id,
483 (unsigned long long)seq_id,
484 (unsigned int)sconn->smb2.credits_granted,
485 (unsigned long long)sconn->smb2.seqnum_low,
486 (unsigned int)sconn->smb2.seqnum_range,
487 offset));
488 return false;
491 /* Mark the message_ids as seen in the bitmap. */
492 bitmap_set(credits_bm, offset);
494 if (seq_id != sconn->smb2.seqnum_low) {
495 return true;
499 * Move the window forward by all the message_id's
500 * already seen.
502 while (bitmap_query(credits_bm, offset)) {
503 DEBUG(10,("smb2_validate_sequence_number: clearing "
504 "id %llu (position %u) from bitmap\n",
505 (unsigned long long)(sconn->smb2.seqnum_low),
506 offset));
507 bitmap_clear(credits_bm, offset);
509 sconn->smb2.seqnum_low += 1;
510 sconn->smb2.seqnum_range -= 1;
511 offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
514 return true;
517 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
518 const uint8_t *inhdr)
520 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
521 uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
522 uint16_t credit_charge = 1;
523 uint64_t i;
525 if (opcode == SMB2_OP_CANCEL) {
526 /* SMB2_CANCEL requests by definition resend messageids. */
527 return true;
530 if (sconn->smb2.supports_multicredit) {
531 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
532 credit_charge = MAX(credit_charge, 1);
535 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
536 "credits_granted %llu, "
537 "seqnum low/range: %llu/%llu\n",
538 (unsigned long long) message_id,
539 (unsigned long long) credit_charge,
540 (unsigned long long) sconn->smb2.credits_granted,
541 (unsigned long long) sconn->smb2.seqnum_low,
542 (unsigned long long) sconn->smb2.seqnum_range));
544 if (sconn->smb2.credits_granted < credit_charge) {
545 DEBUG(0, ("smb2_validate_message_id: client used more "
546 "credits than granted, mid %llu, charge %llu, "
547 "credits_granted %llu, "
548 "seqnum low/range: %llu/%llu\n",
549 (unsigned long long) message_id,
550 (unsigned long long) credit_charge,
551 (unsigned long long) sconn->smb2.credits_granted,
552 (unsigned long long) sconn->smb2.seqnum_low,
553 (unsigned long long) sconn->smb2.seqnum_range));
554 return false;
558 * now check the message ids
560 * for multi-credit requests we need to check all current mid plus
561 * the implicit mids caused by the credit charge
562 * e.g. current mid = 15, charge 5 => mark 15-19 as used
565 for (i = 0; i <= (credit_charge-1); i++) {
566 uint64_t id = message_id + i;
567 bool ok;
569 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
570 (unsigned long long)message_id,
571 credit_charge,
572 (unsigned long long)id));
574 ok = smb2_validate_sequence_number(sconn, message_id, id);
575 if (!ok) {
576 return false;
580 /* substract used credits */
581 sconn->smb2.credits_granted -= credit_charge;
583 return true;
586 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
588 int count;
589 int idx;
591 count = req->in.vector_count;
593 if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
594 /* It's not a SMB2 request */
595 return NT_STATUS_INVALID_PARAMETER;
598 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
599 struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
600 struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx);
601 const uint8_t *inhdr = NULL;
602 uint32_t flags;
604 if (hdr->iov_len != SMB2_HDR_BODY) {
605 return NT_STATUS_INVALID_PARAMETER;
608 if (body->iov_len < 2) {
609 return NT_STATUS_INVALID_PARAMETER;
612 inhdr = (const uint8_t *)hdr->iov_base;
614 /* Check the SMB2 header */
615 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
616 return NT_STATUS_INVALID_PARAMETER;
619 if (!smb2_validate_message_id(req->sconn, inhdr)) {
620 return NT_STATUS_INVALID_PARAMETER;
623 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
624 if (idx == 1) {
626 * the 1st request should never have the
627 * SMB2_HDR_FLAG_CHAINED flag set
629 if (flags & SMB2_HDR_FLAG_CHAINED) {
630 req->next_status = NT_STATUS_INVALID_PARAMETER;
631 return NT_STATUS_OK;
633 } else if (idx == 4) {
635 * the 2nd request triggers related vs. unrelated
636 * compounded requests
638 if (flags & SMB2_HDR_FLAG_CHAINED) {
639 req->compound_related = true;
641 } else if (idx > 4) {
642 #if 0
644 * It seems the this tests are wrong
645 * see the SMB2-COMPOUND test
649 * all other requests should match the 2nd one
651 if (flags & SMB2_HDR_FLAG_CHAINED) {
652 if (!req->compound_related) {
653 req->next_status =
654 NT_STATUS_INVALID_PARAMETER;
655 return NT_STATUS_OK;
657 } else {
658 if (req->compound_related) {
659 req->next_status =
660 NT_STATUS_INVALID_PARAMETER;
661 return NT_STATUS_OK;
664 #endif
668 return NT_STATUS_OK;
671 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
672 const struct iovec *in_vector,
673 struct iovec *out_vector)
675 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
676 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
677 uint16_t credit_charge = 1;
678 uint16_t credits_requested;
679 uint32_t out_flags;
680 uint16_t cmd;
681 NTSTATUS out_status;
682 uint16_t credits_granted = 0;
683 uint64_t credits_possible;
684 uint16_t current_max_credits;
687 * first we grant only 1/16th of the max range.
689 * Windows also starts with the 1/16th and then grants
690 * more later. I was only able to trigger higher
691 * values, when using a verify high credit charge.
693 * TODO: scale up depending one load, free memory
694 * or other stuff.
695 * Maybe also on the relationship between number
696 * of requests and the used sequence number.
697 * Which means we would grant more credits
698 * for client which use multi credit requests.
700 current_max_credits = sconn->smb2.max_credits / 16;
701 current_max_credits = MAX(current_max_credits, 1);
703 if (sconn->smb2.supports_multicredit) {
704 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
705 credit_charge = MAX(credit_charge, 1);
708 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
709 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
710 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
711 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
713 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
714 SMB_ASSERT(sconn->smb2.max_credits >= credit_charge);
716 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
718 * In case we already send an async interim
719 * response, we should not grant
720 * credits on the final response.
722 credits_granted = 0;
723 } else if (credits_requested > 0) {
724 uint16_t additional_max = 0;
725 uint16_t additional_credits = credits_requested - 1;
727 switch (cmd) {
728 case SMB2_OP_NEGPROT:
729 break;
730 case SMB2_OP_SESSSETUP:
732 * Windows 2012 RC1 starts to grant
733 * additional credits
734 * with a successful session setup
736 if (NT_STATUS_IS_OK(out_status)) {
737 additional_max = 32;
739 break;
740 default:
742 * We match windows and only grant additional credits
743 * in chunks of 32.
745 additional_max = 32;
746 break;
749 additional_credits = MIN(additional_credits, additional_max);
751 credits_granted = credit_charge + additional_credits;
752 } else if (sconn->smb2.credits_granted == 0) {
754 * Make sure the client has always at least one credit
756 credits_granted = 1;
760 * sequence numbers should not wrap
762 * 1. calculate the possible credits until
763 * the sequence numbers start to wrap on 64-bit.
765 * 2. UINT64_MAX is used for Break Notifications.
767 * 2. truncate the possible credits to the maximum
768 * credits we want to grant to the client in total.
770 * 3. remove the range we'll already granted to the client
771 * this makes sure the client consumes the lowest sequence
772 * number, before we can grant additional credits.
774 credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
775 if (credits_possible > 0) {
776 /* remove UINT64_MAX */
777 credits_possible -= 1;
779 credits_possible = MIN(credits_possible, current_max_credits);
780 credits_possible -= sconn->smb2.seqnum_range;
782 credits_granted = MIN(credits_granted, credits_possible);
784 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
785 sconn->smb2.credits_granted += credits_granted;
786 sconn->smb2.seqnum_range += credits_granted;
788 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
789 "granted %u, current possible/max %u/%u, "
790 "total granted/max/low/range %u/%u/%llu/%u\n",
791 (unsigned int)credits_requested,
792 (unsigned int)credit_charge,
793 (unsigned int)credits_granted,
794 (unsigned int)credits_possible,
795 (unsigned int)current_max_credits,
796 (unsigned int)sconn->smb2.credits_granted,
797 (unsigned int)sconn->smb2.max_credits,
798 (unsigned long long)sconn->smb2.seqnum_low,
799 (unsigned int)sconn->smb2.seqnum_range));
802 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
803 struct smbd_smb2_request *outreq)
805 int count, idx;
806 uint16_t total_credits = 0;
808 count = outreq->out.vector_count;
810 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
811 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(inreq,in,idx);
812 struct iovec *outhdr_v = SMBD_SMB2_IDX_HDR_IOV(outreq,out,idx);
813 uint8_t *outhdr = (uint8_t *)outhdr_v->iov_base;
815 smb2_set_operation_credit(outreq->sconn, inhdr_v, outhdr_v);
817 /* To match Windows, count up what we
818 just granted. */
819 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
820 /* Set to zero in all but the last reply. */
821 if (idx + SMBD_SMB2_NUM_IOV_PER_REQ < count) {
822 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
823 } else {
824 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
829 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
831 struct iovec *vector;
832 int count;
833 int idx;
835 count = req->in.vector_count;
836 vector = talloc_zero_array(req, struct iovec, count);
837 if (vector == NULL) {
838 return NT_STATUS_NO_MEMORY;
841 vector[0].iov_base = req->out.nbt_hdr;
842 vector[0].iov_len = 4;
843 SIVAL(req->out.nbt_hdr, 0, 0);
845 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
846 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
847 const uint8_t *inhdr = (const uint8_t *)inhdr_v->iov_base;
848 uint8_t *outhdr = NULL;
849 uint8_t *outbody = NULL;
850 uint32_t next_command_ofs = 0;
851 struct iovec *current = &vector[idx];
853 if ((idx + SMBD_SMB2_NUM_IOV_PER_REQ) < count) {
854 /* we have a next command -
855 * setup for the error case. */
856 next_command_ofs = SMB2_HDR_BODY + 9;
859 outhdr = talloc_zero_array(vector, uint8_t,
860 OUTVEC_ALLOC_SIZE);
861 if (outhdr == NULL) {
862 return NT_STATUS_NO_MEMORY;
865 outbody = outhdr + SMB2_HDR_BODY;
867 current[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)outhdr;
868 current[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
870 current[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)outbody;
871 current[SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
873 current[SMBD_SMB2_DYN_IOV_OFS].iov_base = NULL;
874 current[SMBD_SMB2_DYN_IOV_OFS].iov_len = 0;
876 /* setup the SMB2 header */
877 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
878 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
879 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
880 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
881 SIVAL(outhdr, SMB2_HDR_STATUS,
882 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
883 SSVAL(outhdr, SMB2_HDR_OPCODE,
884 SVAL(inhdr, SMB2_HDR_OPCODE));
885 SIVAL(outhdr, SMB2_HDR_FLAGS,
886 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
887 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
888 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
889 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
890 SIVAL(outhdr, SMB2_HDR_PID,
891 IVAL(inhdr, SMB2_HDR_PID));
892 SIVAL(outhdr, SMB2_HDR_TID,
893 IVAL(inhdr, SMB2_HDR_TID));
894 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
895 BVAL(inhdr, SMB2_HDR_SESSION_ID));
896 memcpy(outhdr + SMB2_HDR_SIGNATURE,
897 inhdr + SMB2_HDR_SIGNATURE, 16);
899 /* setup error body header */
900 SSVAL(outbody, 0x00, 0x08 + 1);
901 SSVAL(outbody, 0x02, 0);
902 SIVAL(outbody, 0x04, 0);
905 req->out.vector = vector;
906 req->out.vector_count = count;
908 /* setup the length of the NBT packet */
909 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
911 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
913 return NT_STATUS_OK;
916 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
917 const char *reason,
918 const char *location)
920 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
921 reason, location));
922 exit_server_cleanly(reason);
925 static bool dup_smb2_vec3(TALLOC_CTX *ctx,
926 struct iovec *outvec,
927 const struct iovec *srcvec)
929 /* vec[0] is always boilerplate and must
930 * be allocated with size OUTVEC_ALLOC_SIZE. */
932 outvec[0].iov_base = talloc_memdup(ctx,
933 srcvec[0].iov_base,
934 OUTVEC_ALLOC_SIZE);
935 if (!outvec[0].iov_base) {
936 return false;
938 outvec[0].iov_len = SMB2_HDR_BODY;
941 * If this is a "standard" vec[1] of length 8,
942 * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
943 * then duplicate this. Else use talloc_memdup().
946 if (srcvec[1].iov_len == 8 &&
947 srcvec[1].iov_base ==
948 ((uint8_t *)srcvec[0].iov_base) +
949 SMB2_HDR_BODY) {
950 outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
951 SMB2_HDR_BODY;
952 outvec[1].iov_len = 8;
953 } else {
954 outvec[1].iov_base = talloc_memdup(ctx,
955 srcvec[1].iov_base,
956 srcvec[1].iov_len);
957 if (!outvec[1].iov_base) {
958 return false;
960 outvec[1].iov_len = srcvec[1].iov_len;
964 * If this is a "standard" vec[2] of length 1,
965 * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
966 * then duplicate this. Else use talloc_memdup().
969 if (srcvec[2].iov_base &&
970 srcvec[2].iov_len) {
971 if (srcvec[2].iov_base ==
972 ((uint8_t *)srcvec[0].iov_base) +
973 (OUTVEC_ALLOC_SIZE - 1) &&
974 srcvec[2].iov_len == 1) {
975 /* Common SMB2 error packet case. */
976 outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
977 (OUTVEC_ALLOC_SIZE - 1);
978 } else {
979 outvec[2].iov_base = talloc_memdup(ctx,
980 srcvec[2].iov_base,
981 srcvec[2].iov_len);
982 if (!outvec[2].iov_base) {
983 return false;
986 outvec[2].iov_len = srcvec[2].iov_len;
987 } else {
988 outvec[2].iov_base = NULL;
989 outvec[2].iov_len = 0;
991 return true;
994 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
996 struct smbd_smb2_request *newreq = NULL;
997 struct iovec *outvec = NULL;
998 int count = req->out.vector_count;
999 int i;
1001 newreq = smbd_smb2_request_allocate(req->sconn);
1002 if (!newreq) {
1003 return NULL;
1006 newreq->sconn = req->sconn;
1007 newreq->session = req->session;
1008 newreq->do_signing = req->do_signing;
1009 newreq->current_idx = req->current_idx;
1011 outvec = talloc_zero_array(newreq, struct iovec, count);
1012 if (!outvec) {
1013 TALLOC_FREE(newreq);
1014 return NULL;
1016 newreq->out.vector = outvec;
1017 newreq->out.vector_count = count;
1019 /* Setup the outvec's identically to req. */
1020 outvec[0].iov_base = newreq->out.nbt_hdr;
1021 outvec[0].iov_len = 4;
1022 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
1024 /* Setup the vectors identically to the ones in req. */
1025 for (i = 1; i < count; i += SMBD_SMB2_NUM_IOV_PER_REQ) {
1026 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
1027 break;
1031 if (i < count) {
1032 /* Alloc failed. */
1033 TALLOC_FREE(newreq);
1034 return NULL;
1037 smb2_setup_nbt_length(newreq->out.vector,
1038 newreq->out.vector_count);
1040 return newreq;
1043 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
1045 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1047 int i = 0;
1048 uint8_t *outhdr = NULL;
1049 struct smbd_smb2_request *nreq = NULL;
1051 /* Create a new smb2 request we'll use
1052 for the interim return. */
1053 nreq = dup_smb2_req(req);
1054 if (!nreq) {
1055 return NT_STATUS_NO_MEMORY;
1058 /* Lose the last X out vectors. They're the
1059 ones we'll be using for the async reply. */
1060 nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ;
1062 smb2_setup_nbt_length(nreq->out.vector,
1063 nreq->out.vector_count);
1065 /* Step back to the previous reply. */
1066 i = nreq->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
1067 outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
1068 /* And end the chain. */
1069 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1071 /* Calculate outgoing credits */
1072 smb2_calculate_credits(req, nreq);
1074 /* Re-sign if needed. */
1075 if (nreq->do_signing) {
1076 NTSTATUS status;
1077 struct smbXsrv_session *x = nreq->session;
1078 struct smbXsrv_connection *conn = x->connection;
1079 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1081 status = smb2_signing_sign_pdu(signing_key,
1082 conn->protocol,
1083 &nreq->out.vector[i],
1084 SMBD_SMB2_NUM_IOV_PER_REQ);
1085 if (!NT_STATUS_IS_OK(status)) {
1086 return status;
1089 if (DEBUGLEVEL >= 10) {
1090 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1091 (unsigned int)nreq->current_idx );
1092 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1093 (unsigned int)nreq->out.vector_count );
1094 print_req_vectors(nreq);
1096 nreq->subreq = tstream_writev_queue_send(nreq,
1097 nreq->sconn->ev_ctx,
1098 nreq->sconn->smb2.stream,
1099 nreq->sconn->smb2.send_queue,
1100 nreq->out.vector,
1101 nreq->out.vector_count);
1103 if (nreq->subreq == NULL) {
1104 return NT_STATUS_NO_MEMORY;
1107 tevent_req_set_callback(nreq->subreq,
1108 smbd_smb2_request_writev_done,
1109 nreq);
1111 return NT_STATUS_OK;
1114 struct smbd_smb2_request_pending_state {
1115 struct smbd_server_connection *sconn;
1116 uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
1117 struct iovec vector[3];
1120 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
1122 struct smbd_smb2_request_pending_state *state =
1123 tevent_req_callback_data(subreq,
1124 struct smbd_smb2_request_pending_state);
1125 struct smbd_server_connection *sconn = state->sconn;
1126 int ret;
1127 int sys_errno;
1129 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1130 TALLOC_FREE(subreq);
1131 if (ret == -1) {
1132 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1133 smbd_server_connection_terminate(sconn, nt_errstr(status));
1134 return;
1137 TALLOC_FREE(state);
1140 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1141 struct tevent_timer *te,
1142 struct timeval current_time,
1143 void *private_data);
1145 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1146 struct tevent_req *subreq,
1147 uint32_t defer_time)
1149 NTSTATUS status;
1150 int i = req->current_idx;
1151 struct timeval defer_endtime;
1152 uint8_t *outhdr = NULL;
1153 uint32_t flags;
1155 if (!tevent_req_is_in_progress(subreq)) {
1156 return NT_STATUS_OK;
1159 req->subreq = subreq;
1160 subreq = NULL;
1162 if (req->async_te) {
1163 /* We're already async. */
1164 return NT_STATUS_OK;
1167 outhdr = (uint8_t *)req->out.vector[i].iov_base;
1168 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1169 if (flags & SMB2_HDR_FLAG_ASYNC) {
1170 /* We're already async. */
1171 return NT_STATUS_OK;
1174 if (req->in.vector_count > i + SMBD_SMB2_NUM_IOV_PER_REQ) {
1176 * We're trying to go async in a compound
1177 * request chain. This is not allowed.
1178 * Cancel the outstanding request.
1180 tevent_req_cancel(req->subreq);
1181 return smbd_smb2_request_error(req,
1182 NT_STATUS_INSUFFICIENT_RESOURCES);
1185 if (DEBUGLEVEL >= 10) {
1186 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1187 (unsigned int)req->current_idx );
1188 print_req_vectors(req);
1191 if (req->out.vector_count >= (2*SMBD_SMB2_NUM_IOV_PER_REQ)) {
1193 * This is a compound reply. We
1194 * must do an interim response
1195 * followed by the async response
1196 * to match W2K8R2.
1198 status = smb2_send_async_interim_response(req);
1199 if (!NT_STATUS_IS_OK(status)) {
1200 return status;
1204 * We're splitting off the last SMB2
1205 * request in a compound set, and the
1206 * smb2_send_async_interim_response()
1207 * call above just sent all the replies
1208 * for the previous SMB2 requests in
1209 * this compound set. So we're no longer
1210 * in the "compound_related_in_progress"
1211 * state, and this is no longer a compound
1212 * request.
1214 req->compound_related = false;
1215 req->sconn->smb2.compound_related_in_progress = false;
1217 /* Re-arrange the in.vectors. */
1218 req->in.vector[1] = req->in.vector[i];
1219 req->in.vector[2] = req->in.vector[i+1];
1220 req->in.vector[3] = req->in.vector[i+2];
1221 req->in.vector_count = 4;
1223 /* Reset the new in size. */
1224 smb2_setup_nbt_length(req->in.vector, 4);
1226 /* Now recreate the out.vectors. */
1227 outvec = talloc_zero_array(req, struct iovec, 4);
1228 if (!outvec) {
1229 return NT_STATUS_NO_MEMORY;
1232 /* 0 is always boilerplate and must
1233 * be of size 4 for the length field. */
1235 outvec[0].iov_base = req->out.nbt_hdr;
1236 outvec[0].iov_len = 4;
1237 SIVAL(req->out.nbt_hdr, 0, 0);
1239 if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
1240 return NT_STATUS_NO_MEMORY;
1243 TALLOC_FREE(req->out.vector);
1245 req->out.vector = outvec;
1247 req->current_idx = 1;
1248 req->out.vector_count = 4;
1250 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1251 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1252 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1255 defer_endtime = timeval_current_ofs_usec(defer_time);
1256 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1257 req, defer_endtime,
1258 smbd_smb2_request_pending_timer,
1259 req);
1260 if (req->async_te == NULL) {
1261 return NT_STATUS_NO_MEMORY;
1264 return NT_STATUS_OK;
1267 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1268 struct tevent_timer *te,
1269 struct timeval current_time,
1270 void *private_data)
1272 struct smbd_smb2_request *req =
1273 talloc_get_type_abort(private_data,
1274 struct smbd_smb2_request);
1275 struct smbd_smb2_request_pending_state *state = NULL;
1276 uint8_t *outhdr = NULL;
1277 const uint8_t *inhdr = NULL;
1278 uint8_t *hdr = NULL;
1279 uint8_t *body = NULL;
1280 uint32_t flags = 0;
1281 uint64_t message_id = 0;
1282 uint64_t async_id = 0;
1283 struct tevent_req *subreq = NULL;
1285 TALLOC_FREE(req->async_te);
1287 /* Ensure our final reply matches the interim one. */
1288 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1289 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1290 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1291 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1293 async_id = message_id; /* keep it simple for now... */
1295 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1296 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1298 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1299 "going async\n",
1300 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1301 (unsigned long long)async_id ));
1304 * What we send is identical to a smbd_smb2_request_error
1305 * packet with an error status of STATUS_PENDING. Make use
1306 * of this fact sometime when refactoring. JRA.
1309 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1310 if (state == NULL) {
1311 smbd_server_connection_terminate(req->sconn,
1312 nt_errstr(NT_STATUS_NO_MEMORY));
1313 return;
1315 state->sconn = req->sconn;
1317 state->vector[0].iov_base = (void *)state->buf;
1318 state->vector[0].iov_len = 4;
1320 state->vector[1].iov_base = state->buf + 4;
1321 state->vector[1].iov_len = SMB2_HDR_BODY;
1323 state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
1324 state->vector[2].iov_len = 9;
1326 smb2_setup_nbt_length(state->vector, 3);
1328 hdr = (uint8_t *)state->vector[1].iov_base;
1329 body = (uint8_t *)state->vector[2].iov_base;
1331 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1332 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1333 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1334 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1335 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1337 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1338 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1339 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1340 SBVAL(hdr, SMB2_HDR_PID, async_id);
1341 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1342 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1343 memcpy(hdr+SMB2_HDR_SIGNATURE,
1344 outhdr+SMB2_HDR_SIGNATURE, 16);
1346 SSVAL(body, 0x00, 0x08 + 1);
1348 SCVAL(body, 0x02, 0);
1349 SCVAL(body, 0x03, 0);
1350 SIVAL(body, 0x04, 0);
1351 /* Match W2K8R2... */
1352 SCVAL(body, 0x08, 0x21);
1354 /* Ensure we correctly go through crediting. Grant
1355 the credits now, and zero credits on the final
1356 response. */
1357 smb2_set_operation_credit(req->sconn,
1358 SMBD_SMB2_IN_HDR_IOV(req),
1359 &state->vector[1]);
1361 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1363 if (req->do_signing) {
1364 NTSTATUS status;
1365 struct smbXsrv_session *x = req->session;
1366 struct smbXsrv_connection *conn = x->connection;
1367 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1369 status = smb2_signing_sign_pdu(signing_key,
1370 conn->protocol,
1371 &state->vector[1], 2);
1372 if (!NT_STATUS_IS_OK(status)) {
1373 smbd_server_connection_terminate(req->sconn,
1374 nt_errstr(status));
1375 return;
1379 subreq = tstream_writev_queue_send(state,
1380 state->sconn->ev_ctx,
1381 state->sconn->smb2.stream,
1382 state->sconn->smb2.send_queue,
1383 state->vector,
1385 if (subreq == NULL) {
1386 smbd_server_connection_terminate(state->sconn,
1387 nt_errstr(NT_STATUS_NO_MEMORY));
1388 return;
1390 tevent_req_set_callback(subreq,
1391 smbd_smb2_request_pending_writev_done,
1392 state);
1395 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1397 struct smbd_server_connection *sconn = req->sconn;
1398 struct smbd_smb2_request *cur;
1399 const uint8_t *inhdr;
1400 uint32_t flags;
1401 uint64_t search_message_id;
1402 uint64_t search_async_id;
1403 uint64_t found_id;
1405 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1407 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1408 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1409 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1412 * we don't need the request anymore
1413 * cancel requests never have a response
1415 DLIST_REMOVE(req->sconn->smb2.requests, req);
1416 TALLOC_FREE(req);
1418 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1419 const uint8_t *outhdr;
1420 uint64_t message_id;
1421 uint64_t async_id;
1423 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1425 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1426 async_id = BVAL(outhdr, SMB2_HDR_PID);
1428 if (flags & SMB2_HDR_FLAG_ASYNC) {
1429 if (search_async_id == async_id) {
1430 found_id = async_id;
1431 break;
1433 } else {
1434 if (search_message_id == message_id) {
1435 found_id = message_id;
1436 break;
1441 if (cur && cur->subreq) {
1442 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1443 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1444 "cancel opcode[%s] mid %llu\n",
1445 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1446 (unsigned long long)found_id ));
1447 tevent_req_cancel(cur->subreq);
1450 return NT_STATUS_OK;
1453 /*************************************************************
1454 Ensure an incoming tid is a valid one for us to access.
1455 Change to the associated uid credentials and chdir to the
1456 valid tid directory.
1457 *************************************************************/
1459 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1461 const uint8_t *inhdr;
1462 uint32_t in_flags;
1463 uint32_t in_tid;
1464 struct smbXsrv_tcon *tcon;
1465 NTSTATUS status;
1466 NTTIME now = timeval_to_nttime(&req->request_time);
1468 req->tcon = NULL;
1470 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1472 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1473 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1475 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1476 in_tid = req->last_tid;
1479 status = smb2srv_tcon_lookup(req->session,
1480 in_tid, now, &tcon);
1481 if (!NT_STATUS_IS_OK(status)) {
1482 return status;
1485 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1486 return NT_STATUS_ACCESS_DENIED;
1489 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1490 if (!set_current_service(tcon->compat, 0, true)) {
1491 return NT_STATUS_ACCESS_DENIED;
1494 req->tcon = tcon;
1495 req->last_tid = in_tid;
1497 return NT_STATUS_OK;
1500 /*************************************************************
1501 Ensure an incoming session_id is a valid one for us to access.
1502 *************************************************************/
1504 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1506 const uint8_t *inhdr;
1507 uint32_t in_flags;
1508 uint16_t in_opcode;
1509 uint64_t in_session_id;
1510 struct smbXsrv_session *session = NULL;
1511 struct auth_session_info *session_info;
1512 NTSTATUS status;
1513 NTTIME now = timeval_to_nttime(&req->request_time);
1515 req->session = NULL;
1516 req->tcon = NULL;
1518 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1520 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1521 in_opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1522 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1524 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1525 in_session_id = req->last_session_id;
1528 /* lookup an existing session */
1529 status = smb2srv_session_lookup(req->sconn->conn,
1530 in_session_id, now,
1531 &session);
1532 if (session) {
1533 req->session = session;
1534 req->last_session_id = in_session_id;
1536 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1537 switch (in_opcode) {
1538 case SMB2_OP_SESSSETUP:
1539 status = NT_STATUS_OK;
1540 break;
1541 default:
1542 break;
1545 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1546 switch (in_opcode) {
1547 case SMB2_OP_TCON:
1548 case SMB2_OP_CREATE:
1549 case SMB2_OP_GETINFO:
1550 case SMB2_OP_SETINFO:
1551 return NT_STATUS_INVALID_HANDLE;
1552 default:
1554 * Notice the check for
1555 * (session_info == NULL)
1556 * below.
1558 status = NT_STATUS_OK;
1559 break;
1562 if (!NT_STATUS_IS_OK(status)) {
1563 return status;
1566 session_info = session->global->auth_session_info;
1567 if (session_info == NULL) {
1568 return NT_STATUS_INVALID_HANDLE;
1571 set_current_user_info(session_info->unix_info->sanitized_username,
1572 session_info->unix_info->unix_name,
1573 session_info->info->domain_name);
1575 return NT_STATUS_OK;
1578 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1579 uint32_t data_length)
1581 uint16_t needed_charge;
1582 uint16_t credit_charge = 1;
1583 const uint8_t *inhdr;
1585 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1587 if (req->sconn->smb2.supports_multicredit) {
1588 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1589 credit_charge = MAX(credit_charge, 1);
1592 needed_charge = (data_length - 1)/ 65536 + 1;
1594 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1595 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1596 credit_charge, needed_charge));
1598 if (needed_charge > credit_charge) {
1599 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1600 credit_charge, needed_charge));
1601 return NT_STATUS_INVALID_PARAMETER;
1604 return NT_STATUS_OK;
1607 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1608 size_t expected_body_size)
1610 const uint8_t *inhdr;
1611 uint16_t opcode;
1612 const uint8_t *inbody;
1613 int i = req->current_idx;
1614 size_t body_size;
1615 size_t min_dyn_size = expected_body_size & 0x00000001;
1618 * The following should be checked already.
1620 if ((i+2) > req->in.vector_count) {
1621 return NT_STATUS_INTERNAL_ERROR;
1623 if (req->in.vector[i+0].iov_len != SMB2_HDR_BODY) {
1624 return NT_STATUS_INTERNAL_ERROR;
1626 if (req->in.vector[i+1].iov_len < 2) {
1627 return NT_STATUS_INTERNAL_ERROR;
1630 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
1631 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1633 switch (opcode) {
1634 case SMB2_OP_IOCTL:
1635 case SMB2_OP_GETINFO:
1636 min_dyn_size = 0;
1637 break;
1641 * Now check the expected body size,
1642 * where the last byte might be in the
1643 * dynamic section..
1645 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1646 return NT_STATUS_INVALID_PARAMETER;
1648 if (req->in.vector[i+2].iov_len < min_dyn_size) {
1649 return NT_STATUS_INVALID_PARAMETER;
1652 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1654 body_size = SVAL(inbody, 0x00);
1655 if (body_size != expected_body_size) {
1656 return NT_STATUS_INVALID_PARAMETER;
1659 return NT_STATUS_OK;
1662 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1664 struct smbXsrv_connection *conn = req->sconn->conn;
1665 const struct smbd_smb2_dispatch_table *call = NULL;
1666 const uint8_t *inhdr;
1667 uint16_t opcode;
1668 uint32_t flags;
1669 uint64_t mid;
1670 NTSTATUS status;
1671 NTSTATUS session_status;
1672 uint32_t allowed_flags;
1673 NTSTATUS return_value;
1674 struct smbXsrv_session *x = NULL;
1675 bool signing_required = false;
1677 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1679 /* TODO: verify more things */
1681 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1682 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1683 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1684 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1685 smb2_opcode_name(opcode),
1686 (unsigned long long)mid));
1688 if (conn->protocol >= PROTOCOL_SMB2_02) {
1690 * once the protocol is negotiated
1691 * SMB2_OP_NEGPROT is not allowed anymore
1693 if (opcode == SMB2_OP_NEGPROT) {
1694 /* drop the connection */
1695 return NT_STATUS_INVALID_PARAMETER;
1697 } else {
1699 * if the protocol is not negotiated yet
1700 * only SMB2_OP_NEGPROT is allowed.
1702 if (opcode != SMB2_OP_NEGPROT) {
1703 /* drop the connection */
1704 return NT_STATUS_INVALID_PARAMETER;
1708 call = smbd_smb2_call(opcode);
1709 if (call == NULL) {
1710 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1713 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1714 SMB2_HDR_FLAG_SIGNED |
1715 SMB2_HDR_FLAG_DFS;
1716 if (opcode == SMB2_OP_CANCEL) {
1717 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1719 if ((flags & ~allowed_flags) != 0) {
1720 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1724 * Check if the client provided a valid session id,
1725 * if so smbd_smb2_request_check_session() calls
1726 * set_current_user_info().
1728 * As some command don't require a valid session id
1729 * we defer the check of the session_status
1731 session_status = smbd_smb2_request_check_session(req);
1732 x = req->session;
1734 if (x != NULL) {
1735 signing_required = x->global->signing_required;
1737 if (opcode == SMB2_OP_SESSSETUP &&
1738 x->global->channels[0].signing_key.length) {
1739 signing_required = true;
1743 req->do_signing = false;
1744 if (flags & SMB2_HDR_FLAG_SIGNED) {
1745 DATA_BLOB signing_key;
1747 if (x == NULL) {
1748 return smbd_smb2_request_error(
1749 req, NT_STATUS_ACCESS_DENIED);
1752 signing_key = x->global->channels[0].signing_key;
1754 if (!NT_STATUS_IS_OK(session_status)) {
1755 return smbd_smb2_request_error(req, session_status);
1758 req->do_signing = true;
1759 status = smb2_signing_check_pdu(signing_key,
1760 conn->protocol,
1761 SMBD_SMB2_IN_HDR_IOV(req),
1762 SMBD_SMB2_NUM_IOV_PER_REQ);
1763 if (!NT_STATUS_IS_OK(status)) {
1764 return smbd_smb2_request_error(req, status);
1766 } else if (opcode == SMB2_OP_CANCEL) {
1767 /* Cancel requests are allowed to skip the signing */
1768 } else if (signing_required) {
1769 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1772 if (flags & SMB2_HDR_FLAG_CHAINED) {
1774 * This check is mostly for giving the correct error code
1775 * for compounded requests.
1777 * TODO: we may need to move this after the session
1778 * and tcon checks.
1780 if (!NT_STATUS_IS_OK(req->next_status)) {
1781 return smbd_smb2_request_error(req, req->next_status);
1783 } else {
1784 req->compat_chain_fsp = NULL;
1787 if (req->compound_related) {
1788 req->sconn->smb2.compound_related_in_progress = true;
1791 if (call->need_session) {
1792 if (!NT_STATUS_IS_OK(session_status)) {
1793 return smbd_smb2_request_error(req, session_status);
1797 if (call->need_tcon) {
1798 SMB_ASSERT(call->need_session);
1801 * This call needs to be run as user.
1803 * smbd_smb2_request_check_tcon()
1804 * calls change_to_user() on success.
1806 status = smbd_smb2_request_check_tcon(req);
1807 if (!NT_STATUS_IS_OK(status)) {
1808 return smbd_smb2_request_error(req, status);
1812 if (call->as_root) {
1813 /* This call needs to be run as root */
1814 change_to_root_user();
1815 } else {
1816 SMB_ASSERT(call->need_tcon);
1819 switch (opcode) {
1820 case SMB2_OP_NEGPROT:
1822 START_PROFILE(smb2_negprot);
1823 return_value = smbd_smb2_request_process_negprot(req);
1824 END_PROFILE(smb2_negprot);
1826 break;
1828 case SMB2_OP_SESSSETUP:
1830 START_PROFILE(smb2_sesssetup);
1831 return_value = smbd_smb2_request_process_sesssetup(req);
1832 END_PROFILE(smb2_sesssetup);
1834 break;
1836 case SMB2_OP_LOGOFF:
1838 START_PROFILE(smb2_logoff);
1839 return_value = smbd_smb2_request_process_logoff(req);
1840 END_PROFILE(smb2_logoff);
1842 break;
1844 case SMB2_OP_TCON:
1846 START_PROFILE(smb2_tcon);
1847 return_value = smbd_smb2_request_process_tcon(req);
1848 END_PROFILE(smb2_tcon);
1850 break;
1852 case SMB2_OP_TDIS:
1854 START_PROFILE(smb2_tdis);
1855 return_value = smbd_smb2_request_process_tdis(req);
1856 END_PROFILE(smb2_tdis);
1858 break;
1860 case SMB2_OP_CREATE:
1862 START_PROFILE(smb2_create);
1863 return_value = smbd_smb2_request_process_create(req);
1864 END_PROFILE(smb2_create);
1866 break;
1868 case SMB2_OP_CLOSE:
1870 START_PROFILE(smb2_close);
1871 return_value = smbd_smb2_request_process_close(req);
1872 END_PROFILE(smb2_close);
1874 break;
1876 case SMB2_OP_FLUSH:
1878 START_PROFILE(smb2_flush);
1879 return_value = smbd_smb2_request_process_flush(req);
1880 END_PROFILE(smb2_flush);
1882 break;
1884 case SMB2_OP_READ:
1886 START_PROFILE(smb2_read);
1887 return_value = smbd_smb2_request_process_read(req);
1888 END_PROFILE(smb2_read);
1890 break;
1892 case SMB2_OP_WRITE:
1894 START_PROFILE(smb2_write);
1895 return_value = smbd_smb2_request_process_write(req);
1896 END_PROFILE(smb2_write);
1898 break;
1900 case SMB2_OP_LOCK:
1902 START_PROFILE(smb2_lock);
1903 return_value = smbd_smb2_request_process_lock(req);
1904 END_PROFILE(smb2_lock);
1906 break;
1908 case SMB2_OP_IOCTL:
1910 START_PROFILE(smb2_ioctl);
1911 return_value = smbd_smb2_request_process_ioctl(req);
1912 END_PROFILE(smb2_ioctl);
1914 break;
1916 case SMB2_OP_CANCEL:
1918 START_PROFILE(smb2_cancel);
1919 return_value = smbd_smb2_request_process_cancel(req);
1920 END_PROFILE(smb2_cancel);
1922 break;
1924 case SMB2_OP_KEEPALIVE:
1926 START_PROFILE(smb2_keepalive);
1927 return_value = smbd_smb2_request_process_keepalive(req);
1928 END_PROFILE(smb2_keepalive);
1930 break;
1932 case SMB2_OP_FIND:
1934 START_PROFILE(smb2_find);
1935 return_value = smbd_smb2_request_process_find(req);
1936 END_PROFILE(smb2_find);
1938 break;
1940 case SMB2_OP_NOTIFY:
1942 START_PROFILE(smb2_notify);
1943 return_value = smbd_smb2_request_process_notify(req);
1944 END_PROFILE(smb2_notify);
1946 break;
1948 case SMB2_OP_GETINFO:
1950 START_PROFILE(smb2_getinfo);
1951 return_value = smbd_smb2_request_process_getinfo(req);
1952 END_PROFILE(smb2_getinfo);
1954 break;
1956 case SMB2_OP_SETINFO:
1958 START_PROFILE(smb2_setinfo);
1959 return_value = smbd_smb2_request_process_setinfo(req);
1960 END_PROFILE(smb2_setinfo);
1962 break;
1964 case SMB2_OP_BREAK:
1966 START_PROFILE(smb2_break);
1967 return_value = smbd_smb2_request_process_break(req);
1968 END_PROFILE(smb2_break);
1970 break;
1972 default:
1973 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1974 break;
1976 return return_value;
1979 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
1981 struct tevent_req *subreq;
1982 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
1983 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
1985 req->subreq = NULL;
1986 TALLOC_FREE(req->async_te);
1988 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
1990 if (req->current_idx < req->out.vector_count) {
1992 * We must process the remaining compound
1993 * SMB2 requests before any new incoming SMB2
1994 * requests. This is because incoming SMB2
1995 * requests may include a cancel for a
1996 * compound request we haven't processed
1997 * yet.
1999 struct tevent_immediate *im = tevent_create_immediate(req);
2000 if (!im) {
2001 return NT_STATUS_NO_MEMORY;
2003 tevent_schedule_immediate(im,
2004 req->sconn->ev_ctx,
2005 smbd_smb2_request_dispatch_immediate,
2006 req);
2007 return NT_STATUS_OK;
2010 if (req->compound_related) {
2011 req->sconn->smb2.compound_related_in_progress = false;
2014 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2016 /* Set credit for these operations (zero credits if this
2017 is a final reply for an async operation). */
2018 smb2_calculate_credits(req, req);
2020 if (req->do_signing) {
2021 NTSTATUS status;
2022 struct smbXsrv_session *x = req->session;
2023 struct smbXsrv_connection *conn = x->connection;
2024 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2026 status = smb2_signing_sign_pdu(signing_key,
2027 conn->protocol,
2028 outhdr,
2029 SMBD_SMB2_NUM_IOV_PER_REQ);
2030 if (!NT_STATUS_IS_OK(status)) {
2031 return status;
2035 if (DEBUGLEVEL >= 10) {
2036 dbgtext("smbd_smb2_request_reply: sending...\n");
2037 print_req_vectors(req);
2040 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2041 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2042 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2043 /* Dynamic part is NULL. Chop it off,
2044 We're going to send it via sendfile. */
2045 req->out.vector_count -= 1;
2048 subreq = tstream_writev_queue_send(req,
2049 req->sconn->ev_ctx,
2050 req->sconn->smb2.stream,
2051 req->sconn->smb2.send_queue,
2052 req->out.vector,
2053 req->out.vector_count);
2054 if (subreq == NULL) {
2055 return NT_STATUS_NO_MEMORY;
2057 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
2059 * We're done with this request -
2060 * move it off the "being processed" queue.
2062 DLIST_REMOVE(req->sconn->smb2.requests, req);
2064 return NT_STATUS_OK;
2067 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2069 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2070 struct tevent_immediate *im,
2071 void *private_data)
2073 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2074 struct smbd_smb2_request);
2075 struct smbd_server_connection *sconn = req->sconn;
2076 NTSTATUS status;
2078 TALLOC_FREE(im);
2080 if (DEBUGLEVEL >= 10) {
2081 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2082 req->current_idx, req->in.vector_count));
2083 print_req_vectors(req);
2086 status = smbd_smb2_request_dispatch(req);
2087 if (!NT_STATUS_IS_OK(status)) {
2088 smbd_server_connection_terminate(sconn, nt_errstr(status));
2089 return;
2092 status = smbd_smb2_request_next_incoming(sconn);
2093 if (!NT_STATUS_IS_OK(status)) {
2094 smbd_server_connection_terminate(sconn, nt_errstr(status));
2095 return;
2099 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
2101 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
2102 struct smbd_smb2_request);
2103 struct smbd_server_connection *sconn = req->sconn;
2104 int ret;
2105 int sys_errno;
2106 NTSTATUS status;
2108 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2109 TALLOC_FREE(subreq);
2110 TALLOC_FREE(req);
2111 if (ret == -1) {
2112 status = map_nt_error_from_unix(sys_errno);
2113 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
2114 nt_errstr(status)));
2115 smbd_server_connection_terminate(sconn, nt_errstr(status));
2116 return;
2119 status = smbd_smb2_request_next_incoming(sconn);
2120 if (!NT_STATUS_IS_OK(status)) {
2121 smbd_server_connection_terminate(sconn, nt_errstr(status));
2122 return;
2126 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2127 NTSTATUS status,
2128 DATA_BLOB body, DATA_BLOB *dyn,
2129 const char *location)
2131 uint8_t *outhdr;
2132 int i = req->current_idx;
2133 uint32_t next_command_ofs;
2135 DEBUG(10,("smbd_smb2_request_done_ex: "
2136 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2137 i, nt_errstr(status), (unsigned int)body.length,
2138 dyn ? "yes": "no",
2139 (unsigned int)(dyn ? dyn->length : 0),
2140 location));
2142 if (body.length < 2) {
2143 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2146 if ((body.length % 2) != 0) {
2147 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2150 outhdr = (uint8_t *)req->out.vector[i].iov_base;
2152 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2153 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2155 req->out.vector[i+1].iov_base = (void *)body.data;
2156 req->out.vector[i+1].iov_len = body.length;
2158 if (dyn) {
2159 req->out.vector[i+2].iov_base = (void *)dyn->data;
2160 req->out.vector[i+2].iov_len = dyn->length;
2161 } else {
2162 req->out.vector[i+2].iov_base = NULL;
2163 req->out.vector[i+2].iov_len = 0;
2166 /* see if we need to recalculate the offset to the next response */
2167 if (next_command_ofs > 0) {
2168 next_command_ofs = SMB2_HDR_BODY;
2169 next_command_ofs += req->out.vector[i+1].iov_len;
2170 next_command_ofs += req->out.vector[i+2].iov_len;
2173 if ((next_command_ofs % 8) != 0) {
2174 size_t pad_size = 8 - (next_command_ofs % 8);
2175 if (req->out.vector[i+2].iov_len == 0) {
2177 * if the dyn buffer is empty
2178 * we can use it to add padding
2180 uint8_t *pad;
2182 pad = talloc_zero_array(req->out.vector,
2183 uint8_t, pad_size);
2184 if (pad == NULL) {
2185 return smbd_smb2_request_error(req,
2186 NT_STATUS_NO_MEMORY);
2189 req->out.vector[i+2].iov_base = (void *)pad;
2190 req->out.vector[i+2].iov_len = pad_size;
2191 } else {
2193 * For now we copy the dynamic buffer
2194 * and add the padding to the new buffer
2196 size_t old_size;
2197 uint8_t *old_dyn;
2198 size_t new_size;
2199 uint8_t *new_dyn;
2201 old_size = req->out.vector[i+2].iov_len;
2202 old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
2204 new_size = old_size + pad_size;
2205 new_dyn = talloc_zero_array(req->out.vector,
2206 uint8_t, new_size);
2207 if (new_dyn == NULL) {
2208 return smbd_smb2_request_error(req,
2209 NT_STATUS_NO_MEMORY);
2212 memcpy(new_dyn, old_dyn, old_size);
2213 memset(new_dyn + old_size, 0, pad_size);
2215 req->out.vector[i+2].iov_base = (void *)new_dyn;
2216 req->out.vector[i+2].iov_len = new_size;
2218 next_command_ofs += pad_size;
2221 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2223 return smbd_smb2_request_reply(req);
2226 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2227 NTSTATUS status,
2228 DATA_BLOB *info,
2229 const char *location)
2231 DATA_BLOB body;
2232 int i = req->current_idx;
2233 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2235 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2236 i, nt_errstr(status), info ? " +info" : "",
2237 location));
2239 body.data = outhdr + SMB2_HDR_BODY;
2240 body.length = 8;
2241 SSVAL(body.data, 0, 9);
2243 if (info) {
2244 SIVAL(body.data, 0x04, info->length);
2245 } else {
2246 /* Allocated size of req->out.vector[i].iov_base
2247 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2248 * 1 byte without having to do an alloc.
2250 info = talloc_zero_array(req->out.vector,
2251 DATA_BLOB,
2253 if (!info) {
2254 return NT_STATUS_NO_MEMORY;
2256 info->data = ((uint8_t *)outhdr) +
2257 OUTVEC_ALLOC_SIZE - 1;
2258 info->length = 1;
2259 SCVAL(info->data, 0, 0);
2263 * if a request fails, all other remaining
2264 * compounded requests should fail too
2266 req->next_status = NT_STATUS_INVALID_PARAMETER;
2268 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2272 struct smbd_smb2_send_oplock_break_state {
2273 struct smbd_server_connection *sconn;
2274 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
2275 struct iovec vector;
2278 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2280 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2281 uint64_t file_id_persistent,
2282 uint64_t file_id_volatile,
2283 uint8_t oplock_level)
2285 struct smbd_smb2_send_oplock_break_state *state;
2286 struct tevent_req *subreq;
2287 uint8_t *hdr;
2288 uint8_t *body;
2290 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2291 if (state == NULL) {
2292 return NT_STATUS_NO_MEMORY;
2294 state->sconn = sconn;
2296 state->vector.iov_base = (void *)state->buf;
2297 state->vector.iov_len = sizeof(state->buf);
2299 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
2300 hdr = state->buf + 4;
2301 body = hdr + SMB2_HDR_BODY;
2303 SIVAL(hdr, 0, SMB2_MAGIC);
2304 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2305 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2306 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2307 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2308 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2309 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2310 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2311 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2312 SIVAL(hdr, SMB2_HDR_PID, 0);
2313 SIVAL(hdr, SMB2_HDR_TID, 0);
2314 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2315 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2317 SSVAL(body, 0x00, 0x18);
2319 SCVAL(body, 0x02, oplock_level);
2320 SCVAL(body, 0x03, 0); /* reserved */
2321 SIVAL(body, 0x04, 0); /* reserved */
2322 SBVAL(body, 0x08, file_id_persistent);
2323 SBVAL(body, 0x10, file_id_volatile);
2325 subreq = tstream_writev_queue_send(state,
2326 sconn->ev_ctx,
2327 sconn->smb2.stream,
2328 sconn->smb2.send_queue,
2329 &state->vector, 1);
2330 if (subreq == NULL) {
2331 return NT_STATUS_NO_MEMORY;
2333 tevent_req_set_callback(subreq,
2334 smbd_smb2_oplock_break_writev_done,
2335 state);
2337 return NT_STATUS_OK;
2340 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2342 struct smbd_smb2_send_oplock_break_state *state =
2343 tevent_req_callback_data(subreq,
2344 struct smbd_smb2_send_oplock_break_state);
2345 struct smbd_server_connection *sconn = state->sconn;
2346 int ret;
2347 int sys_errno;
2349 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2350 TALLOC_FREE(subreq);
2351 if (ret == -1) {
2352 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2353 smbd_server_connection_terminate(sconn, nt_errstr(status));
2354 return;
2357 TALLOC_FREE(state);
2360 struct smbd_smb2_request_read_state {
2361 struct tevent_context *ev;
2362 struct smbd_server_connection *sconn;
2363 struct smbd_smb2_request *smb2_req;
2364 struct {
2365 uint8_t nbt[NBT_HDR_SIZE];
2366 bool done;
2367 } hdr;
2368 size_t pktlen;
2369 uint8_t *pktbuf;
2372 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2373 void *private_data,
2374 TALLOC_CTX *mem_ctx,
2375 struct iovec **_vector,
2376 size_t *_count);
2377 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2379 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2380 struct tevent_context *ev,
2381 struct smbd_server_connection *sconn)
2383 struct tevent_req *req;
2384 struct smbd_smb2_request_read_state *state;
2385 struct tevent_req *subreq;
2387 req = tevent_req_create(mem_ctx, &state,
2388 struct smbd_smb2_request_read_state);
2389 if (req == NULL) {
2390 return NULL;
2392 state->ev = ev;
2393 state->sconn = sconn;
2395 state->smb2_req = smbd_smb2_request_allocate(state);
2396 if (tevent_req_nomem(state->smb2_req, req)) {
2397 return tevent_req_post(req, ev);
2399 state->smb2_req->sconn = sconn;
2401 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2402 state->ev,
2403 state->sconn->smb2.stream,
2404 state->sconn->smb2.recv_queue,
2405 smbd_smb2_request_next_vector,
2406 state);
2407 if (tevent_req_nomem(subreq, req)) {
2408 return tevent_req_post(req, ev);
2410 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2412 return req;
2415 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2416 void *private_data,
2417 TALLOC_CTX *mem_ctx,
2418 struct iovec **_vector,
2419 size_t *_count)
2421 struct smbd_smb2_request_read_state *state =
2422 talloc_get_type_abort(private_data,
2423 struct smbd_smb2_request_read_state);
2424 struct iovec *vector;
2426 if (state->pktlen > 0) {
2427 /* if there're no remaining bytes, we're done */
2428 *_vector = NULL;
2429 *_count = 0;
2430 return 0;
2433 if (!state->hdr.done) {
2435 * first we need to get the NBT header
2437 vector = talloc_array(mem_ctx, struct iovec, 1);
2438 if (vector == NULL) {
2439 return -1;
2442 vector[0].iov_base = (void *)state->hdr.nbt;
2443 vector[0].iov_len = NBT_HDR_SIZE;
2445 *_vector = vector;
2446 *_count = 1;
2448 state->hdr.done = true;
2449 return 0;
2453 * Now we analyze the NBT header
2455 state->pktlen = smb2_len(state->hdr.nbt);
2457 if (state->pktlen == 0) {
2458 /* if there're no remaining bytes, we're done */
2459 *_vector = NULL;
2460 *_count = 0;
2461 return 0;
2464 state->pktbuf = talloc_array(state->smb2_req, uint8_t, state->pktlen);
2465 if (state->pktbuf == NULL) {
2466 return -1;
2469 vector = talloc_array(mem_ctx, struct iovec, 1);
2470 if (vector == NULL) {
2471 return -1;
2474 vector[0].iov_base = (void *)state->pktbuf;
2475 vector[0].iov_len = state->pktlen;
2477 *_vector = vector;
2478 *_count = 1;
2479 return 0;
2482 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2484 struct tevent_req *req =
2485 tevent_req_callback_data(subreq,
2486 struct tevent_req);
2487 struct smbd_smb2_request_read_state *state =
2488 tevent_req_data(req,
2489 struct smbd_smb2_request_read_state);
2490 int ret;
2491 int sys_errno;
2492 NTSTATUS status;
2493 NTTIME now;
2495 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2496 TALLOC_FREE(subreq);
2497 if (ret == -1) {
2498 status = map_nt_error_from_unix(sys_errno);
2499 tevent_req_nterror(req, status);
2500 return;
2503 if (state->hdr.nbt[0] != 0x00) {
2504 DEBUG(1,("smbd_smb2_request_read_done: ignore NBT[0x%02X] msg\n",
2505 state->hdr.nbt[0]));
2507 ZERO_STRUCT(state->hdr);
2508 TALLOC_FREE(state->pktbuf);
2509 state->pktlen = 0;
2511 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2512 state->ev,
2513 state->sconn->smb2.stream,
2514 state->sconn->smb2.recv_queue,
2515 smbd_smb2_request_next_vector,
2516 state);
2517 if (tevent_req_nomem(subreq, req)) {
2518 return;
2520 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2521 return;
2524 state->smb2_req->request_time = timeval_current();
2525 now = timeval_to_nttime(&state->smb2_req->request_time);
2527 status = smbd_smb2_inbuf_parse_compound(state->smb2_req->sconn->conn,
2528 now,
2529 state->pktbuf,
2530 state->pktlen,
2531 state->smb2_req,
2532 &state->smb2_req->in.vector,
2533 &state->smb2_req->in.vector_count);
2534 if (tevent_req_nterror(req, status)) {
2535 return;
2538 state->smb2_req->current_idx = 1;
2540 tevent_req_done(req);
2543 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2544 TALLOC_CTX *mem_ctx,
2545 struct smbd_smb2_request **_smb2_req)
2547 struct smbd_smb2_request_read_state *state =
2548 tevent_req_data(req,
2549 struct smbd_smb2_request_read_state);
2550 NTSTATUS status;
2552 if (tevent_req_is_nterror(req, &status)) {
2553 tevent_req_received(req);
2554 return status;
2557 *_smb2_req = talloc_move(mem_ctx, &state->smb2_req);
2558 tevent_req_received(req);
2559 return NT_STATUS_OK;
2562 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
2564 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2566 size_t max_send_queue_len;
2567 size_t cur_send_queue_len;
2568 struct tevent_req *subreq;
2570 if (sconn->smb2.compound_related_in_progress) {
2572 * Can't read another until the related
2573 * compound is done.
2575 return NT_STATUS_OK;
2578 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
2580 * if there is already a smbd_smb2_request_read
2581 * pending, we are done.
2583 return NT_STATUS_OK;
2586 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2587 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
2589 if (cur_send_queue_len > max_send_queue_len) {
2591 * if we have a lot of requests to send,
2592 * we wait until they are on the wire until we
2593 * ask for the next request.
2595 return NT_STATUS_OK;
2598 /* ask for the next request */
2599 subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn);
2600 if (subreq == NULL) {
2601 return NT_STATUS_NO_MEMORY;
2603 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
2605 return NT_STATUS_OK;
2608 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2609 uint8_t *inbuf, size_t size)
2611 NTSTATUS status;
2612 struct smbd_smb2_request *req = NULL;
2614 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2615 (unsigned int)size));
2617 status = smbd_initialize_smb2(sconn);
2618 if (!NT_STATUS_IS_OK(status)) {
2619 smbd_server_connection_terminate(sconn, nt_errstr(status));
2620 return;
2623 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2624 if (!NT_STATUS_IS_OK(status)) {
2625 smbd_server_connection_terminate(sconn, nt_errstr(status));
2626 return;
2629 status = smbd_smb2_request_validate(req);
2630 if (!NT_STATUS_IS_OK(status)) {
2631 smbd_server_connection_terminate(sconn, nt_errstr(status));
2632 return;
2635 status = smbd_smb2_request_setup_out(req);
2636 if (!NT_STATUS_IS_OK(status)) {
2637 smbd_server_connection_terminate(sconn, nt_errstr(status));
2638 return;
2641 status = smbd_smb2_request_dispatch(req);
2642 if (!NT_STATUS_IS_OK(status)) {
2643 smbd_server_connection_terminate(sconn, nt_errstr(status));
2644 return;
2647 status = smbd_smb2_request_next_incoming(sconn);
2648 if (!NT_STATUS_IS_OK(status)) {
2649 smbd_server_connection_terminate(sconn, nt_errstr(status));
2650 return;
2653 sconn->num_requests++;
2656 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
2658 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
2659 struct smbd_server_connection);
2660 NTSTATUS status;
2661 struct smbd_smb2_request *req = NULL;
2663 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
2664 TALLOC_FREE(subreq);
2665 if (!NT_STATUS_IS_OK(status)) {
2666 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
2667 nt_errstr(status)));
2668 smbd_server_connection_terminate(sconn, nt_errstr(status));
2669 return;
2672 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
2673 req->current_idx, req->in.vector_count));
2675 status = smbd_smb2_request_validate(req);
2676 if (!NT_STATUS_IS_OK(status)) {
2677 smbd_server_connection_terminate(sconn, nt_errstr(status));
2678 return;
2681 status = smbd_smb2_request_setup_out(req);
2682 if (!NT_STATUS_IS_OK(status)) {
2683 smbd_server_connection_terminate(sconn, nt_errstr(status));
2684 return;
2687 status = smbd_smb2_request_dispatch(req);
2688 if (!NT_STATUS_IS_OK(status)) {
2689 smbd_server_connection_terminate(sconn, nt_errstr(status));
2690 return;
2693 status = smbd_smb2_request_next_incoming(sconn);
2694 if (!NT_STATUS_IS_OK(status)) {
2695 smbd_server_connection_terminate(sconn, nt_errstr(status));
2696 return;
2699 sconn->num_requests++;
2701 /* The timeout_processing function isn't run nearly
2702 often enough to implement 'max log size' without
2703 overrunning the size of the file by many megabytes.
2704 This is especially true if we are running at debug
2705 level 10. Checking every 50 SMB2s is a nice
2706 tradeoff of performance vs log file size overrun. */
2708 if ((sconn->num_requests % 50) == 0 &&
2709 need_to_check_log_size()) {
2710 change_to_root_user();
2711 check_log_size();