s3:smb2_server: protect against integer wrap with "smb2 max credits = 65535"
[Samba.git] / source3 / smbd / smb2_server.c
blob98c6e58d2325b7f1d3a6615b07628e36a33e556e
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 static void smbd_smb2_connection_handler(struct tevent_context *ev,
34 struct tevent_fd *fde,
35 uint16_t flags,
36 void *private_data);
37 static NTSTATUS smbd_smb2_io_handler(struct smbd_server_connection *sconn,
38 uint16_t fde_flags);
40 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
42 static const struct smbd_smb2_dispatch_table {
43 uint16_t opcode;
44 const char *name;
45 bool need_session;
46 bool need_tcon;
47 bool as_root;
48 uint16_t fileid_ofs;
49 bool allow_invalid_fileid;
50 } smbd_smb2_table[] = {
51 #define _OP(o) .opcode = o, .name = #o
53 _OP(SMB2_OP_NEGPROT),
54 .as_root = true,
55 },{
56 _OP(SMB2_OP_SESSSETUP),
57 .as_root = true,
58 },{
59 _OP(SMB2_OP_LOGOFF),
60 .need_session = true,
61 .as_root = true,
62 },{
63 _OP(SMB2_OP_TCON),
64 .need_session = true,
66 * This call needs to be run as root.
68 * smbd_smb2_request_process_tcon()
69 * calls make_connection_snum(), which will call
70 * change_to_user(), when needed.
72 .as_root = true,
73 },{
74 _OP(SMB2_OP_TDIS),
75 .need_session = true,
76 .need_tcon = true,
77 .as_root = true,
78 },{
79 _OP(SMB2_OP_CREATE),
80 .need_session = true,
81 .need_tcon = true,
82 },{
83 _OP(SMB2_OP_CLOSE),
84 .need_session = true,
85 .need_tcon = true,
86 .fileid_ofs = 0x08,
87 },{
88 _OP(SMB2_OP_FLUSH),
89 .need_session = true,
90 .need_tcon = true,
91 .fileid_ofs = 0x08,
92 },{
93 _OP(SMB2_OP_READ),
94 .need_session = true,
95 .need_tcon = true,
96 .fileid_ofs = 0x10,
97 },{
98 _OP(SMB2_OP_WRITE),
99 .need_session = true,
100 .need_tcon = true,
101 .fileid_ofs = 0x10,
103 _OP(SMB2_OP_LOCK),
104 .need_session = true,
105 .need_tcon = true,
106 .fileid_ofs = 0x08,
108 _OP(SMB2_OP_IOCTL),
109 .need_session = true,
110 .need_tcon = true,
111 .fileid_ofs = 0x08,
112 .allow_invalid_fileid = true,
114 _OP(SMB2_OP_CANCEL),
115 .as_root = true,
117 _OP(SMB2_OP_KEEPALIVE),
118 .as_root = true,
120 _OP(SMB2_OP_FIND),
121 .need_session = true,
122 .need_tcon = true,
123 .fileid_ofs = 0x08,
125 _OP(SMB2_OP_NOTIFY),
126 .need_session = true,
127 .need_tcon = true,
128 .fileid_ofs = 0x08,
130 _OP(SMB2_OP_GETINFO),
131 .need_session = true,
132 .need_tcon = true,
133 .fileid_ofs = 0x18,
135 _OP(SMB2_OP_SETINFO),
136 .need_session = true,
137 .need_tcon = true,
138 .fileid_ofs = 0x10,
140 _OP(SMB2_OP_BREAK),
141 .need_session = true,
142 .need_tcon = true,
144 * we do not set
145 * .fileid_ofs here
146 * as LEASE breaks does not
147 * have a file id
152 const char *smb2_opcode_name(uint16_t opcode)
154 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
155 return "Bad SMB2 opcode";
157 return smbd_smb2_table[opcode].name;
160 static const struct smbd_smb2_dispatch_table *smbd_smb2_call(uint16_t opcode)
162 const struct smbd_smb2_dispatch_table *ret = NULL;
164 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
165 return NULL;
168 ret = &smbd_smb2_table[opcode];
170 SMB_ASSERT(ret->opcode == opcode);
172 return ret;
175 static void print_req_vectors(const struct smbd_smb2_request *req)
177 int i;
179 for (i = 0; i < req->in.vector_count; i++) {
180 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
181 (unsigned int)i,
182 (unsigned int)req->in.vector[i].iov_len);
184 for (i = 0; i < req->out.vector_count; i++) {
185 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
186 (unsigned int)i,
187 (unsigned int)req->out.vector[i].iov_len);
191 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
193 if (size < (4 + SMB2_HDR_BODY)) {
194 return false;
197 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
198 return false;
201 return true;
204 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
206 TALLOC_FREE(sconn->smb1.fde);
208 sconn->smb2.send_queue = NULL;
210 sconn->smb2.seqnum_low = 0;
211 sconn->smb2.seqnum_range = 1;
212 sconn->smb2.credits_granted = 1;
213 sconn->smb2.max_credits = lp_smb2_max_credits();
214 sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
215 sconn->smb2.max_credits);
216 if (sconn->smb2.credits_bitmap == NULL) {
217 return NT_STATUS_NO_MEMORY;
220 sconn->smb2.fde = tevent_add_fd(sconn->ev_ctx,
221 sconn,
222 sconn->sock,
223 TEVENT_FD_READ,
224 smbd_smb2_connection_handler,
225 sconn);
226 if (sconn->smb2.fde == NULL) {
227 return NT_STATUS_NO_MEMORY;
230 /* Ensure child is set to non-blocking mode */
231 set_blocking(sconn->sock, false);
232 return NT_STATUS_OK;
235 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
236 #define _smb2_setlen(_buf,len) do { \
237 uint8_t *buf = (uint8_t *)_buf; \
238 buf[0] = 0; \
239 buf[1] = ((len)&0xFF0000)>>16; \
240 buf[2] = ((len)&0xFF00)>>8; \
241 buf[3] = (len)&0xFF; \
242 } while (0)
244 static void smb2_setup_nbt_length(struct iovec *vector, int count)
246 size_t len = 0;
247 int i;
249 for (i=1; i < count; i++) {
250 len += vector[i].iov_len;
253 _smb2_setlen(vector[0].iov_base, len);
256 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
258 data_blob_clear_free(&req->first_key);
259 data_blob_clear_free(&req->last_key);
260 return 0;
263 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
265 TALLOC_CTX *mem_pool;
266 struct smbd_smb2_request *req;
268 #if 0
269 /* Enable this to find subtle valgrind errors. */
270 mem_pool = talloc_init("smbd_smb2_request_allocate");
271 #else
272 mem_pool = talloc_tos();
273 #endif
274 if (mem_pool == NULL) {
275 return NULL;
278 req = talloc_zero(mem_pool, struct smbd_smb2_request);
279 if (req == NULL) {
280 talloc_free(mem_pool);
281 return NULL;
283 talloc_reparent(mem_pool, mem_ctx, req);
284 #if 0
285 TALLOC_FREE(mem_pool);
286 #endif
288 req->last_session_id = UINT64_MAX;
289 req->last_tid = UINT32_MAX;
291 talloc_set_destructor(req, smbd_smb2_request_destructor);
293 return req;
296 static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
297 NTTIME now,
298 uint8_t *buf,
299 size_t buflen,
300 TALLOC_CTX *mem_ctx,
301 struct iovec **piov,
302 int *pnum_iov)
304 struct iovec *iov;
305 int num_iov = 1;
306 size_t taken = 0;
307 uint8_t *first_hdr = buf;
308 size_t verified_buflen = 0;
309 uint8_t *tf = NULL;
310 size_t tf_len = 0;
313 * Note: index '0' is reserved for the transport protocol
315 iov = talloc_zero_array(mem_ctx, struct iovec, num_iov);
316 if (iov == NULL) {
317 return NT_STATUS_NO_MEMORY;
320 while (taken < buflen) {
321 size_t len = buflen - taken;
322 uint8_t *hdr = first_hdr + taken;
323 struct iovec *cur;
324 size_t full_size;
325 size_t next_command_ofs;
326 uint16_t body_size;
327 uint8_t *body = NULL;
328 uint32_t dyn_size;
329 uint8_t *dyn = NULL;
330 struct iovec *iov_tmp;
332 if (verified_buflen > taken) {
333 len = verified_buflen - taken;
334 } else {
335 tf = NULL;
336 tf_len = 0;
339 if (len < 4) {
340 DEBUG(10, ("%d bytes left, expected at least %d\n",
341 (int)len, 4));
342 goto inval;
344 if (IVAL(hdr, 0) == SMB2_TF_MAGIC) {
345 struct smbXsrv_session *s = NULL;
346 uint64_t uid;
347 struct iovec tf_iov[2];
348 NTSTATUS status;
349 size_t enc_len;
351 if (conn->protocol < PROTOCOL_SMB2_24) {
352 DEBUG(10, ("Got SMB2_TRANSFORM header, "
353 "but dialect[0x%04X] is used\n",
354 conn->smb2.server.dialect));
355 goto inval;
358 if (!(conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) {
359 DEBUG(10, ("Got SMB2_TRANSFORM header, "
360 "but not negotiated "
361 "client[0x%08X] server[0x%08X]\n",
362 conn->smb2.client.capabilities,
363 conn->smb2.server.capabilities));
364 goto inval;
367 if (len < SMB2_TF_HDR_SIZE) {
368 DEBUG(1, ("%d bytes left, expected at least %d\n",
369 (int)len, SMB2_TF_HDR_SIZE));
370 goto inval;
372 tf = hdr;
373 tf_len = SMB2_TF_HDR_SIZE;
374 taken += tf_len;
376 hdr = first_hdr + taken;
377 enc_len = IVAL(tf, SMB2_TF_MSG_SIZE);
378 uid = BVAL(tf, SMB2_TF_SESSION_ID);
380 if (len < SMB2_TF_HDR_SIZE + enc_len) {
381 DEBUG(1, ("%d bytes left, expected at least %d\n",
382 (int)len,
383 (int)(SMB2_TF_HDR_SIZE + enc_len)));
384 goto inval;
387 status = smb2srv_session_lookup(conn, uid, now, &s);
388 if (s == NULL) {
389 DEBUG(1, ("invalid session[%llu] in "
390 "SMB2_TRANSFORM header\n",
391 (unsigned long long)uid));
392 TALLOC_FREE(iov);
393 return NT_STATUS_USER_SESSION_DELETED;
396 tf_iov[0].iov_base = (void *)tf;
397 tf_iov[0].iov_len = tf_len;
398 tf_iov[1].iov_base = (void *)hdr;
399 tf_iov[1].iov_len = enc_len;
401 status = smb2_signing_decrypt_pdu(s->global->decryption_key,
402 conn->protocol,
403 tf_iov, 2);
404 if (!NT_STATUS_IS_OK(status)) {
405 TALLOC_FREE(iov);
406 return status;
409 verified_buflen = taken + enc_len;
410 len = enc_len;
414 * We need the header plus the body length field
417 if (len < SMB2_HDR_BODY + 2) {
418 DEBUG(10, ("%d bytes left, expected at least %d\n",
419 (int)len, SMB2_HDR_BODY));
420 goto inval;
422 if (IVAL(hdr, 0) != SMB2_MAGIC) {
423 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
424 IVAL(hdr, 0)));
425 goto inval;
427 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
428 DEBUG(10, ("Got HDR len %d, expected %d\n",
429 SVAL(hdr, 4), SMB2_HDR_BODY));
430 goto inval;
433 full_size = len;
434 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
435 body_size = SVAL(hdr, SMB2_HDR_BODY);
437 if (next_command_ofs != 0) {
438 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
439 goto inval;
441 if (next_command_ofs > full_size) {
442 goto inval;
444 full_size = next_command_ofs;
446 if (body_size < 2) {
447 goto inval;
449 body_size &= 0xfffe;
451 if (body_size > (full_size - SMB2_HDR_BODY)) {
453 * let the caller handle the error
455 body_size = full_size - SMB2_HDR_BODY;
457 body = hdr + SMB2_HDR_BODY;
458 dyn = body + body_size;
459 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
461 iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
462 num_iov + SMBD_SMB2_NUM_IOV_PER_REQ);
463 if (iov_tmp == NULL) {
464 TALLOC_FREE(iov);
465 return NT_STATUS_NO_MEMORY;
467 iov = iov_tmp;
468 cur = &iov[num_iov];
469 num_iov += SMBD_SMB2_NUM_IOV_PER_REQ;
471 cur[SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
472 cur[SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
473 cur[SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
474 cur[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
475 cur[SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
476 cur[SMBD_SMB2_BODY_IOV_OFS].iov_len = body_size;
477 cur[SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
478 cur[SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_size;
480 taken += full_size;
483 *piov = iov;
484 *pnum_iov = num_iov;
485 return NT_STATUS_OK;
487 inval:
488 TALLOC_FREE(iov);
489 return NT_STATUS_INVALID_PARAMETER;
492 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
493 uint8_t *inbuf, size_t size,
494 struct smbd_smb2_request **_req)
496 struct smbd_smb2_request *req;
497 uint32_t protocol_version;
498 const uint8_t *inhdr = NULL;
499 uint16_t cmd;
500 uint32_t next_command_ofs;
501 NTSTATUS status;
502 NTTIME now;
504 if (size < (4 + SMB2_HDR_BODY + 2)) {
505 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
506 return NT_STATUS_INVALID_PARAMETER;
509 inhdr = inbuf + 4;
511 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
512 if (protocol_version != SMB2_MAGIC) {
513 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
514 protocol_version));
515 return NT_STATUS_INVALID_PARAMETER;
518 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
519 if (cmd != SMB2_OP_NEGPROT) {
520 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
521 cmd));
522 return NT_STATUS_INVALID_PARAMETER;
525 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
526 if (next_command_ofs != 0) {
527 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
528 next_command_ofs));
529 return NT_STATUS_INVALID_PARAMETER;
532 req = smbd_smb2_request_allocate(sconn);
533 if (req == NULL) {
534 return NT_STATUS_NO_MEMORY;
536 req->sconn = sconn;
538 talloc_steal(req, inbuf);
540 req->request_time = timeval_current();
541 now = timeval_to_nttime(&req->request_time);
543 status = smbd_smb2_inbuf_parse_compound(sconn->conn,
544 now,
545 inbuf + NBT_HDR_SIZE,
546 size - NBT_HDR_SIZE,
547 req, &req->in.vector,
548 &req->in.vector_count);
549 if (!NT_STATUS_IS_OK(status)) {
550 TALLOC_FREE(req);
551 return status;
554 req->current_idx = 1;
556 *_req = req;
557 return NT_STATUS_OK;
560 static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
561 uint64_t message_id, uint64_t seq_id)
563 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
564 unsigned int offset;
566 if (seq_id < sconn->smb2.seqnum_low) {
567 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
568 "%llu (sequence id %llu) "
569 "(granted = %u, low = %llu, range = %u)\n",
570 (unsigned long long)message_id,
571 (unsigned long long)seq_id,
572 (unsigned int)sconn->smb2.credits_granted,
573 (unsigned long long)sconn->smb2.seqnum_low,
574 (unsigned int)sconn->smb2.seqnum_range));
575 return false;
578 if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
579 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
580 "%llu (sequence id %llu) "
581 "(granted = %u, low = %llu, range = %u)\n",
582 (unsigned long long)message_id,
583 (unsigned long long)seq_id,
584 (unsigned int)sconn->smb2.credits_granted,
585 (unsigned long long)sconn->smb2.seqnum_low,
586 (unsigned int)sconn->smb2.seqnum_range));
587 return false;
590 offset = seq_id % sconn->smb2.max_credits;
592 if (bitmap_query(credits_bm, offset)) {
593 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
594 "%llu (sequence id %llu) "
595 "(granted = %u, low = %llu, range = %u) "
596 "(bm offset %u)\n",
597 (unsigned long long)message_id,
598 (unsigned long long)seq_id,
599 (unsigned int)sconn->smb2.credits_granted,
600 (unsigned long long)sconn->smb2.seqnum_low,
601 (unsigned int)sconn->smb2.seqnum_range,
602 offset));
603 return false;
606 /* Mark the message_ids as seen in the bitmap. */
607 bitmap_set(credits_bm, offset);
609 if (seq_id != sconn->smb2.seqnum_low) {
610 return true;
614 * Move the window forward by all the message_id's
615 * already seen.
617 while (bitmap_query(credits_bm, offset)) {
618 DEBUG(10,("smb2_validate_sequence_number: clearing "
619 "id %llu (position %u) from bitmap\n",
620 (unsigned long long)(sconn->smb2.seqnum_low),
621 offset));
622 bitmap_clear(credits_bm, offset);
624 sconn->smb2.seqnum_low += 1;
625 sconn->smb2.seqnum_range -= 1;
626 offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
629 return true;
632 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
633 const uint8_t *inhdr)
635 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
636 uint16_t opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
637 uint16_t credit_charge = 1;
638 uint64_t i;
640 if (opcode == SMB2_OP_CANCEL) {
641 /* SMB2_CANCEL requests by definition resend messageids. */
642 return true;
645 if (sconn->smb2.supports_multicredit) {
646 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
647 credit_charge = MAX(credit_charge, 1);
650 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
651 "credits_granted %llu, "
652 "seqnum low/range: %llu/%llu\n",
653 (unsigned long long) message_id,
654 (unsigned long long) credit_charge,
655 (unsigned long long) sconn->smb2.credits_granted,
656 (unsigned long long) sconn->smb2.seqnum_low,
657 (unsigned long long) sconn->smb2.seqnum_range));
659 if (sconn->smb2.credits_granted < credit_charge) {
660 DEBUG(0, ("smb2_validate_message_id: client used more "
661 "credits than granted, mid %llu, charge %llu, "
662 "credits_granted %llu, "
663 "seqnum low/range: %llu/%llu\n",
664 (unsigned long long) message_id,
665 (unsigned long long) credit_charge,
666 (unsigned long long) sconn->smb2.credits_granted,
667 (unsigned long long) sconn->smb2.seqnum_low,
668 (unsigned long long) sconn->smb2.seqnum_range));
669 return false;
673 * now check the message ids
675 * for multi-credit requests we need to check all current mid plus
676 * the implicit mids caused by the credit charge
677 * e.g. current mid = 15, charge 5 => mark 15-19 as used
680 for (i = 0; i <= (credit_charge-1); i++) {
681 uint64_t id = message_id + i;
682 bool ok;
684 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
685 (unsigned long long)message_id,
686 credit_charge,
687 (unsigned long long)id));
689 ok = smb2_validate_sequence_number(sconn, message_id, id);
690 if (!ok) {
691 return false;
695 /* substract used credits */
696 sconn->smb2.credits_granted -= credit_charge;
698 return true;
701 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
703 int count;
704 int idx;
706 count = req->in.vector_count;
708 if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
709 /* It's not a SMB2 request */
710 return NT_STATUS_INVALID_PARAMETER;
713 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
714 struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
715 struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx);
716 const uint8_t *inhdr = NULL;
718 if (hdr->iov_len != SMB2_HDR_BODY) {
719 return NT_STATUS_INVALID_PARAMETER;
722 if (body->iov_len < 2) {
723 return NT_STATUS_INVALID_PARAMETER;
726 inhdr = (const uint8_t *)hdr->iov_base;
728 /* Check the SMB2 header */
729 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
730 return NT_STATUS_INVALID_PARAMETER;
733 if (!smb2_validate_message_id(req->sconn, inhdr)) {
734 return NT_STATUS_INVALID_PARAMETER;
738 return NT_STATUS_OK;
741 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
742 const struct iovec *in_vector,
743 struct iovec *out_vector)
745 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
746 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
747 uint16_t credit_charge = 1;
748 uint16_t credits_requested;
749 uint32_t out_flags;
750 uint16_t cmd;
751 NTSTATUS out_status;
752 uint16_t credits_granted = 0;
753 uint64_t credits_possible;
754 uint16_t current_max_credits;
757 * first we grant only 1/16th of the max range.
759 * Windows also starts with the 1/16th and then grants
760 * more later. I was only able to trigger higher
761 * values, when using a verify high credit charge.
763 * TODO: scale up depending one load, free memory
764 * or other stuff.
765 * Maybe also on the relationship between number
766 * of requests and the used sequence number.
767 * Which means we would grant more credits
768 * for client which use multi credit requests.
770 current_max_credits = sconn->smb2.max_credits / 16;
771 current_max_credits = MAX(current_max_credits, 1);
773 if (sconn->smb2.supports_multicredit) {
774 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
775 credit_charge = MAX(credit_charge, 1);
778 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
779 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
780 credits_requested = MAX(credits_requested, 1);
781 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
782 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
784 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
786 if (sconn->smb2.max_credits < credit_charge) {
787 smbd_server_connection_terminate(sconn,
788 "client error: credit charge > max credits\n");
789 return;
792 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
794 * In case we already send an async interim
795 * response, we should not grant
796 * credits on the final response.
798 credits_granted = 0;
799 } else {
800 uint16_t additional_possible =
801 sconn->smb2.max_credits - credit_charge;
802 uint16_t additional_max = 0;
803 uint16_t additional_credits = credits_requested - 1;
805 switch (cmd) {
806 case SMB2_OP_NEGPROT:
807 break;
808 case SMB2_OP_SESSSETUP:
810 * Windows 2012 RC1 starts to grant
811 * additional credits
812 * with a successful session setup
814 if (NT_STATUS_IS_OK(out_status)) {
815 additional_max = 32;
817 break;
818 default:
820 * We match windows and only grant additional credits
821 * in chunks of 32.
823 additional_max = 32;
824 break;
827 additional_max = MIN(additional_max, additional_possible);
828 additional_credits = MIN(additional_credits, additional_max);
830 credits_granted = credit_charge + additional_credits;
834 * sequence numbers should not wrap
836 * 1. calculate the possible credits until
837 * the sequence numbers start to wrap on 64-bit.
839 * 2. UINT64_MAX is used for Break Notifications.
841 * 2. truncate the possible credits to the maximum
842 * credits we want to grant to the client in total.
844 * 3. remove the range we'll already granted to the client
845 * this makes sure the client consumes the lowest sequence
846 * number, before we can grant additional credits.
848 credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
849 if (credits_possible > 0) {
850 /* remove UINT64_MAX */
851 credits_possible -= 1;
853 credits_possible = MIN(credits_possible, current_max_credits);
854 credits_possible -= sconn->smb2.seqnum_range;
856 credits_granted = MIN(credits_granted, credits_possible);
858 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
859 sconn->smb2.credits_granted += credits_granted;
860 sconn->smb2.seqnum_range += credits_granted;
862 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
863 "granted %u, current possible/max %u/%u, "
864 "total granted/max/low/range %u/%u/%llu/%u\n",
865 (unsigned int)credits_requested,
866 (unsigned int)credit_charge,
867 (unsigned int)credits_granted,
868 (unsigned int)credits_possible,
869 (unsigned int)current_max_credits,
870 (unsigned int)sconn->smb2.credits_granted,
871 (unsigned int)sconn->smb2.max_credits,
872 (unsigned long long)sconn->smb2.seqnum_low,
873 (unsigned int)sconn->smb2.seqnum_range));
876 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
877 struct smbd_smb2_request *outreq)
879 int count, idx;
880 uint16_t total_credits = 0;
882 count = outreq->out.vector_count;
884 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
885 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(inreq,in,idx);
886 struct iovec *outhdr_v = SMBD_SMB2_IDX_HDR_IOV(outreq,out,idx);
887 uint8_t *outhdr = (uint8_t *)outhdr_v->iov_base;
889 smb2_set_operation_credit(outreq->sconn, inhdr_v, outhdr_v);
891 /* To match Windows, count up what we
892 just granted. */
893 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
894 /* Set to zero in all but the last reply. */
895 if (idx + SMBD_SMB2_NUM_IOV_PER_REQ < count) {
896 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
897 } else {
898 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
903 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
905 struct iovec *vector;
906 int count;
907 int idx;
909 count = req->in.vector_count;
910 vector = talloc_zero_array(req, struct iovec, count);
911 if (vector == NULL) {
912 return NT_STATUS_NO_MEMORY;
915 vector[0].iov_base = req->out.nbt_hdr;
916 vector[0].iov_len = 4;
917 SIVAL(req->out.nbt_hdr, 0, 0);
919 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
920 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
921 const uint8_t *inhdr = (const uint8_t *)inhdr_v->iov_base;
922 uint8_t *outhdr = NULL;
923 uint8_t *outbody = NULL;
924 uint32_t next_command_ofs = 0;
925 struct iovec *current = &vector[idx];
927 if ((idx + SMBD_SMB2_NUM_IOV_PER_REQ) < count) {
928 /* we have a next command -
929 * setup for the error case. */
930 next_command_ofs = SMB2_HDR_BODY + 9;
933 outhdr = talloc_zero_array(vector, uint8_t,
934 OUTVEC_ALLOC_SIZE);
935 if (outhdr == NULL) {
936 return NT_STATUS_NO_MEMORY;
939 outbody = outhdr + SMB2_HDR_BODY;
942 * SMBD_SMB2_TF_IOV_OFS might be used later
944 current[SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
945 current[SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
947 current[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)outhdr;
948 current[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
950 current[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)outbody;
951 current[SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
953 current[SMBD_SMB2_DYN_IOV_OFS].iov_base = NULL;
954 current[SMBD_SMB2_DYN_IOV_OFS].iov_len = 0;
956 /* setup the SMB2 header */
957 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
958 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
959 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
960 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
961 SIVAL(outhdr, SMB2_HDR_STATUS,
962 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
963 SSVAL(outhdr, SMB2_HDR_OPCODE,
964 SVAL(inhdr, SMB2_HDR_OPCODE));
965 SIVAL(outhdr, SMB2_HDR_FLAGS,
966 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
967 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
968 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
969 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
970 SIVAL(outhdr, SMB2_HDR_PID,
971 IVAL(inhdr, SMB2_HDR_PID));
972 SIVAL(outhdr, SMB2_HDR_TID,
973 IVAL(inhdr, SMB2_HDR_TID));
974 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
975 BVAL(inhdr, SMB2_HDR_SESSION_ID));
976 memcpy(outhdr + SMB2_HDR_SIGNATURE,
977 inhdr + SMB2_HDR_SIGNATURE, 16);
979 /* setup error body header */
980 SSVAL(outbody, 0x00, 0x08 + 1);
981 SSVAL(outbody, 0x02, 0);
982 SIVAL(outbody, 0x04, 0);
985 req->out.vector = vector;
986 req->out.vector_count = count;
988 /* setup the length of the NBT packet */
989 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
991 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
993 return NT_STATUS_OK;
996 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
997 const char *reason,
998 const char *location)
1000 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
1001 reason, location));
1002 exit_server_cleanly(reason);
1005 static bool dup_smb2_vec4(TALLOC_CTX *ctx,
1006 struct iovec *outvec,
1007 const struct iovec *srcvec)
1009 const uint8_t *srctf;
1010 size_t srctf_len;
1011 const uint8_t *srchdr;
1012 size_t srchdr_len;
1013 const uint8_t *srcbody;
1014 size_t srcbody_len;
1015 const uint8_t *expected_srcbody;
1016 const uint8_t *srcdyn;
1017 size_t srcdyn_len;
1018 const uint8_t *expected_srcdyn;
1019 uint8_t *dsttf;
1020 uint8_t *dsthdr;
1021 uint8_t *dstbody;
1022 uint8_t *dstdyn;
1024 srctf = (const uint8_t *)srcvec[SMBD_SMB2_TF_IOV_OFS].iov_base;
1025 srctf_len = srcvec[SMBD_SMB2_TF_IOV_OFS].iov_len;
1026 srchdr = (const uint8_t *)srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base;
1027 srchdr_len = srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_len;
1028 srcbody = (const uint8_t *)srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_base;
1029 srcbody_len = srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_len;
1030 expected_srcbody = srchdr + SMB2_HDR_BODY;
1031 srcdyn = (const uint8_t *)srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_base;
1032 srcdyn_len = srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_len;
1033 expected_srcdyn = srcbody + 8;
1035 if ((srctf_len != SMB2_TF_HDR_SIZE) && (srctf_len != 0)) {
1036 return false;
1039 if (srchdr_len != SMB2_HDR_BODY) {
1040 return false;
1043 if (srctf_len == SMB2_TF_HDR_SIZE) {
1044 dsttf = talloc_memdup(ctx, srctf, SMB2_TF_HDR_SIZE);
1045 if (dsttf == NULL) {
1046 return false;
1048 } else {
1049 dsttf = NULL;
1051 outvec[SMBD_SMB2_TF_IOV_OFS].iov_base = (void *)dsttf;
1052 outvec[SMBD_SMB2_TF_IOV_OFS].iov_len = srctf_len;
1054 /* vec[SMBD_SMB2_HDR_IOV_OFS] is always boilerplate and must
1055 * be allocated with size OUTVEC_ALLOC_SIZE. */
1057 dsthdr = talloc_memdup(ctx, srchdr, OUTVEC_ALLOC_SIZE);
1058 if (dsthdr == NULL) {
1059 return false;
1061 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)dsthdr;
1062 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1065 * If this is a "standard" vec[SMBD_SMB2_BOFY_IOV_OFS] of length 8,
1066 * pointing to srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + SMB2_HDR_BODY,
1067 * then duplicate this. Else use talloc_memdup().
1070 if ((srcbody == expected_srcbody) && (srcbody_len == 8)) {
1071 dstbody = dsthdr + SMB2_HDR_BODY;
1072 } else {
1073 dstbody = talloc_memdup(ctx, srcbody, srcbody_len);
1074 if (dstbody == NULL) {
1075 return false;
1078 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)dstbody;
1079 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_len = srcbody_len;
1082 * If this is a "standard" vec[SMBD_SMB2_DYN_IOV_OFS] of length 1,
1083 * pointing to
1084 * srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + 8
1085 * then duplicate this. Else use talloc_memdup().
1088 if ((srcdyn == expected_srcdyn) && (srcdyn_len == 1)) {
1089 dstdyn = dsthdr + SMB2_HDR_BODY + 8;
1090 } else if (srcdyn == NULL) {
1091 dstdyn = NULL;
1092 } else {
1093 dstdyn = talloc_memdup(ctx, srcdyn, srcdyn_len);
1094 if (dstdyn == NULL) {
1095 return false;
1098 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_base = (void *)dstdyn;
1099 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_len = srcdyn_len;
1101 return true;
1104 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
1106 struct smbd_smb2_request *newreq = NULL;
1107 struct iovec *outvec = NULL;
1108 int count = req->out.vector_count;
1109 int i;
1111 newreq = smbd_smb2_request_allocate(req->sconn);
1112 if (!newreq) {
1113 return NULL;
1116 newreq->sconn = req->sconn;
1117 newreq->session = req->session;
1118 newreq->do_encryption = req->do_encryption;
1119 newreq->do_signing = req->do_signing;
1120 newreq->current_idx = req->current_idx;
1122 outvec = talloc_zero_array(newreq, struct iovec, count);
1123 if (!outvec) {
1124 TALLOC_FREE(newreq);
1125 return NULL;
1127 newreq->out.vector = outvec;
1128 newreq->out.vector_count = count;
1130 /* Setup the outvec's identically to req. */
1131 outvec[0].iov_base = newreq->out.nbt_hdr;
1132 outvec[0].iov_len = 4;
1133 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
1135 /* Setup the vectors identically to the ones in req. */
1136 for (i = 1; i < count; i += SMBD_SMB2_NUM_IOV_PER_REQ) {
1137 if (!dup_smb2_vec4(outvec, &outvec[i], &req->out.vector[i])) {
1138 break;
1142 if (i < count) {
1143 /* Alloc failed. */
1144 TALLOC_FREE(newreq);
1145 return NULL;
1148 smb2_setup_nbt_length(newreq->out.vector,
1149 newreq->out.vector_count);
1151 return newreq;
1154 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1156 struct smbd_server_connection *sconn = req->sconn;
1157 struct smbXsrv_connection *conn = req->sconn->conn;
1158 int first_idx = 1;
1159 struct iovec *firsttf = NULL;
1160 struct iovec *outhdr_v = NULL;
1161 uint8_t *outhdr = NULL;
1162 struct smbd_smb2_request *nreq = NULL;
1163 NTSTATUS status;
1165 /* Create a new smb2 request we'll use
1166 for the interim return. */
1167 nreq = dup_smb2_req(req);
1168 if (!nreq) {
1169 return NT_STATUS_NO_MEMORY;
1172 /* Lose the last X out vectors. They're the
1173 ones we'll be using for the async reply. */
1174 nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ;
1176 smb2_setup_nbt_length(nreq->out.vector,
1177 nreq->out.vector_count);
1179 /* Step back to the previous reply. */
1180 nreq->current_idx -= SMBD_SMB2_NUM_IOV_PER_REQ;
1181 firsttf = SMBD_SMB2_IDX_TF_IOV(nreq,out,first_idx);
1182 outhdr_v = SMBD_SMB2_OUT_HDR_IOV(nreq);
1183 outhdr = SMBD_SMB2_OUT_HDR_PTR(nreq);
1184 /* And end the chain. */
1185 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1187 /* Calculate outgoing credits */
1188 smb2_calculate_credits(req, nreq);
1190 if (DEBUGLEVEL >= 10) {
1191 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1192 (unsigned int)nreq->current_idx );
1193 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1194 (unsigned int)nreq->out.vector_count );
1195 print_req_vectors(nreq);
1199 * As we have changed the header (SMB2_HDR_NEXT_COMMAND),
1200 * we need to sign/encrypt here with the last/first key we remembered
1202 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
1203 status = smb2_signing_encrypt_pdu(req->first_key,
1204 conn->protocol,
1205 firsttf,
1206 nreq->out.vector_count - first_idx);
1207 if (!NT_STATUS_IS_OK(status)) {
1208 return status;
1210 } else if (req->last_key.length > 0) {
1211 status = smb2_signing_sign_pdu(req->last_key,
1212 conn->protocol,
1213 outhdr_v,
1214 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1215 if (!NT_STATUS_IS_OK(status)) {
1216 return status;
1220 nreq->queue_entry.mem_ctx = nreq;
1221 nreq->queue_entry.vector = nreq->out.vector;
1222 nreq->queue_entry.count = nreq->out.vector_count;
1223 DLIST_ADD_END(nreq->sconn->smb2.send_queue, &nreq->queue_entry, NULL);
1224 nreq->sconn->smb2.send_queue_len++;
1226 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
1227 if (!NT_STATUS_IS_OK(status)) {
1228 return status;
1231 return NT_STATUS_OK;
1234 struct smbd_smb2_request_pending_state {
1235 struct smbd_server_connection *sconn;
1236 struct smbd_smb2_send_queue queue_entry;
1237 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x08 + 1];
1238 struct iovec vector[1 + SMBD_SMB2_NUM_IOV_PER_REQ];
1241 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1242 struct tevent_timer *te,
1243 struct timeval current_time,
1244 void *private_data);
1246 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1247 struct tevent_req *subreq,
1248 uint32_t defer_time)
1250 NTSTATUS status;
1251 struct timeval defer_endtime;
1252 uint8_t *outhdr = NULL;
1253 uint32_t flags;
1255 if (!tevent_req_is_in_progress(subreq)) {
1257 * This is a performance optimization,
1258 * it avoids one tevent_loop iteration,
1259 * which means we avoid one
1260 * talloc_stackframe_pool/talloc_free pair.
1262 tevent_req_notify_callback(subreq);
1263 return NT_STATUS_OK;
1266 req->subreq = subreq;
1267 subreq = NULL;
1269 if (req->async_te) {
1270 /* We're already async. */
1271 return NT_STATUS_OK;
1274 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1275 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1276 if (flags & SMB2_HDR_FLAG_ASYNC) {
1277 /* We're already async. */
1278 return NT_STATUS_OK;
1281 if (req->in.vector_count > req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
1283 * We're trying to go async in a compound
1284 * request chain.
1285 * This is only allowed for opens that
1286 * cause an oplock break, otherwise it
1287 * is not allowed. See [MS-SMB2].pdf
1288 * note <194> on Section 3.3.5.2.7.
1290 const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1292 if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_CREATE) {
1294 * Cancel the outstanding request.
1296 bool ok = tevent_req_cancel(req->subreq);
1297 if (ok) {
1298 return NT_STATUS_OK;
1300 TALLOC_FREE(req->subreq);
1301 return smbd_smb2_request_error(req,
1302 NT_STATUS_INTERNAL_ERROR);
1306 if (DEBUGLEVEL >= 10) {
1307 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1308 (unsigned int)req->current_idx );
1309 print_req_vectors(req);
1312 if (req->current_idx > 1) {
1314 * We're going async in a compound
1315 * chain after the first request has
1316 * already been processed. Send an
1317 * interim response containing the
1318 * set of replies already generated.
1320 int idx = req->current_idx;
1322 status = smb2_send_async_interim_response(req);
1323 if (!NT_STATUS_IS_OK(status)) {
1324 return status;
1326 data_blob_clear_free(&req->first_key);
1328 req->current_idx = 1;
1331 * Re-arrange the in.vectors to remove what
1332 * we just sent.
1334 memmove(&req->in.vector[1],
1335 &req->in.vector[idx],
1336 sizeof(req->in.vector[0])*(req->in.vector_count - idx));
1337 req->in.vector_count = 1 + (req->in.vector_count - idx);
1339 /* Re-arrange the out.vectors to match. */
1340 memmove(&req->out.vector[1],
1341 &req->out.vector[idx],
1342 sizeof(req->out.vector[0])*(req->out.vector_count - idx));
1343 req->out.vector_count = 1 + (req->out.vector_count - idx);
1345 if (req->in.vector_count == 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
1347 * We only have one remaining request as
1348 * we've processed everything else.
1349 * This is no longer a compound request.
1351 req->compound_related = false;
1352 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1353 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1354 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1357 data_blob_clear_free(&req->last_key);
1359 defer_endtime = timeval_current_ofs_usec(defer_time);
1360 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1361 req, defer_endtime,
1362 smbd_smb2_request_pending_timer,
1363 req);
1364 if (req->async_te == NULL) {
1365 return NT_STATUS_NO_MEMORY;
1368 return NT_STATUS_OK;
1371 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1372 struct tevent_timer *te,
1373 struct timeval current_time,
1374 void *private_data)
1376 struct smbd_smb2_request *req =
1377 talloc_get_type_abort(private_data,
1378 struct smbd_smb2_request);
1379 struct smbd_server_connection *sconn = req->sconn;
1380 struct smbd_smb2_request_pending_state *state = NULL;
1381 uint8_t *outhdr = NULL;
1382 const uint8_t *inhdr = NULL;
1383 uint8_t *tf = NULL;
1384 size_t tf_len = 0;
1385 uint8_t *hdr = NULL;
1386 uint8_t *body = NULL;
1387 uint8_t *dyn = NULL;
1388 uint32_t flags = 0;
1389 uint64_t session_id = 0;
1390 uint64_t message_id = 0;
1391 uint64_t nonce_high = 0;
1392 uint64_t nonce_low = 0;
1393 uint64_t async_id = 0;
1394 NTSTATUS status;
1396 TALLOC_FREE(req->async_te);
1398 /* Ensure our final reply matches the interim one. */
1399 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1400 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1401 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1402 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1403 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1405 async_id = message_id; /* keep it simple for now... */
1407 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1408 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1410 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1411 "going async\n",
1412 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1413 (unsigned long long)async_id ));
1416 * What we send is identical to a smbd_smb2_request_error
1417 * packet with an error status of STATUS_PENDING. Make use
1418 * of this fact sometime when refactoring. JRA.
1421 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1422 if (state == NULL) {
1423 smbd_server_connection_terminate(req->sconn,
1424 nt_errstr(NT_STATUS_NO_MEMORY));
1425 return;
1427 state->sconn = req->sconn;
1429 tf = state->buf + NBT_HDR_SIZE;
1430 tf_len = SMB2_TF_HDR_SIZE;
1432 hdr = tf + SMB2_TF_HDR_SIZE;
1433 body = hdr + SMB2_HDR_BODY;
1434 dyn = body + 8;
1436 if (req->do_encryption) {
1437 struct smbXsrv_session *x = req->session;
1439 nonce_high = x->nonce_high;
1440 nonce_low = x->nonce_low;
1442 x->nonce_low += 1;
1443 if (x->nonce_low == 0) {
1444 x->nonce_low += 1;
1445 x->nonce_high += 1;
1449 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1450 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1451 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1452 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1454 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1455 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1456 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1457 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1458 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1460 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1461 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1462 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1463 SBVAL(hdr, SMB2_HDR_PID, async_id);
1464 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1465 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1466 memcpy(hdr+SMB2_HDR_SIGNATURE,
1467 outhdr+SMB2_HDR_SIGNATURE, 16);
1469 SSVAL(body, 0x00, 0x08 + 1);
1471 SCVAL(body, 0x02, 0);
1472 SCVAL(body, 0x03, 0);
1473 SIVAL(body, 0x04, 0);
1474 /* Match W2K8R2... */
1475 SCVAL(dyn, 0x00, 0x21);
1477 state->vector[0].iov_base = (void *)state->buf;
1478 state->vector[0].iov_len = NBT_HDR_SIZE;
1480 if (req->do_encryption) {
1481 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1482 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1483 } else {
1484 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1485 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1488 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1489 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1491 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1492 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1494 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1495 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1497 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1499 /* Ensure we correctly go through crediting. Grant
1500 the credits now, and zero credits on the final
1501 response. */
1502 smb2_set_operation_credit(req->sconn,
1503 SMBD_SMB2_IN_HDR_IOV(req),
1504 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1506 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1508 if (DEBUGLVL(10)) {
1509 int i;
1511 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1512 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1513 (unsigned int)i,
1514 (unsigned int)ARRAY_SIZE(state->vector),
1515 (unsigned int)state->vector[i].iov_len);
1519 if (req->do_encryption) {
1520 struct smbXsrv_session *x = req->session;
1521 struct smbXsrv_connection *conn = x->connection;
1522 DATA_BLOB encryption_key = x->global->encryption_key;
1524 status = smb2_signing_encrypt_pdu(encryption_key,
1525 conn->protocol,
1526 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1527 SMBD_SMB2_NUM_IOV_PER_REQ);
1528 if (!NT_STATUS_IS_OK(status)) {
1529 smbd_server_connection_terminate(req->sconn,
1530 nt_errstr(status));
1531 return;
1533 } else if (req->do_signing) {
1534 struct smbXsrv_session *x = req->session;
1535 struct smbXsrv_connection *conn = x->connection;
1536 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1538 status = smb2_signing_sign_pdu(signing_key,
1539 conn->protocol,
1540 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1541 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1542 if (!NT_STATUS_IS_OK(status)) {
1543 smbd_server_connection_terminate(req->sconn,
1544 nt_errstr(status));
1545 return;
1549 state->queue_entry.mem_ctx = state;
1550 state->queue_entry.vector = state->vector;
1551 state->queue_entry.count = ARRAY_SIZE(state->vector);
1552 DLIST_ADD_END(sconn->smb2.send_queue, &state->queue_entry, NULL);
1553 sconn->smb2.send_queue_len++;
1555 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
1556 if (!NT_STATUS_IS_OK(status)) {
1557 smbd_server_connection_terminate(sconn,
1558 nt_errstr(status));
1559 return;
1563 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1565 struct smbd_server_connection *sconn = req->sconn;
1566 struct smbd_smb2_request *cur;
1567 const uint8_t *inhdr;
1568 uint32_t flags;
1569 uint64_t search_message_id;
1570 uint64_t search_async_id;
1571 uint64_t found_id;
1573 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1575 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1576 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1577 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1580 * we don't need the request anymore
1581 * cancel requests never have a response
1583 DLIST_REMOVE(req->sconn->smb2.requests, req);
1584 TALLOC_FREE(req);
1586 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1587 const uint8_t *outhdr;
1588 uint64_t message_id;
1589 uint64_t async_id;
1591 if (cur->compound_related) {
1593 * Never cancel anything in a compound request.
1594 * Way too hard to deal with the result.
1596 continue;
1599 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1601 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1602 async_id = BVAL(outhdr, SMB2_HDR_PID);
1604 if (flags & SMB2_HDR_FLAG_ASYNC) {
1605 if (search_async_id == async_id) {
1606 found_id = async_id;
1607 break;
1609 } else {
1610 if (search_message_id == message_id) {
1611 found_id = message_id;
1612 break;
1617 if (cur && cur->subreq) {
1618 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1619 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1620 "cancel opcode[%s] mid %llu\n",
1621 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1622 (unsigned long long)found_id ));
1623 tevent_req_cancel(cur->subreq);
1626 return NT_STATUS_OK;
1629 /*************************************************************
1630 Ensure an incoming tid is a valid one for us to access.
1631 Change to the associated uid credentials and chdir to the
1632 valid tid directory.
1633 *************************************************************/
1635 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1637 const uint8_t *inhdr;
1638 uint32_t in_flags;
1639 uint32_t in_tid;
1640 struct smbXsrv_tcon *tcon;
1641 NTSTATUS status;
1642 NTTIME now = timeval_to_nttime(&req->request_time);
1644 req->tcon = NULL;
1646 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1648 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1649 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1651 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1652 in_tid = req->last_tid;
1655 req->last_tid = 0;
1657 status = smb2srv_tcon_lookup(req->session,
1658 in_tid, now, &tcon);
1659 if (!NT_STATUS_IS_OK(status)) {
1660 return status;
1663 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1664 return NT_STATUS_ACCESS_DENIED;
1667 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1668 if (!set_current_service(tcon->compat, 0, true)) {
1669 return NT_STATUS_ACCESS_DENIED;
1672 req->tcon = tcon;
1673 req->last_tid = in_tid;
1675 return NT_STATUS_OK;
1678 /*************************************************************
1679 Ensure an incoming session_id is a valid one for us to access.
1680 *************************************************************/
1682 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1684 const uint8_t *inhdr;
1685 uint32_t in_flags;
1686 uint16_t in_opcode;
1687 uint64_t in_session_id;
1688 struct smbXsrv_session *session = NULL;
1689 struct auth_session_info *session_info;
1690 NTSTATUS status;
1691 NTTIME now = timeval_to_nttime(&req->request_time);
1693 req->session = NULL;
1694 req->tcon = NULL;
1696 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1698 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1699 in_opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1700 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1702 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1703 in_session_id = req->last_session_id;
1706 req->last_session_id = 0;
1708 /* lookup an existing session */
1709 status = smb2srv_session_lookup(req->sconn->conn,
1710 in_session_id, now,
1711 &session);
1712 if (session) {
1713 req->session = session;
1714 req->last_session_id = in_session_id;
1716 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1717 switch (in_opcode) {
1718 case SMB2_OP_SESSSETUP:
1719 status = NT_STATUS_OK;
1720 break;
1721 default:
1722 break;
1725 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1726 switch (in_opcode) {
1727 case SMB2_OP_TCON:
1728 case SMB2_OP_CREATE:
1729 case SMB2_OP_GETINFO:
1730 case SMB2_OP_SETINFO:
1731 return NT_STATUS_INVALID_HANDLE;
1732 default:
1734 * Notice the check for
1735 * (session_info == NULL)
1736 * below.
1738 status = NT_STATUS_OK;
1739 break;
1742 if (!NT_STATUS_IS_OK(status)) {
1743 return status;
1746 session_info = session->global->auth_session_info;
1747 if (session_info == NULL) {
1748 return NT_STATUS_INVALID_HANDLE;
1751 if (in_session_id != req->sconn->conn->last_session_id) {
1752 req->sconn->conn->last_session_id = in_session_id;
1753 set_current_user_info(session_info->unix_info->sanitized_username,
1754 session_info->unix_info->unix_name,
1755 session_info->info->domain_name);
1758 return NT_STATUS_OK;
1761 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1762 uint32_t data_length)
1764 uint16_t needed_charge;
1765 uint16_t credit_charge = 1;
1766 const uint8_t *inhdr;
1768 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1770 if (req->sconn->smb2.supports_multicredit) {
1771 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1772 credit_charge = MAX(credit_charge, 1);
1775 needed_charge = (data_length - 1)/ 65536 + 1;
1777 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1778 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1779 credit_charge, needed_charge));
1781 if (needed_charge > credit_charge) {
1782 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1783 credit_charge, needed_charge));
1784 return NT_STATUS_INVALID_PARAMETER;
1787 return NT_STATUS_OK;
1790 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1791 size_t expected_body_size)
1793 struct iovec *inhdr_v;
1794 const uint8_t *inhdr;
1795 uint16_t opcode;
1796 const uint8_t *inbody;
1797 size_t body_size;
1798 size_t min_dyn_size = expected_body_size & 0x00000001;
1799 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1802 * The following should be checked already.
1804 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1805 return NT_STATUS_INTERNAL_ERROR;
1807 if (req->current_idx > max_idx) {
1808 return NT_STATUS_INTERNAL_ERROR;
1811 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1812 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1813 return NT_STATUS_INTERNAL_ERROR;
1815 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1816 return NT_STATUS_INTERNAL_ERROR;
1819 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1820 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1822 switch (opcode) {
1823 case SMB2_OP_IOCTL:
1824 case SMB2_OP_GETINFO:
1825 min_dyn_size = 0;
1826 break;
1830 * Now check the expected body size,
1831 * where the last byte might be in the
1832 * dynamic section..
1834 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1835 return NT_STATUS_INVALID_PARAMETER;
1837 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1838 return NT_STATUS_INVALID_PARAMETER;
1841 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1843 body_size = SVAL(inbody, 0x00);
1844 if (body_size != expected_body_size) {
1845 return NT_STATUS_INVALID_PARAMETER;
1848 return NT_STATUS_OK;
1851 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1853 struct smbXsrv_connection *conn = req->sconn->conn;
1854 const struct smbd_smb2_dispatch_table *call = NULL;
1855 const struct iovec *intf_v = SMBD_SMB2_IN_TF_IOV(req);
1856 const uint8_t *inhdr;
1857 uint16_t opcode;
1858 uint32_t flags;
1859 uint64_t mid;
1860 NTSTATUS status;
1861 NTSTATUS session_status;
1862 uint32_t allowed_flags;
1863 NTSTATUS return_value;
1864 struct smbXsrv_session *x = NULL;
1865 bool signing_required = false;
1866 bool encryption_required = false;
1868 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1870 /* TODO: verify more things */
1872 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1873 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1874 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1875 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1876 smb2_opcode_name(opcode),
1877 (unsigned long long)mid));
1879 if (conn->protocol >= PROTOCOL_SMB2_02) {
1881 * once the protocol is negotiated
1882 * SMB2_OP_NEGPROT is not allowed anymore
1884 if (opcode == SMB2_OP_NEGPROT) {
1885 /* drop the connection */
1886 return NT_STATUS_INVALID_PARAMETER;
1888 } else {
1890 * if the protocol is not negotiated yet
1891 * only SMB2_OP_NEGPROT is allowed.
1893 if (opcode != SMB2_OP_NEGPROT) {
1894 /* drop the connection */
1895 return NT_STATUS_INVALID_PARAMETER;
1900 * Check if the client provided a valid session id,
1901 * if so smbd_smb2_request_check_session() calls
1902 * set_current_user_info().
1904 * As some command don't require a valid session id
1905 * we defer the check of the session_status
1907 session_status = smbd_smb2_request_check_session(req);
1908 x = req->session;
1909 if (x != NULL) {
1910 signing_required = x->global->signing_required;
1911 encryption_required = x->global->encryption_required;
1914 req->do_signing = false;
1915 req->do_encryption = false;
1916 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
1917 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
1918 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
1920 if (x != NULL && x->global->session_wire_id != tf_session_id) {
1921 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1922 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
1923 (unsigned long long)x->global->session_wire_id,
1924 (unsigned long long)tf_session_id));
1926 * TODO: windows allows this...
1927 * should we drop the connection?
1929 * For now we just return ACCESS_DENIED
1930 * (Windows clients never trigger this)
1931 * and wait for an update of [MS-SMB2].
1933 return smbd_smb2_request_error(req,
1934 NT_STATUS_ACCESS_DENIED);
1937 req->do_encryption = true;
1940 if (encryption_required && !req->do_encryption) {
1941 return smbd_smb2_request_error(req,
1942 NT_STATUS_ACCESS_DENIED);
1945 call = smbd_smb2_call(opcode);
1946 if (call == NULL) {
1947 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1950 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1951 SMB2_HDR_FLAG_SIGNED |
1952 SMB2_HDR_FLAG_DFS;
1953 if (opcode == SMB2_OP_CANCEL) {
1954 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1956 if ((flags & ~allowed_flags) != 0) {
1957 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1960 if (flags & SMB2_HDR_FLAG_CHAINED) {
1962 * This check is mostly for giving the correct error code
1963 * for compounded requests.
1965 if (!NT_STATUS_IS_OK(session_status)) {
1966 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1968 } else {
1969 req->compat_chain_fsp = NULL;
1972 if (req->do_encryption) {
1973 signing_required = false;
1974 } else if (flags & SMB2_HDR_FLAG_SIGNED) {
1975 DATA_BLOB signing_key;
1977 if (x == NULL) {
1978 return smbd_smb2_request_error(
1979 req, NT_STATUS_ACCESS_DENIED);
1982 signing_key = x->global->channels[0].signing_key;
1985 * If we have a signing key, we should
1986 * sign the response
1988 if (signing_key.length > 0) {
1989 req->do_signing = true;
1992 status = smb2_signing_check_pdu(signing_key,
1993 conn->protocol,
1994 SMBD_SMB2_IN_HDR_IOV(req),
1995 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1996 if (!NT_STATUS_IS_OK(status)) {
1997 return smbd_smb2_request_error(req, status);
2001 * Now that we know the request was correctly signed
2002 * we have to sign the response too.
2004 req->do_signing = true;
2006 if (!NT_STATUS_IS_OK(session_status)) {
2007 return smbd_smb2_request_error(req, session_status);
2009 } else if (opcode == SMB2_OP_CANCEL) {
2010 /* Cancel requests are allowed to skip the signing */
2011 } else if (signing_required) {
2013 * If signing is required we try to sign
2014 * a possible error response
2016 req->do_signing = true;
2017 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2020 if (flags & SMB2_HDR_FLAG_CHAINED) {
2021 req->compound_related = true;
2024 if (call->need_session) {
2025 if (!NT_STATUS_IS_OK(session_status)) {
2026 return smbd_smb2_request_error(req, session_status);
2030 if (call->need_tcon) {
2031 SMB_ASSERT(call->need_session);
2034 * This call needs to be run as user.
2036 * smbd_smb2_request_check_tcon()
2037 * calls change_to_user() on success.
2039 status = smbd_smb2_request_check_tcon(req);
2040 if (!NT_STATUS_IS_OK(status)) {
2041 return smbd_smb2_request_error(req, status);
2043 if (req->tcon->global->encryption_required) {
2044 encryption_required = true;
2046 if (encryption_required && !req->do_encryption) {
2047 return smbd_smb2_request_error(req,
2048 NT_STATUS_ACCESS_DENIED);
2052 if (call->fileid_ofs != 0) {
2053 size_t needed = call->fileid_ofs + 16;
2054 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2055 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2056 uint64_t file_id_persistent;
2057 uint64_t file_id_volatile;
2058 struct files_struct *fsp;
2060 SMB_ASSERT(call->need_tcon);
2062 if (needed > body_size) {
2063 return smbd_smb2_request_error(req,
2064 NT_STATUS_INVALID_PARAMETER);
2067 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2068 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2070 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2071 if (fsp == NULL) {
2072 if (!call->allow_invalid_fileid) {
2073 return smbd_smb2_request_error(req,
2074 NT_STATUS_FILE_CLOSED);
2077 if (file_id_persistent != UINT64_MAX) {
2078 return smbd_smb2_request_error(req,
2079 NT_STATUS_FILE_CLOSED);
2081 if (file_id_volatile != UINT64_MAX) {
2082 return smbd_smb2_request_error(req,
2083 NT_STATUS_FILE_CLOSED);
2088 if (call->as_root) {
2089 SMB_ASSERT(call->fileid_ofs == 0);
2090 /* This call needs to be run as root */
2091 change_to_root_user();
2092 } else {
2093 SMB_ASSERT(call->need_tcon);
2096 switch (opcode) {
2097 case SMB2_OP_NEGPROT:
2099 START_PROFILE(smb2_negprot);
2100 return_value = smbd_smb2_request_process_negprot(req);
2101 END_PROFILE(smb2_negprot);
2103 break;
2105 case SMB2_OP_SESSSETUP:
2107 START_PROFILE(smb2_sesssetup);
2108 return_value = smbd_smb2_request_process_sesssetup(req);
2109 END_PROFILE(smb2_sesssetup);
2111 break;
2113 case SMB2_OP_LOGOFF:
2115 START_PROFILE(smb2_logoff);
2116 return_value = smbd_smb2_request_process_logoff(req);
2117 END_PROFILE(smb2_logoff);
2119 break;
2121 case SMB2_OP_TCON:
2123 START_PROFILE(smb2_tcon);
2124 return_value = smbd_smb2_request_process_tcon(req);
2125 END_PROFILE(smb2_tcon);
2127 break;
2129 case SMB2_OP_TDIS:
2131 START_PROFILE(smb2_tdis);
2132 return_value = smbd_smb2_request_process_tdis(req);
2133 END_PROFILE(smb2_tdis);
2135 break;
2137 case SMB2_OP_CREATE:
2139 START_PROFILE(smb2_create);
2140 return_value = smbd_smb2_request_process_create(req);
2141 END_PROFILE(smb2_create);
2143 break;
2145 case SMB2_OP_CLOSE:
2147 START_PROFILE(smb2_close);
2148 return_value = smbd_smb2_request_process_close(req);
2149 END_PROFILE(smb2_close);
2151 break;
2153 case SMB2_OP_FLUSH:
2155 START_PROFILE(smb2_flush);
2156 return_value = smbd_smb2_request_process_flush(req);
2157 END_PROFILE(smb2_flush);
2159 break;
2161 case SMB2_OP_READ:
2163 START_PROFILE(smb2_read);
2164 return_value = smbd_smb2_request_process_read(req);
2165 END_PROFILE(smb2_read);
2167 break;
2169 case SMB2_OP_WRITE:
2171 START_PROFILE(smb2_write);
2172 return_value = smbd_smb2_request_process_write(req);
2173 END_PROFILE(smb2_write);
2175 break;
2177 case SMB2_OP_LOCK:
2179 START_PROFILE(smb2_lock);
2180 return_value = smbd_smb2_request_process_lock(req);
2181 END_PROFILE(smb2_lock);
2183 break;
2185 case SMB2_OP_IOCTL:
2187 START_PROFILE(smb2_ioctl);
2188 return_value = smbd_smb2_request_process_ioctl(req);
2189 END_PROFILE(smb2_ioctl);
2191 break;
2193 case SMB2_OP_CANCEL:
2195 START_PROFILE(smb2_cancel);
2196 return_value = smbd_smb2_request_process_cancel(req);
2197 END_PROFILE(smb2_cancel);
2199 break;
2201 case SMB2_OP_KEEPALIVE:
2203 START_PROFILE(smb2_keepalive);
2204 return_value = smbd_smb2_request_process_keepalive(req);
2205 END_PROFILE(smb2_keepalive);
2207 break;
2209 case SMB2_OP_FIND:
2211 START_PROFILE(smb2_find);
2212 return_value = smbd_smb2_request_process_find(req);
2213 END_PROFILE(smb2_find);
2215 break;
2217 case SMB2_OP_NOTIFY:
2219 START_PROFILE(smb2_notify);
2220 return_value = smbd_smb2_request_process_notify(req);
2221 END_PROFILE(smb2_notify);
2223 break;
2225 case SMB2_OP_GETINFO:
2227 START_PROFILE(smb2_getinfo);
2228 return_value = smbd_smb2_request_process_getinfo(req);
2229 END_PROFILE(smb2_getinfo);
2231 break;
2233 case SMB2_OP_SETINFO:
2235 START_PROFILE(smb2_setinfo);
2236 return_value = smbd_smb2_request_process_setinfo(req);
2237 END_PROFILE(smb2_setinfo);
2239 break;
2241 case SMB2_OP_BREAK:
2243 START_PROFILE(smb2_break);
2244 return_value = smbd_smb2_request_process_break(req);
2245 END_PROFILE(smb2_break);
2247 break;
2249 default:
2250 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2251 break;
2253 return return_value;
2256 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2258 struct smbd_server_connection *sconn = req->sconn;
2259 struct smbXsrv_connection *conn = req->sconn->conn;
2260 int first_idx = 1;
2261 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2262 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2263 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2264 NTSTATUS status;
2266 req->subreq = NULL;
2267 TALLOC_FREE(req->async_te);
2269 if (req->do_encryption &&
2270 (firsttf->iov_len == 0) &&
2271 (req->first_key.length == 0) &&
2272 (req->session != NULL) &&
2273 (req->session->global->encryption_key.length != 0))
2275 DATA_BLOB encryption_key = req->session->global->encryption_key;
2276 uint8_t *tf;
2277 uint64_t session_id = req->session->global->session_wire_id;
2278 struct smbXsrv_session *x = req->session;
2279 uint64_t nonce_high;
2280 uint64_t nonce_low;
2282 nonce_high = x->nonce_high;
2283 nonce_low = x->nonce_low;
2285 x->nonce_low += 1;
2286 if (x->nonce_low == 0) {
2287 x->nonce_low += 1;
2288 x->nonce_high += 1;
2292 * We need to place the SMB2_TRANSFORM header before the
2293 * first SMB2 header
2297 * we need to remember the encryption key
2298 * and defer the signing/encryption until
2299 * we are sure that we do not change
2300 * the header again.
2302 req->first_key = data_blob_dup_talloc(req, encryption_key);
2303 if (req->first_key.data == NULL) {
2304 return NT_STATUS_NO_MEMORY;
2307 tf = talloc_zero_array(req->out.vector, uint8_t,
2308 SMB2_TF_HDR_SIZE);
2309 if (tf == NULL) {
2310 return NT_STATUS_NO_MEMORY;
2313 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2314 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2315 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2316 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2318 firsttf->iov_base = (void *)tf;
2319 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2322 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2323 (req->last_key.length > 0) &&
2324 (firsttf->iov_len == 0))
2326 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2327 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2330 * As we are sure the header of the last request in the
2331 * compound chain will not change, we can to sign here
2332 * with the last signing key we remembered.
2334 status = smb2_signing_sign_pdu(req->last_key,
2335 conn->protocol,
2336 lasthdr,
2337 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2338 if (!NT_STATUS_IS_OK(status)) {
2339 return status;
2342 data_blob_clear_free(&req->last_key);
2344 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2346 if (req->current_idx < req->out.vector_count) {
2348 * We must process the remaining compound
2349 * SMB2 requests before any new incoming SMB2
2350 * requests. This is because incoming SMB2
2351 * requests may include a cancel for a
2352 * compound request we haven't processed
2353 * yet.
2355 struct tevent_immediate *im = tevent_create_immediate(req);
2356 if (!im) {
2357 return NT_STATUS_NO_MEMORY;
2360 if (req->do_signing && firsttf->iov_len == 0) {
2361 struct smbXsrv_session *x = req->session;
2362 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2365 * we need to remember the signing key
2366 * and defer the signing until
2367 * we are sure that we do not change
2368 * the header again.
2370 req->last_key = data_blob_dup_talloc(req, signing_key);
2371 if (req->last_key.data == NULL) {
2372 return NT_STATUS_NO_MEMORY;
2376 tevent_schedule_immediate(im,
2377 req->sconn->ev_ctx,
2378 smbd_smb2_request_dispatch_immediate,
2379 req);
2380 return NT_STATUS_OK;
2383 if (req->compound_related) {
2384 req->compound_related = false;
2387 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2389 /* Set credit for these operations (zero credits if this
2390 is a final reply for an async operation). */
2391 smb2_calculate_credits(req, req);
2394 * now check if we need to sign the current response
2396 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2397 status = smb2_signing_encrypt_pdu(req->first_key,
2398 conn->protocol,
2399 firsttf,
2400 req->out.vector_count - first_idx);
2401 if (!NT_STATUS_IS_OK(status)) {
2402 return status;
2404 } else if (req->do_signing) {
2405 struct smbXsrv_session *x = req->session;
2406 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2408 status = smb2_signing_sign_pdu(signing_key,
2409 conn->protocol,
2410 outhdr,
2411 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2412 if (!NT_STATUS_IS_OK(status)) {
2413 return status;
2416 data_blob_clear_free(&req->first_key);
2418 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2419 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2420 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2421 /* Dynamic part is NULL. Chop it off,
2422 We're going to send it via sendfile. */
2423 req->out.vector_count -= 1;
2427 * We're done with this request -
2428 * move it off the "being processed" queue.
2430 DLIST_REMOVE(req->sconn->smb2.requests, req);
2432 req->queue_entry.mem_ctx = req;
2433 req->queue_entry.vector = req->out.vector;
2434 req->queue_entry.count = req->out.vector_count;
2435 DLIST_ADD_END(req->sconn->smb2.send_queue, &req->queue_entry, NULL);
2436 req->sconn->smb2.send_queue_len++;
2438 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
2439 if (!NT_STATUS_IS_OK(status)) {
2440 return status;
2443 return NT_STATUS_OK;
2446 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2448 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2449 struct tevent_immediate *im,
2450 void *private_data)
2452 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2453 struct smbd_smb2_request);
2454 struct smbd_server_connection *sconn = req->sconn;
2455 NTSTATUS status;
2457 TALLOC_FREE(im);
2459 if (DEBUGLEVEL >= 10) {
2460 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2461 req->current_idx, req->in.vector_count));
2462 print_req_vectors(req);
2465 status = smbd_smb2_request_dispatch(req);
2466 if (!NT_STATUS_IS_OK(status)) {
2467 smbd_server_connection_terminate(sconn, nt_errstr(status));
2468 return;
2471 status = smbd_smb2_request_next_incoming(sconn);
2472 if (!NT_STATUS_IS_OK(status)) {
2473 smbd_server_connection_terminate(sconn, nt_errstr(status));
2474 return;
2478 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2479 NTSTATUS status,
2480 DATA_BLOB body, DATA_BLOB *dyn,
2481 const char *location)
2483 uint8_t *outhdr;
2484 struct iovec *outbody_v;
2485 struct iovec *outdyn_v;
2486 uint32_t next_command_ofs;
2488 DEBUG(10,("smbd_smb2_request_done_ex: "
2489 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2490 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2491 dyn ? "yes": "no",
2492 (unsigned int)(dyn ? dyn->length : 0),
2493 location));
2495 if (body.length < 2) {
2496 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2499 if ((body.length % 2) != 0) {
2500 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2503 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2504 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2505 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2507 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2508 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2510 outbody_v->iov_base = (void *)body.data;
2511 outbody_v->iov_len = body.length;
2513 if (dyn) {
2514 outdyn_v->iov_base = (void *)dyn->data;
2515 outdyn_v->iov_len = dyn->length;
2516 } else {
2517 outdyn_v->iov_base = NULL;
2518 outdyn_v->iov_len = 0;
2521 /* see if we need to recalculate the offset to the next response */
2522 if (next_command_ofs > 0) {
2523 next_command_ofs = SMB2_HDR_BODY;
2524 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2525 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2528 if ((next_command_ofs % 8) != 0) {
2529 size_t pad_size = 8 - (next_command_ofs % 8);
2530 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2532 * if the dyn buffer is empty
2533 * we can use it to add padding
2535 uint8_t *pad;
2537 pad = talloc_zero_array(req->out.vector,
2538 uint8_t, pad_size);
2539 if (pad == NULL) {
2540 return smbd_smb2_request_error(req,
2541 NT_STATUS_NO_MEMORY);
2544 outdyn_v->iov_base = (void *)pad;
2545 outdyn_v->iov_len = pad_size;
2546 } else {
2548 * For now we copy the dynamic buffer
2549 * and add the padding to the new buffer
2551 size_t old_size;
2552 uint8_t *old_dyn;
2553 size_t new_size;
2554 uint8_t *new_dyn;
2556 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2557 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2559 new_size = old_size + pad_size;
2560 new_dyn = talloc_zero_array(req->out.vector,
2561 uint8_t, new_size);
2562 if (new_dyn == NULL) {
2563 return smbd_smb2_request_error(req,
2564 NT_STATUS_NO_MEMORY);
2567 memcpy(new_dyn, old_dyn, old_size);
2568 memset(new_dyn + old_size, 0, pad_size);
2570 outdyn_v->iov_base = (void *)new_dyn;
2571 outdyn_v->iov_len = new_size;
2573 next_command_ofs += pad_size;
2576 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2578 return smbd_smb2_request_reply(req);
2581 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2582 NTSTATUS status,
2583 DATA_BLOB *info,
2584 const char *location)
2586 DATA_BLOB body;
2587 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2588 size_t unread_bytes = smbd_smb2_unread_bytes(req);
2590 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2591 req->current_idx, nt_errstr(status), info ? " +info" : "",
2592 location));
2594 if (unread_bytes) {
2595 /* Recvfile error. Drain incoming socket. */
2596 size_t ret;
2598 errno = 0;
2599 ret = drain_socket(req->sconn->sock, unread_bytes);
2600 if (ret != unread_bytes) {
2601 NTSTATUS error;
2603 if (errno == 0) {
2604 error = NT_STATUS_IO_DEVICE_ERROR;
2605 } else {
2606 error = map_nt_error_from_unix_common(errno);
2609 DEBUG(2, ("Failed to drain %u bytes from SMB2 socket: "
2610 "ret[%u] errno[%d] => %s\n",
2611 (unsigned)unread_bytes,
2612 (unsigned)ret, errno, nt_errstr(error)));
2613 return error;
2617 body.data = outhdr + SMB2_HDR_BODY;
2618 body.length = 8;
2619 SSVAL(body.data, 0, 9);
2621 if (info) {
2622 SIVAL(body.data, 0x04, info->length);
2623 } else {
2624 /* Allocated size of req->out.vector[i].iov_base
2625 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2626 * 1 byte without having to do an alloc.
2628 info = talloc_zero_array(req->out.vector,
2629 DATA_BLOB,
2631 if (!info) {
2632 return NT_STATUS_NO_MEMORY;
2634 info->data = ((uint8_t *)outhdr) +
2635 OUTVEC_ALLOC_SIZE - 1;
2636 info->length = 1;
2637 SCVAL(info->data, 0, 0);
2641 * Note: Even if there is an error, continue to process the request.
2642 * per MS-SMB2.
2645 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2649 struct smbd_smb2_send_oplock_break_state {
2650 struct smbd_server_connection *sconn;
2651 struct smbd_smb2_send_queue queue_entry;
2652 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x18];
2653 struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ];
2656 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2657 struct smbXsrv_session *session,
2658 struct smbXsrv_tcon *tcon,
2659 struct smbXsrv_open *op,
2660 uint8_t oplock_level)
2662 struct smbd_smb2_send_oplock_break_state *state;
2663 struct smbXsrv_connection *conn = sconn->conn;
2664 uint8_t *tf;
2665 size_t tf_len;
2666 uint8_t *hdr;
2667 uint8_t *body;
2668 size_t body_len;
2669 uint8_t *dyn;
2670 size_t dyn_len;
2671 bool do_encryption = session->global->encryption_required;
2672 uint64_t nonce_high = 0;
2673 uint64_t nonce_low = 0;
2674 NTSTATUS status;
2676 if (tcon->global->encryption_required) {
2677 do_encryption = true;
2680 state = talloc_zero(sconn, struct smbd_smb2_send_oplock_break_state);
2681 if (state == NULL) {
2682 return NT_STATUS_NO_MEMORY;
2684 state->sconn = sconn;
2686 tf = state->buf + NBT_HDR_SIZE;
2687 tf_len = SMB2_TF_HDR_SIZE;
2688 hdr = tf + tf_len;
2689 body = hdr + SMB2_HDR_BODY;
2690 body_len = 0x18;
2691 dyn = body + body_len;
2692 dyn_len = 0;
2694 if (do_encryption) {
2695 nonce_high = session->nonce_high;
2696 nonce_low = session->nonce_low;
2698 session->nonce_low += 1;
2699 if (session->nonce_low == 0) {
2700 session->nonce_low += 1;
2701 session->nonce_high += 1;
2705 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2706 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2707 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2708 SBVAL(tf, SMB2_TF_SESSION_ID, session->global->session_wire_id);
2710 SIVAL(hdr, 0, SMB2_MAGIC);
2711 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2712 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2713 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2714 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2715 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2716 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2717 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2718 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2719 SIVAL(hdr, SMB2_HDR_PID, 0);
2720 SIVAL(hdr, SMB2_HDR_TID, 0);
2721 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2722 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2724 SSVAL(body, 0x00, body_len);
2726 SCVAL(body, 0x02, oplock_level);
2727 SCVAL(body, 0x03, 0); /* reserved */
2728 SIVAL(body, 0x04, 0); /* reserved */
2729 SBVAL(body, 0x08, op->global->open_persistent_id);
2730 SBVAL(body, 0x10, op->global->open_volatile_id);
2732 state->vector[0].iov_base = (void *)state->buf;
2733 state->vector[0].iov_len = NBT_HDR_SIZE;
2735 if (do_encryption) {
2736 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
2737 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
2738 } else {
2739 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
2740 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
2743 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
2744 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
2746 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
2747 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = body_len;
2749 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
2750 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_len;
2752 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
2754 if (do_encryption) {
2755 DATA_BLOB encryption_key = session->global->encryption_key;
2757 status = smb2_signing_encrypt_pdu(encryption_key,
2758 conn->protocol,
2759 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
2760 SMBD_SMB2_NUM_IOV_PER_REQ);
2761 if (!NT_STATUS_IS_OK(status)) {
2762 return status;
2766 state->queue_entry.mem_ctx = state;
2767 state->queue_entry.vector = state->vector;
2768 state->queue_entry.count = ARRAY_SIZE(state->vector);
2769 DLIST_ADD_END(state->sconn->smb2.send_queue, &state->queue_entry, NULL);
2770 state->sconn->smb2.send_queue_len++;
2772 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
2773 if (!NT_STATUS_IS_OK(status)) {
2774 return status;
2777 return NT_STATUS_OK;
2780 static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req)
2782 if (smb2_req->do_signing) {
2783 return 0;
2785 if (smb2_req->do_encryption) {
2786 return 0;
2788 return (size_t)lp_min_receive_file_size();
2791 static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
2793 uint32_t flags;
2795 if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
2796 /* Transform header. Cannot recvfile. */
2797 return false;
2799 if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
2800 /* Not SMB2. Normal error path will cope. */
2801 return false;
2803 if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
2804 /* Not SMB2. Normal error path will cope. */
2805 return false;
2807 if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
2808 /* Needs to be a WRITE. */
2809 return false;
2811 if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
2812 /* Chained. Cannot recvfile. */
2813 return false;
2815 flags = IVAL(state->pktbuf, SMB2_HDR_FLAGS);
2816 if (flags & SMB2_HDR_FLAG_CHAINED) {
2817 /* Chained. Cannot recvfile. */
2818 return false;
2820 if (flags & SMB2_HDR_FLAG_SIGNED) {
2821 /* Signed. Cannot recvfile. */
2822 return false;
2825 DEBUG(10,("Doing recvfile write len = %u\n",
2826 (unsigned int)(state->pktlen -
2827 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN)));
2829 return true;
2832 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2834 struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state;
2835 size_t max_send_queue_len;
2836 size_t cur_send_queue_len;
2838 if (!NT_STATUS_IS_OK(sconn->status)) {
2840 * we're not supposed to do any io
2842 return NT_STATUS_OK;
2845 if (state->req != NULL) {
2847 * if there is already a tstream_readv_pdu
2848 * pending, we are done.
2850 return NT_STATUS_OK;
2853 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2854 cur_send_queue_len = sconn->smb2.send_queue_len;
2856 if (cur_send_queue_len > max_send_queue_len) {
2858 * if we have a lot of requests to send,
2859 * we wait until they are on the wire until we
2860 * ask for the next request.
2862 return NT_STATUS_OK;
2865 /* ask for the next request */
2866 ZERO_STRUCTP(state);
2867 state->req = smbd_smb2_request_allocate(sconn);
2868 if (state->req == NULL) {
2869 return NT_STATUS_NO_MEMORY;
2871 state->req->sconn = sconn;
2872 state->min_recv_size = get_min_receive_file_size(state->req);
2874 TEVENT_FD_READABLE(sconn->smb2.fde);
2876 return NT_STATUS_OK;
2879 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2880 uint8_t *inbuf, size_t size)
2882 NTSTATUS status;
2883 struct smbd_smb2_request *req = NULL;
2885 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2886 (unsigned int)size));
2888 status = smbd_initialize_smb2(sconn);
2889 if (!NT_STATUS_IS_OK(status)) {
2890 smbd_server_connection_terminate(sconn, nt_errstr(status));
2891 return;
2894 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2895 if (!NT_STATUS_IS_OK(status)) {
2896 smbd_server_connection_terminate(sconn, nt_errstr(status));
2897 return;
2900 status = smbd_smb2_request_validate(req);
2901 if (!NT_STATUS_IS_OK(status)) {
2902 smbd_server_connection_terminate(sconn, nt_errstr(status));
2903 return;
2906 status = smbd_smb2_request_setup_out(req);
2907 if (!NT_STATUS_IS_OK(status)) {
2908 smbd_server_connection_terminate(sconn, nt_errstr(status));
2909 return;
2912 status = smbd_smb2_request_dispatch(req);
2913 if (!NT_STATUS_IS_OK(status)) {
2914 smbd_server_connection_terminate(sconn, nt_errstr(status));
2915 return;
2918 status = smbd_smb2_request_next_incoming(sconn);
2919 if (!NT_STATUS_IS_OK(status)) {
2920 smbd_server_connection_terminate(sconn, nt_errstr(status));
2921 return;
2924 sconn->num_requests++;
2927 static int socket_error_from_errno(int ret,
2928 int sys_errno,
2929 bool *retry)
2931 *retry = false;
2933 if (ret >= 0) {
2934 return 0;
2937 if (ret != -1) {
2938 return EIO;
2941 if (sys_errno == 0) {
2942 return EIO;
2945 if (sys_errno == EINTR) {
2946 *retry = true;
2947 return sys_errno;
2950 if (sys_errno == EINPROGRESS) {
2951 *retry = true;
2952 return sys_errno;
2955 if (sys_errno == EAGAIN) {
2956 *retry = true;
2957 return sys_errno;
2960 /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
2961 if (sys_errno == ENOMEM) {
2962 *retry = true;
2963 return sys_errno;
2966 #ifdef EWOULDBLOCK
2967 if (sys_errno == EWOULDBLOCK) {
2968 *retry = true;
2969 return sys_errno;
2971 #endif
2973 return sys_errno;
2976 static NTSTATUS smbd_smb2_flush_send_queue(struct smbd_server_connection *sconn)
2978 int ret;
2979 int err;
2980 bool retry;
2982 if (sconn->smb2.send_queue == NULL) {
2983 TEVENT_FD_NOT_WRITEABLE(sconn->smb2.fde);
2984 return NT_STATUS_OK;
2987 while (sconn->smb2.send_queue != NULL) {
2988 struct smbd_smb2_send_queue *e = sconn->smb2.send_queue;
2990 if (e->sendfile_header != NULL) {
2991 size_t size = 0;
2992 size_t i = 0;
2993 uint8_t *buf;
2995 for (i=0; i < e->count; i++) {
2996 size += e->vector[i].iov_len;
2999 buf = talloc_array(e->mem_ctx, uint8_t, size);
3000 if (buf == NULL) {
3001 return NT_STATUS_NO_MEMORY;
3004 size = 0;
3005 for (i=0; i < e->count; i++) {
3006 memcpy(buf+size,
3007 e->vector[i].iov_base,
3008 e->vector[i].iov_len);
3009 size += e->vector[i].iov_len;
3012 e->sendfile_header->data = buf;
3013 e->sendfile_header->length = size;
3014 e->count = 0;
3016 sconn->smb2.send_queue_len--;
3017 DLIST_REMOVE(sconn->smb2.send_queue, e);
3018 talloc_free(e->mem_ctx);
3019 continue;
3022 ret = writev(sconn->sock, e->vector, e->count);
3023 if (ret == 0) {
3024 /* propagate end of file */
3025 return NT_STATUS_INTERNAL_ERROR;
3027 err = socket_error_from_errno(ret, errno, &retry);
3028 if (retry) {
3029 /* retry later */
3030 TEVENT_FD_WRITEABLE(sconn->smb2.fde);
3031 return NT_STATUS_OK;
3033 if (err != 0) {
3034 return map_nt_error_from_unix_common(err);
3036 while (ret > 0) {
3037 if (ret < e->vector[0].iov_len) {
3038 uint8_t *base;
3039 base = (uint8_t *)e->vector[0].iov_base;
3040 base += ret;
3041 e->vector[0].iov_base = (void *)base;
3042 e->vector[0].iov_len -= ret;
3043 break;
3045 ret -= e->vector[0].iov_len;
3046 e->vector += 1;
3047 e->count -= 1;
3051 * there're maybe some empty vectors at the end
3052 * which we need to skip, otherwise we would get
3053 * ret == 0 from the readv() call and return EPIPE
3055 while (e->count > 0) {
3056 if (e->vector[0].iov_len > 0) {
3057 break;
3059 e->vector += 1;
3060 e->count -= 1;
3063 if (e->count > 0) {
3064 /* we have more to write */
3065 TEVENT_FD_WRITEABLE(sconn->smb2.fde);
3066 return NT_STATUS_OK;
3069 sconn->smb2.send_queue_len--;
3070 DLIST_REMOVE(sconn->smb2.send_queue, e);
3071 talloc_free(e->mem_ctx);
3074 return NT_STATUS_OK;
3077 static NTSTATUS smbd_smb2_io_handler(struct smbd_server_connection *sconn,
3078 uint16_t fde_flags)
3080 struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state;
3081 struct smbd_smb2_request *req = NULL;
3082 size_t min_recvfile_size = UINT32_MAX;
3083 int ret;
3084 int err;
3085 bool retry;
3086 NTSTATUS status;
3087 NTTIME now;
3089 if (!NT_STATUS_IS_OK(sconn->status)) {
3091 * we're not supposed to do any io
3093 TEVENT_FD_NOT_READABLE(sconn->smb2.fde);
3094 TEVENT_FD_NOT_WRITEABLE(sconn->smb2.fde);
3095 return NT_STATUS_OK;
3098 if (fde_flags & TEVENT_FD_WRITE) {
3099 status = smbd_smb2_flush_send_queue(sconn);
3100 if (!NT_STATUS_IS_OK(status)) {
3101 return status;
3105 if (!(fde_flags & TEVENT_FD_READ)) {
3106 return NT_STATUS_OK;
3109 if (state->req == NULL) {
3110 TEVENT_FD_NOT_READABLE(sconn->smb2.fde);
3111 return NT_STATUS_OK;
3114 again:
3115 if (!state->hdr.done) {
3116 state->hdr.done = true;
3118 state->vector.iov_base = (void *)state->hdr.nbt;
3119 state->vector.iov_len = NBT_HDR_SIZE;
3122 ret = readv(sconn->sock, &state->vector, 1);
3123 if (ret == 0) {
3124 /* propagate end of file */
3125 return NT_STATUS_END_OF_FILE;
3127 err = socket_error_from_errno(ret, errno, &retry);
3128 if (retry) {
3129 /* retry later */
3130 TEVENT_FD_READABLE(sconn->smb2.fde);
3131 return NT_STATUS_OK;
3133 if (err != 0) {
3134 return map_nt_error_from_unix_common(err);
3137 if (ret < state->vector.iov_len) {
3138 uint8_t *base;
3139 base = (uint8_t *)state->vector.iov_base;
3140 base += ret;
3141 state->vector.iov_base = (void *)base;
3142 state->vector.iov_len -= ret;
3143 /* we have more to read */
3144 TEVENT_FD_READABLE(sconn->smb2.fde);
3145 return NT_STATUS_OK;
3148 if (state->pktlen > 0) {
3149 if (state->doing_receivefile && !is_smb2_recvfile_write(state)) {
3151 * Not a possible receivefile write.
3152 * Read the rest of the data.
3154 state->doing_receivefile = false;
3155 state->vector.iov_base = (void *)(state->pktbuf +
3156 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
3157 state->vector.iov_len = (state->pktlen -
3158 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
3159 goto again;
3163 * Either this is a receivefile write so we've
3164 * done a short read, or if not we have all the data.
3166 goto got_full;
3170 * Now we analyze the NBT header
3172 state->pktlen = smb2_len(state->hdr.nbt);
3173 if (state->pktlen == 0) {
3174 goto got_full;
3177 state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen);
3178 if (state->pktbuf == NULL) {
3179 return NT_STATUS_NO_MEMORY;
3182 state->vector.iov_base = (void *)state->pktbuf;
3184 if (state->min_recv_size != 0) {
3185 min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3186 min_recvfile_size += state->min_recv_size;
3189 if (state->pktlen > min_recvfile_size) {
3191 * Might be a receivefile write. Read the SMB2 HEADER +
3192 * SMB2_WRITE header first. Set 'doing_receivefile'
3193 * as we're *attempting* receivefile write. If this
3194 * turns out not to be a SMB2_WRITE request or otherwise
3195 * not suitable then we'll just read the rest of the data
3196 * the next time this function is called.
3198 state->vector.iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3199 state->doing_receivefile = true;
3200 } else {
3201 state->vector.iov_len = state->pktlen;
3204 goto again;
3206 got_full:
3208 if (state->hdr.nbt[0] != 0x00) {
3209 DEBUG(1,("ignore NBT[0x%02X] msg\n",
3210 state->hdr.nbt[0]));
3212 req = state->req;
3213 ZERO_STRUCTP(state);
3214 state->req = req;
3215 state->min_recv_size = get_min_receive_file_size(state->req);
3216 req = NULL;
3217 goto again;
3220 req = state->req;
3221 state->req = NULL;
3223 req->request_time = timeval_current();
3224 now = timeval_to_nttime(&req->request_time);
3226 status = smbd_smb2_inbuf_parse_compound(req->sconn->conn,
3227 now,
3228 state->pktbuf,
3229 state->pktlen,
3230 req,
3231 &req->in.vector,
3232 &req->in.vector_count);
3233 if (!NT_STATUS_IS_OK(status)) {
3234 return status;
3237 if (state->doing_receivefile) {
3238 req->smb1req = talloc_zero(req, struct smb_request);
3239 if (req->smb1req == NULL) {
3240 return NT_STATUS_NO_MEMORY;
3242 req->smb1req->unread_bytes =
3243 state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3246 ZERO_STRUCTP(state);
3248 req->current_idx = 1;
3250 DEBUG(10,("smbd_smb2_request idx[%d] of %d vectors\n",
3251 req->current_idx, req->in.vector_count));
3253 status = smbd_smb2_request_validate(req);
3254 if (!NT_STATUS_IS_OK(status)) {
3255 return status;
3258 status = smbd_smb2_request_setup_out(req);
3259 if (!NT_STATUS_IS_OK(status)) {
3260 return status;
3263 status = smbd_smb2_request_dispatch(req);
3264 if (!NT_STATUS_IS_OK(status)) {
3265 return status;
3268 sconn->num_requests++;
3270 /* The timeout_processing function isn't run nearly
3271 often enough to implement 'max log size' without
3272 overrunning the size of the file by many megabytes.
3273 This is especially true if we are running at debug
3274 level 10. Checking every 50 SMB2s is a nice
3275 tradeoff of performance vs log file size overrun. */
3277 if ((sconn->num_requests % 50) == 0 &&
3278 need_to_check_log_size()) {
3279 change_to_root_user();
3280 check_log_size();
3283 status = smbd_smb2_request_next_incoming(sconn);
3284 if (!NT_STATUS_IS_OK(status)) {
3285 return status;
3288 return NT_STATUS_OK;
3291 static void smbd_smb2_connection_handler(struct tevent_context *ev,
3292 struct tevent_fd *fde,
3293 uint16_t flags,
3294 void *private_data)
3296 struct smbd_server_connection *sconn =
3297 talloc_get_type_abort(private_data,
3298 struct smbd_server_connection);
3299 NTSTATUS status;
3301 status = smbd_smb2_io_handler(sconn, flags);
3302 if (!NT_STATUS_IS_OK(status)) {
3303 smbd_server_connection_terminate(sconn, nt_errstr(status));
3304 return;