s3:smbd: update comment to correctly reflect MS-SMB2
[Samba.git] / source3 / smbd / smb2_server.c
blob1e4bedae39cea7cdbaecf11245ef4a03034dccd6
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 very high credit charge.
763 * TODO: scale up depending on 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 request
1284 * chain. This is only allowed for opens that cause an
1285 * oplock break or for the last operation in the
1286 * chain, otherwise it is not allowed. See
1287 * [MS-SMB2].pdf note <206> on Section 3.3.5.2.7.
1289 const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1291 if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_CREATE) {
1293 * Cancel the outstanding request.
1295 bool ok = tevent_req_cancel(req->subreq);
1296 if (ok) {
1297 return NT_STATUS_OK;
1299 TALLOC_FREE(req->subreq);
1300 return smbd_smb2_request_error(req,
1301 NT_STATUS_INTERNAL_ERROR);
1305 if (DEBUGLEVEL >= 10) {
1306 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1307 (unsigned int)req->current_idx );
1308 print_req_vectors(req);
1311 if (req->current_idx > 1) {
1313 * We're going async in a compound
1314 * chain after the first request has
1315 * already been processed. Send an
1316 * interim response containing the
1317 * set of replies already generated.
1319 int idx = req->current_idx;
1321 status = smb2_send_async_interim_response(req);
1322 if (!NT_STATUS_IS_OK(status)) {
1323 return status;
1325 data_blob_clear_free(&req->first_key);
1327 req->current_idx = 1;
1330 * Re-arrange the in.vectors to remove what
1331 * we just sent.
1333 memmove(&req->in.vector[1],
1334 &req->in.vector[idx],
1335 sizeof(req->in.vector[0])*(req->in.vector_count - idx));
1336 req->in.vector_count = 1 + (req->in.vector_count - idx);
1338 /* Re-arrange the out.vectors to match. */
1339 memmove(&req->out.vector[1],
1340 &req->out.vector[idx],
1341 sizeof(req->out.vector[0])*(req->out.vector_count - idx));
1342 req->out.vector_count = 1 + (req->out.vector_count - idx);
1344 if (req->in.vector_count == 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
1346 * We only have one remaining request as
1347 * we've processed everything else.
1348 * This is no longer a compound request.
1350 req->compound_related = false;
1351 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1352 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1353 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1356 data_blob_clear_free(&req->last_key);
1358 defer_endtime = timeval_current_ofs_usec(defer_time);
1359 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1360 req, defer_endtime,
1361 smbd_smb2_request_pending_timer,
1362 req);
1363 if (req->async_te == NULL) {
1364 return NT_STATUS_NO_MEMORY;
1367 return NT_STATUS_OK;
1370 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1371 struct tevent_timer *te,
1372 struct timeval current_time,
1373 void *private_data)
1375 struct smbd_smb2_request *req =
1376 talloc_get_type_abort(private_data,
1377 struct smbd_smb2_request);
1378 struct smbd_server_connection *sconn = req->sconn;
1379 struct smbd_smb2_request_pending_state *state = NULL;
1380 uint8_t *outhdr = NULL;
1381 const uint8_t *inhdr = NULL;
1382 uint8_t *tf = NULL;
1383 size_t tf_len = 0;
1384 uint8_t *hdr = NULL;
1385 uint8_t *body = NULL;
1386 uint8_t *dyn = NULL;
1387 uint32_t flags = 0;
1388 uint64_t session_id = 0;
1389 uint64_t message_id = 0;
1390 uint64_t nonce_high = 0;
1391 uint64_t nonce_low = 0;
1392 uint64_t async_id = 0;
1393 NTSTATUS status;
1395 TALLOC_FREE(req->async_te);
1397 /* Ensure our final reply matches the interim one. */
1398 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1399 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1400 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1401 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1402 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1404 async_id = message_id; /* keep it simple for now... */
1406 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1407 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1409 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1410 "going async\n",
1411 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1412 (unsigned long long)async_id ));
1415 * What we send is identical to a smbd_smb2_request_error
1416 * packet with an error status of STATUS_PENDING. Make use
1417 * of this fact sometime when refactoring. JRA.
1420 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1421 if (state == NULL) {
1422 smbd_server_connection_terminate(req->sconn,
1423 nt_errstr(NT_STATUS_NO_MEMORY));
1424 return;
1426 state->sconn = req->sconn;
1428 tf = state->buf + NBT_HDR_SIZE;
1429 tf_len = SMB2_TF_HDR_SIZE;
1431 hdr = tf + SMB2_TF_HDR_SIZE;
1432 body = hdr + SMB2_HDR_BODY;
1433 dyn = body + 8;
1435 if (req->do_encryption) {
1436 struct smbXsrv_session *x = req->session;
1438 nonce_high = x->nonce_high;
1439 nonce_low = x->nonce_low;
1441 x->nonce_low += 1;
1442 if (x->nonce_low == 0) {
1443 x->nonce_low += 1;
1444 x->nonce_high += 1;
1448 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1449 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1450 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1451 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1453 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1454 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1455 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1456 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1457 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1459 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1460 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1461 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1462 SBVAL(hdr, SMB2_HDR_PID, async_id);
1463 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1464 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1465 memcpy(hdr+SMB2_HDR_SIGNATURE,
1466 outhdr+SMB2_HDR_SIGNATURE, 16);
1468 SSVAL(body, 0x00, 0x08 + 1);
1470 SCVAL(body, 0x02, 0);
1471 SCVAL(body, 0x03, 0);
1472 SIVAL(body, 0x04, 0);
1473 /* Match W2K8R2... */
1474 SCVAL(dyn, 0x00, 0x21);
1476 state->vector[0].iov_base = (void *)state->buf;
1477 state->vector[0].iov_len = NBT_HDR_SIZE;
1479 if (req->do_encryption) {
1480 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1481 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1482 } else {
1483 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1484 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1487 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1488 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1490 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1491 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1493 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1494 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1496 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1498 /* Ensure we correctly go through crediting. Grant
1499 the credits now, and zero credits on the final
1500 response. */
1501 smb2_set_operation_credit(req->sconn,
1502 SMBD_SMB2_IN_HDR_IOV(req),
1503 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1505 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1507 if (DEBUGLVL(10)) {
1508 int i;
1510 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1511 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1512 (unsigned int)i,
1513 (unsigned int)ARRAY_SIZE(state->vector),
1514 (unsigned int)state->vector[i].iov_len);
1518 if (req->do_encryption) {
1519 struct smbXsrv_session *x = req->session;
1520 struct smbXsrv_connection *conn = x->connection;
1521 DATA_BLOB encryption_key = x->global->encryption_key;
1523 status = smb2_signing_encrypt_pdu(encryption_key,
1524 conn->protocol,
1525 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1526 SMBD_SMB2_NUM_IOV_PER_REQ);
1527 if (!NT_STATUS_IS_OK(status)) {
1528 smbd_server_connection_terminate(req->sconn,
1529 nt_errstr(status));
1530 return;
1532 } else if (req->do_signing) {
1533 struct smbXsrv_session *x = req->session;
1534 struct smbXsrv_connection *conn = x->connection;
1535 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1537 status = smb2_signing_sign_pdu(signing_key,
1538 conn->protocol,
1539 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1540 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1541 if (!NT_STATUS_IS_OK(status)) {
1542 smbd_server_connection_terminate(req->sconn,
1543 nt_errstr(status));
1544 return;
1548 state->queue_entry.mem_ctx = state;
1549 state->queue_entry.vector = state->vector;
1550 state->queue_entry.count = ARRAY_SIZE(state->vector);
1551 DLIST_ADD_END(sconn->smb2.send_queue, &state->queue_entry, NULL);
1552 sconn->smb2.send_queue_len++;
1554 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
1555 if (!NT_STATUS_IS_OK(status)) {
1556 smbd_server_connection_terminate(sconn,
1557 nt_errstr(status));
1558 return;
1562 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1564 struct smbd_server_connection *sconn = req->sconn;
1565 struct smbd_smb2_request *cur;
1566 const uint8_t *inhdr;
1567 uint32_t flags;
1568 uint64_t search_message_id;
1569 uint64_t search_async_id;
1570 uint64_t found_id;
1572 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1574 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1575 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1576 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1579 * we don't need the request anymore
1580 * cancel requests never have a response
1582 DLIST_REMOVE(req->sconn->smb2.requests, req);
1583 TALLOC_FREE(req);
1585 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1586 const uint8_t *outhdr;
1587 uint64_t message_id;
1588 uint64_t async_id;
1590 if (cur->compound_related) {
1592 * Never cancel anything in a compound request.
1593 * Way too hard to deal with the result.
1595 continue;
1598 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1600 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1601 async_id = BVAL(outhdr, SMB2_HDR_PID);
1603 if (flags & SMB2_HDR_FLAG_ASYNC) {
1604 if (search_async_id == async_id) {
1605 found_id = async_id;
1606 break;
1608 } else {
1609 if (search_message_id == message_id) {
1610 found_id = message_id;
1611 break;
1616 if (cur && cur->subreq) {
1617 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1618 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1619 "cancel opcode[%s] mid %llu\n",
1620 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1621 (unsigned long long)found_id ));
1622 tevent_req_cancel(cur->subreq);
1625 return NT_STATUS_OK;
1628 /*************************************************************
1629 Ensure an incoming tid is a valid one for us to access.
1630 Change to the associated uid credentials and chdir to the
1631 valid tid directory.
1632 *************************************************************/
1634 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1636 const uint8_t *inhdr;
1637 uint32_t in_flags;
1638 uint32_t in_tid;
1639 struct smbXsrv_tcon *tcon;
1640 NTSTATUS status;
1641 NTTIME now = timeval_to_nttime(&req->request_time);
1643 req->tcon = NULL;
1645 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1647 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1648 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1650 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1651 in_tid = req->last_tid;
1654 req->last_tid = 0;
1656 status = smb2srv_tcon_lookup(req->session,
1657 in_tid, now, &tcon);
1658 if (!NT_STATUS_IS_OK(status)) {
1659 return status;
1662 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1663 return NT_STATUS_ACCESS_DENIED;
1666 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1667 if (!set_current_service(tcon->compat, 0, true)) {
1668 return NT_STATUS_ACCESS_DENIED;
1671 req->tcon = tcon;
1672 req->last_tid = in_tid;
1674 return NT_STATUS_OK;
1677 /*************************************************************
1678 Ensure an incoming session_id is a valid one for us to access.
1679 *************************************************************/
1681 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1683 const uint8_t *inhdr;
1684 uint32_t in_flags;
1685 uint16_t in_opcode;
1686 uint64_t in_session_id;
1687 struct smbXsrv_session *session = NULL;
1688 struct auth_session_info *session_info;
1689 NTSTATUS status;
1690 NTTIME now = timeval_to_nttime(&req->request_time);
1692 req->session = NULL;
1693 req->tcon = NULL;
1695 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1697 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1698 in_opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1699 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1701 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1702 in_session_id = req->last_session_id;
1705 req->last_session_id = 0;
1707 /* lookup an existing session */
1708 status = smb2srv_session_lookup(req->sconn->conn,
1709 in_session_id, now,
1710 &session);
1711 if (session) {
1712 req->session = session;
1713 req->last_session_id = in_session_id;
1715 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1716 switch (in_opcode) {
1717 case SMB2_OP_SESSSETUP:
1718 status = NT_STATUS_OK;
1719 break;
1720 default:
1721 break;
1724 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1725 switch (in_opcode) {
1726 case SMB2_OP_TCON:
1727 case SMB2_OP_CREATE:
1728 case SMB2_OP_GETINFO:
1729 case SMB2_OP_SETINFO:
1730 return NT_STATUS_INVALID_HANDLE;
1731 default:
1733 * Notice the check for
1734 * (session_info == NULL)
1735 * below.
1737 status = NT_STATUS_OK;
1738 break;
1741 if (!NT_STATUS_IS_OK(status)) {
1742 return status;
1745 session_info = session->global->auth_session_info;
1746 if (session_info == NULL) {
1747 return NT_STATUS_INVALID_HANDLE;
1750 if (in_session_id != req->sconn->conn->last_session_id) {
1751 req->sconn->conn->last_session_id = in_session_id;
1752 set_current_user_info(session_info->unix_info->sanitized_username,
1753 session_info->unix_info->unix_name,
1754 session_info->info->domain_name);
1757 return NT_STATUS_OK;
1760 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1761 uint32_t data_length)
1763 uint16_t needed_charge;
1764 uint16_t credit_charge = 1;
1765 const uint8_t *inhdr;
1767 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1769 if (req->sconn->smb2.supports_multicredit) {
1770 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1771 credit_charge = MAX(credit_charge, 1);
1774 needed_charge = (data_length - 1)/ 65536 + 1;
1776 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1777 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1778 credit_charge, needed_charge));
1780 if (needed_charge > credit_charge) {
1781 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1782 credit_charge, needed_charge));
1783 return NT_STATUS_INVALID_PARAMETER;
1786 return NT_STATUS_OK;
1789 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1790 size_t expected_body_size)
1792 struct iovec *inhdr_v;
1793 const uint8_t *inhdr;
1794 uint16_t opcode;
1795 const uint8_t *inbody;
1796 size_t body_size;
1797 size_t min_dyn_size = expected_body_size & 0x00000001;
1798 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1801 * The following should be checked already.
1803 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1804 return NT_STATUS_INTERNAL_ERROR;
1806 if (req->current_idx > max_idx) {
1807 return NT_STATUS_INTERNAL_ERROR;
1810 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1811 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1812 return NT_STATUS_INTERNAL_ERROR;
1814 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1815 return NT_STATUS_INTERNAL_ERROR;
1818 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1819 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1821 switch (opcode) {
1822 case SMB2_OP_IOCTL:
1823 case SMB2_OP_GETINFO:
1824 min_dyn_size = 0;
1825 break;
1829 * Now check the expected body size,
1830 * where the last byte might be in the
1831 * dynamic section..
1833 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1834 return NT_STATUS_INVALID_PARAMETER;
1836 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1837 return NT_STATUS_INVALID_PARAMETER;
1840 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1842 body_size = SVAL(inbody, 0x00);
1843 if (body_size != expected_body_size) {
1844 return NT_STATUS_INVALID_PARAMETER;
1847 return NT_STATUS_OK;
1850 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1852 struct smbXsrv_connection *conn = req->sconn->conn;
1853 const struct smbd_smb2_dispatch_table *call = NULL;
1854 const struct iovec *intf_v = SMBD_SMB2_IN_TF_IOV(req);
1855 const uint8_t *inhdr;
1856 uint16_t opcode;
1857 uint32_t flags;
1858 uint64_t mid;
1859 NTSTATUS status;
1860 NTSTATUS session_status;
1861 uint32_t allowed_flags;
1862 NTSTATUS return_value;
1863 struct smbXsrv_session *x = NULL;
1864 bool signing_required = false;
1865 bool encryption_required = false;
1867 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1869 /* TODO: verify more things */
1871 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1872 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1873 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1874 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1875 smb2_opcode_name(opcode),
1876 (unsigned long long)mid));
1878 if (conn->protocol >= PROTOCOL_SMB2_02) {
1880 * once the protocol is negotiated
1881 * SMB2_OP_NEGPROT is not allowed anymore
1883 if (opcode == SMB2_OP_NEGPROT) {
1884 /* drop the connection */
1885 return NT_STATUS_INVALID_PARAMETER;
1887 } else {
1889 * if the protocol is not negotiated yet
1890 * only SMB2_OP_NEGPROT is allowed.
1892 if (opcode != SMB2_OP_NEGPROT) {
1893 /* drop the connection */
1894 return NT_STATUS_INVALID_PARAMETER;
1899 * Check if the client provided a valid session id,
1900 * if so smbd_smb2_request_check_session() calls
1901 * set_current_user_info().
1903 * As some command don't require a valid session id
1904 * we defer the check of the session_status
1906 session_status = smbd_smb2_request_check_session(req);
1907 x = req->session;
1908 if (x != NULL) {
1909 signing_required = x->global->signing_required;
1910 encryption_required = x->global->encryption_required;
1913 req->do_signing = false;
1914 req->do_encryption = false;
1915 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
1916 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
1917 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
1919 if (x != NULL && x->global->session_wire_id != tf_session_id) {
1920 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1921 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
1922 (unsigned long long)x->global->session_wire_id,
1923 (unsigned long long)tf_session_id));
1925 * TODO: windows allows this...
1926 * should we drop the connection?
1928 * For now we just return ACCESS_DENIED
1929 * (Windows clients never trigger this)
1930 * and wait for an update of [MS-SMB2].
1932 return smbd_smb2_request_error(req,
1933 NT_STATUS_ACCESS_DENIED);
1936 req->do_encryption = true;
1939 if (encryption_required && !req->do_encryption) {
1940 return smbd_smb2_request_error(req,
1941 NT_STATUS_ACCESS_DENIED);
1944 call = smbd_smb2_call(opcode);
1945 if (call == NULL) {
1946 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1949 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1950 SMB2_HDR_FLAG_SIGNED |
1951 SMB2_HDR_FLAG_DFS;
1952 if (opcode == SMB2_OP_CANCEL) {
1953 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1955 if ((flags & ~allowed_flags) != 0) {
1956 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1959 if (flags & SMB2_HDR_FLAG_CHAINED) {
1961 * This check is mostly for giving the correct error code
1962 * for compounded requests.
1964 if (!NT_STATUS_IS_OK(session_status)) {
1965 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1967 } else {
1968 req->compat_chain_fsp = NULL;
1971 if (req->do_encryption) {
1972 signing_required = false;
1973 } else if (flags & SMB2_HDR_FLAG_SIGNED) {
1974 DATA_BLOB signing_key;
1976 if (x == NULL) {
1977 return smbd_smb2_request_error(
1978 req, NT_STATUS_ACCESS_DENIED);
1981 signing_key = x->global->channels[0].signing_key;
1984 * If we have a signing key, we should
1985 * sign the response
1987 if (signing_key.length > 0) {
1988 req->do_signing = true;
1991 status = smb2_signing_check_pdu(signing_key,
1992 conn->protocol,
1993 SMBD_SMB2_IN_HDR_IOV(req),
1994 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1995 if (!NT_STATUS_IS_OK(status)) {
1996 return smbd_smb2_request_error(req, status);
2000 * Now that we know the request was correctly signed
2001 * we have to sign the response too.
2003 req->do_signing = true;
2005 if (!NT_STATUS_IS_OK(session_status)) {
2006 return smbd_smb2_request_error(req, session_status);
2008 } else if (opcode == SMB2_OP_CANCEL) {
2009 /* Cancel requests are allowed to skip the signing */
2010 } else if (signing_required) {
2012 * If signing is required we try to sign
2013 * a possible error response
2015 req->do_signing = true;
2016 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2019 if (flags & SMB2_HDR_FLAG_CHAINED) {
2020 req->compound_related = true;
2023 if (call->need_session) {
2024 if (!NT_STATUS_IS_OK(session_status)) {
2025 return smbd_smb2_request_error(req, session_status);
2029 if (call->need_tcon) {
2030 SMB_ASSERT(call->need_session);
2033 * This call needs to be run as user.
2035 * smbd_smb2_request_check_tcon()
2036 * calls change_to_user() on success.
2038 status = smbd_smb2_request_check_tcon(req);
2039 if (!NT_STATUS_IS_OK(status)) {
2040 return smbd_smb2_request_error(req, status);
2042 if (req->tcon->global->encryption_required) {
2043 encryption_required = true;
2045 if (encryption_required && !req->do_encryption) {
2046 return smbd_smb2_request_error(req,
2047 NT_STATUS_ACCESS_DENIED);
2051 if (call->fileid_ofs != 0) {
2052 size_t needed = call->fileid_ofs + 16;
2053 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2054 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2055 uint64_t file_id_persistent;
2056 uint64_t file_id_volatile;
2057 struct files_struct *fsp;
2059 SMB_ASSERT(call->need_tcon);
2061 if (needed > body_size) {
2062 return smbd_smb2_request_error(req,
2063 NT_STATUS_INVALID_PARAMETER);
2066 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2067 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2069 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2070 if (fsp == NULL) {
2071 if (!call->allow_invalid_fileid) {
2072 return smbd_smb2_request_error(req,
2073 NT_STATUS_FILE_CLOSED);
2076 if (file_id_persistent != UINT64_MAX) {
2077 return smbd_smb2_request_error(req,
2078 NT_STATUS_FILE_CLOSED);
2080 if (file_id_volatile != UINT64_MAX) {
2081 return smbd_smb2_request_error(req,
2082 NT_STATUS_FILE_CLOSED);
2087 if (call->as_root) {
2088 SMB_ASSERT(call->fileid_ofs == 0);
2089 /* This call needs to be run as root */
2090 change_to_root_user();
2091 } else {
2092 SMB_ASSERT(call->need_tcon);
2095 switch (opcode) {
2096 case SMB2_OP_NEGPROT:
2098 START_PROFILE(smb2_negprot);
2099 return_value = smbd_smb2_request_process_negprot(req);
2100 END_PROFILE(smb2_negprot);
2102 break;
2104 case SMB2_OP_SESSSETUP:
2106 START_PROFILE(smb2_sesssetup);
2107 return_value = smbd_smb2_request_process_sesssetup(req);
2108 END_PROFILE(smb2_sesssetup);
2110 break;
2112 case SMB2_OP_LOGOFF:
2114 START_PROFILE(smb2_logoff);
2115 return_value = smbd_smb2_request_process_logoff(req);
2116 END_PROFILE(smb2_logoff);
2118 break;
2120 case SMB2_OP_TCON:
2122 START_PROFILE(smb2_tcon);
2123 return_value = smbd_smb2_request_process_tcon(req);
2124 END_PROFILE(smb2_tcon);
2126 break;
2128 case SMB2_OP_TDIS:
2130 START_PROFILE(smb2_tdis);
2131 return_value = smbd_smb2_request_process_tdis(req);
2132 END_PROFILE(smb2_tdis);
2134 break;
2136 case SMB2_OP_CREATE:
2138 START_PROFILE(smb2_create);
2139 return_value = smbd_smb2_request_process_create(req);
2140 END_PROFILE(smb2_create);
2142 break;
2144 case SMB2_OP_CLOSE:
2146 START_PROFILE(smb2_close);
2147 return_value = smbd_smb2_request_process_close(req);
2148 END_PROFILE(smb2_close);
2150 break;
2152 case SMB2_OP_FLUSH:
2154 START_PROFILE(smb2_flush);
2155 return_value = smbd_smb2_request_process_flush(req);
2156 END_PROFILE(smb2_flush);
2158 break;
2160 case SMB2_OP_READ:
2162 START_PROFILE(smb2_read);
2163 return_value = smbd_smb2_request_process_read(req);
2164 END_PROFILE(smb2_read);
2166 break;
2168 case SMB2_OP_WRITE:
2170 START_PROFILE(smb2_write);
2171 return_value = smbd_smb2_request_process_write(req);
2172 END_PROFILE(smb2_write);
2174 break;
2176 case SMB2_OP_LOCK:
2178 START_PROFILE(smb2_lock);
2179 return_value = smbd_smb2_request_process_lock(req);
2180 END_PROFILE(smb2_lock);
2182 break;
2184 case SMB2_OP_IOCTL:
2186 START_PROFILE(smb2_ioctl);
2187 return_value = smbd_smb2_request_process_ioctl(req);
2188 END_PROFILE(smb2_ioctl);
2190 break;
2192 case SMB2_OP_CANCEL:
2194 START_PROFILE(smb2_cancel);
2195 return_value = smbd_smb2_request_process_cancel(req);
2196 END_PROFILE(smb2_cancel);
2198 break;
2200 case SMB2_OP_KEEPALIVE:
2202 START_PROFILE(smb2_keepalive);
2203 return_value = smbd_smb2_request_process_keepalive(req);
2204 END_PROFILE(smb2_keepalive);
2206 break;
2208 case SMB2_OP_FIND:
2210 START_PROFILE(smb2_find);
2211 return_value = smbd_smb2_request_process_find(req);
2212 END_PROFILE(smb2_find);
2214 break;
2216 case SMB2_OP_NOTIFY:
2218 START_PROFILE(smb2_notify);
2219 return_value = smbd_smb2_request_process_notify(req);
2220 END_PROFILE(smb2_notify);
2222 break;
2224 case SMB2_OP_GETINFO:
2226 START_PROFILE(smb2_getinfo);
2227 return_value = smbd_smb2_request_process_getinfo(req);
2228 END_PROFILE(smb2_getinfo);
2230 break;
2232 case SMB2_OP_SETINFO:
2234 START_PROFILE(smb2_setinfo);
2235 return_value = smbd_smb2_request_process_setinfo(req);
2236 END_PROFILE(smb2_setinfo);
2238 break;
2240 case SMB2_OP_BREAK:
2242 START_PROFILE(smb2_break);
2243 return_value = smbd_smb2_request_process_break(req);
2244 END_PROFILE(smb2_break);
2246 break;
2248 default:
2249 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2250 break;
2252 return return_value;
2255 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2257 struct smbd_server_connection *sconn = req->sconn;
2258 struct smbXsrv_connection *conn = req->sconn->conn;
2259 int first_idx = 1;
2260 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2261 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2262 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2263 NTSTATUS status;
2265 req->subreq = NULL;
2266 TALLOC_FREE(req->async_te);
2268 if (req->do_encryption &&
2269 (firsttf->iov_len == 0) &&
2270 (req->first_key.length == 0) &&
2271 (req->session != NULL) &&
2272 (req->session->global->encryption_key.length != 0))
2274 DATA_BLOB encryption_key = req->session->global->encryption_key;
2275 uint8_t *tf;
2276 uint64_t session_id = req->session->global->session_wire_id;
2277 struct smbXsrv_session *x = req->session;
2278 uint64_t nonce_high;
2279 uint64_t nonce_low;
2281 nonce_high = x->nonce_high;
2282 nonce_low = x->nonce_low;
2284 x->nonce_low += 1;
2285 if (x->nonce_low == 0) {
2286 x->nonce_low += 1;
2287 x->nonce_high += 1;
2291 * We need to place the SMB2_TRANSFORM header before the
2292 * first SMB2 header
2296 * we need to remember the encryption key
2297 * and defer the signing/encryption until
2298 * we are sure that we do not change
2299 * the header again.
2301 req->first_key = data_blob_dup_talloc(req, encryption_key);
2302 if (req->first_key.data == NULL) {
2303 return NT_STATUS_NO_MEMORY;
2306 tf = talloc_zero_array(req->out.vector, uint8_t,
2307 SMB2_TF_HDR_SIZE);
2308 if (tf == NULL) {
2309 return NT_STATUS_NO_MEMORY;
2312 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2313 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2314 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2315 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2317 firsttf->iov_base = (void *)tf;
2318 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2321 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2322 (req->last_key.length > 0) &&
2323 (firsttf->iov_len == 0))
2325 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2326 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2329 * As we are sure the header of the last request in the
2330 * compound chain will not change, we can to sign here
2331 * with the last signing key we remembered.
2333 status = smb2_signing_sign_pdu(req->last_key,
2334 conn->protocol,
2335 lasthdr,
2336 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2337 if (!NT_STATUS_IS_OK(status)) {
2338 return status;
2341 data_blob_clear_free(&req->last_key);
2343 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2345 if (req->current_idx < req->out.vector_count) {
2347 * We must process the remaining compound
2348 * SMB2 requests before any new incoming SMB2
2349 * requests. This is because incoming SMB2
2350 * requests may include a cancel for a
2351 * compound request we haven't processed
2352 * yet.
2354 struct tevent_immediate *im = tevent_create_immediate(req);
2355 if (!im) {
2356 return NT_STATUS_NO_MEMORY;
2359 if (req->do_signing && firsttf->iov_len == 0) {
2360 struct smbXsrv_session *x = req->session;
2361 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2364 * we need to remember the signing key
2365 * and defer the signing until
2366 * we are sure that we do not change
2367 * the header again.
2369 req->last_key = data_blob_dup_talloc(req, signing_key);
2370 if (req->last_key.data == NULL) {
2371 return NT_STATUS_NO_MEMORY;
2375 tevent_schedule_immediate(im,
2376 req->sconn->ev_ctx,
2377 smbd_smb2_request_dispatch_immediate,
2378 req);
2379 return NT_STATUS_OK;
2382 if (req->compound_related) {
2383 req->compound_related = false;
2386 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2388 /* Set credit for these operations (zero credits if this
2389 is a final reply for an async operation). */
2390 smb2_calculate_credits(req, req);
2393 * now check if we need to sign the current response
2395 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2396 status = smb2_signing_encrypt_pdu(req->first_key,
2397 conn->protocol,
2398 firsttf,
2399 req->out.vector_count - first_idx);
2400 if (!NT_STATUS_IS_OK(status)) {
2401 return status;
2403 } else if (req->do_signing) {
2404 struct smbXsrv_session *x = req->session;
2405 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2407 status = smb2_signing_sign_pdu(signing_key,
2408 conn->protocol,
2409 outhdr,
2410 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2411 if (!NT_STATUS_IS_OK(status)) {
2412 return status;
2415 data_blob_clear_free(&req->first_key);
2417 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2418 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2419 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2420 /* Dynamic part is NULL. Chop it off,
2421 We're going to send it via sendfile. */
2422 req->out.vector_count -= 1;
2426 * We're done with this request -
2427 * move it off the "being processed" queue.
2429 DLIST_REMOVE(req->sconn->smb2.requests, req);
2431 req->queue_entry.mem_ctx = req;
2432 req->queue_entry.vector = req->out.vector;
2433 req->queue_entry.count = req->out.vector_count;
2434 DLIST_ADD_END(req->sconn->smb2.send_queue, &req->queue_entry, NULL);
2435 req->sconn->smb2.send_queue_len++;
2437 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
2438 if (!NT_STATUS_IS_OK(status)) {
2439 return status;
2442 return NT_STATUS_OK;
2445 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2447 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2448 struct tevent_immediate *im,
2449 void *private_data)
2451 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2452 struct smbd_smb2_request);
2453 struct smbd_server_connection *sconn = req->sconn;
2454 NTSTATUS status;
2456 TALLOC_FREE(im);
2458 if (DEBUGLEVEL >= 10) {
2459 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2460 req->current_idx, req->in.vector_count));
2461 print_req_vectors(req);
2464 status = smbd_smb2_request_dispatch(req);
2465 if (!NT_STATUS_IS_OK(status)) {
2466 smbd_server_connection_terminate(sconn, nt_errstr(status));
2467 return;
2470 status = smbd_smb2_request_next_incoming(sconn);
2471 if (!NT_STATUS_IS_OK(status)) {
2472 smbd_server_connection_terminate(sconn, nt_errstr(status));
2473 return;
2477 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2478 NTSTATUS status,
2479 DATA_BLOB body, DATA_BLOB *dyn,
2480 const char *location)
2482 uint8_t *outhdr;
2483 struct iovec *outbody_v;
2484 struct iovec *outdyn_v;
2485 uint32_t next_command_ofs;
2487 DEBUG(10,("smbd_smb2_request_done_ex: "
2488 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2489 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2490 dyn ? "yes": "no",
2491 (unsigned int)(dyn ? dyn->length : 0),
2492 location));
2494 if (body.length < 2) {
2495 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2498 if ((body.length % 2) != 0) {
2499 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2502 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2503 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2504 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2506 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2507 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2509 outbody_v->iov_base = (void *)body.data;
2510 outbody_v->iov_len = body.length;
2512 if (dyn) {
2513 outdyn_v->iov_base = (void *)dyn->data;
2514 outdyn_v->iov_len = dyn->length;
2515 } else {
2516 outdyn_v->iov_base = NULL;
2517 outdyn_v->iov_len = 0;
2520 /* see if we need to recalculate the offset to the next response */
2521 if (next_command_ofs > 0) {
2522 next_command_ofs = SMB2_HDR_BODY;
2523 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2524 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2527 if ((next_command_ofs % 8) != 0) {
2528 size_t pad_size = 8 - (next_command_ofs % 8);
2529 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2531 * if the dyn buffer is empty
2532 * we can use it to add padding
2534 uint8_t *pad;
2536 pad = talloc_zero_array(req->out.vector,
2537 uint8_t, pad_size);
2538 if (pad == NULL) {
2539 return smbd_smb2_request_error(req,
2540 NT_STATUS_NO_MEMORY);
2543 outdyn_v->iov_base = (void *)pad;
2544 outdyn_v->iov_len = pad_size;
2545 } else {
2547 * For now we copy the dynamic buffer
2548 * and add the padding to the new buffer
2550 size_t old_size;
2551 uint8_t *old_dyn;
2552 size_t new_size;
2553 uint8_t *new_dyn;
2555 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2556 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2558 new_size = old_size + pad_size;
2559 new_dyn = talloc_zero_array(req->out.vector,
2560 uint8_t, new_size);
2561 if (new_dyn == NULL) {
2562 return smbd_smb2_request_error(req,
2563 NT_STATUS_NO_MEMORY);
2566 memcpy(new_dyn, old_dyn, old_size);
2567 memset(new_dyn + old_size, 0, pad_size);
2569 outdyn_v->iov_base = (void *)new_dyn;
2570 outdyn_v->iov_len = new_size;
2572 next_command_ofs += pad_size;
2575 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2577 return smbd_smb2_request_reply(req);
2580 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2581 NTSTATUS status,
2582 DATA_BLOB *info,
2583 const char *location)
2585 DATA_BLOB body;
2586 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2587 size_t unread_bytes = smbd_smb2_unread_bytes(req);
2589 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2590 req->current_idx, nt_errstr(status), info ? " +info" : "",
2591 location));
2593 if (unread_bytes) {
2594 /* Recvfile error. Drain incoming socket. */
2595 size_t ret;
2597 errno = 0;
2598 ret = drain_socket(req->sconn->sock, unread_bytes);
2599 if (ret != unread_bytes) {
2600 NTSTATUS error;
2602 if (errno == 0) {
2603 error = NT_STATUS_IO_DEVICE_ERROR;
2604 } else {
2605 error = map_nt_error_from_unix_common(errno);
2608 DEBUG(2, ("Failed to drain %u bytes from SMB2 socket: "
2609 "ret[%u] errno[%d] => %s\n",
2610 (unsigned)unread_bytes,
2611 (unsigned)ret, errno, nt_errstr(error)));
2612 return error;
2616 body.data = outhdr + SMB2_HDR_BODY;
2617 body.length = 8;
2618 SSVAL(body.data, 0, 9);
2620 if (info) {
2621 SIVAL(body.data, 0x04, info->length);
2622 } else {
2623 /* Allocated size of req->out.vector[i].iov_base
2624 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2625 * 1 byte without having to do an alloc.
2627 info = talloc_zero_array(req->out.vector,
2628 DATA_BLOB,
2630 if (!info) {
2631 return NT_STATUS_NO_MEMORY;
2633 info->data = ((uint8_t *)outhdr) +
2634 OUTVEC_ALLOC_SIZE - 1;
2635 info->length = 1;
2636 SCVAL(info->data, 0, 0);
2640 * Note: Even if there is an error, continue to process the request.
2641 * per MS-SMB2.
2644 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2648 struct smbd_smb2_send_oplock_break_state {
2649 struct smbd_server_connection *sconn;
2650 struct smbd_smb2_send_queue queue_entry;
2651 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x18];
2652 struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ];
2655 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2656 struct smbXsrv_session *session,
2657 struct smbXsrv_tcon *tcon,
2658 struct smbXsrv_open *op,
2659 uint8_t oplock_level)
2661 struct smbd_smb2_send_oplock_break_state *state;
2662 struct smbXsrv_connection *conn = sconn->conn;
2663 uint8_t *tf;
2664 size_t tf_len;
2665 uint8_t *hdr;
2666 uint8_t *body;
2667 size_t body_len;
2668 uint8_t *dyn;
2669 size_t dyn_len;
2670 bool do_encryption = session->global->encryption_required;
2671 uint64_t nonce_high = 0;
2672 uint64_t nonce_low = 0;
2673 NTSTATUS status;
2675 if (tcon->global->encryption_required) {
2676 do_encryption = true;
2679 state = talloc_zero(sconn, struct smbd_smb2_send_oplock_break_state);
2680 if (state == NULL) {
2681 return NT_STATUS_NO_MEMORY;
2683 state->sconn = sconn;
2685 tf = state->buf + NBT_HDR_SIZE;
2686 tf_len = SMB2_TF_HDR_SIZE;
2687 hdr = tf + tf_len;
2688 body = hdr + SMB2_HDR_BODY;
2689 body_len = 0x18;
2690 dyn = body + body_len;
2691 dyn_len = 0;
2693 if (do_encryption) {
2694 nonce_high = session->nonce_high;
2695 nonce_low = session->nonce_low;
2697 session->nonce_low += 1;
2698 if (session->nonce_low == 0) {
2699 session->nonce_low += 1;
2700 session->nonce_high += 1;
2704 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2705 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2706 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2707 SBVAL(tf, SMB2_TF_SESSION_ID, session->global->session_wire_id);
2709 SIVAL(hdr, 0, SMB2_MAGIC);
2710 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2711 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2712 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2713 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2714 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2715 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2716 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2717 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2718 SIVAL(hdr, SMB2_HDR_PID, 0);
2719 SIVAL(hdr, SMB2_HDR_TID, 0);
2720 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2721 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2723 SSVAL(body, 0x00, body_len);
2725 SCVAL(body, 0x02, oplock_level);
2726 SCVAL(body, 0x03, 0); /* reserved */
2727 SIVAL(body, 0x04, 0); /* reserved */
2728 SBVAL(body, 0x08, op->global->open_persistent_id);
2729 SBVAL(body, 0x10, op->global->open_volatile_id);
2731 state->vector[0].iov_base = (void *)state->buf;
2732 state->vector[0].iov_len = NBT_HDR_SIZE;
2734 if (do_encryption) {
2735 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
2736 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
2737 } else {
2738 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
2739 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
2742 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
2743 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
2745 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
2746 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = body_len;
2748 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
2749 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_len;
2751 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
2753 if (do_encryption) {
2754 DATA_BLOB encryption_key = session->global->encryption_key;
2756 status = smb2_signing_encrypt_pdu(encryption_key,
2757 conn->protocol,
2758 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
2759 SMBD_SMB2_NUM_IOV_PER_REQ);
2760 if (!NT_STATUS_IS_OK(status)) {
2761 return status;
2765 state->queue_entry.mem_ctx = state;
2766 state->queue_entry.vector = state->vector;
2767 state->queue_entry.count = ARRAY_SIZE(state->vector);
2768 DLIST_ADD_END(state->sconn->smb2.send_queue, &state->queue_entry, NULL);
2769 state->sconn->smb2.send_queue_len++;
2771 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
2772 if (!NT_STATUS_IS_OK(status)) {
2773 return status;
2776 return NT_STATUS_OK;
2779 static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req)
2781 if (smb2_req->do_signing) {
2782 return 0;
2784 if (smb2_req->do_encryption) {
2785 return 0;
2787 return (size_t)lp_min_receive_file_size();
2790 static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
2792 uint32_t flags;
2794 if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
2795 /* Transform header. Cannot recvfile. */
2796 return false;
2798 if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
2799 /* Not SMB2. Normal error path will cope. */
2800 return false;
2802 if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
2803 /* Not SMB2. Normal error path will cope. */
2804 return false;
2806 if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
2807 /* Needs to be a WRITE. */
2808 return false;
2810 if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
2811 /* Chained. Cannot recvfile. */
2812 return false;
2814 flags = IVAL(state->pktbuf, SMB2_HDR_FLAGS);
2815 if (flags & SMB2_HDR_FLAG_CHAINED) {
2816 /* Chained. Cannot recvfile. */
2817 return false;
2819 if (flags & SMB2_HDR_FLAG_SIGNED) {
2820 /* Signed. Cannot recvfile. */
2821 return false;
2824 DEBUG(10,("Doing recvfile write len = %u\n",
2825 (unsigned int)(state->pktlen -
2826 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN)));
2828 return true;
2831 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2833 struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state;
2834 size_t max_send_queue_len;
2835 size_t cur_send_queue_len;
2837 if (!NT_STATUS_IS_OK(sconn->status)) {
2839 * we're not supposed to do any io
2841 return NT_STATUS_OK;
2844 if (state->req != NULL) {
2846 * if there is already a tstream_readv_pdu
2847 * pending, we are done.
2849 return NT_STATUS_OK;
2852 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2853 cur_send_queue_len = sconn->smb2.send_queue_len;
2855 if (cur_send_queue_len > max_send_queue_len) {
2857 * if we have a lot of requests to send,
2858 * we wait until they are on the wire until we
2859 * ask for the next request.
2861 return NT_STATUS_OK;
2864 /* ask for the next request */
2865 ZERO_STRUCTP(state);
2866 state->req = smbd_smb2_request_allocate(sconn);
2867 if (state->req == NULL) {
2868 return NT_STATUS_NO_MEMORY;
2870 state->req->sconn = sconn;
2871 state->min_recv_size = get_min_receive_file_size(state->req);
2873 TEVENT_FD_READABLE(sconn->smb2.fde);
2875 return NT_STATUS_OK;
2878 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2879 uint8_t *inbuf, size_t size)
2881 NTSTATUS status;
2882 struct smbd_smb2_request *req = NULL;
2884 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2885 (unsigned int)size));
2887 status = smbd_initialize_smb2(sconn);
2888 if (!NT_STATUS_IS_OK(status)) {
2889 smbd_server_connection_terminate(sconn, nt_errstr(status));
2890 return;
2893 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2894 if (!NT_STATUS_IS_OK(status)) {
2895 smbd_server_connection_terminate(sconn, nt_errstr(status));
2896 return;
2899 status = smbd_smb2_request_validate(req);
2900 if (!NT_STATUS_IS_OK(status)) {
2901 smbd_server_connection_terminate(sconn, nt_errstr(status));
2902 return;
2905 status = smbd_smb2_request_setup_out(req);
2906 if (!NT_STATUS_IS_OK(status)) {
2907 smbd_server_connection_terminate(sconn, nt_errstr(status));
2908 return;
2911 status = smbd_smb2_request_dispatch(req);
2912 if (!NT_STATUS_IS_OK(status)) {
2913 smbd_server_connection_terminate(sconn, nt_errstr(status));
2914 return;
2917 status = smbd_smb2_request_next_incoming(sconn);
2918 if (!NT_STATUS_IS_OK(status)) {
2919 smbd_server_connection_terminate(sconn, nt_errstr(status));
2920 return;
2923 sconn->num_requests++;
2926 static int socket_error_from_errno(int ret,
2927 int sys_errno,
2928 bool *retry)
2930 *retry = false;
2932 if (ret >= 0) {
2933 return 0;
2936 if (ret != -1) {
2937 return EIO;
2940 if (sys_errno == 0) {
2941 return EIO;
2944 if (sys_errno == EINTR) {
2945 *retry = true;
2946 return sys_errno;
2949 if (sys_errno == EINPROGRESS) {
2950 *retry = true;
2951 return sys_errno;
2954 if (sys_errno == EAGAIN) {
2955 *retry = true;
2956 return sys_errno;
2959 /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
2960 if (sys_errno == ENOMEM) {
2961 *retry = true;
2962 return sys_errno;
2965 #ifdef EWOULDBLOCK
2966 if (sys_errno == EWOULDBLOCK) {
2967 *retry = true;
2968 return sys_errno;
2970 #endif
2972 return sys_errno;
2975 static NTSTATUS smbd_smb2_flush_send_queue(struct smbd_server_connection *sconn)
2977 int ret;
2978 int err;
2979 bool retry;
2981 if (sconn->smb2.send_queue == NULL) {
2982 TEVENT_FD_NOT_WRITEABLE(sconn->smb2.fde);
2983 return NT_STATUS_OK;
2986 while (sconn->smb2.send_queue != NULL) {
2987 struct smbd_smb2_send_queue *e = sconn->smb2.send_queue;
2989 if (e->sendfile_header != NULL) {
2990 size_t size = 0;
2991 size_t i = 0;
2992 uint8_t *buf;
2994 for (i=0; i < e->count; i++) {
2995 size += e->vector[i].iov_len;
2998 buf = talloc_array(e->mem_ctx, uint8_t, size);
2999 if (buf == NULL) {
3000 return NT_STATUS_NO_MEMORY;
3003 size = 0;
3004 for (i=0; i < e->count; i++) {
3005 memcpy(buf+size,
3006 e->vector[i].iov_base,
3007 e->vector[i].iov_len);
3008 size += e->vector[i].iov_len;
3011 e->sendfile_header->data = buf;
3012 e->sendfile_header->length = size;
3013 e->count = 0;
3015 sconn->smb2.send_queue_len--;
3016 DLIST_REMOVE(sconn->smb2.send_queue, e);
3017 talloc_free(e->mem_ctx);
3018 continue;
3021 ret = writev(sconn->sock, e->vector, e->count);
3022 if (ret == 0) {
3023 /* propagate end of file */
3024 return NT_STATUS_INTERNAL_ERROR;
3026 err = socket_error_from_errno(ret, errno, &retry);
3027 if (retry) {
3028 /* retry later */
3029 TEVENT_FD_WRITEABLE(sconn->smb2.fde);
3030 return NT_STATUS_OK;
3032 if (err != 0) {
3033 return map_nt_error_from_unix_common(err);
3035 while (ret > 0) {
3036 if (ret < e->vector[0].iov_len) {
3037 uint8_t *base;
3038 base = (uint8_t *)e->vector[0].iov_base;
3039 base += ret;
3040 e->vector[0].iov_base = (void *)base;
3041 e->vector[0].iov_len -= ret;
3042 break;
3044 ret -= e->vector[0].iov_len;
3045 e->vector += 1;
3046 e->count -= 1;
3050 * there're maybe some empty vectors at the end
3051 * which we need to skip, otherwise we would get
3052 * ret == 0 from the readv() call and return EPIPE
3054 while (e->count > 0) {
3055 if (e->vector[0].iov_len > 0) {
3056 break;
3058 e->vector += 1;
3059 e->count -= 1;
3062 if (e->count > 0) {
3063 /* we have more to write */
3064 TEVENT_FD_WRITEABLE(sconn->smb2.fde);
3065 return NT_STATUS_OK;
3068 sconn->smb2.send_queue_len--;
3069 DLIST_REMOVE(sconn->smb2.send_queue, e);
3070 talloc_free(e->mem_ctx);
3073 return NT_STATUS_OK;
3076 static NTSTATUS smbd_smb2_io_handler(struct smbd_server_connection *sconn,
3077 uint16_t fde_flags)
3079 struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state;
3080 struct smbd_smb2_request *req = NULL;
3081 size_t min_recvfile_size = UINT32_MAX;
3082 int ret;
3083 int err;
3084 bool retry;
3085 NTSTATUS status;
3086 NTTIME now;
3088 if (!NT_STATUS_IS_OK(sconn->status)) {
3090 * we're not supposed to do any io
3092 TEVENT_FD_NOT_READABLE(sconn->smb2.fde);
3093 TEVENT_FD_NOT_WRITEABLE(sconn->smb2.fde);
3094 return NT_STATUS_OK;
3097 if (fde_flags & TEVENT_FD_WRITE) {
3098 status = smbd_smb2_flush_send_queue(sconn);
3099 if (!NT_STATUS_IS_OK(status)) {
3100 return status;
3104 if (!(fde_flags & TEVENT_FD_READ)) {
3105 return NT_STATUS_OK;
3108 if (state->req == NULL) {
3109 TEVENT_FD_NOT_READABLE(sconn->smb2.fde);
3110 return NT_STATUS_OK;
3113 again:
3114 if (!state->hdr.done) {
3115 state->hdr.done = true;
3117 state->vector.iov_base = (void *)state->hdr.nbt;
3118 state->vector.iov_len = NBT_HDR_SIZE;
3121 ret = readv(sconn->sock, &state->vector, 1);
3122 if (ret == 0) {
3123 /* propagate end of file */
3124 return NT_STATUS_END_OF_FILE;
3126 err = socket_error_from_errno(ret, errno, &retry);
3127 if (retry) {
3128 /* retry later */
3129 TEVENT_FD_READABLE(sconn->smb2.fde);
3130 return NT_STATUS_OK;
3132 if (err != 0) {
3133 return map_nt_error_from_unix_common(err);
3136 if (ret < state->vector.iov_len) {
3137 uint8_t *base;
3138 base = (uint8_t *)state->vector.iov_base;
3139 base += ret;
3140 state->vector.iov_base = (void *)base;
3141 state->vector.iov_len -= ret;
3142 /* we have more to read */
3143 TEVENT_FD_READABLE(sconn->smb2.fde);
3144 return NT_STATUS_OK;
3147 if (state->pktlen > 0) {
3148 if (state->doing_receivefile && !is_smb2_recvfile_write(state)) {
3150 * Not a possible receivefile write.
3151 * Read the rest of the data.
3153 state->doing_receivefile = false;
3154 state->vector.iov_base = (void *)(state->pktbuf +
3155 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
3156 state->vector.iov_len = (state->pktlen -
3157 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
3158 goto again;
3162 * Either this is a receivefile write so we've
3163 * done a short read, or if not we have all the data.
3165 goto got_full;
3169 * Now we analyze the NBT header
3171 state->pktlen = smb2_len(state->hdr.nbt);
3172 if (state->pktlen == 0) {
3173 goto got_full;
3176 state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen);
3177 if (state->pktbuf == NULL) {
3178 return NT_STATUS_NO_MEMORY;
3181 state->vector.iov_base = (void *)state->pktbuf;
3183 if (state->min_recv_size != 0) {
3184 min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3185 min_recvfile_size += state->min_recv_size;
3188 if (state->pktlen > min_recvfile_size) {
3190 * Might be a receivefile write. Read the SMB2 HEADER +
3191 * SMB2_WRITE header first. Set 'doing_receivefile'
3192 * as we're *attempting* receivefile write. If this
3193 * turns out not to be a SMB2_WRITE request or otherwise
3194 * not suitable then we'll just read the rest of the data
3195 * the next time this function is called.
3197 state->vector.iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3198 state->doing_receivefile = true;
3199 } else {
3200 state->vector.iov_len = state->pktlen;
3203 goto again;
3205 got_full:
3207 if (state->hdr.nbt[0] != 0x00) {
3208 DEBUG(1,("ignore NBT[0x%02X] msg\n",
3209 state->hdr.nbt[0]));
3211 req = state->req;
3212 ZERO_STRUCTP(state);
3213 state->req = req;
3214 state->min_recv_size = get_min_receive_file_size(state->req);
3215 req = NULL;
3216 goto again;
3219 req = state->req;
3220 state->req = NULL;
3222 req->request_time = timeval_current();
3223 now = timeval_to_nttime(&req->request_time);
3225 status = smbd_smb2_inbuf_parse_compound(req->sconn->conn,
3226 now,
3227 state->pktbuf,
3228 state->pktlen,
3229 req,
3230 &req->in.vector,
3231 &req->in.vector_count);
3232 if (!NT_STATUS_IS_OK(status)) {
3233 return status;
3236 if (state->doing_receivefile) {
3237 req->smb1req = talloc_zero(req, struct smb_request);
3238 if (req->smb1req == NULL) {
3239 return NT_STATUS_NO_MEMORY;
3241 req->smb1req->unread_bytes =
3242 state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3245 ZERO_STRUCTP(state);
3247 req->current_idx = 1;
3249 DEBUG(10,("smbd_smb2_request idx[%d] of %d vectors\n",
3250 req->current_idx, req->in.vector_count));
3252 status = smbd_smb2_request_validate(req);
3253 if (!NT_STATUS_IS_OK(status)) {
3254 return status;
3257 status = smbd_smb2_request_setup_out(req);
3258 if (!NT_STATUS_IS_OK(status)) {
3259 return status;
3262 status = smbd_smb2_request_dispatch(req);
3263 if (!NT_STATUS_IS_OK(status)) {
3264 return status;
3267 sconn->num_requests++;
3269 /* The timeout_processing function isn't run nearly
3270 often enough to implement 'max log size' without
3271 overrunning the size of the file by many megabytes.
3272 This is especially true if we are running at debug
3273 level 10. Checking every 50 SMB2s is a nice
3274 tradeoff of performance vs log file size overrun. */
3276 if ((sconn->num_requests % 50) == 0 &&
3277 need_to_check_log_size()) {
3278 change_to_root_user();
3279 check_log_size();
3282 status = smbd_smb2_request_next_incoming(sconn);
3283 if (!NT_STATUS_IS_OK(status)) {
3284 return status;
3287 return NT_STATUS_OK;
3290 static void smbd_smb2_connection_handler(struct tevent_context *ev,
3291 struct tevent_fd *fde,
3292 uint16_t flags,
3293 void *private_data)
3295 struct smbd_server_connection *sconn =
3296 talloc_get_type_abort(private_data,
3297 struct smbd_server_connection);
3298 NTSTATUS status;
3300 status = smbd_smb2_io_handler(sconn, flags);
3301 if (!NT_STATUS_IS_OK(status)) {
3302 smbd_server_connection_terminate(sconn, nt_errstr(status));
3303 return;